Skip to content

Commit 956abb6

Browse files
melodicoresgammon
authored andcommitted
feat(secrets): allow changing remote superuser credentials
Signed-off-by: melodicore <[email protected]>
1 parent b418e23 commit 956abb6

File tree

7 files changed

+38
-1
lines changed

7 files changed

+38
-1
lines changed

packages/cli/src/main/kotlin/elide/tool/cli/cmd/secrets/ToolSecretsCommand.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ internal class ToolSecretsCommand : ProjectAwareSubcommand<ToolState, CommandCon
245245
ManageRemoteOptions.CREATE -> createAccess(remote)
246246
ManageRemoteOptions.LIST -> println(remote.listAccesses())
247247
ManageRemoteOptions.SELECT -> selectAccess(remote)
248+
ManageRemoteOptions.CHANGE -> remote.changeSuperEncryption()
248249
ManageRemoteOptions.REMOVE -> removeAccess(remote)
249250
ManageRemoteOptions.REKEY -> rekeyProfiles(remote)
250251
ManageRemoteOptions.DELETE -> deleteProfile(remote)
@@ -379,6 +380,7 @@ internal class ToolSecretsCommand : ProjectAwareSubcommand<ToolState, CommandCon
379380
CREATE("Create an access file"),
380381
LIST("List access files"),
381382
SELECT("Select an access file"),
383+
CHANGE("Change superuser encryption details"),
382384
REMOVE("Remove an access file"),
383385
REKEY("Regenerate profile keys"),
384386
DELETE("Delete a profile"),

packages/secrets/api/secrets.api

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
public abstract interface class elide/secrets/RemoteManagement {
22
public abstract fun addProfile (Ljava/lang/String;)V
33
public abstract fun changeEncryption ()V
4+
public abstract fun changeSuperEncryption ()V
45
public abstract fun createAccess (Ljava/lang/String;)V
56
public abstract fun deleteAccess (Ljava/lang/String;)V
67
public abstract fun deleteProfile (Ljava/lang/String;)V

packages/secrets/src/main/kotlin/elide/secrets/RemoteManagement.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ public interface RemoteManagement {
4848
/** Deselects the selected access file. */
4949
public fun deselectAccess()
5050

51+
/** Prompts user on a new encryption mode for superuser access. */
52+
public fun changeSuperEncryption()
53+
5154
/** Generates new keys for specified profiles. */
5255
public fun rekeyProfile(profile: String)
5356

packages/secrets/src/main/kotlin/elide/secrets/SecretValues.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ internal object SecretValues {
8787
const val DELETE_PROFILES_MESSAGE = "Deleting the profile will also delete it from your local secrets!"
8888
const val GPG_KEY_REVOKED_MISSING_MESSAGE =
8989
"GPG private key is expired, revoked or not present. If secrets load correctly, please update your encryption mode!"
90+
const val INVALID_SUPER_CREDENTIALS_MESSAGE = "Invalid superuser credentials."
9091

9192
fun accessesWithProfileMessage(accesses: String) =
9293
"The following access files contain the profile:\n$accesses\n" +

packages/secrets/src/main/kotlin/elide/secrets/impl/RemoteManagementImpl.kt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,16 @@ internal class RemoteManagementImpl(
139139
access = null
140140
}
141141

142+
override fun changeSuperEncryption() {
143+
val mode = SecretPrompts.accessMode(prompts)
144+
superKey = when (mode) {
145+
EncryptionMode.PASSPHRASE ->
146+
UserKey(encryption.hashKeySHA256(SecretPrompts.passphrase(prompts).encodeToByteString()))
147+
148+
EncryptionMode.GPG -> UserKey(SecretPrompts.gpgPrivateKey())
149+
}
150+
}
151+
142152
override fun rekeyProfile(profile: String) {
143153
rekeyed.add(profile)
144154
}
@@ -212,7 +222,9 @@ internal class RemoteManagementImpl(
212222
)
213223
deleted.forEach { files.removeProfile(it) }
214224
SecretsState.updateMetadata { removeAll(deleted) }
225+
SecretsState.updateLocal { add(BinarySecret(SecretValues.SUPER_ACCESS_KEY_SECRET, superKey.key)) }
215226
files.writeMetadata()
227+
files.writeLocal()
216228
}
217229

218230
private fun rekeyProfiles() {

packages/secrets/src/main/kotlin/elide/secrets/impl/SecretManagementImpl.kt

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import java.nio.file.Path
1919
import kotlinx.io.bytestring.ByteString
2020
import kotlinx.io.files.SystemFileSystem
2121
import kotlinx.serialization.BinaryFormat
22+
import kotlinx.serialization.SerializationException
2223
import kotlinx.serialization.json.Json
2324
import elide.annotations.Singleton
2425
import elide.secrets.*
@@ -291,8 +292,20 @@ internal class SecretManagementImpl(
291292
)
292293
EncryptionMode.GPG -> UserKey(remoteMetadata.superAccess.fingerprint!!)
293294
}
294-
val superAccess: SuperAccess =
295+
val superAccess: SuperAccess = try {
295296
SecretsState.remote.getSuperAccess()!!.decrypt(superKey, encryption).deserialize(cbor)
297+
} catch(_: SerializationException) {
298+
println(SecretValues.INVALID_SUPER_CREDENTIALS_MESSAGE)
299+
val superKey: UserKey =
300+
when (remoteMetadata.superAccess.mode) {
301+
EncryptionMode.PASSPHRASE ->
302+
UserKey(prompts.removeFirstOrNull()?.hashKey(encryption)
303+
?: KInquirer.promptInputPassword(SecretValues.SUPERUSER_PASSPHRASE_PROMPT).hashKey(encryption),
304+
)
305+
EncryptionMode.GPG -> UserKey(remoteMetadata.superAccess.fingerprint!!)
306+
}
307+
SecretsState.remote.getSuperAccess()!!.decrypt(superKey, encryption).deserialize(cbor)
308+
}
296309
return RemoteManagementImpl(secrets, files, encryption, json, cbor, remoteMetadata, superAccess, superKey, prompts)
297310
.apply {
298311
init()

packages/secrets/src/test/kotlin/elide/secrets/ManagementTest.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,11 @@ class ManagementTest : AbstractSecretTest() {
254254
// regenerate profile key
255255
remote.rekeyProfile("test")
256256

257+
// change superuser access passphrase
258+
// remote.changeSuperEncryption() asks for encryption mode and passphrase twice.
259+
queuePrompts(EncryptionMode.PASSPHRASE, "seus", "seus")
260+
remote.changeSuperEncryption()
261+
257262
// push changes and check for files
258263
remote.push()
259264
assertTrue(path.resolve(SecretValues.PROJECT_REMOTE_DEFAULT_PATH).resolve(SecretValues.METADATA_FILE).exists())

0 commit comments

Comments
 (0)