diff --git a/tests/test_ssh_proto.py b/tests/test_ssh_proto.py index 3d5ecb05..62807092 100644 --- a/tests/test_ssh_proto.py +++ b/tests/test_ssh_proto.py @@ -48,6 +48,7 @@ def setup_user_and_target( api.create_public_key_credential( user.id, sdk.NewPublicKeyCredential( + label="Public Key", openssh_public_key=open("ssh-keys/id_ed25519.pub").read().strip(), ), ) diff --git a/tests/test_ssh_user_auth_otp.py b/tests/test_ssh_user_auth_otp.py index 4e819236..7cb429c5 100644 --- a/tests/test_ssh_user_auth_otp.py +++ b/tests/test_ssh_user_auth_otp.py @@ -35,6 +35,7 @@ class Test: api.create_public_key_credential( user.id, sdk.NewPublicKeyCredential( + label="Public Key", openssh_public_key=open("ssh-keys/id_ed25519.pub").read().strip() ), ) diff --git a/tests/test_ssh_user_auth_pubkey.py b/tests/test_ssh_user_auth_pubkey.py index bb5b533a..9359d2a6 100644 --- a/tests/test_ssh_user_auth_pubkey.py +++ b/tests/test_ssh_user_auth_pubkey.py @@ -29,6 +29,7 @@ class Test: api.create_public_key_credential( user.id, sdk.NewPublicKeyCredential( + label="Public Key", openssh_public_key=open("ssh-keys/id_ed25519.pub").read().strip() ), ) @@ -104,6 +105,7 @@ class Test: api.create_public_key_credential( user.id, sdk.NewPublicKeyCredential( + label="Public Key", openssh_public_key=open("ssh-keys/id_rsa.pub").read().strip() ), ) diff --git a/warpgate-admin/src/api/public_key_credentials.rs b/warpgate-admin/src/api/public_key_credentials.rs index b271778e..cd43bb00 100644 --- a/warpgate-admin/src/api/public_key_credentials.rs +++ b/warpgate-admin/src/api/public_key_credentials.rs @@ -18,11 +18,13 @@ use super::AnySecurityScheme; #[derive(Object)] struct ExistingPublicKeyCredential { id: Uuid, + label: String, openssh_public_key: String, } #[derive(Object)] struct NewPublicKeyCredential { + label: String, openssh_public_key: String, } @@ -30,6 +32,7 @@ impl From for ExistingPublicKeyCredential { fn from(credential: PublicKeyCredential::Model) -> Self { Self { id: credential.id, + label: credential.label, openssh_public_key: credential.openssh_public_key, } } @@ -112,6 +115,7 @@ impl ListApi { let object = PublicKeyCredential::ActiveModel { id: Set(Uuid::new_v4()), user_id: Set(*user_id), + label: Set(body.label.clone()), ..PublicKeyCredential::ActiveModel::from(UserPublicKeyCredential::try_from(&*body)?) } .insert(&*db) @@ -154,6 +158,7 @@ impl DetailApi { let model = PublicKeyCredential::ActiveModel { id: Set(id.0), user_id: Set(*user_id), + label: Set(body.label.clone()), ..<_>::from(UserPublicKeyCredential::try_from(&*body)?) } .update(&*db) diff --git a/warpgate-db-entities/src/PublicKeyCredential.rs b/warpgate-db-entities/src/PublicKeyCredential.rs index 74c9fb5c..46e8a55f 100644 --- a/warpgate-db-entities/src/PublicKeyCredential.rs +++ b/warpgate-db-entities/src/PublicKeyCredential.rs @@ -11,6 +11,7 @@ pub struct Model { #[sea_orm(primary_key, auto_increment = false)] pub id: Uuid, pub user_id: Uuid, + pub label: String, pub openssh_public_key: String, } diff --git a/warpgate-db-migrations/src/lib.rs b/warpgate-db-migrations/src/lib.rs index dd5f3068..e192bd84 100644 --- a/warpgate-db-migrations/src/lib.rs +++ b/warpgate-db-migrations/src/lib.rs @@ -13,6 +13,7 @@ mod m00008_users; mod m00009_credential_models; mod m00010_parameters; mod m00011_rsa_key_algos; +mod m00012_add_openssh_public_key_label; pub struct Migrator; @@ -31,6 +32,7 @@ impl MigratorTrait for Migrator { Box::new(m00009_credential_models::Migration), Box::new(m00010_parameters::Migration), Box::new(m00011_rsa_key_algos::Migration), + Box::new(m00012_add_openssh_public_key_label::Migration), ] } } diff --git a/warpgate-db-migrations/src/m00012_add_openssh_public_key_label.rs b/warpgate-db-migrations/src/m00012_add_openssh_public_key_label.rs new file mode 100644 index 00000000..7d4a0524 --- /dev/null +++ b/warpgate-db-migrations/src/m00012_add_openssh_public_key_label.rs @@ -0,0 +1,42 @@ +use sea_orm_migration::prelude::*; + +pub struct Migration; + +impl MigrationName for Migration { + fn name(&self) -> &str { + "m00012_add_openssh_public_key_label" + } +} + +use crate::m00009_credential_models::public_key_credential; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .alter_table( + Table::alter() + .table(public_key_credential::Entity) + .add_column( + ColumnDef::new(Alias::new("label")) + .string() + .not_null() + .default("Public Key") + ) + .to_owned() + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .alter_table( + Table::alter() + .table(public_key_credential::Entity) + .drop_column(Alias::new("label")) + .to_owned(), + ) + .await + } + +} diff --git a/warpgate-protocol-http/src/api/credentials.rs b/warpgate-protocol-http/src/api/credentials.rs index e7cb4b29..93cc8235 100644 --- a/warpgate-protocol-http/src/api/credentials.rs +++ b/warpgate-protocol-http/src/api/credentials.rs @@ -72,6 +72,7 @@ enum CredentialsStateResponse { #[derive(Object)] struct NewPublicKeyCredential { + label: String, openssh_public_key: String, } @@ -79,14 +80,19 @@ struct NewPublicKeyCredential { struct ExistingPublicKeyCredential { id: Uuid, label: String, + abbreviated: String, } fn abbreviate_public_key(k: &str) -> String { let l = 10; + if k.len() <= l { + return k.to_string(); // Return the full key if it's shorter than or equal to `l`. + } + format!( "{}...{}", - &k[..l.min(k.len())], - &k[(k.len() - l).max(l).min(k.len() - 1)..] + &k[..l.min(k.len())], // Take the first `l` characters. + &k[k.len().saturating_sub(l)..] // Take the last `l` characters safely. ) } @@ -94,7 +100,8 @@ impl From for ExistingPublicKeyCredential fn from(credential: entities::PublicKeyCredential::Model) -> Self { Self { id: credential.id, - label: abbreviate_public_key(&credential.openssh_public_key), + label: credential.label, + abbreviated: abbreviate_public_key(&credential.openssh_public_key), } } } @@ -288,6 +295,7 @@ impl Api { let object = PublicKeyCredential::ActiveModel { id: Set(Uuid::new_v4()), user_id: Set(user_model.id), + label: Set(body.label.clone()), openssh_public_key: Set(body.openssh_public_key.clone()), } .insert(&*db) diff --git a/warpgate-web/src/admin/CredentialEditor.svelte b/warpgate-web/src/admin/CredentialEditor.svelte index 2465c6c6..3c41c38e 100644 --- a/warpgate-web/src/admin/CredentialEditor.svelte +++ b/warpgate-web/src/admin/CredentialEditor.svelte @@ -184,8 +184,9 @@ editingSsoCredentialInstance = null } - async function savePublicKeyCredential (opensshPublicKey: string) { + async function savePublicKeyCredential (label: string, opensshPublicKey: string) { if (editingPublicKeyCredentialInstance) { + editingPublicKeyCredentialInstance.label = label editingPublicKeyCredentialInstance.opensshPublicKey = opensshPublicKey await api.updatePublicKeyCredential({ userId, @@ -196,6 +197,7 @@ const credential = await api.createPublicKeyCredential({ userId, newPublicKeyCredential: { + label, opensshPublicKey, }, }) @@ -250,7 +252,7 @@ {/if} {#if credential.kind === 'PublicKey'} - Public key + {credential.label} {abbreviatePublicKey(credential.opensshPublicKey)} {/if} {#if credential.kind === 'Totp'} diff --git a/warpgate-web/src/admin/PublicKeyCredentialModal.svelte b/warpgate-web/src/admin/PublicKeyCredentialModal.svelte index e33a0bce..212deade 100644 --- a/warpgate-web/src/admin/PublicKeyCredentialModal.svelte +++ b/warpgate-web/src/admin/PublicKeyCredentialModal.svelte @@ -15,7 +15,7 @@ interface Props { isOpen: boolean instance?: ExistingPublicKeyCredential - save: (opensshPublicKey: string) => void + save: (label: string, opensshPublicKey: string) => void } let { @@ -25,11 +25,12 @@ }: Props = $props() let field: HTMLInputElement|undefined = $state() + let label: string = $state('') let opensshPublicKey: string = $state('') let validated = $state(false) function _save () { - if (!opensshPublicKey) { + if (!opensshPublicKey || !label) { return } if (opensshPublicKey.includes(' ')) { @@ -37,7 +38,7 @@ opensshPublicKey = `${parts[0]} ${parts[1]}` } isOpen = false - save(opensshPublicKey) + save(label, opensshPublicKey) } function _cancel () { @@ -47,6 +48,7 @@ { if (instance) { + label = instance.label opensshPublicKey = instance.opensshPublicKey } field?.focus() @@ -56,9 +58,16 @@ e.preventDefault() }}> - Public key + Add an SSH public key + + + {credential.label} + {credential.abbreviated}