diff --git a/repertory/repertory/src/ui/handlers.cpp b/repertory/repertory/src/ui/handlers.cpp index 5810e29d..c8ef41ac 100644 --- a/repertory/repertory/src/ui/handlers.cpp +++ b/repertory/repertory/src/ui/handlers.cpp @@ -29,10 +29,33 @@ #include "utils/common.hpp" #include "utils/error_utils.hpp" #include "utils/file.hpp" +#include "utils/hash.hpp" #include "utils/path.hpp" #include "utils/string.hpp" namespace { +[[nodiscard]] auto decrypt(std::string_view data, std::string_view password) + -> std::string { + auto decoded = macaron::Base64::Decode(data); + repertory::data_buffer buffer(decoded.size()); + + auto key = repertory::utils::encryption::create_hash_blake2b_256(password); + + std::uint64_t size{}; + crypto_aead_xchacha20poly1305_ietf_decrypt( + reinterpret_cast(buffer.data()), &size, nullptr, + reinterpret_cast( + &decoded.at(crypto_aead_xchacha20poly1305_IETF_NPUBBYTES)), + decoded.size() - crypto_aead_xchacha20poly1305_IETF_NPUBBYTES, + reinterpret_cast(REPERTORY.data()), 9U, + reinterpret_cast(decoded.data()), + reinterpret_cast(key.data())); + + return std::string( + buffer.begin(), + std::next(buffer.begin(), static_cast(size))); +} + [[nodiscard]] constexpr auto is_restricted(std::string_view data) -> bool { constexpr std::string_view invalid_chars = "&;|><$()`{}!*?"; return data.find_first_of(invalid_chars) != std::string_view::npos; @@ -386,6 +409,7 @@ void handlers::handle_post_mount(auto &&req, auto &&res) const { void handlers::handle_put_set_value_by_name(auto &&req, auto &&res) const { auto name = req.get_param_value("name"); + auto prov = provider_type_from_string(req.get_param_value("type")); if (not data_directory_exists(prov, name)) { @@ -394,8 +418,19 @@ void handlers::handle_put_set_value_by_name(auto &&req, auto &&res) const { } auto key = req.get_param_value("key"); + auto last_key{key}; auto value = req.get_param_value("value"); + auto parts = utils::string::split(key, '.', false); + if (parts.size() > 1U) { + last_key = parts.at(parts.size() - 1U); + } + + if (last_key == JSON_API_PASSWORD || last_key == JSON_ENCRYPTION_TOKEN || + last_key == JSON_SECRET_KEY) { + value = decrypt(value, config_->get_api_password()); + } + set_key_value(prov, name, key, value); res.status = http_error_codes::ok; diff --git a/web/repertory/lib/helpers.dart b/web/repertory/lib/helpers.dart index 3e75d9ed..dd4b71be 100644 --- a/web/repertory/lib/helpers.dart +++ b/web/repertory/lib/helpers.dart @@ -227,6 +227,8 @@ bool validateSettings( } Map convertAllToString(Map settings) { + final password = 'test'; + settings.forEach((key, value) { if (value is Map) { convertAllToString(value); @@ -236,7 +238,7 @@ Map convertAllToString(Map settings) { if (key == 'ApiPassword' || key == 'EncryptionToken' || key == 'SecretKey') { - value = encryptValue(value); + value = encryptValue(value, password); } else if (value is String) { return; } @@ -247,7 +249,7 @@ Map convertAllToString(Map settings) { return settings; } -String encryptValue(String value) { +String encryptValue(String value, String password) { final sodium = constants.sodium; if (sodium == null) { return value; @@ -255,19 +257,18 @@ String encryptValue(String value) { final keyHash = sodium.crypto.genericHash( outLen: sodium.crypto.aeadChaCha20Poly1305.keyBytes, - message: Uint8List.fromList('test'.toCharArray()), + message: Uint8List.fromList(password.toCharArray()), ); final crypto = sodium.crypto.aeadXChaCha20Poly1305IETF; + final nonce = sodium.secureRandom(crypto.nonceBytes).extractBytes(); final data = crypto.encrypt( - additionalData: Uint8List.fromList( - 'repertory'.toCharArray(), - ), + additionalData: Uint8List.fromList('repertory'.toCharArray()), key: SecureKey.fromList(sodium, keyHash), message: Uint8List.fromList(value.toCharArray()), - nonce: sodium.secureRandom(crypto.nonceBytes).extractBytes(), + nonce: nonce, ); - return base64Encode(data); + return base64Encode(Uint8List.fromList([...nonce, ...data])); }