diff --git a/v-api/src/context/magic_link.rs b/v-api/src/context/magic_link.rs index 9e6c6c7..253659e 100644 --- a/v-api/src/context/magic_link.rs +++ b/v-api/src/context/magic_link.rs @@ -286,6 +286,7 @@ where client_id: TypedUuid, redirect_uri: &Url, medium: MagicLinkMedium, + channel: &str, scope: &str, expiration: DateTime, recipient: &str, @@ -338,6 +339,7 @@ where magic_link_client_id: client_id, recipient: recipient_signature.to_string(), medium: medium.to_string(), + channel: channel.to_string(), redirect_uri: redirect_uri.to_string(), scope: scope.to_string(), nonce_signature: signature, @@ -484,6 +486,7 @@ mod tests { magic_link_client_id: arg.magic_link_client_id, recipient: arg.recipient, medium: arg.medium, + channel: arg.channel, redirect_uri: arg.redirect_uri, scope: arg.scope, nonce_signature: arg.nonce_signature, @@ -505,6 +508,7 @@ mod tests { TypedUuid::new_v4(), &Url::parse("http://127.0.0.1").unwrap(), MagicLinkMedium::Email, + "all", "", Utc::now().add(Duration::seconds(60)), "ducks@oxidecomputer.com", @@ -525,6 +529,7 @@ mod tests { magic_link_client_id: arg.magic_link_client_id, recipient: arg.recipient, medium: arg.medium, + channel: arg.channel, redirect_uri: arg.redirect_uri, scope: arg.scope, nonce_signature: arg.nonce_signature, @@ -566,6 +571,7 @@ mod tests { TypedUuid::new_v4(), &Url::parse("http://127.0.0.1").unwrap(), MagicLinkMedium::Email, + "all", "", Utc::now().add(Duration::seconds(60)), "ducks@oxidecomputer.com", @@ -587,6 +593,7 @@ mod tests { magic_link_client_id: arg.magic_link_client_id, recipient: arg.recipient, medium: arg.medium, + channel: arg.channel, redirect_uri: arg.redirect_uri, scope: arg.scope, nonce_signature: arg.nonce_signature, @@ -630,6 +637,7 @@ mod tests { TypedUuid::new_v4(), &Url::parse("http://127.0.0.1").unwrap(), MagicLinkMedium::Email, + "all", "", Utc::now().add(Duration::seconds(60)), "ducks@oxidecomputer.com", @@ -657,6 +665,7 @@ mod tests { magic_link_client_id: TypedUuid::new_v4(), recipient: String::new(), medium: String::new(), + channel: String::new(), redirect_uri: String::new(), scope: String::new(), nonce_signature: signature, diff --git a/v-api/src/endpoints/handlers.rs b/v-api/src/endpoints/handlers.rs index b482bfc..246ca08 100644 --- a/v-api/src/endpoints/handlers.rs +++ b/v-api/src/endpoints/handlers.rs @@ -332,7 +332,7 @@ mod macros { #[endpoint { method = POST, - path = "/login/magic/{medium}/send" + path = "/login/magic/{channel}/send" }] pub async fn magic_link_send( rqctx: RequestContext<$context_type>, diff --git a/v-api/src/endpoints/login/magic_link/mod.rs b/v-api/src/endpoints/login/magic_link/mod.rs index 97b3404..47127c2 100644 --- a/v-api/src/endpoints/login/magic_link/mod.rs +++ b/v-api/src/endpoints/login/magic_link/mod.rs @@ -32,11 +32,12 @@ pub mod client; #[derive(Debug, Deserialize, JsonSchema)] pub struct MagicLinkPath { - medium: MagicLinkMedium, + channel: String, } #[derive(Debug, Deserialize, JsonSchema)] pub struct MagicLinkSendRequest { + medium: MagicLinkMedium, secret: String, recipient: String, redirect_uri: Url, @@ -65,7 +66,8 @@ where Ok(HttpResponseOk( magic_link_send_op_inner( ctx, - path.medium, + body.medium, + &path.channel, body.secret, body.recipient, body.redirect_uri, @@ -80,6 +82,7 @@ where async fn magic_link_send_op_inner( ctx: &VContext, medium: MagicLinkMedium, + channel: &str, secret: String, recipient: String, redirect_uri: Url, @@ -114,6 +117,7 @@ where client.id, &redirect_uri, medium, + channel, &scope, Utc::now().add(Duration::seconds(expires_in)), &recipient, @@ -139,9 +143,7 @@ impl From for HttpError { MagicLinkSendError::NoMessageSender(medium) => { internal_error(format!("No message sender is available for {}", medium)) } - MagicLinkSendError::Send(err) => { - internal_error(err.to_string()) - } + MagicLinkSendError::Send(err) => internal_error(err.to_string()), MagicLinkSendError::Signing(err) => ResourceError::InternalError(err).into(), MagicLinkSendError::Storage(err) => ResourceError::InternalError(err).into(), } diff --git a/v-model/migrations/2024-08-02-144835_magic_link_attempt/up.sql b/v-model/migrations/2024-08-02-144835_magic_link_attempt/up.sql index 0af13e9..5fc8a5a 100644 --- a/v-model/migrations/2024-08-02-144835_magic_link_attempt/up.sql +++ b/v-model/migrations/2024-08-02-144835_magic_link_attempt/up.sql @@ -6,6 +6,7 @@ CREATE TABLE magic_link_attempt( magic_link_client_id UUID REFERENCES magic_link_client (id) NOT NULL, medium VARCHAR NOT NULL, + channel VARCHAR NOT NULL, recipient VARCHAR NOT NULL, redirect_uri VARCHAR NOT NULL, scope VARCHAR NOT NULL DEFAULT '', diff --git a/v-model/src/db.rs b/v-model/src/db.rs index 98efdd9..1aade83 100644 --- a/v-model/src/db.rs +++ b/v-model/src/db.rs @@ -153,6 +153,7 @@ pub struct MagicLinkAttemptModel { pub magic_link_client_id: Uuid, // TODO: This needs to be the MagicLinkMedium enum pub medium: String, + pub channel: String, pub recipient: String, pub redirect_uri: String, pub scope: String, diff --git a/v-model/src/lib.rs b/v-model/src/lib.rs index 45dee03..f1e1d0a 100644 --- a/v-model/src/lib.rs +++ b/v-model/src/lib.rs @@ -566,6 +566,7 @@ pub struct MagicLinkAttempt { pub magic_link_client_id: TypedUuid, pub recipient: String, pub medium: String, + pub channel: String, pub redirect_uri: String, pub scope: String, pub nonce_signature: String, @@ -584,6 +585,7 @@ impl From for MagicLinkAttempt { magic_link_client_id: TypedUuid::from_untyped_uuid(value.magic_link_client_id), recipient: value.recipient, medium: value.medium, + channel: value.channel, redirect_uri: value.redirect_uri, scope: value.scope, nonce_signature: value.nonce_signature, diff --git a/v-model/src/schema.rs b/v-model/src/schema.rs index f004a79..4f64ea0 100644 --- a/v-model/src/schema.rs +++ b/v-model/src/schema.rs @@ -118,6 +118,7 @@ diesel::table! { attempt_state -> MlinkAttemptState, magic_link_client_id -> Uuid, medium -> Varchar, + channel -> Varchar, recipient -> Varchar, redirect_uri -> Varchar, scope -> Varchar, diff --git a/v-model/src/storage/mod.rs b/v-model/src/storage/mod.rs index 395e878..f38727b 100644 --- a/v-model/src/storage/mod.rs +++ b/v-model/src/storage/mod.rs @@ -311,6 +311,7 @@ pub struct MagicLinkAttemptFilter { pub client_id: Option>>, pub attempt_state: Option>, pub medium: Option>, + pub channel: Option>, pub signature: Option>, } diff --git a/v-model/src/storage/postgres.rs b/v-model/src/storage/postgres.rs index ed94925..937ad9e 100644 --- a/v-model/src/storage/postgres.rs +++ b/v-model/src/storage/postgres.rs @@ -1061,6 +1061,7 @@ impl MagicLinkAttemptStore for PostgresStore { client_id, attempt_state, medium, + channel, signature, } = filter; @@ -1089,6 +1090,10 @@ impl MagicLinkAttemptStore for PostgresStore { query = query.filter(magic_link_attempt::medium.eq_any(medium)); } + if let Some(channel) = channel { + query = query.filter(magic_link_attempt::channel.eq_any(channel)); + } + if let Some(signature) = signature { query = query.filter(magic_link_attempt::nonce_signature.eq_any(signature)); } diff --git a/v-model/tests/postgres.rs b/v-model/tests/postgres.rs index cec52cb..8b94eb4 100644 --- a/v-model/tests/postgres.rs +++ b/v-model/tests/postgres.rs @@ -386,6 +386,7 @@ async fn test_magic_link_attempt() { magic_link_client_id: client_id, recipient: String::new(), medium: String::new(), + channel: String::new(), redirect_uri: String::new(), scope: String::new(), nonce_signature: "xxxxx".to_string(), @@ -468,6 +469,7 @@ async fn test_magic_link_attempt() { magic_link_client_id: client_id, recipient: String::new(), medium: String::new(), + channel: String::new(), redirect_uri: String::new(), scope: String::new(), nonce_signature: "xxxxx".to_string(),