diff --git a/.vscode/settings.json b/.vscode/settings.json index 934e178..9031fe0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,5 +17,6 @@ "userid", "writedoc" ], - "rust-analyzer.check.command": "clippy" + "rust-analyzer.check.command": "clippy", + "rust-analyzer.showUnlinkedFileNotification": false } \ No newline at end of file diff --git a/crates/migrations/src/lib.rs b/crates/migrations/src/lib.rs index 8387950..aa4edda 100644 --- a/crates/migrations/src/lib.rs +++ b/crates/migrations/src/lib.rs @@ -1,5 +1,5 @@ -mod m_20230701_000001_create_keys_table; -mod m_20242801_000002_create_profiles_table; +mod m20230701_000001_create_keys_table; +mod m20242801_000002_create_profiles_table; use sea_orm_migration::prelude::*; @@ -10,8 +10,8 @@ pub struct Migrator; impl MigratorTrait for Migrator { fn migrations() -> Vec> { vec![ - Box::new(m_20230701_000001_create_keys_table::Migration), - Box::new(m_20242801_000002_create_profiles_table::Migration), + Box::new(m20230701_000001_create_keys_table::Migration), + Box::new(m20242801_000002_create_profiles_table::Migration), ] } } diff --git a/crates/migrations/src/m_20230701_000001_create_keys_table.rs b/crates/migrations/src/m20230701_000001_create_keys_table.rs similarity index 90% rename from crates/migrations/src/m_20230701_000001_create_keys_table.rs rename to crates/migrations/src/m20230701_000001_create_keys_table.rs index bda9a79..ebbe3de 100644 --- a/crates/migrations/src/m_20230701_000001_create_keys_table.rs +++ b/crates/migrations/src/m20230701_000001_create_keys_table.rs @@ -1,13 +1,8 @@ use sea_orm_migration::prelude::*; +#[derive(DeriveMigrationName)] pub struct Migration; -impl MigrationName for Migration { - fn name(&self) -> &str { - "m_20230701_000001_create_keys_table" - } -} - #[async_trait::async_trait] impl MigrationTrait for Migration { // Define how to apply this migration: Create the Keys table. diff --git a/crates/migrations/src/m_20242801_000002_create_profiles_table.rs b/crates/migrations/src/m20242801_000002_create_profiles_table.rs similarity index 87% rename from crates/migrations/src/m_20242801_000002_create_profiles_table.rs rename to crates/migrations/src/m20242801_000002_create_profiles_table.rs index 1b3feaa..df64598 100644 --- a/crates/migrations/src/m_20242801_000002_create_profiles_table.rs +++ b/crates/migrations/src/m20242801_000002_create_profiles_table.rs @@ -1,13 +1,8 @@ use sea_orm_migration::prelude::*; +#[derive(DeriveMigrationName)] pub struct Migration; -impl MigrationName for Migration { - fn name(&self) -> &str { - "m_20242801_000002_create_profiles_table" - } -} - #[async_trait::async_trait] impl MigrationTrait for Migration { // Define how to apply this migration: Create the Keys table. @@ -52,13 +47,19 @@ impl MigrationTrait for Migration { .name("fk-profiles_key-keys_fingerprint") .from(Profiles::Table, Profiles::Key) .to( - super::m_20230701_000001_create_keys_table::Keys::Table, - super::m_20230701_000001_create_keys_table::Keys::Fingerprint, + super::m20230701_000001_create_keys_table::Keys::Table, + super::m20230701_000001_create_keys_table::Keys::Fingerprint, ) .on_update(ForeignKeyAction::Cascade) .on_delete(ForeignKeyAction::Cascade), ) - .col(ColumnDef::new(Profiles::Alias).string().not_null()) + .col( + ColumnDef::new(Profiles::Alias) + .string() + .not_null() + .extra("COLLATE NOCASE") + .unique_key(), + ) .col(ColumnDef::new(Profiles::Name).string().not_null()) .col(ColumnDef::new(Profiles::Description).string().null()) .col(ColumnDef::new(Profiles::AvatarUrl).string().null()) diff --git a/src/commands/profiles/export.rs b/src/commands/profiles/export.rs index 2b753e2..ffabdbf 100644 --- a/src/commands/profiles/export.rs +++ b/src/commands/profiles/export.rs @@ -13,26 +13,37 @@ use clap::Parser; use data_encoding::BASE64_NOPAD; use dialoguer::{theme::ColorfulTheme, Password}; use josekit::jwk::Jwk; -use sea_orm::{EntityTrait, ModelTrait}; +use sea_orm::{ColumnTrait, Condition, EntityTrait, ModelTrait, QueryFilter}; -use crate::{commands::AspmSubcommand, entities::prelude::*}; +use crate::{ + commands::AspmSubcommand, + entities::{prelude::*, profiles}, +}; /// Exports a profile in JWT format #[derive(Parser, Debug)] pub struct ProfilesExportCommand { - /// The fingerprint of the profile to export - fingerprint: String, + /// The fingerprint or alias of the profile to export + profile: String, + /// The key to sign this profile with + #[clap(short, long)] + key: Option, } #[async_trait::async_trait] impl AspmSubcommand for ProfilesExportCommand { async fn execute(self, state: crate::AspmState) -> Result<(), anyhow::Error> { - let Some(profile) = Profiles::find_by_id(&self.fingerprint) + let Some(profile) = Profiles::find() + .filter( + Condition::any() + .add(profiles::Column::Key.eq(&self.profile)) + .add(profiles::Column::Alias.eq(&self.profile)), + ) .one(&state.db) .await - .context("Unable to query for profiles with fingerprint")? + .context("Unable to query for profiles with fingerprint or alias")? else { - bail!("No profile found with that fingerprint"); + bail!("No profile found with that fingerprint or alias"); }; let claims = profile @@ -41,13 +52,12 @@ impl AspmSubcommand for ProfilesExportCommand { .await .context("Unable to query for related claims")?; - let Some(key) = profile - .find_related(Keys) + let Some(key) = Keys::find_by_id(self.key.unwrap_or(profile.key)) .one(&state.db) .await .context("Unable to query database for key")? else { - bail!("The key associated with the queried profile could not be found") + bail!("The key to sign the profile with could not be found") }; let asp = AriadneSignatureProfile {