|
|
@@ -106,7 +106,7 @@ Result<CredentialInfo> CredentialStore::create(const CreateCredentialRequest& re
|
|
|
return Error(ErrorCode::InvalidArgument, "API key value is required");
|
|
|
}
|
|
|
data_to_encrypt = data.toJson();
|
|
|
- public_data = {{"header_name", data.header_name}};
|
|
|
+ public_data = {{"header_name", data.header_name}, {"value_prefix", data.value_prefix}};
|
|
|
break;
|
|
|
}
|
|
|
case CredentialType::OAuth2: {
|
|
|
@@ -251,26 +251,56 @@ Result<void> CredentialStore::update(const std::string& id, const UpdateCredenti
|
|
|
nlohmann::json data_to_encrypt;
|
|
|
nlohmann::json public_data;
|
|
|
|
|
|
+ // Merged over what is stored rather than replacing it. Every branch
|
|
|
+ // below parses the request into a typed struct and re-encrypts the
|
|
|
+ // result, so a field the caller left out came back as an empty string
|
|
|
+ // and overwrote the secret with nothing. The edit form says
|
|
|
+ // "(unchanged)" next to a blank password box - so renaming a
|
|
|
+ // credential silently destroyed the very thing it exists to hold.
|
|
|
+ //
|
|
|
+ // A key present but empty means "leave it alone"; a key present with a
|
|
|
+ // value means "use this". Booleans and numbers pass through either way,
|
|
|
+ // so a port of 0 or an SSL flag of false can still be set.
|
|
|
+ nlohmann::json merged = request.data;
|
|
|
+ {
|
|
|
+ auto existing = decryptData(doc.encrypted_data);
|
|
|
+ if (existing.ok() && existing.value().is_object()) {
|
|
|
+ const nlohmann::json& stored = existing.value();
|
|
|
+ for (auto it = stored.begin(); it != stored.end(); ++it) {
|
|
|
+ const bool absent = !merged.contains(it.key());
|
|
|
+ const bool blank = !absent && merged[it.key()].is_string() &&
|
|
|
+ merged[it.key()].get<std::string>().empty();
|
|
|
+ if (absent || blank) {
|
|
|
+ merged[it.key()] = it.value();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ LOG_WARN("Could not read the stored secret for {} while updating it - "
|
|
|
+ "anything the caller left out cannot be preserved", id);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ const nlohmann::json& request_data = merged;
|
|
|
+
|
|
|
switch (doc.metadata.type) {
|
|
|
case CredentialType::Basic: {
|
|
|
- auto data = BasicAuthData::fromJson(request.data);
|
|
|
+ auto data = BasicAuthData::fromJson(request_data);
|
|
|
data_to_encrypt = data.toJson();
|
|
|
public_data = {{"username", data.username}};
|
|
|
break;
|
|
|
}
|
|
|
case CredentialType::Bearer: {
|
|
|
- auto data = BearerTokenData::fromJson(request.data);
|
|
|
+ auto data = BearerTokenData::fromJson(request_data);
|
|
|
data_to_encrypt = data.toJson();
|
|
|
break;
|
|
|
}
|
|
|
case CredentialType::ApiKey: {
|
|
|
- auto data = ApiKeyData::fromJson(request.data);
|
|
|
+ auto data = ApiKeyData::fromJson(request_data);
|
|
|
data_to_encrypt = data.toJson();
|
|
|
- public_data = {{"header_name", data.header_name}};
|
|
|
+ public_data = {{"header_name", data.header_name}, {"value_prefix", data.value_prefix}};
|
|
|
break;
|
|
|
}
|
|
|
case CredentialType::OAuth2: {
|
|
|
- auto data = OAuth2Data::fromJson(request.data);
|
|
|
+ auto data = OAuth2Data::fromJson(request_data);
|
|
|
data_to_encrypt = data.toJson();
|
|
|
public_data = {
|
|
|
{"grant_type", data.grant_type},
|
|
|
@@ -282,7 +312,7 @@ Result<void> CredentialStore::update(const std::string& id, const UpdateCredenti
|
|
|
break;
|
|
|
}
|
|
|
case CredentialType::Imap: {
|
|
|
- auto data = ImapData::fromJson(request.data);
|
|
|
+ auto data = ImapData::fromJson(request_data);
|
|
|
data_to_encrypt = data.toJson();
|
|
|
public_data = {
|
|
|
{"host", data.host},
|
|
|
@@ -293,7 +323,7 @@ Result<void> CredentialStore::update(const std::string& id, const UpdateCredenti
|
|
|
break;
|
|
|
}
|
|
|
case CredentialType::Smtp: {
|
|
|
- auto data = SmtpData::fromJson(request.data);
|
|
|
+ auto data = SmtpData::fromJson(request_data);
|
|
|
data_to_encrypt = data.toJson();
|
|
|
public_data = {
|
|
|
{"host", data.host},
|
|
|
@@ -306,7 +336,7 @@ Result<void> CredentialStore::update(const std::string& id, const UpdateCredenti
|
|
|
break;
|
|
|
}
|
|
|
case CredentialType::Mysql: {
|
|
|
- auto data = MysqlData::fromJson(request.data);
|
|
|
+ auto data = MysqlData::fromJson(request_data);
|
|
|
data_to_encrypt = data.toJson();
|
|
|
public_data = {
|
|
|
{"host", data.host},
|
|
|
@@ -318,7 +348,7 @@ Result<void> CredentialStore::update(const std::string& id, const UpdateCredenti
|
|
|
break;
|
|
|
}
|
|
|
case CredentialType::Postgresql: {
|
|
|
- auto data = PostgresqlData::fromJson(request.data);
|
|
|
+ auto data = PostgresqlData::fromJson(request_data);
|
|
|
data_to_encrypt = data.toJson();
|
|
|
public_data = {
|
|
|
{"host", data.host},
|