diff --git a/packages/cli/src/main/kotlin/elide/tool/cli/cmd/secrets/ToolSecretsCommand.kt b/packages/cli/src/main/kotlin/elide/tool/cli/cmd/secrets/ToolSecretsCommand.kt index 37c00debe6..64168fc65f 100644 --- a/packages/cli/src/main/kotlin/elide/tool/cli/cmd/secrets/ToolSecretsCommand.kt +++ b/packages/cli/src/main/kotlin/elide/tool/cli/cmd/secrets/ToolSecretsCommand.kt @@ -245,6 +245,7 @@ internal class ToolSecretsCommand : ProjectAwareSubcommand createAccess(remote) ManageRemoteOptions.LIST -> println(remote.listAccesses()) ManageRemoteOptions.SELECT -> selectAccess(remote) + ManageRemoteOptions.CHANGE -> remote.changeSuperEncryption() ManageRemoteOptions.REMOVE -> removeAccess(remote) ManageRemoteOptions.REKEY -> rekeyProfiles(remote) ManageRemoteOptions.DELETE -> deleteProfile(remote) @@ -379,6 +380,7 @@ internal class ToolSecretsCommand : ProjectAwareSubcommand + UserKey(encryption.hashKeySHA256(SecretPrompts.passphrase(prompts).encodeToByteString())) + + EncryptionMode.GPG -> UserKey(SecretPrompts.gpgPrivateKey()) + } + } + override fun rekeyProfile(profile: String) { rekeyed.add(profile) } @@ -212,7 +222,9 @@ internal class RemoteManagementImpl( ) deleted.forEach { files.removeProfile(it) } SecretsState.updateMetadata { removeAll(deleted) } + SecretsState.updateLocal { add(BinarySecret(SecretValues.SUPER_ACCESS_KEY_SECRET, superKey.key)) } files.writeMetadata() + files.writeLocal() } private fun rekeyProfiles() { diff --git a/packages/secrets/src/main/kotlin/elide/secrets/impl/SecretManagementImpl.kt b/packages/secrets/src/main/kotlin/elide/secrets/impl/SecretManagementImpl.kt index 29e9e29b0b..ed6f88f459 100644 --- a/packages/secrets/src/main/kotlin/elide/secrets/impl/SecretManagementImpl.kt +++ b/packages/secrets/src/main/kotlin/elide/secrets/impl/SecretManagementImpl.kt @@ -19,6 +19,7 @@ import java.nio.file.Path import kotlinx.io.bytestring.ByteString import kotlinx.io.files.SystemFileSystem import kotlinx.serialization.BinaryFormat +import kotlinx.serialization.SerializationException import kotlinx.serialization.json.Json import elide.annotations.Singleton import elide.secrets.* @@ -291,8 +292,20 @@ internal class SecretManagementImpl( ) EncryptionMode.GPG -> UserKey(remoteMetadata.superAccess.fingerprint!!) } - val superAccess: SuperAccess = + val superAccess: SuperAccess = try { SecretsState.remote.getSuperAccess()!!.decrypt(superKey, encryption).deserialize(cbor) + } catch(_: SerializationException) { + println(SecretValues.INVALID_SUPER_CREDENTIALS_MESSAGE) + val superKey: UserKey = + when (remoteMetadata.superAccess.mode) { + EncryptionMode.PASSPHRASE -> + UserKey(prompts.removeFirstOrNull()?.hashKey(encryption) + ?: KInquirer.promptInputPassword(SecretValues.SUPERUSER_PASSPHRASE_PROMPT).hashKey(encryption), + ) + EncryptionMode.GPG -> UserKey(remoteMetadata.superAccess.fingerprint!!) + } + SecretsState.remote.getSuperAccess()!!.decrypt(superKey, encryption).deserialize(cbor) + } return RemoteManagementImpl(secrets, files, encryption, json, cbor, remoteMetadata, superAccess, superKey, prompts) .apply { init() diff --git a/packages/secrets/src/test/kotlin/elide/secrets/ManagementTest.kt b/packages/secrets/src/test/kotlin/elide/secrets/ManagementTest.kt index 7ec9198602..4ce0f89e2d 100644 --- a/packages/secrets/src/test/kotlin/elide/secrets/ManagementTest.kt +++ b/packages/secrets/src/test/kotlin/elide/secrets/ManagementTest.kt @@ -254,6 +254,11 @@ class ManagementTest : AbstractSecretTest() { // regenerate profile key remote.rekeyProfile("test") + // change superuser access passphrase + // remote.changeSuperEncryption() asks for encryption mode and passphrase twice. + queuePrompts(EncryptionMode.PASSPHRASE, "seus", "seus") + remote.changeSuperEncryption() + // push changes and check for files remote.push() assertTrue(path.resolve(SecretValues.PROJECT_REMOTE_DEFAULT_PATH).resolve(SecretValues.METADATA_FILE).exists())