From ae2042fc37015ee540b21d34da1bba5c153a2561 Mon Sep 17 00:00:00 2001 From: kozabrada123 Date: Wed, 16 Oct 2024 12:17:22 +0200 Subject: [PATCH] api: easier mfa api - Added two aliases for ChorusUser::complete_mfa_challenge, MfaChallenge::complete and MfaVerifySchema::verify_mfa --- src/types/schema/mfa.rs | 95 +++++++++++++++++++++++++++++++++++------ 1 file changed, 82 insertions(+), 13 deletions(-) diff --git a/src/types/schema/mfa.rs b/src/types/schema/mfa.rs index 62f8c320..19a556e9 100644 --- a/src/types/schema/mfa.rs +++ b/src/types/schema/mfa.rs @@ -3,7 +3,11 @@ use std::fmt::Display; use serde::{Deserialize, Serialize}; use serde_repr::{Deserialize_repr, Serialize_repr}; -use crate::{errors::ChorusError, types::Snowflake}; +use crate::{ + errors::{ChorusError, ChorusResult}, + instance::ChorusUser, + types::Snowflake, +}; #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] #[serde(rename_all = "snake_case")] @@ -31,7 +35,7 @@ impl Display for MfaRequiredSchema { /// /// (Normally returned in [MfaRequiredSchema] as [ChorusError::MfaRequired]) /// -/// To complete the challenge, see [crate::instance::ChorusUser::complete_mfa_challenge]. +/// To complete the challenge, see [ChorusUser::complete_mfa_challenge]. pub struct MfaChallenge { /// A unique ticket which identifies this challenge pub ticket: String, @@ -39,6 +43,37 @@ pub struct MfaChallenge { pub methods: Vec, } +impl MfaChallenge { + /// Attempts to complete the [MfaChallenge] with authentication data from the user. + /// + /// If successful, the MFA verification JWT returned is set on the provided [ChorusUser]. + /// + /// The JWT token expires after 5 minutes. + /// + /// # Arguments + /// `authentication_type` is the way the user has chosen to authenticate. + /// + /// It must be the type of one of the provided `methods` in the challenge. + /// + /// `data` is specific to the `authentication_type`. + /// + /// For example, a totp authenticator uses a 6 digit code as the `data`. + /// + /// # Notes + /// Alias of [ChorusUser::complete_mfa_challenge] + pub async fn complete( + self, + user: &mut ChorusUser, + authentication_type: MfaAuthenticationType, + data: String, + ) -> ChorusResult<()> { + let schema = + MfaVerifySchema::from_challenge_and_verification_data(self, authentication_type, data); + + user.complete_mfa_challenge(schema).await + } +} + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)] #[serde(rename_all = "snake_case")] /// A way we can verify the user's identity, found in [MfaChallenge] @@ -47,7 +82,7 @@ pub struct MfaMethod { #[serde(rename = "type")] pub kind: MfaAuthenticationType, - /// A challenge string unique to this type, [None] if the type does not need a challenge string + /// A challenge string unique to the authentication type, [None] if the type does not need a challenge string #[serde(skip_serializing_if = "Option::is_none")] pub challenge: Option, @@ -183,27 +218,61 @@ pub struct MfaBackupCode { #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] #[serde(rename_all = "snake_case")] -/// A schema used for the [crate::instance::ChorusUser::complete_mfa_challenge] route. +/// A schema used for the [ChorusUser::complete_mfa_challenge] route. pub struct MfaVerifySchema { /// Usually obtained from [MfaChallenge] pub ticket: String, - /// The way we are authenticating + /// The way the user has chosen to authenticate + /// + /// Must be one of the available methods in from the [MfaChallenge] pub mfa_type: MfaAuthenticationType, - /// Data unique to the authentication type (ex. a 6 digit totp code, a password) + /// Data unique to the authentication type (ex. a 6 digit totp code for totp, a password) pub data: String, } +impl MfaVerifySchema { + /// Creates the verify schema from an [MfaChallenge] and data needed to complete it. + /// + /// Shorthand for initializing [Self] with mfa_type, data and ticket = challenge.ticket + pub fn from_challenge_and_verification_data( + challenge: MfaChallenge, + mfa_type: MfaAuthenticationType, + data: String, + ) -> Self { + Self { + ticket: challenge.ticket, + mfa_type, + data, + } + } + + /// Uses the verification schema to attempt to complete an [MfaChallenge]. + /// + /// If successful, the MFA verification JWT returned is set on the provided [ChorusUser]. + /// + /// The JWT token expires after 5 minutes. + /// + /// # Notes + /// Alias of [ChorusUser::complete_mfa_challenge] + pub async fn verify_mfa(self, user: &mut ChorusUser) -> ChorusResult<()> { + user.complete_mfa_challenge(self).await + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] +/// An MFA token generated by the server after completing and mfa challenge ([crate::instance::ChorusUser::complete_mfa_challenge]) pub struct MfaTokenSchema { pub token: String, } #[derive(Debug, Clone, Serialize, Deserialize)] +/// Schema for the Send Mfa SMS route ([crate::instance::Instance::send_mfa_sms]) pub struct SendMfaSmsSchema { pub ticket: String, } #[derive(Debug, Clone, Serialize, Deserialize)] +/// Return type for the Send Mfa SMS route ([crate::instance::Instance::send_mfa_sms]) pub struct SendMfaSmsResponse { pub phone: String, } @@ -255,7 +324,7 @@ pub struct SmsMfaRouteSchema { } #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] -/// A return type for the [crate::instance::ChorusUser::begin_webauthn_authenticator_creation] route (Create WebAuthn Authenticator with no arguments). +/// A return type for the [ChorusUser::begin_webauthn_authenticator_creation] route (Create WebAuthn Authenticator with no arguments). /// /// Includes the MFA ticket and a stringified JSON object of the public key credential challenge. /// @@ -268,21 +337,21 @@ pub struct BeginWebAuthnAuthenticatorCreationReturn { } #[derive(Debug, Default, Deserialize, Serialize, Clone, PartialEq, Eq)] -/// A schema for the [crate::instance::ChorusUser::finish_webauthn_authenticator_creation] route (Create WebAuthn Authenticator). +/// A schema for the [ChorusUser::finish_webauthn_authenticator_creation] route (Create WebAuthn Authenticator). /// /// # Reference /// See pub struct FinishWebAuthnAuthenticatorCreationSchema { /// Name of the authenticator to create (1 - 32 characters) pub name: String, - /// The MFA ticket returned by the (begin creation)[crate::instance::ChorusUser::begin_webauthn_authenticator_creation] endpoint + /// The MFA ticket returned by the (begin creation)[ChorusUser::begin_webauthn_authenticator_creation] endpoint pub ticket: String, /// A stringified JSON object of the public key credential response. pub credential: String, } #[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq)] -/// A return type for the [crate::instance::ChorusUser::finish_webauthn_authenticator_creation] route (Create WebAuthn Authenticator). +/// A return type for the [ChorusUser::finish_webauthn_authenticator_creation] route (Create WebAuthn Authenticator). /// /// Includes the MFA ticket and a stringified JSON object of the public key credential challenge. /// @@ -325,13 +394,13 @@ pub struct SendBackupCodesChallengeSchema { pub struct SendBackupCodesChallengeReturn { /// A one-time verification nonce used to view the backup codes /// - /// Send this in the [crate::instance::ChorusUser::get_backup_codes] endpoint as the nonce if you want to view + /// Send this in the [ChorusUser::get_backup_codes] endpoint as the nonce if you want to view /// the existing codes #[serde(rename = "nonce")] pub view_nonce: String, /// A one-time verification nonce used to regenerate the backup codes /// - /// Send this in the [crate::instance::ChorusUser::get_backup_codes] endpoint as the nonce if you want to + /// Send this in the [ChorusUser::get_backup_codes] endpoint as the nonce if you want to /// regenerate the backup codes pub regenerate_nonce: String, } @@ -344,7 +413,7 @@ pub struct SendBackupCodesChallengeReturn { pub struct GetBackupCodesSchema { /// The one-time verification nonce used to view or regenerate the backup codes. /// - /// Obtained from the [crate::instance::ChorusUser::send_backup_codes_challenge] route. + /// Obtained from the [ChorusUser::send_backup_codes_challenge] route. pub nonce: String, /// The backup verification key received in the email pub key: String,