From ef3274137594065718896758cc3e92d72aad27a2 Mon Sep 17 00:00:00 2001 From: Nikita Poltorapavlo Date: Mon, 15 Jul 2024 16:38:47 +0300 Subject: [PATCH] RDKTV-31830 : split Secure Store in a separate plugin Reason for change: Separate plugin for separate functionality. Fixes the problem of FTA/IPC/Thunder thread pool. Test Procedure: None Risks: None Signed-off-by: Nikita Poltorapavlo --- .github/workflows/BuildThunder.sh | 2 +- ...Store-grpc.yml => L0-SecureStore-grpc.yml} | 12 +- .github/workflows/L0-SecureStore.yml | 55 ++++++ .github/workflows/L2-PersistentStore.yml | 6 +- ...Store-grpc.yml => L2-SecureStore-grpc.yml} | 12 +- .github/workflows/L2-SecureStore.yml | 40 ++++ CMakeLists.txt | 4 + PersistentStore/CMakeLists.txt | 35 ---- PersistentStore/Module.h | 2 - PersistentStore/PersistentStore.conf.in | 1 - PersistentStore/PersistentStore.config | 1 - PersistentStore/PersistentStore.cpp | 20 +- PersistentStore/PersistentStore.h | 2 - .../PersistentStoreImplementation.cpp | 12 -- .../PersistentStoreImplementation.h | 87 +++------ .../l0test/PersistentStoreTest.cpp | 137 ------------- SecureStore/CHANGELOG.md | 25 +++ SecureStore/CMakeLists.txt | 97 ++++++++++ SecureStore/Module.cpp | 22 +++ SecureStore/Module.h | 37 ++++ SecureStore/SecureStore.conf.in | 12 ++ SecureStore/SecureStore.config | 17 ++ SecureStore/SecureStore.cpp | 128 +++++++++++++ SecureStore/SecureStore.h | 144 ++++++++++++++ SecureStore/SecureStoreImplementation.cpp | 43 +++++ SecureStore/SecureStoreImplementation.h | 90 +++++++++ SecureStore/SecureStorePlugin.json | 10 + .../grpc/Store2.h | 0 .../grpc/l0test/CMakeLists.txt | 11 +- .../grpc/l0test/SecureStorageServiceMock.h | 0 .../grpc/l0test/Server.h | 0 .../grpc/l0test/Store2Test.cpp | 0 .../grpc/l2test/CMakeLists.txt | 11 +- .../grpc/l2test/StubTest.cpp | 0 .../grpc/secure_storage/secure_storage.proto | 0 SecureStore/l0test/CMakeLists.txt | 47 +++++ .../l0test/SecureStoreImplementationMock.h | 41 ++++ SecureStore/l0test/SecureStoreTest.cpp | 181 ++++++++++++++++++ SecureStore/l0test/ServiceMock.h | 60 ++++++ 39 files changed, 1101 insertions(+), 303 deletions(-) rename .github/workflows/{L0-PersistentStore-grpc.yml => L0-SecureStore-grpc.yml} (80%) create mode 100644 .github/workflows/L0-SecureStore.yml rename .github/workflows/{L2-PersistentStore-grpc.yml => L2-SecureStore-grpc.yml} (70%) create mode 100644 .github/workflows/L2-SecureStore.yml create mode 100644 SecureStore/CHANGELOG.md create mode 100644 SecureStore/CMakeLists.txt create mode 100644 SecureStore/Module.cpp create mode 100644 SecureStore/Module.h create mode 100644 SecureStore/SecureStore.conf.in create mode 100644 SecureStore/SecureStore.config create mode 100644 SecureStore/SecureStore.cpp create mode 100644 SecureStore/SecureStore.h create mode 100644 SecureStore/SecureStoreImplementation.cpp create mode 100644 SecureStore/SecureStoreImplementation.h create mode 100644 SecureStore/SecureStorePlugin.json rename {PersistentStore => SecureStore}/grpc/Store2.h (100%) rename {PersistentStore => SecureStore}/grpc/l0test/CMakeLists.txt (88%) rename {PersistentStore => SecureStore}/grpc/l0test/SecureStorageServiceMock.h (100%) rename {PersistentStore => SecureStore}/grpc/l0test/Server.h (100%) rename {PersistentStore => SecureStore}/grpc/l0test/Store2Test.cpp (100%) rename {PersistentStore => SecureStore}/grpc/l2test/CMakeLists.txt (87%) rename {PersistentStore => SecureStore}/grpc/l2test/StubTest.cpp (100%) rename {PersistentStore => SecureStore}/grpc/secure_storage/secure_storage.proto (100%) create mode 100644 SecureStore/l0test/CMakeLists.txt create mode 100644 SecureStore/l0test/SecureStoreImplementationMock.h create mode 100644 SecureStore/l0test/SecureStoreTest.cpp create mode 100644 SecureStore/l0test/ServiceMock.h diff --git a/.github/workflows/BuildThunder.sh b/.github/workflows/BuildThunder.sh index f6621cc266..ed68ca254d 100755 --- a/.github/workflows/BuildThunder.sh +++ b/.github/workflows/BuildThunder.sh @@ -39,7 +39,7 @@ cmake --build build/Thunder --target install ############################ # 4. Build ThunderInterfaces -git clone https://github.com/rdkcentral/ThunderInterfaces.git +git clone -b RDKTV-31830 https://github.com/npoltorapavlo/ThunderInterfaces.git cmake -G Ninja -S ThunderInterfaces -B build/ThunderInterfaces \ -DCMAKE_INSTALL_PREFIX="install" diff --git a/.github/workflows/L0-PersistentStore-grpc.yml b/.github/workflows/L0-SecureStore-grpc.yml similarity index 80% rename from .github/workflows/L0-PersistentStore-grpc.yml rename to .github/workflows/L0-SecureStore-grpc.yml index b58268a672..b4855ee049 100644 --- a/.github/workflows/L0-PersistentStore-grpc.yml +++ b/.github/workflows/L0-SecureStore-grpc.yml @@ -1,14 +1,14 @@ -name: L0-PersistentStore-grpc +name: L0-SecureStore-grpc on: push: paths: - - PersistentStore/** - - .github/workflows/*PersistentStore*.yml + - SecureStore/** + - .github/workflows/*SecureStore*.yml pull_request: paths: - - PersistentStore/** - - .github/workflows/*PersistentStore*.yml + - SecureStore/** + - .github/workflows/*SecureStore*.yml jobs: build: @@ -31,7 +31,7 @@ jobs: - name: Build working-directory: ${{github.workspace}} run: | - cmake -S ${GITHUB_REPOSITORY}/PersistentStore/grpc/l0test -B build/grpcl0test -DCMAKE_INSTALL_PREFIX="install" -DCMAKE_CXX_FLAGS="--coverage -Wall -Werror" + cmake -S ${GITHUB_REPOSITORY}/SecureStore/grpc/l0test -B build/grpcl0test -DCMAKE_INSTALL_PREFIX="install" -DCMAKE_CXX_FLAGS="--coverage -Wall -Werror" cmake --build build/grpcl0test --target install - name: Run diff --git a/.github/workflows/L0-SecureStore.yml b/.github/workflows/L0-SecureStore.yml new file mode 100644 index 0000000000..8f5c7167ce --- /dev/null +++ b/.github/workflows/L0-SecureStore.yml @@ -0,0 +1,55 @@ +name: L0-SecureStore + +on: + push: + paths: + - SecureStore/** + - .github/workflows/*SecureStore*.yml + pull_request: + paths: + - SecureStore/** + - .github/workflows/*SecureStore*.yml + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + path: ${{github.repository}} + + - name: Install valgrind, coverage, cmake + run: | + sudo apt update + sudo apt install -y valgrind lcov cmake + + - name: Build Thunder + working-directory: ${{github.workspace}} + run: sh +x ${GITHUB_REPOSITORY}/.github/workflows/BuildThunder.sh + + - name: Build + working-directory: ${{github.workspace}} + run: | + cmake -S ${GITHUB_REPOSITORY}/SecureStore/l0test -B build/securestorel0test -DCMAKE_INSTALL_PREFIX="install" -DCMAKE_CXX_FLAGS="--coverage -Wall -Werror" + cmake --build build/securestorel0test --target install + + - name: Run + working-directory: ${{github.workspace}} + run: PATH=${PWD}/install/bin:${PATH} LD_LIBRARY_PATH=${PWD}/install/lib:${LD_LIBRARY_PATH} valgrind --tool=memcheck --log-file=valgrind_log --leak-check=yes --show-reachable=yes --track-fds=yes --fair-sched=try securestorel0test + + - name: Generate coverage + working-directory: ${{github.workspace}} + run: | + lcov -c -o coverage.info -d build/securestorel0test + genhtml -o coverage coverage.info + + - name: Upload artifacts + if: ${{ !env.ACT }} + uses: actions/upload-artifact@v4 + with: + name: artifacts + path: | + coverage/ + valgrind_log + if-no-files-found: warn diff --git a/.github/workflows/L2-PersistentStore.yml b/.github/workflows/L2-PersistentStore.yml index 73b1b41762..fd21d9356f 100644 --- a/.github/workflows/L2-PersistentStore.yml +++ b/.github/workflows/L2-PersistentStore.yml @@ -19,10 +19,10 @@ jobs: with: path: ${{github.repository}} - - name: Install cmake, sqlite, protoc, grpc_cpp_plugin, grpc + - name: Install cmake, sqlite run: | sudo apt update - sudo apt install -y cmake libsqlite3-dev protobuf-compiler protobuf-compiler-grpc libgrpc++-dev + sudo apt install -y cmake libsqlite3-dev - name: Build Thunder working-directory: ${{github.workspace}} @@ -31,7 +31,7 @@ jobs: - name: Build working-directory: ${{github.workspace}} run: | - cmake -S ${GITHUB_REPOSITORY}/PersistentStore -B build/PersistentStore -DCMAKE_INSTALL_PREFIX="install" -DCMAKE_CXX_FLAGS="-Wall -Werror" -DPLUGIN_PERSISTENTSTORE_PATH="/tmp/persistentstore/l2test/test" -DPLUGIN_PERSISTENTSTORE_WITH_ACCOUNT_SCOPE=true -DPLUGIN_PERSISTENTSTORE_MODE=Local -DPLUGIN_PERSISTENTSTORE_URI=ss.eu.prod.developer.comcast.com:443 + cmake -S ${GITHUB_REPOSITORY}/PersistentStore -B build/PersistentStore -DCMAKE_INSTALL_PREFIX="install" -DCMAKE_CXX_FLAGS="-Wall -Werror" -DPLUGIN_PERSISTENTSTORE_PATH="/tmp/persistentstore/l2test/test" -DPLUGIN_PERSISTENTSTORE_MODE=Local cmake --build build/PersistentStore --target install # Usage: diff --git a/.github/workflows/L2-PersistentStore-grpc.yml b/.github/workflows/L2-SecureStore-grpc.yml similarity index 70% rename from .github/workflows/L2-PersistentStore-grpc.yml rename to .github/workflows/L2-SecureStore-grpc.yml index 6488f5ec99..68e5eecd9a 100644 --- a/.github/workflows/L2-PersistentStore-grpc.yml +++ b/.github/workflows/L2-SecureStore-grpc.yml @@ -1,14 +1,14 @@ -name: L2-PersistentStore-grpc +name: L2-SecureStore-grpc on: push: paths: - - PersistentStore/** - - .github/workflows/*PersistentStore*.yml + - SecureStore/** + - .github/workflows/*SecureStore*.yml pull_request: paths: - - PersistentStore/** - - .github/workflows/*PersistentStore*.yml + - SecureStore/** + - .github/workflows/*SecureStore*.yml jobs: build: @@ -27,7 +27,7 @@ jobs: - name: Build working-directory: ${{github.workspace}} run: | - cmake -S ${GITHUB_REPOSITORY}/PersistentStore/grpc/l2test -B build/grpcl2test -DCMAKE_INSTALL_PREFIX="install" -DCMAKE_CXX_FLAGS="-Wall -Werror" + cmake -S ${GITHUB_REPOSITORY}/SecureStore/grpc/l2test -B build/grpcl2test -DCMAKE_INSTALL_PREFIX="install" -DCMAKE_CXX_FLAGS="-Wall -Werror" cmake --build build/grpcl2test --target install # Usage: diff --git a/.github/workflows/L2-SecureStore.yml b/.github/workflows/L2-SecureStore.yml new file mode 100644 index 0000000000..5f6f34804c --- /dev/null +++ b/.github/workflows/L2-SecureStore.yml @@ -0,0 +1,40 @@ +name: L2-SecureStore + +on: + push: + paths: + - SecureStore/** + - .github/workflows/*SecureStore*.yml + pull_request: + paths: + - SecureStore/** + - .github/workflows/*SecureStore*.yml + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + path: ${{github.repository}} + + - name: Install cmake, protoc, grpc_cpp_plugin, grpc + run: | + sudo apt update + sudo apt install -y cmake protobuf-compiler protobuf-compiler-grpc libgrpc++-dev + + - name: Build Thunder + working-directory: ${{github.workspace}} + run: sh +x ${GITHUB_REPOSITORY}/.github/workflows/BuildThunder.sh + + - name: Build + working-directory: ${{github.workspace}} + run: | + cmake -S ${GITHUB_REPOSITORY}/SecureStore -B build/SecureStore -DCMAKE_INSTALL_PREFIX="install" -DCMAKE_CXX_FLAGS="-Wall -Werror" -DPLUGIN_SECURESTORE_MODE=Local -DPLUGIN_SECURESTORE_URI=ss.eu.prod.developer.comcast.com:443 + cmake --build build/SecureStore --target install + +# Usage: +# PATH=${PWD}/install/bin:${PATH} LD_LIBRARY_PATH=${PWD}/install/lib:${LD_LIBRARY_PATH} valgrind --tool=memcheck --log-file=valgrind_log --leak-check=yes --show-reachable=yes --track-fds=yes --fair-sched=try Thunder -f -c ${PWD}/install/etc/Thunder/config.json +# (to stop press q & enter) +# curl -d '{"jsonrpc":"2.0","id":0,"method":"org.rdk.SecureStore.setValue","params":{"namespace":"test","key":"key1","value":"1","ttl":100}}' http://localhost:55555/jsonrpc diff --git a/CMakeLists.txt b/CMakeLists.txt index 42bdfd13f8..a328577b36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -393,6 +393,10 @@ if (PLUGIN_RESOURCEMANAGER) add_subdirectory(ResourceManager) endif() +if(PLUGIN_SECURESTORE) + add_subdirectory(SecureStore) +endif() + if(WPEFRAMEWORK_CREATE_IPKG_TARGETS) set(CPACK_GENERATOR "DEB") set(CPACK_DEB_COMPONENT_INSTALL ON) diff --git a/PersistentStore/CMakeLists.txt b/PersistentStore/CMakeLists.txt index 3a19f4c1fb..73216a78ea 100644 --- a/PersistentStore/CMakeLists.txt +++ b/PersistentStore/CMakeLists.txt @@ -24,16 +24,13 @@ set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) set(CMAKE_CXX_STANDARD 11) set(PLUGIN_PERSISTENTSTORE_MODE "Off" CACHE STRING "Controls if the plugin should run in its own process, in process or remote") -set(PLUGIN_PERSISTENTSTORE_URI "" CACHE STRING "Account scope endpoint") set(PLUGIN_PERSISTENTSTORE_PATH "/opt/secure/persistent/rdkservicestore" CACHE STRING "Path") set(PLUGIN_PERSISTENTSTORE_LEGACYPATH "/opt/persistent/rdkservicestore" CACHE STRING "Previously used path") set(PLUGIN_PERSISTENTSTORE_KEY "" CACHE STRING "Encryption key") set(PLUGIN_PERSISTENTSTORE_MAXSIZE "1000000" CACHE STRING "For all text data, in bytes") set(PLUGIN_PERSISTENTSTORE_MAXVALUE "3000" CACHE STRING "For single text data, in bytes") set(PLUGIN_PERSISTENTSTORE_LIMIT "10000" CACHE STRING "Default for all text data in namespace, in bytes") -set(PLUGIN_PERSISTENTSTORE_TOKEN_COMMAND "" CACHE STRING "Shell command to get the service access token") set(PLUGIN_PERSISTENTSTORE_STARTUPORDER "" CACHE STRING "To configure startup order of PersistentStore plugin") -set(PLUGIN_PERSISTENTSTORE_WITH_ACCOUNT_SCOPE false CACHE BOOL "Enable account scope") add_library(${MODULE_NAME} SHARED PersistentStore.cpp @@ -48,14 +45,6 @@ target_link_libraries(${MODULE_NAME} PRIVATE ${NAMESPACE}Definitions::${NAMESPACE}Definitions ) -find_library(RFC_LIBRARIES NAMES rfcapi) -if (RFC_LIBRARIES) - find_path(RFC_INCLUDE_DIRS NAMES rfcapi.h REQUIRED) - target_include_directories(${MODULE_NAME} PRIVATE ${RFC_INCLUDE_DIRS}) - target_link_libraries(${MODULE_NAME} PRIVATE ${RFC_LIBRARIES}) - target_compile_definitions(${MODULE_NAME} PRIVATE WITH_RFC) -endif () - install(TARGETS ${MODULE_NAME} DESTINATION lib/${STORAGE_DIRECTORY}/plugins) @@ -83,30 +72,6 @@ if (IARMBUS_LIBRARIES) target_compile_definitions(${PLUGIN_IMPLEMENTATION} PRIVATE WITH_SYSMGR) endif () -if (PLUGIN_PERSISTENTSTORE_WITH_ACCOUNT_SCOPE) - find_package(Protobuf REQUIRED) - target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${Protobuf_LIBRARIES}) - - add_custom_target(protoc - ${Protobuf_PROTOC_EXECUTABLE} --cpp_out ${CMAKE_CURRENT_BINARY_DIR} -I ${CMAKE_CURRENT_SOURCE_DIR}/grpc/secure_storage ${CMAKE_CURRENT_SOURCE_DIR}/grpc/secure_storage/secure_storage.proto - ) - add_dependencies(${PLUGIN_IMPLEMENTATION} protoc) - - target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE grpc++) - find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin REQUIRED) - - add_custom_target(protoc-gen-grpc - ${Protobuf_PROTOC_EXECUTABLE} --grpc_out ${CMAKE_CURRENT_BINARY_DIR} --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN} -I ${CMAKE_CURRENT_SOURCE_DIR}/grpc/secure_storage ${CMAKE_CURRENT_SOURCE_DIR}/grpc/secure_storage/secure_storage.proto - ) - add_dependencies(${PLUGIN_IMPLEMENTATION} protoc-gen-grpc) - - set(PROTO_SRCS secure_storage.pb.cc secure_storage.grpc.pb.cc) - target_sources(${PLUGIN_IMPLEMENTATION} PRIVATE ${PROTO_SRCS}) - set_property(SOURCE ${PROTO_SRCS} PROPERTY GENERATED 1) - target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) - target_compile_definitions(${PLUGIN_IMPLEMENTATION} PRIVATE WITH_ACCOUNT_SCOPE) -endif () - install(TARGETS ${PLUGIN_IMPLEMENTATION} DESTINATION lib/${STORAGE_DIRECTORY}/plugins) diff --git a/PersistentStore/Module.h b/PersistentStore/Module.h index bce1d970a4..342536a741 100644 --- a/PersistentStore/Module.h +++ b/PersistentStore/Module.h @@ -29,13 +29,11 @@ #include #endif -#define URI_ENV "PERSISTENTSTORE_URI" #define PATH_ENV "PERSISTENTSTORE_PATH" #define MAXSIZE_ENV "PERSISTENTSTORE_MAXSIZE" #define MAXVALUE_ENV "PERSISTENTSTORE_MAXVALUE" #define LIMIT_ENV "PERSISTENTSTORE_LIMIT" #define IARM_INIT_NAME "Thunder_Plugins" -#define URI_RFC "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.PersistentStore.Uri" #undef EXTERNAL #define EXTERNAL diff --git a/PersistentStore/PersistentStore.conf.in b/PersistentStore/PersistentStore.conf.in index d5b5965460..22022868af 100644 --- a/PersistentStore/PersistentStore.conf.in +++ b/PersistentStore/PersistentStore.conf.in @@ -9,7 +9,6 @@ rootobject.add("mode", "@PLUGIN_PERSISTENTSTORE_MODE@") rootobject.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") configuration.add("root", rootobject) -configuration.add("uri", "@PLUGIN_PERSISTENTSTORE_URI@") configuration.add("path", "@PLUGIN_PERSISTENTSTORE_PATH@") configuration.add("legacypath", "@PLUGIN_PERSISTENTSTORE_LEGACYPATH@") configuration.add("key", "@PLUGIN_PERSISTENTSTORE_KEY@") diff --git a/PersistentStore/PersistentStore.config b/PersistentStore/PersistentStore.config index 3b6fde49f1..510372c4c0 100644 --- a/PersistentStore/PersistentStore.config +++ b/PersistentStore/PersistentStore.config @@ -12,7 +12,6 @@ map() kv(mode ${PLUGIN_PERSISTENTSTORE_MODE}) kv(locator lib${PLUGIN_IMPLEMENTATION}.so) end() - kv(uri ${PLUGIN_PERSISTENTSTORE_URI}) kv(path ${PLUGIN_PERSISTENTSTORE_PATH}) kv(legacypath ${PLUGIN_PERSISTENTSTORE_LEGACYPATH}) kv(key ${PLUGIN_PERSISTENTSTORE_KEY}) diff --git a/PersistentStore/PersistentStore.cpp b/PersistentStore/PersistentStore.cpp index f508217482..54a8446b15 100644 --- a/PersistentStore/PersistentStore.cpp +++ b/PersistentStore/PersistentStore.cpp @@ -19,9 +19,6 @@ #include "PersistentStore.h" #include -#ifdef WITH_RFC -#include "rfcapi.h" -#endif #define API_VERSION_NUMBER_MAJOR 1 #define API_VERSION_NUMBER_MINOR 0 @@ -83,21 +80,6 @@ namespace Plugin { } } - auto uri = _config.Uri.Value(); - -#ifdef WITH_RFC - RFC_ParamData_t rfcParam; - auto rfcStatus = getRFCParameter(nullptr, URI_RFC, &rfcParam); - if (rfcStatus == WDMP_SUCCESS) { - if (rfcParam.value[0]) { - uri = rfcParam.value; - } - } else { - TRACE(Trace::Error, (_T("%s rfc error %d"), __FUNCTION__, rfcStatus)); - } -#endif - - Core::SystemInfo::SetEnvironment(URI_ENV, uri); Core::SystemInfo::SetEnvironment(PATH_ENV, _config.Path.Value()); Core::SystemInfo::SetEnvironment(MAXSIZE_ENV, std::to_string(_config.MaxSize.Value())); Core::SystemInfo::SetEnvironment(MAXVALUE_ENV, std::to_string(_config.MaxValue.Value())); @@ -130,7 +112,7 @@ namespace Plugin { { ASSERT(_service == service); - SYSLOG(Logging::Shutdown, (string(_T("DTV::Deinitialize")))); + SYSLOG(Logging::Shutdown, (string(_T("PersistentStore::Deinitialize")))); _service->Unregister(&_notification); diff --git a/PersistentStore/PersistentStore.h b/PersistentStore/PersistentStore.h index 91c50655d2..f07008d7e0 100644 --- a/PersistentStore/PersistentStore.h +++ b/PersistentStore/PersistentStore.h @@ -42,7 +42,6 @@ namespace Plugin { , MaxValue(0) , Limit(0) { - Add(_T("uri"), &Uri); Add(_T("path"), &Path); Add(_T("legacypath"), &LegacyPath); Add(_T("key"), &Key); @@ -52,7 +51,6 @@ namespace Plugin { } public: - Core::JSON::String Uri; Core::JSON::String Path; Core::JSON::String LegacyPath; Core::JSON::String Key; diff --git a/PersistentStore/PersistentStoreImplementation.cpp b/PersistentStore/PersistentStoreImplementation.cpp index f57ca52682..a0804aeb54 100644 --- a/PersistentStore/PersistentStoreImplementation.cpp +++ b/PersistentStore/PersistentStoreImplementation.cpp @@ -18,9 +18,6 @@ */ #include "PersistentStoreImplementation.h" -#ifdef WITH_ACCOUNT_SCOPE -#include "grpc/Store2.h" -#endif #include "sqlite/Store2.h" namespace WPEFramework { @@ -33,7 +30,6 @@ namespace Plugin { , _deviceStoreCache(nullptr) , _deviceStoreInspector(nullptr) , _deviceStoreLimit(nullptr) - , _accountStore2(nullptr) , _store2Sink(*this) { if (_deviceStore2 != nullptr) { @@ -47,10 +43,6 @@ namespace Plugin { ASSERT(_deviceStoreCache != nullptr); ASSERT(_deviceStoreInspector != nullptr); ASSERT(_deviceStoreLimit != nullptr); -#ifdef WITH_ACCOUNT_SCOPE - _accountStore2 = Core::Service::Create(); - ASSERT(_accountStore2 != nullptr); -#endif } PersistentStoreImplementation::~PersistentStoreImplementation() @@ -72,10 +64,6 @@ namespace Plugin { _deviceStoreLimit->Release(); _deviceStoreLimit = nullptr; } - if (_accountStore2 != nullptr) { - _accountStore2->Release(); - _accountStore2 = nullptr; - } } } // namespace Plugin diff --git a/PersistentStore/PersistentStoreImplementation.h b/PersistentStore/PersistentStoreImplementation.h index bf01e00632..52c8d56b1c 100644 --- a/PersistentStore/PersistentStoreImplementation.h +++ b/PersistentStore/PersistentStoreImplementation.h @@ -135,9 +135,6 @@ namespace Plugin { if (_deviceStore2 != nullptr) { _deviceStore2->Register(notification); } - if (_accountStore2 != nullptr) { - _accountStore2->Register(notification); - } return Core::ERROR_NONE; } uint32_t Unregister(IStore2::INotification* notification) override @@ -145,52 +142,33 @@ namespace Plugin { if (_deviceStore2 != nullptr) { _deviceStore2->Unregister(notification); } - if (_accountStore2 != nullptr) { - _accountStore2->Unregister(notification); - } return Core::ERROR_NONE; } - uint32_t SetValue(const IStore2::ScopeType scope, const string& ns, const string& key, const string& value, const uint32_t ttl) override + uint32_t SetValue(const IStore2::ScopeType, const string& ns, const string& key, const string& value, const uint32_t ttl) override { - if (scope == IStore2::ScopeType::ACCOUNT) { - if (_accountStore2 != nullptr) { - return _accountStore2->SetValue(scope, ns, key, value, ttl); - } - } else if (_deviceStore2 != nullptr) { - return _deviceStore2->SetValue(scope, ns, key, value, ttl); + if (_deviceStore2 != nullptr) { + return _deviceStore2->SetValue(IStore2::ScopeType::DEVICE, ns, key, value, ttl); } return Core::ERROR_NOT_SUPPORTED; } - uint32_t GetValue(const IStore2::ScopeType scope, const string& ns, const string& key, string& value, uint32_t& ttl) override + uint32_t GetValue(const IStore2::ScopeType, const string& ns, const string& key, string& value, uint32_t& ttl) override { - if (scope == IStore2::ScopeType::ACCOUNT) { - if (_accountStore2 != nullptr) { - return _accountStore2->GetValue(scope, ns, key, value, ttl); - } - } else if (_deviceStore2 != nullptr) { - return _deviceStore2->GetValue(scope, ns, key, value, ttl); + if (_deviceStore2 != nullptr) { + return _deviceStore2->GetValue(IStore2::ScopeType::DEVICE, ns, key, value, ttl); } return Core::ERROR_NOT_SUPPORTED; } - uint32_t DeleteKey(const IStore2::ScopeType scope, const string& ns, const string& key) override + uint32_t DeleteKey(const IStore2::ScopeType, const string& ns, const string& key) override { - if (scope == IStore2::ScopeType::ACCOUNT) { - if (_accountStore2 != nullptr) { - return _accountStore2->DeleteKey(scope, ns, key); - } - } else if (_deviceStore2 != nullptr) { - return _deviceStore2->DeleteKey(scope, ns, key); + if (_deviceStore2 != nullptr) { + return _deviceStore2->DeleteKey(IStore2::ScopeType::DEVICE, ns, key); } return Core::ERROR_NOT_SUPPORTED; } - uint32_t DeleteNamespace(const IStore2::ScopeType scope, const string& ns) override + uint32_t DeleteNamespace(const IStore2::ScopeType, const string& ns) override { - if (scope == IStore2::ScopeType::ACCOUNT) { - if (_accountStore2 != nullptr) { - return _accountStore2->DeleteNamespace(scope, ns); - } - } else if (_deviceStore2 != nullptr) { - return _deviceStore2->DeleteNamespace(scope, ns); + if (_deviceStore2 != nullptr) { + return _deviceStore2->DeleteNamespace(IStore2::ScopeType::DEVICE, ns); } return Core::ERROR_NOT_SUPPORTED; } @@ -201,48 +179,38 @@ namespace Plugin { } return Core::ERROR_NOT_SUPPORTED; } - uint32_t GetKeys(const IStoreInspector::ScopeType scope, const string& ns, RPC::IStringIterator*& keys) override + uint32_t GetKeys(const IStoreInspector::ScopeType, const string& ns, RPC::IStringIterator*& keys) override { - if (scope == IStoreInspector::ScopeType::DEVICE) { - if (_deviceStoreInspector != nullptr) { - return _deviceStoreInspector->GetKeys(scope, ns, keys); - } + if (_deviceStoreInspector != nullptr) { + return _deviceStoreInspector->GetKeys(IStore2::ScopeType::DEVICE, ns, keys); } return Core::ERROR_NOT_SUPPORTED; } - uint32_t GetNamespaces(const IStoreInspector::ScopeType scope, RPC::IStringIterator*& namespaces) override + uint32_t GetNamespaces(const IStoreInspector::ScopeType, RPC::IStringIterator*& namespaces) override { - if (scope == IStoreInspector::ScopeType::DEVICE) { - if (_deviceStoreInspector != nullptr) { - return _deviceStoreInspector->GetNamespaces(scope, namespaces); - } + if (_deviceStoreInspector != nullptr) { + return _deviceStoreInspector->GetNamespaces(IStore2::ScopeType::DEVICE, namespaces); } return Core::ERROR_NOT_SUPPORTED; } - uint32_t GetStorageSizes(const IStoreInspector::ScopeType scope, INamespaceSizeIterator*& storageList) override + uint32_t GetStorageSizes(const IStoreInspector::ScopeType, INamespaceSizeIterator*& storageList) override { - if (scope == IStoreInspector::ScopeType::DEVICE) { - if (_deviceStoreInspector != nullptr) { - return _deviceStoreInspector->GetStorageSizes(scope, storageList); - } + if (_deviceStoreInspector != nullptr) { + return _deviceStoreInspector->GetStorageSizes(IStore2::ScopeType::DEVICE, storageList); } return Core::ERROR_NOT_SUPPORTED; } - uint32_t SetNamespaceStorageLimit(const IStoreLimit::ScopeType scope, const string& ns, const uint32_t size) override + uint32_t SetNamespaceStorageLimit(const IStoreLimit::ScopeType, const string& ns, const uint32_t size) override { - if (scope == IStoreLimit::ScopeType::DEVICE) { - if (_deviceStoreLimit != nullptr) { - return _deviceStoreLimit->SetNamespaceStorageLimit(scope, ns, size); - } + if (_deviceStoreLimit != nullptr) { + return _deviceStoreLimit->SetNamespaceStorageLimit(IStore2::ScopeType::DEVICE, ns, size); } return Core::ERROR_NOT_SUPPORTED; } - uint32_t GetNamespaceStorageLimit(const IStoreLimit::ScopeType scope, const string& ns, uint32_t& size) override + uint32_t GetNamespaceStorageLimit(const IStoreLimit::ScopeType, const string& ns, uint32_t& size) override { - if (scope == IStoreLimit::ScopeType::DEVICE) { - if (_deviceStoreLimit != nullptr) { - return _deviceStoreLimit->GetNamespaceStorageLimit(scope, ns, size); - } + if (_deviceStoreLimit != nullptr) { + return _deviceStoreLimit->GetNamespaceStorageLimit(IStore2::ScopeType::DEVICE, ns, size); } return Core::ERROR_NOT_SUPPORTED; } @@ -252,7 +220,6 @@ namespace Plugin { IStoreCache* _deviceStoreCache; IStoreInspector* _deviceStoreInspector; IStoreLimit* _deviceStoreLimit; - IStore2* _accountStore2; Core::Sink _store2Sink; std::list _clients; Core::CriticalSection _clientLock; diff --git a/PersistentStore/l0test/PersistentStoreTest.cpp b/PersistentStore/l0test/PersistentStoreTest.cpp index d547c1aeb4..be3c9da7b3 100644 --- a/PersistentStore/l0test/PersistentStoreTest.cpp +++ b/PersistentStore/l0test/PersistentStoreTest.cpp @@ -20,7 +20,6 @@ using ::WPEFramework::Exchange::IStoreInspector; using ::WPEFramework::JsonData::PersistentStore::DeleteKeyParamsInfo; using ::WPEFramework::JsonData::PersistentStore::DeleteNamespaceParamsInfo; using ::WPEFramework::JsonData::PersistentStore::GetKeysResultData; -using ::WPEFramework::JsonData::PersistentStore::GetNamespacesParamsInfo; using ::WPEFramework::JsonData::PersistentStore::GetNamespacesResultData; using ::WPEFramework::JsonData::PersistentStore::GetNamespaceStorageLimitResultData; using ::WPEFramework::JsonData::PersistentStore::GetStorageSizesResultData; @@ -96,44 +95,6 @@ TEST_F(APersistentStore, GetsValueInDeviceScopeViaJsonRpc) plugin->Deinitialize(service); } -TEST_F(APersistentStore, GetsValueInAccountScopeViaJsonRpc) -{ - class PersistentStoreImplementation : public NiceMock { - public: - PersistentStoreImplementation() - { - EXPECT_CALL(*this, GetValue(_, _, _, _, _)) - .WillRepeatedly(Invoke( - [](const IStore2::ScopeType scope, const string& ns, const string& key, string& value, uint32_t& ttl) { - EXPECT_THAT(scope, Eq(IStore2::ScopeType::ACCOUNT)); - EXPECT_THAT(ns, Eq(kAppId)); - EXPECT_THAT(key, Eq(kKey)); - value = kValue; - ttl = kTtl; - return WPEFramework::Core::ERROR_NONE; - })); - } - }; - PublishedServiceType metadata(WPEFramework::Core::System::MODULE_NAME, 1, 0, 0); - ASSERT_THAT(plugin->Initialize(service), Eq("")); - auto jsonRpc = plugin->QueryInterface(); - ASSERT_THAT(jsonRpc, NotNull()); - DeleteKeyParamsInfo params; - params.Scope = WPEFramework::JsonData::PersistentStore::ScopeType::ACCOUNT; - params.Namespace = kAppId; - params.Key = kKey; - string paramsJsonStr; - params.ToString(paramsJsonStr); - string resultJsonStr; - ASSERT_THAT(jsonRpc->Invoke(0, 0, "", "getValue", paramsJsonStr, resultJsonStr), Eq(WPEFramework::Core::ERROR_NONE)); - GetValueResultData result; - result.FromString(resultJsonStr); - EXPECT_THAT(result.Value.Value(), Eq(kValue)); - EXPECT_THAT(result.Ttl.Value(), Eq(kTtl)); - jsonRpc->Release(); - plugin->Deinitialize(service); -} - TEST_F(APersistentStore, SetsValueInDeviceScopeViaJsonRpc) { class PersistentStoreImplementation : public NiceMock { @@ -169,42 +130,6 @@ TEST_F(APersistentStore, SetsValueInDeviceScopeViaJsonRpc) plugin->Deinitialize(service); } -TEST_F(APersistentStore, SetsValueInAccountScopeViaJsonRpc) -{ - class PersistentStoreImplementation : public NiceMock { - public: - PersistentStoreImplementation() - { - EXPECT_CALL(*this, SetValue(_, _, _, _, _)) - .WillRepeatedly(Invoke( - [](const IStore2::ScopeType scope, const string& ns, const string& key, const string& value, const uint32_t ttl) { - EXPECT_THAT(scope, Eq(IStore2::ScopeType::ACCOUNT)); - EXPECT_THAT(ns, Eq(kAppId)); - EXPECT_THAT(key, Eq(kKey)); - EXPECT_THAT(value, Eq(kValue)); - EXPECT_THAT(ttl, Eq(kTtl)); - return WPEFramework::Core::ERROR_NONE; - })); - } - }; - PublishedServiceType metadata(WPEFramework::Core::System::MODULE_NAME, 1, 0, 0); - ASSERT_THAT(plugin->Initialize(service), Eq("")); - auto jsonRpc = plugin->QueryInterface(); - ASSERT_THAT(jsonRpc, NotNull()); - SetValueParamsData params; - params.Scope = WPEFramework::JsonData::PersistentStore::ScopeType::ACCOUNT; - params.Namespace = kAppId; - params.Key = kKey; - params.Value = kValue; - params.Ttl = kTtl; - string paramsJsonStr; - params.ToString(paramsJsonStr); - string resultJsonStr; - EXPECT_THAT(jsonRpc->Invoke(0, 0, "", "setValue", paramsJsonStr, resultJsonStr), Eq(WPEFramework::Core::ERROR_NONE)); - jsonRpc->Release(); - plugin->Deinitialize(service); -} - TEST_F(APersistentStore, DeletesKeyInDeviceScopeViaJsonRpc) { class PersistentStoreImplementation : public NiceMock { @@ -236,38 +161,6 @@ TEST_F(APersistentStore, DeletesKeyInDeviceScopeViaJsonRpc) plugin->Deinitialize(service); } -TEST_F(APersistentStore, DeletesKeyInAccountScopeViaJsonRpc) -{ - class PersistentStoreImplementation : public NiceMock { - public: - PersistentStoreImplementation() - { - EXPECT_CALL(*this, DeleteKey(_, _, _)) - .WillRepeatedly(Invoke( - [](const IStore2::ScopeType scope, const string& ns, const string& key) { - EXPECT_THAT(scope, Eq(IStore2::ScopeType::ACCOUNT)); - EXPECT_THAT(ns, Eq(kAppId)); - EXPECT_THAT(key, Eq(kKey)); - return WPEFramework::Core::ERROR_NONE; - })); - } - }; - PublishedServiceType metadata(WPEFramework::Core::System::MODULE_NAME, 1, 0, 0); - ASSERT_THAT(plugin->Initialize(service), Eq("")); - auto jsonRpc = plugin->QueryInterface(); - ASSERT_THAT(jsonRpc, NotNull()); - DeleteKeyParamsInfo params; - params.Scope = WPEFramework::JsonData::PersistentStore::ScopeType::ACCOUNT; - params.Namespace = kAppId; - params.Key = kKey; - string paramsJsonStr; - params.ToString(paramsJsonStr); - string resultJsonStr; - EXPECT_THAT(jsonRpc->Invoke(0, 0, "", "deleteKey", paramsJsonStr, resultJsonStr), Eq(WPEFramework::Core::ERROR_NONE)); - jsonRpc->Release(); - plugin->Deinitialize(service); -} - TEST_F(APersistentStore, DeletesNamespaceInDeviceScopeViaJsonRpc) { class PersistentStoreImplementation : public NiceMock { @@ -297,36 +190,6 @@ TEST_F(APersistentStore, DeletesNamespaceInDeviceScopeViaJsonRpc) plugin->Deinitialize(service); } -TEST_F(APersistentStore, DeletesNamespaceInAccountScopeViaJsonRpc) -{ - class PersistentStoreImplementation : public NiceMock { - public: - PersistentStoreImplementation() - { - EXPECT_CALL(*this, DeleteNamespace(_, _)) - .WillRepeatedly(Invoke( - [](const IStore2::ScopeType scope, const string& ns) { - EXPECT_THAT(scope, Eq(IStore2::ScopeType::ACCOUNT)); - EXPECT_THAT(ns, Eq(kAppId)); - return WPEFramework::Core::ERROR_NONE; - })); - } - }; - PublishedServiceType metadata(WPEFramework::Core::System::MODULE_NAME, 1, 0, 0); - ASSERT_THAT(plugin->Initialize(service), Eq("")); - auto jsonRpc = plugin->QueryInterface(); - ASSERT_THAT(jsonRpc, NotNull()); - DeleteNamespaceParamsInfo params; - params.Scope = WPEFramework::JsonData::PersistentStore::ScopeType::ACCOUNT; - params.Namespace = kAppId; - string paramsJsonStr; - params.ToString(paramsJsonStr); - string resultJsonStr; - EXPECT_THAT(jsonRpc->Invoke(0, 0, "", "deleteNamespace", paramsJsonStr, resultJsonStr), Eq(WPEFramework::Core::ERROR_NONE)); - jsonRpc->Release(); - plugin->Deinitialize(service); -} - TEST_F(APersistentStore, FlushesCacheViaJsonRpc) { class PersistentStoreImplementation : public NiceMock { diff --git a/SecureStore/CHANGELOG.md b/SecureStore/CHANGELOG.md new file mode 100644 index 0000000000..7864154892 --- /dev/null +++ b/SecureStore/CHANGELOG.md @@ -0,0 +1,25 @@ +# Changelog + +All notable changes to this RDK Service will be documented in this file. + +* Each RDK Service has a CHANGELOG file that contains all changes done so far. When version is updated, add a entry in the CHANGELOG.md at the top with user friendly information on what was changed with the new version. Please don't mention JIRA tickets in CHANGELOG. + +* Please Add entry in the CHANGELOG for each version change and indicate the type of change with these labels: + * **Added** for new features. + * **Changed** for changes in existing functionality. + * **Deprecated** for soon-to-be removed features. + * **Removed** for now removed features. + * **Fixed** for any bug fixes. + * **Security** in case of vulnerabilities. + +* Changes in CHANGELOG should be updated when commits are added to the main or release branches. There should be one CHANGELOG entry per JIRA Ticket. This is not enforced on sprint branches since there could be multiple changes for the same JIRA ticket during development. + +* For more details, refer to [versioning](https://github.com/rdkcentral/rdkservices#versioning) section under Main README. + +## [1.0.0] - 2024-07-15 +### Added +- Add CHANGELOG + +### Change +- Reset API version to 1.0.0 +- Change README to inform how to update changelog and API version diff --git a/SecureStore/CMakeLists.txt b/SecureStore/CMakeLists.txt new file mode 100644 index 0000000000..c281eed98a --- /dev/null +++ b/SecureStore/CMakeLists.txt @@ -0,0 +1,97 @@ +# If not stated otherwise in this file or this component's LICENSE file the +# following copyright and licenses apply: +# +# Copyright 2022 RDK Management +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.14) + +set(PLUGIN_NAME SecureStore) +find_package(WPEFramework NAMES WPEFramework Thunder) +set(MODULE_NAME ${NAMESPACE}${PLUGIN_NAME}) + +set(CMAKE_CXX_STANDARD 11) + +set(PLUGIN_SECURESTORE_MODE "Off" CACHE STRING "Controls if the plugin should run in its own process, in process or remote") +set(PLUGIN_SECURESTORE_URI "" CACHE STRING "Endpoint") +set(PLUGIN_SECURESTORE_STARTUPORDER "" CACHE STRING "To configure startup order of the plugin") + +add_library(${MODULE_NAME} SHARED + SecureStore.cpp + Module.cpp +) + +find_package(${NAMESPACE}Plugins REQUIRED) +find_package(${NAMESPACE}Definitions REQUIRED) +target_link_libraries(${MODULE_NAME} PRIVATE + ${NAMESPACE}Plugins::${NAMESPACE}Plugins + ${NAMESPACE}Definitions::${NAMESPACE}Definitions +) + +find_library(RFC_LIBRARIES NAMES rfcapi) +if (RFC_LIBRARIES) + find_path(RFC_INCLUDE_DIRS NAMES rfcapi.h REQUIRED) + target_include_directories(${MODULE_NAME} PRIVATE ${RFC_INCLUDE_DIRS}) + target_link_libraries(${MODULE_NAME} PRIVATE ${RFC_LIBRARIES}) + target_compile_definitions(${MODULE_NAME} PRIVATE WITH_RFC) +endif () + +install(TARGETS ${MODULE_NAME} + DESTINATION lib/${STORAGE_DIRECTORY}/plugins) + +set(PLUGIN_IMPLEMENTATION ${MODULE_NAME}Implementation) +add_library(${PLUGIN_IMPLEMENTATION} SHARED + Module.cpp + SecureStoreImplementation.cpp +) + +target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE + ${NAMESPACE}Plugins::${NAMESPACE}Plugins + ${NAMESPACE}Definitions::${NAMESPACE}Definitions +) + +find_library(IARMBUS_LIBRARIES NAMES IARMBus) +if (IARMBUS_LIBRARIES) + find_path(IARMBUS_INCLUDE_DIRS NAMES libIBus.h PATH_SUFFIXES rdk/iarmbus REQUIRED) + find_path(IARMSYS_INCLUDE_DIRS NAMES sysMgr.h PATH_SUFFIXES rdk/iarmmgrs/sysmgr REQUIRED) + target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ${IARMBUS_INCLUDE_DIRS} ${IARMSYS_INCLUDE_DIRS}) + target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${IARMBUS_LIBRARIES}) + target_compile_definitions(${PLUGIN_IMPLEMENTATION} PRIVATE WITH_SYSMGR) +endif () + +find_package(Protobuf REQUIRED) +target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE ${Protobuf_LIBRARIES}) + +add_custom_target(protoc + ${Protobuf_PROTOC_EXECUTABLE} --cpp_out ${CMAKE_CURRENT_BINARY_DIR} -I ${CMAKE_CURRENT_SOURCE_DIR}/grpc/secure_storage ${CMAKE_CURRENT_SOURCE_DIR}/grpc/secure_storage/secure_storage.proto +) +add_dependencies(${PLUGIN_IMPLEMENTATION} protoc) + +target_link_libraries(${PLUGIN_IMPLEMENTATION} PRIVATE grpc++) +find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin REQUIRED) + +add_custom_target(protoc-gen-grpc + ${Protobuf_PROTOC_EXECUTABLE} --grpc_out ${CMAKE_CURRENT_BINARY_DIR} --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN} -I ${CMAKE_CURRENT_SOURCE_DIR}/grpc/secure_storage ${CMAKE_CURRENT_SOURCE_DIR}/grpc/secure_storage/secure_storage.proto +) +add_dependencies(${PLUGIN_IMPLEMENTATION} protoc-gen-grpc) + +set(PROTO_SRCS secure_storage.pb.cc secure_storage.grpc.pb.cc) +target_sources(${PLUGIN_IMPLEMENTATION} PRIVATE ${PROTO_SRCS}) +set_property(SOURCE ${PROTO_SRCS} PROPERTY GENERATED 1) +target_include_directories(${PLUGIN_IMPLEMENTATION} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + +install(TARGETS ${PLUGIN_IMPLEMENTATION} + DESTINATION lib/${STORAGE_DIRECTORY}/plugins) + +write_config(${PLUGIN_NAME}) diff --git a/SecureStore/Module.cpp b/SecureStore/Module.cpp new file mode 100644 index 0000000000..f3869fc7b9 --- /dev/null +++ b/SecureStore/Module.cpp @@ -0,0 +1,22 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2022 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Module.h" + +MODULE_NAME_DECLARATION(BUILD_REFERENCE) diff --git a/SecureStore/Module.h b/SecureStore/Module.h new file mode 100644 index 0000000000..f3d2429450 --- /dev/null +++ b/SecureStore/Module.h @@ -0,0 +1,37 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2022 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#ifndef MODULE_NAME +#define MODULE_NAME Plugin_SecureStore +#endif + +#include +#if (((THUNDER_VERSION_MAJOR >= 4) && (THUNDER_VERSION_MINOR == 4)) || ((THUNDER_VERSION >= 4) && !defined(THUNDER_VERSION_MINOR))) +#include +#else +#include +#endif + +#define URI_ENV "SECURESTORE_URI" +#define IARM_INIT_NAME "Thunder_Plugins" +#define URI_RFC "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.SecureStore.Uri" + +#undef EXTERNAL +#define EXTERNAL diff --git a/SecureStore/SecureStore.conf.in b/SecureStore/SecureStore.conf.in new file mode 100644 index 0000000000..d7e5af1187 --- /dev/null +++ b/SecureStore/SecureStore.conf.in @@ -0,0 +1,12 @@ +precondition = ["Platform"] +callsign = "org.rdk.SecureStore" +startuporder = "@PLUGIN_SECURESTORE_STARTUPORDER@" + +configuration = JSON() + +rootobject = JSON() +rootobject.add("mode", "@PLUGIN_SECURESTORE_MODE@") +rootobject.add("locator", "lib@PLUGIN_IMPLEMENTATION@.so") +configuration.add("root", rootobject) + +configuration.add("uri", "@PLUGIN_SECURESTORE_URI@") diff --git a/SecureStore/SecureStore.config b/SecureStore/SecureStore.config new file mode 100644 index 0000000000..848a5ac79d --- /dev/null +++ b/SecureStore/SecureStore.config @@ -0,0 +1,17 @@ +set(autostart true) +set(preconditions Platform) +set(callsign "org.rdk.SecureStore") + +if(PLUGIN_SECURESTORE_STARTUPORDER) +set (startuporder ${PLUGIN_SECURESTORE_STARTUPORDER}) +endif() + +map() + key(root) + map() + kv(mode ${PLUGIN_SECURESTORE_MODE}) + kv(locator lib${PLUGIN_IMPLEMENTATION}.so) + end() + kv(uri ${PLUGIN_SECURESTORE_URI}) +end() +ans(configuration) diff --git a/SecureStore/SecureStore.cpp b/SecureStore/SecureStore.cpp new file mode 100644 index 0000000000..b3dbb658d8 --- /dev/null +++ b/SecureStore/SecureStore.cpp @@ -0,0 +1,128 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2022 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SecureStore.h" +#ifdef WITH_RFC +#include "rfcapi.h" +#endif + +#define API_VERSION_NUMBER_MAJOR 1 +#define API_VERSION_NUMBER_MINOR 0 +#define API_VERSION_NUMBER_PATCH 0 + +namespace WPEFramework { + +namespace Plugin { + + namespace { + + static Metadata metadata( + // Version (Major, Minor, Patch) + API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH, + // Preconditions + {}, + // Terminations + {}, + // Controls + {}); + } + + SERVICE_REGISTRATION(SecureStore, API_VERSION_NUMBER_MAJOR, API_VERSION_NUMBER_MINOR, API_VERSION_NUMBER_PATCH); + + const string SecureStore::Initialize(PluginHost::IShell* service) + { + string result; + + ASSERT(service != nullptr); + ASSERT(_store2 == nullptr); + ASSERT(_service == nullptr); + ASSERT(_connectionId == 0); + + SYSLOG(Logging::Startup, (_T("SecureStore::Initialize: PID=%u"), getpid())); + + _service = service; + _service->AddRef(); + + auto configLine = _service->ConfigLine(); + _config.FromString(configLine); + + auto uri = _config.Uri.Value(); + +#ifdef WITH_RFC + RFC_ParamData_t rfcParam; + auto rfcStatus = getRFCParameter(nullptr, URI_RFC, &rfcParam); + if (rfcStatus == WDMP_SUCCESS) { + if (rfcParam.value[0]) { + uri = rfcParam.value; + } + } else { + TRACE(Trace::Error, (_T("%s rfc error %d"), __FUNCTION__, rfcStatus)); + } +#endif + + Core::SystemInfo::SetEnvironment(URI_ENV, uri); + + _service->Register(&_notification); + + _store2 = _service->Root(_connectionId, RPC::CommunicationTimeOut, _T("SecureStoreImplementation")); + if (_store2 != nullptr) { + Exchange::JStore2::Register(*this, _store2); + _store2->Register(&_store2Sink); + } else { + result = _T("Couldn't create implementation instance"); + } + + return result; + } + + void SecureStore::Deinitialize(PluginHost::IShell* service) + { + ASSERT(_service == service); + + SYSLOG(Logging::Shutdown, (string(_T("SecureStore::Deinitialize")))); + + _service->Unregister(&_notification); + + if (_store2 != nullptr) { + _store2->Unregister(&_store2Sink); + Exchange::JStore2::Unregister(*this); + + auto connection = _service->RemoteConnection(_connectionId); + VARIABLE_IS_NOT_USED auto result = _store2->Release(); + _store2 = nullptr; + ASSERT(result == Core::ERROR_DESTRUCTION_SUCCEEDED); + if (connection != nullptr) { + connection->Terminate(); + connection->Release(); + } + } + + _connectionId = 0; + _service->Release(); + _service = nullptr; + SYSLOG(Logging::Shutdown, (string(_T("SecureStore de-initialised")))); + } + + string SecureStore::Information() const + { + return (string()); + } + +} // namespace Plugin +} // namespace WPEFramework diff --git a/SecureStore/SecureStore.h b/SecureStore/SecureStore.h new file mode 100644 index 0000000000..e74764a09d --- /dev/null +++ b/SecureStore/SecureStore.h @@ -0,0 +1,144 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2022 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Module.h" +#include + +namespace WPEFramework { +namespace Plugin { + + class SecureStore : public PluginHost::IPlugin, public PluginHost::JSONRPC { + private: + class Config : public Core::JSON::Container { + private: + Config(const Config&) = delete; + Config& operator=(const Config&) = delete; + + public: + Config() + : Core::JSON::Container() + { + Add(_T("uri"), &Uri); + } + + public: + Core::JSON::String Uri; + }; + + class Store2Notification : public Exchange::IStore2::INotification { + private: + Store2Notification(const Store2Notification&) = delete; + Store2Notification& operator=(const Store2Notification&) = delete; + + public: + explicit Store2Notification(SecureStore& parent) + : _parent(parent) + { + } + ~Store2Notification() override = default; + + public: + void ValueChanged(const Exchange::IStore2::ScopeType scope, const string& ns, const string& key, const string& value) override + { + Exchange::JStore2::Event::ValueChanged(_parent, scope, ns, key, value); + } + + BEGIN_INTERFACE_MAP(Store2Notification) + INTERFACE_ENTRY(Exchange::IStore2::INotification) + END_INTERFACE_MAP + + private: + SecureStore& _parent; + }; + + class RemoteConnectionNotification : public RPC::IRemoteConnection::INotification { + private: + RemoteConnectionNotification() = delete; + RemoteConnectionNotification(const RemoteConnectionNotification&) = delete; + RemoteConnectionNotification& operator=(const RemoteConnectionNotification&) = delete; + + public: + explicit RemoteConnectionNotification(SecureStore& parent) + : _parent(parent) + { + } + ~RemoteConnectionNotification() override = default; + + BEGIN_INTERFACE_MAP(RemoteConnectionNotification) + INTERFACE_ENTRY(RPC::IRemoteConnection::INotification) + END_INTERFACE_MAP + + void Activated(RPC::IRemoteConnection*) override + { + } + void Deactivated(RPC::IRemoteConnection* connection) override + { + if (connection->Id() == _parent._connectionId) { + ASSERT(_parent._service != nullptr); + Core::IWorkerPool::Instance().Schedule( + Core::Time::Now(), + PluginHost::IShell::Job::Create( + _parent._service, PluginHost::IShell::DEACTIVATED, PluginHost::IShell::FAILURE)); + } + } + + private: + SecureStore& _parent; + }; + + private: + SecureStore(const SecureStore&) = delete; + SecureStore& operator=(const SecureStore&) = delete; + + public: + SecureStore() + : PluginHost::JSONRPC() + , _service(nullptr) + , _connectionId(0) + , _store2(nullptr) + , _store2Sink(*this) + , _notification(*this) + { + } + ~SecureStore() override = default; + + BEGIN_INTERFACE_MAP(SecureStore) + INTERFACE_ENTRY(PluginHost::IPlugin) + INTERFACE_ENTRY(PluginHost::IDispatcher) + INTERFACE_AGGREGATE(Exchange::IStore2, _store2) + END_INTERFACE_MAP + + public: + const string Initialize(PluginHost::IShell* service) override; + void Deinitialize(PluginHost::IShell* service) override; + string Information() const override; + + private: + Config _config; + PluginHost::IShell* _service; + uint32_t _connectionId; + Exchange::IStore2* _store2; + Core::Sink _store2Sink; + Core::Sink _notification; + }; + +} // namespace Plugin +} // namespace WPEFramework diff --git a/SecureStore/SecureStoreImplementation.cpp b/SecureStore/SecureStoreImplementation.cpp new file mode 100644 index 0000000000..73a4dda1fe --- /dev/null +++ b/SecureStore/SecureStoreImplementation.cpp @@ -0,0 +1,43 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2022 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SecureStoreImplementation.h" +#include "grpc/Store2.h" + +namespace WPEFramework { +namespace Plugin { + + SERVICE_REGISTRATION(SecureStoreImplementation, 1, 0); + + SecureStoreImplementation::SecureStoreImplementation() + : _accountStore2(Core::Service::Create()) + { + ASSERT(_accountStore2 != nullptr); + } + + SecureStoreImplementation::~SecureStoreImplementation() + { + if (_accountStore2 != nullptr) { + _accountStore2->Release(); + _accountStore2 = nullptr; + } + } + +} // namespace Plugin +} // namespace WPEFramework diff --git a/SecureStore/SecureStoreImplementation.h b/SecureStore/SecureStoreImplementation.h new file mode 100644 index 0000000000..ecd9e55c12 --- /dev/null +++ b/SecureStore/SecureStoreImplementation.h @@ -0,0 +1,90 @@ +/* + * If not stated otherwise in this file or this component's LICENSE file the + * following copyright and licenses apply: + * + * Copyright 2022 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "Module.h" +#include + +namespace WPEFramework { +namespace Plugin { + + class SecureStoreImplementation : public Exchange::IStore2 { + private: + SecureStoreImplementation(const SecureStoreImplementation&) = delete; + SecureStoreImplementation& operator=(const SecureStoreImplementation&) = delete; + + public: + SecureStoreImplementation(); + ~SecureStoreImplementation() override; + + BEGIN_INTERFACE_MAP(SecureStoreImplementation) + INTERFACE_ENTRY(IStore2) + END_INTERFACE_MAP + + private: + uint32_t Register(IStore2::INotification* notification) override + { + if (_accountStore2 != nullptr) { + _accountStore2->Register(notification); + } + return Core::ERROR_NONE; + } + uint32_t Unregister(IStore2::INotification* notification) override + { + if (_accountStore2 != nullptr) { + _accountStore2->Unregister(notification); + } + return Core::ERROR_NONE; + } + uint32_t SetValue(const IStore2::ScopeType, const string& ns, const string& key, const string& value, const uint32_t ttl) override + { + if (_accountStore2 != nullptr) { + return _accountStore2->SetValue(IStore2::ScopeType::ACCOUNT, ns, key, value, ttl); + } + return Core::ERROR_NOT_SUPPORTED; + } + uint32_t GetValue(const IStore2::ScopeType, const string& ns, const string& key, string& value, uint32_t& ttl) override + { + if (_accountStore2 != nullptr) { + return _accountStore2->GetValue(IStore2::ScopeType::ACCOUNT, ns, key, value, ttl); + } + return Core::ERROR_NOT_SUPPORTED; + } + uint32_t DeleteKey(const IStore2::ScopeType, const string& ns, const string& key) override + { + if (_accountStore2 != nullptr) { + return _accountStore2->DeleteKey(IStore2::ScopeType::ACCOUNT, ns, key); + } + return Core::ERROR_NOT_SUPPORTED; + } + uint32_t DeleteNamespace(const IStore2::ScopeType, const string& ns) override + { + if (_accountStore2 != nullptr) { + return _accountStore2->DeleteNamespace(IStore2::ScopeType::ACCOUNT, ns); + } + return Core::ERROR_NOT_SUPPORTED; + } + + private: + IStore2* _accountStore2; + }; + +} // namespace Plugin +} // namespace WPEFramework diff --git a/SecureStore/SecureStorePlugin.json b/SecureStore/SecureStorePlugin.json new file mode 100644 index 0000000000..759b2a9ed5 --- /dev/null +++ b/SecureStore/SecureStorePlugin.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://raw.githubusercontent.com/rdkcentral/rdkservices/main/Tools/json_generator/schemas/plugin.schema.json", + "info": { + "title": "SecureStore Plugin", + "callsign": "org.rdk.SecureStore", + "locator": "libWPEFrameworkSecureStore.so", + "status": "production", + "description": "The `SecureStore` plugin allows you to persist key/value pairs by namespace" + } +} \ No newline at end of file diff --git a/PersistentStore/grpc/Store2.h b/SecureStore/grpc/Store2.h similarity index 100% rename from PersistentStore/grpc/Store2.h rename to SecureStore/grpc/Store2.h diff --git a/PersistentStore/grpc/l0test/CMakeLists.txt b/SecureStore/grpc/l0test/CMakeLists.txt similarity index 88% rename from PersistentStore/grpc/l0test/CMakeLists.txt rename to SecureStore/grpc/l0test/CMakeLists.txt index bbfa97c27c..4f0b61c724 100644 --- a/PersistentStore/grpc/l0test/CMakeLists.txt +++ b/SecureStore/grpc/l0test/CMakeLists.txt @@ -46,15 +46,8 @@ add_custom_target(protoc ) add_dependencies(${PROJECT_NAME} protoc) -find_package(gRPC CONFIG) -if (gRPC_FOUND) - set(GRPC_LIBS gRPC::grpc++) - set(GRPC_CPP_PLUGIN $) -else () - set(GRPC_LIBS grpc++) - find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin REQUIRED) -endif () -target_link_libraries(${PROJECT_NAME} PRIVATE ${GRPC_LIBS}) +target_link_libraries(${PROJECT_NAME} PRIVATE grpc++) +find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin REQUIRED) add_custom_target(protoc-gen-grpc ${Protobuf_PROTOC_EXECUTABLE} --grpc_out ${CMAKE_CURRENT_BINARY_DIR} --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN} -I ${CMAKE_CURRENT_SOURCE_DIR}/../secure_storage ${CMAKE_CURRENT_SOURCE_DIR}/../secure_storage/secure_storage.proto diff --git a/PersistentStore/grpc/l0test/SecureStorageServiceMock.h b/SecureStore/grpc/l0test/SecureStorageServiceMock.h similarity index 100% rename from PersistentStore/grpc/l0test/SecureStorageServiceMock.h rename to SecureStore/grpc/l0test/SecureStorageServiceMock.h diff --git a/PersistentStore/grpc/l0test/Server.h b/SecureStore/grpc/l0test/Server.h similarity index 100% rename from PersistentStore/grpc/l0test/Server.h rename to SecureStore/grpc/l0test/Server.h diff --git a/PersistentStore/grpc/l0test/Store2Test.cpp b/SecureStore/grpc/l0test/Store2Test.cpp similarity index 100% rename from PersistentStore/grpc/l0test/Store2Test.cpp rename to SecureStore/grpc/l0test/Store2Test.cpp diff --git a/PersistentStore/grpc/l2test/CMakeLists.txt b/SecureStore/grpc/l2test/CMakeLists.txt similarity index 87% rename from PersistentStore/grpc/l2test/CMakeLists.txt rename to SecureStore/grpc/l2test/CMakeLists.txt index 24b36fcab7..e4a1d395e6 100644 --- a/PersistentStore/grpc/l2test/CMakeLists.txt +++ b/SecureStore/grpc/l2test/CMakeLists.txt @@ -41,15 +41,8 @@ add_custom_target(protoc ) add_dependencies(${PROJECT_NAME} protoc) -find_package(gRPC CONFIG) -if (gRPC_FOUND) - set(GRPC_LIBS gRPC::grpc++) - set(GRPC_CPP_PLUGIN $) -else () - set(GRPC_LIBS grpc++) - find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin REQUIRED) -endif () -target_link_libraries(${PROJECT_NAME} PRIVATE ${GRPC_LIBS}) +target_link_libraries(${PROJECT_NAME} PRIVATE grpc++) +find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin REQUIRED) add_custom_target(protoc-gen-grpc ${Protobuf_PROTOC_EXECUTABLE} --grpc_out ${CMAKE_CURRENT_BINARY_DIR} --plugin=protoc-gen-grpc=${GRPC_CPP_PLUGIN} -I ${CMAKE_CURRENT_SOURCE_DIR}/../secure_storage ${CMAKE_CURRENT_SOURCE_DIR}/../secure_storage/secure_storage.proto diff --git a/PersistentStore/grpc/l2test/StubTest.cpp b/SecureStore/grpc/l2test/StubTest.cpp similarity index 100% rename from PersistentStore/grpc/l2test/StubTest.cpp rename to SecureStore/grpc/l2test/StubTest.cpp diff --git a/PersistentStore/grpc/secure_storage/secure_storage.proto b/SecureStore/grpc/secure_storage/secure_storage.proto similarity index 100% rename from PersistentStore/grpc/secure_storage/secure_storage.proto rename to SecureStore/grpc/secure_storage/secure_storage.proto diff --git a/SecureStore/l0test/CMakeLists.txt b/SecureStore/l0test/CMakeLists.txt new file mode 100644 index 0000000000..e82cf1f59a --- /dev/null +++ b/SecureStore/l0test/CMakeLists.txt @@ -0,0 +1,47 @@ +# If not stated otherwise in this file or this component's LICENSE file the +# following copyright and licenses apply: +# +# Copyright 2020 RDK Management +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +cmake_minimum_required(VERSION 3.14) + +project(securestorel0test) + +set(CMAKE_CXX_STANDARD 11) + +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/609281088cfefc76f9d0ce82e1ff6c30cc3591e5.zip +) +FetchContent_MakeAvailable(googletest) + +find_package(WPEFramework NAMES WPEFramework Thunder) +find_package(${NAMESPACE}Plugins REQUIRED) +find_package(${NAMESPACE}Definitions REQUIRED) + +add_executable(${PROJECT_NAME} + ../Module.cpp + ../SecureStore.cpp + SecureStoreTest.cpp +) + +target_link_libraries(${PROJECT_NAME} PRIVATE + gmock_main + ${NAMESPACE}Plugins::${NAMESPACE}Plugins + ${NAMESPACE}Definitions::${NAMESPACE}Definitions +) + +install(TARGETS ${PROJECT_NAME} DESTINATION bin) diff --git a/SecureStore/l0test/SecureStoreImplementationMock.h b/SecureStore/l0test/SecureStoreImplementationMock.h new file mode 100644 index 0000000000..b834056ae3 --- /dev/null +++ b/SecureStore/l0test/SecureStoreImplementationMock.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include +#include +#include + +class SecureStoreImplementationMock + : public WPEFramework::Exchange::IStore, + public WPEFramework::Exchange::IStore2, + public WPEFramework::Exchange::IStoreCache, + public WPEFramework::Exchange::IStoreInspector, + public WPEFramework::Exchange::IStoreLimit { +public: + ~SecureStoreImplementationMock() override = default; + MOCK_METHOD(uint32_t, Register, (IStore::INotification * notification), (override)); + MOCK_METHOD(uint32_t, Unregister, (IStore::INotification * notification), (override)); + MOCK_METHOD(uint32_t, SetValue, (const string& ns, const string& key, const string& value), (override)); + MOCK_METHOD(uint32_t, GetValue, (const string& ns, const string& key, string& value), (override)); + MOCK_METHOD(uint32_t, DeleteKey, (const string& ns, const string& key), (override)); + MOCK_METHOD(uint32_t, DeleteNamespace, (const string& ns), (override)); + MOCK_METHOD(uint32_t, Register, (IStore2::INotification*), (override)); + MOCK_METHOD(uint32_t, Unregister, (IStore2::INotification*), (override)); + MOCK_METHOD(uint32_t, SetValue, (const IStore2::ScopeType scope, const string& ns, const string& key, const string& value, const uint32_t ttl), (override)); + MOCK_METHOD(uint32_t, GetValue, (const IStore2::ScopeType scope, const string& ns, const string& key, string& value, uint32_t& ttl), (override)); + MOCK_METHOD(uint32_t, DeleteKey, (const IStore2::ScopeType scope, const string& ns, const string& key), (override)); + MOCK_METHOD(uint32_t, DeleteNamespace, (const IStore2::ScopeType scope, const string& ns), (override)); + MOCK_METHOD(uint32_t, FlushCache, (), (override)); + MOCK_METHOD(uint32_t, GetKeys, (const IStoreInspector::ScopeType scope, const string& ns, IStringIterator*& keys), (override)); + MOCK_METHOD(uint32_t, GetNamespaces, (const IStoreInspector::ScopeType scope, IStringIterator*& namespaces), (override)); + MOCK_METHOD(uint32_t, GetStorageSizes, (const IStoreInspector::ScopeType scope, INamespaceSizeIterator*& storageList), (override)); + MOCK_METHOD(uint32_t, GetNamespaceStorageLimit, (const IStoreLimit::ScopeType scope, const string& ns, uint32_t& size), (override)); + MOCK_METHOD(uint32_t, SetNamespaceStorageLimit, (const IStoreLimit::ScopeType scope, const string& ns, const uint32_t size), (override)); + BEGIN_INTERFACE_MAP(SecureStoreImplementationMock) + INTERFACE_ENTRY(IStore) + INTERFACE_ENTRY(IStore2) + INTERFACE_ENTRY(IStoreCache) + INTERFACE_ENTRY(IStoreInspector) + INTERFACE_ENTRY(IStoreLimit) + END_INTERFACE_MAP +}; diff --git a/SecureStore/l0test/SecureStoreTest.cpp b/SecureStore/l0test/SecureStoreTest.cpp new file mode 100644 index 0000000000..9ac24db395 --- /dev/null +++ b/SecureStore/l0test/SecureStoreTest.cpp @@ -0,0 +1,181 @@ +#include +#include + +#include "../SecureStore.h" +#include "SecureStoreImplementationMock.h" +#include "ServiceMock.h" +#include + +using ::testing::_; +using ::testing::Eq; +using ::testing::Invoke; +using ::testing::NiceMock; +using ::testing::NotNull; +using ::testing::Return; +using ::testing::Test; +using ::WPEFramework::Core::PublishedServiceType; +using ::WPEFramework::Exchange::IStore2; +using ::WPEFramework::JsonData::Store2::DeleteNamespaceParamsData; +using ::WPEFramework::JsonData::Store2::GetValueParamsInfo; +using ::WPEFramework::JsonData::Store2::GetValueResultData; +using ::WPEFramework::JsonData::Store2::SetValueParamsData; +using ::WPEFramework::Plugin::SecureStore; +using ::WPEFramework::PluginHost::IDispatcher; +using ::WPEFramework::PluginHost::IPlugin; + +const auto kValue = "value_1"; +const auto kKey = "key_1"; +const auto kAppId = "app_id_1"; +const auto kTtl = 100; + +class ASecureStore : public Test { +protected: + NiceMock* service; + IPlugin* plugin; + ASecureStore() + : service(WPEFramework::Core::Service>::Create>()) + , plugin(WPEFramework::Core::Service::Create()) + { + } + ~ASecureStore() override + { + plugin->Release(); + service->Release(); + } +}; + +TEST_F(ASecureStore, GetsValueInAccountScopeViaJsonRpc) +{ + class SecureStoreImplementation : public NiceMock { + public: + SecureStoreImplementation() + { + EXPECT_CALL(*this, GetValue(_, _, _, _, _)) + .WillRepeatedly(Invoke( + [](const IStore2::ScopeType scope, const string& ns, const string& key, string& value, uint32_t& ttl) { + EXPECT_THAT(scope, Eq(IStore2::ScopeType::ACCOUNT)); + EXPECT_THAT(ns, Eq(kAppId)); + EXPECT_THAT(key, Eq(kKey)); + value = kValue; + ttl = kTtl; + return WPEFramework::Core::ERROR_NONE; + })); + } + }; + PublishedServiceType metadata(WPEFramework::Core::System::MODULE_NAME, 1, 0, 0); + ASSERT_THAT(plugin->Initialize(service), Eq("")); + auto jsonRpc = plugin->QueryInterface(); + ASSERT_THAT(jsonRpc, NotNull()); + GetValueParamsInfo params; + params.Scope = IStore2::ScopeType::ACCOUNT; + params.Ns = kAppId; + params.Key = kKey; + string paramsJsonStr; + params.ToString(paramsJsonStr); + string resultJsonStr; + ASSERT_THAT(jsonRpc->Invoke(0, 0, "", "getValue", paramsJsonStr, resultJsonStr), Eq(WPEFramework::Core::ERROR_NONE)); + GetValueResultData result; + result.FromString(resultJsonStr); + EXPECT_THAT(result.Value.Value(), Eq(kValue)); + EXPECT_THAT(result.Ttl.Value(), Eq(kTtl)); + jsonRpc->Release(); + plugin->Deinitialize(service); +} + +TEST_F(ASecureStore, SetsValueInAccountScopeViaJsonRpc) +{ + class SecureStoreImplementation : public NiceMock { + public: + SecureStoreImplementation() + { + EXPECT_CALL(*this, SetValue(_, _, _, _, _)) + .WillRepeatedly(Invoke( + [](const IStore2::ScopeType scope, const string& ns, const string& key, const string& value, const uint32_t ttl) { + EXPECT_THAT(scope, Eq(IStore2::ScopeType::ACCOUNT)); + EXPECT_THAT(ns, Eq(kAppId)); + EXPECT_THAT(key, Eq(kKey)); + EXPECT_THAT(value, Eq(kValue)); + EXPECT_THAT(ttl, Eq(kTtl)); + return WPEFramework::Core::ERROR_NONE; + })); + } + }; + PublishedServiceType metadata(WPEFramework::Core::System::MODULE_NAME, 1, 0, 0); + ASSERT_THAT(plugin->Initialize(service), Eq("")); + auto jsonRpc = plugin->QueryInterface(); + ASSERT_THAT(jsonRpc, NotNull()); + SetValueParamsData params; + params.Scope = IStore2::ScopeType::ACCOUNT; + params.Ns = kAppId; + params.Key = kKey; + params.Value = kValue; + params.Ttl = kTtl; + string paramsJsonStr; + params.ToString(paramsJsonStr); + string resultJsonStr; + EXPECT_THAT(jsonRpc->Invoke(0, 0, "", "setValue", paramsJsonStr, resultJsonStr), Eq(WPEFramework::Core::ERROR_NONE)); + jsonRpc->Release(); + plugin->Deinitialize(service); +} + +TEST_F(ASecureStore, DeletesKeyInAccountScopeViaJsonRpc) +{ + class SecureStoreImplementation : public NiceMock { + public: + SecureStoreImplementation() + { + EXPECT_CALL(*this, DeleteKey(_, _, _)) + .WillRepeatedly(Invoke( + [](const IStore2::ScopeType scope, const string& ns, const string& key) { + EXPECT_THAT(scope, Eq(IStore2::ScopeType::ACCOUNT)); + EXPECT_THAT(ns, Eq(kAppId)); + EXPECT_THAT(key, Eq(kKey)); + return WPEFramework::Core::ERROR_NONE; + })); + } + }; + PublishedServiceType metadata(WPEFramework::Core::System::MODULE_NAME, 1, 0, 0); + ASSERT_THAT(plugin->Initialize(service), Eq("")); + auto jsonRpc = plugin->QueryInterface(); + ASSERT_THAT(jsonRpc, NotNull()); + GetValueParamsInfo params; + params.Scope = IStore2::ScopeType::ACCOUNT; + params.Ns = kAppId; + params.Key = kKey; + string paramsJsonStr; + params.ToString(paramsJsonStr); + string resultJsonStr; + EXPECT_THAT(jsonRpc->Invoke(0, 0, "", "deleteKey", paramsJsonStr, resultJsonStr), Eq(WPEFramework::Core::ERROR_NONE)); + jsonRpc->Release(); + plugin->Deinitialize(service); +} + +TEST_F(ASecureStore, DeletesNamespaceInAccountScopeViaJsonRpc) +{ + class SecureStoreImplementation : public NiceMock { + public: + SecureStoreImplementation() + { + EXPECT_CALL(*this, DeleteNamespace(_, _)) + .WillRepeatedly(Invoke( + [](const IStore2::ScopeType scope, const string& ns) { + EXPECT_THAT(scope, Eq(IStore2::ScopeType::ACCOUNT)); + EXPECT_THAT(ns, Eq(kAppId)); + return WPEFramework::Core::ERROR_NONE; + })); + } + }; + PublishedServiceType metadata(WPEFramework::Core::System::MODULE_NAME, 1, 0, 0); + ASSERT_THAT(plugin->Initialize(service), Eq("")); + auto jsonRpc = plugin->QueryInterface(); + ASSERT_THAT(jsonRpc, NotNull()); + DeleteNamespaceParamsData params; + params.Scope = IStore2::ScopeType::ACCOUNT; + params.Ns = kAppId; + string paramsJsonStr; + params.ToString(paramsJsonStr); + string resultJsonStr; + EXPECT_THAT(jsonRpc->Invoke(0, 0, "", "deleteNamespace", paramsJsonStr, resultJsonStr), Eq(WPEFramework::Core::ERROR_NONE)); + jsonRpc->Release(); + plugin->Deinitialize(service); +} diff --git a/SecureStore/l0test/ServiceMock.h b/SecureStore/l0test/ServiceMock.h new file mode 100644 index 0000000000..63fa33379f --- /dev/null +++ b/SecureStore/l0test/ServiceMock.h @@ -0,0 +1,60 @@ +#pragma once + +#include "../Module.h" +#include + +class ServiceMock : public WPEFramework::PluginHost::IShell, + public WPEFramework::PluginHost::IShell::ICOMLink { +public: + ~ServiceMock() override = default; + MOCK_METHOD(string, Versions, (), (const, override)); + MOCK_METHOD(string, Locator, (), (const, override)); + MOCK_METHOD(string, ClassName, (), (const, override)); + MOCK_METHOD(string, Callsign, (), (const, override)); + MOCK_METHOD(string, WebPrefix, (), (const, override)); + MOCK_METHOD(string, ConfigLine, (), (const, override)); + MOCK_METHOD(string, PersistentPath, (), (const, override)); + MOCK_METHOD(string, VolatilePath, (), (const, override)); + MOCK_METHOD(string, DataPath, (), (const, override)); + MOCK_METHOD(state, State, (), (const, override)); + MOCK_METHOD(bool, Resumed, (), (const, override)); + MOCK_METHOD(bool, IsSupported, (const uint8_t), (const, override)); + MOCK_METHOD(void, EnableWebServer, (const string&, const string&), (override)); + MOCK_METHOD(void, DisableWebServer, (), (override)); + MOCK_METHOD(WPEFramework::PluginHost::ISubSystem*, SubSystems, (), (override)); + MOCK_METHOD(uint32_t, Submit, (const uint32_t, const WPEFramework::Core::ProxyType&), (override)); + MOCK_METHOD(void, Notify, (const string&, const string&), (override)); + MOCK_METHOD(void*, QueryInterfaceByCallsign, (const uint32_t, const string&), (override)); + MOCK_METHOD(void, Register, (WPEFramework::PluginHost::IPlugin::INotification*), (override)); + MOCK_METHOD(void, Unregister, (WPEFramework::PluginHost::IPlugin::INotification*), (override)); + MOCK_METHOD(string, Model, (), (const, override)); + MOCK_METHOD(bool, Background, (), (const, override)); + MOCK_METHOD(string, Accessor, (), (const, override)); + MOCK_METHOD(string, ProxyStubPath, (), (const, override)); + MOCK_METHOD(string, HashKey, (), (const, override)); + MOCK_METHOD(string, Substitute, (const string&), (const, override)); + MOCK_METHOD(uint32_t, Activate, (const reason), (override)); + MOCK_METHOD(uint32_t, Deactivate, (const reason), (override)); + MOCK_METHOD(uint32_t, Unavailable, (const reason), (override)); + MOCK_METHOD(reason, Reason, (), (const, override)); + MOCK_METHOD(uint32_t, ConfigLine, (const string&), (override)); + MOCK_METHOD(string, SystemRootPath, (), (const, override)); + MOCK_METHOD(uint32_t, SystemRootPath, (const string&), (override)); + MOCK_METHOD(string, SystemPath, (), (const, override)); + MOCK_METHOD(string, PluginPath, (), (const, override)); + MOCK_METHOD(WPEFramework::PluginHost::IShell::startmode, StartMode, (), (const, override)); + MOCK_METHOD(WPEFramework::Core::hresult, StartMode, (const startmode), (override)); + MOCK_METHOD(WPEFramework::Core::hresult, Resumed, (const bool), (override)); + MOCK_METHOD(WPEFramework::Core::hresult, Metadata, (string&), (const, override)); + MOCK_METHOD(WPEFramework::Core::hresult, Hibernate, (const uint32_t), (override)); + MOCK_METHOD(void, Register, (WPEFramework::RPC::IRemoteConnection::INotification*), (override)); + MOCK_METHOD(void, Unregister, (const WPEFramework::RPC::IRemoteConnection::INotification*), (override)); + MOCK_METHOD(void, Register, (IShell::ICOMLink::INotification*), (override)); + MOCK_METHOD(void, Unregister, (const IShell::ICOMLink::INotification*), (override)); + MOCK_METHOD(WPEFramework::RPC::IRemoteConnection*, RemoteConnection, (const uint32_t), (override)); + MOCK_METHOD(void*, Instantiate, (const WPEFramework::RPC::Object&, const uint32_t, uint32_t&), (override)); + BEGIN_INTERFACE_MAP(ServiceMock) + INTERFACE_ENTRY(IShell) + INTERFACE_ENTRY(IShell::ICOMLink) + END_INTERFACE_MAP +};