diff --git a/build b/build index f11c82a..9d60796 100644 --- a/build +++ b/build @@ -1 +1 @@ -9 \ No newline at end of file +11 \ No newline at end of file diff --git a/openpapi/owsec.yaml b/openpapi/owsec.yaml index 4423548..151c7bf 100644 --- a/openpapi/owsec.yaml +++ b/openpapi/owsec.yaml @@ -1983,9 +1983,19 @@ paths: schema: type: string required: true + - in: query + name: all + schema: + type: boolean + required: false responses: 200: - $ref: '#/components/schemas/SystemSecretEntry' + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/SystemSecretEntry' + - $ref: '#/components/schemas/SystemSecretEntryList' 403: $ref: '#/components/responses/Unauthorized' 404: diff --git a/src/Daemon.cpp b/src/Daemon.cpp index 81b06f4..c29744c 100644 --- a/src/Daemon.cpp +++ b/src/Daemon.cpp @@ -28,6 +28,7 @@ #include "TotpCache.h" #include "framework/RESTAPI_RateLimiter.h" #include "framework/UI_WebSocketClientServer.h" +#include namespace OpenWifi { class Daemon *Daemon::instance_ = nullptr; @@ -47,7 +48,8 @@ namespace OpenWifi { RESTAPI_RateLimiter(), TotpCache(), AuthService(), - UI_WebSocketClientServer() + UI_WebSocketClientServer(), + SecretStore() }); } return instance_; diff --git a/src/RESTAPI/RESTAPI_systemSecret_handler.cpp b/src/RESTAPI/RESTAPI_systemSecret_handler.cpp index 4d7ed8a..7282f39 100644 --- a/src/RESTAPI/RESTAPI_systemSecret_handler.cpp +++ b/src/RESTAPI/RESTAPI_systemSecret_handler.cpp @@ -3,6 +3,7 @@ // #include "RESTAPI_systemSecret_handler.h" +#include namespace OpenWifi { @@ -10,6 +11,35 @@ namespace OpenWifi { if(!Internal_ && UserInfo_.userinfo.userRole!=SecurityObjects::ROOT) { return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); } + + if(GetBoolParameter("all")) { + auto Store = SecretStore()->Store(); + Poco::JSON::Array Entries; + Poco::JSON::Object List; + + for(const auto &[Key,Value]:Store) { + Poco::JSON::Object E; + E.set("key",Key); + E.set("value",Value); + Entries.add(E); + } + List.set("secrets",Entries); + return ReturnObject(List); + } + + auto Key = GetBinding("secret"); + if(Key.empty()) { + return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); + } + + std::string Value; + if(SecretStore()->Get(Key,Value,"")) { + Poco::JSON::Object Answer; + Answer.set("key", Key); + Answer.set("value", Value); + return ReturnObject(Answer); + } + return NotFound(); } void RESTAPI_systemSecret_handler::DoDelete() { @@ -17,6 +47,14 @@ namespace OpenWifi { return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); } + auto Key = GetBinding("secret"); + if(Key.empty()) { + return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); + } + + SecretStore()->Remove(Key); + return OK(); + } void RESTAPI_systemSecret_handler::DoPut() { @@ -24,6 +62,17 @@ namespace OpenWifi { return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); } + auto Key = GetBinding("secret"); + auto Value = GetParameter("value","_______no_value_____"); + if(Key.empty() || Value == "_______no_value_____") { + return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); + } + + SecretStore()->Set(Key,Value); + Poco::JSON::Object Answer; + Answer.set("key", Key); + Answer.set("value", Value); + return ReturnObject(Answer); } } // OpenWifi \ No newline at end of file diff --git a/src/SecretStore.cpp b/src/SecretStore.cpp index 6870bc4..64b009a 100644 --- a/src/SecretStore.cpp +++ b/src/SecretStore.cpp @@ -2,15 +2,91 @@ // Created by stephane bourque on 2023-01-25. // +#include #include "SecretStore.h" +#include +#include +#include namespace OpenWifi { + int SecretStore::Start() { + std::lock_guard G(Mutex_); + ReadStore(); return 0; } void SecretStore::Stop() { + std::lock_guard G(Mutex_); + SaveStore(); + } + void SecretStore::ReadStore() { + Poco::File StoreFileName(MicroServiceDataDirectory() + "/secrets.json"); + if(StoreFileName.exists() && StoreFileName.isFile()) { + try { + std::ostringstream OS; + std::ifstream IF(StoreFileName.path().c_str()); + Poco::StreamCopier::copyStream(IF, OS); + Poco::JSON::Parser P; + auto Doc = P.parse(OS.str()).extract(); + if(Doc->isArray("secrets")) { + auto Secrets = Doc->getArray("secrets"); + for(const auto &secret:*Secrets) { + const auto &entry = secret.extract(); + if(entry->has("key") && entry->has("value")) { + Store_[entry->get("key")] = entry->get("value").toString(); + } + } + } + } catch (const Poco::Exception &E) { + Logger().log(E); + } + } + } + + void SecretStore::SaveStore() { + Poco::JSON::Object StoreJSON; + Poco::JSON::Array Secrets; + + for(const auto &[key,value]:Store_) { + Poco::JSON::Object Entry; + Entry.set("key", key); + Entry.set("value", value); + Secrets.add(Entry); + } + + StoreJSON.set("secrets",Secrets); + Poco::File StoreFileName(MicroServiceDataDirectory() + "/secrets.json"); + std::ofstream OF(StoreFileName.path(),std::ios_base::trunc); + StoreJSON.stringify(OF); + } + + bool SecretStore::Get(const std::string & key, std::string & value, const std::string & default_value) { + std::lock_guard G(Mutex_); + + auto It = Store_.find(key); + if(It!=end(Store_)) { + value = It->second; + return true; + } else { + value = default_value; + return false; + } + } + + void SecretStore::Set(const std::string & key, const std::string & value ) { + std::lock_guard G(Mutex_); + + Store_[key] = value; + SaveStore(); + } + + void SecretStore::Remove(const std::string & key) { + std::lock_guard G(Mutex_); + + Store_.erase(key); + SaveStore(); } } // OpenWifi \ No newline at end of file diff --git a/src/SecretStore.h b/src/SecretStore.h index d528b63..b605d52 100644 --- a/src/SecretStore.h +++ b/src/SecretStore.h @@ -10,6 +10,8 @@ namespace OpenWifi { class SecretStore : public SubSystemServer { public: + + using SecretStoreType = std::map; static SecretStore *instance() { static auto *instance_ = new SecretStore; return instance_; @@ -17,9 +19,18 @@ namespace OpenWifi { int Start() final; void Stop() final; + void ReadStore(); + void SaveStore(); + bool Get(const std::string & key, std::string & value, const std::string & default_value); + void Set(const std::string & key, const std::string & value ); + void Remove(const std::string &key); + inline SecretStoreType Store() { + std::lock_guard G(Mutex_); + return Store_; + } private: - + SecretStoreType Store_; SecretStore() noexcept: SubSystemServer("SecretStore", "SECRET-SVR", "secret.store") {