Skip to content

Commit

Permalink
api: easier mfa api
Browse files Browse the repository at this point in the history
- Added two aliases for ChorusUser::complete_mfa_challenge, MfaChallenge::complete and MfaVerifySchema::verify_mfa
  • Loading branch information
kozabrada123 committed Oct 16, 2024
1 parent f0aef03 commit ae2042f
Showing 1 changed file with 82 additions and 13 deletions.
95 changes: 82 additions & 13 deletions src/types/schema/mfa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down Expand Up @@ -31,14 +35,45 @@ 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,
/// The ways we can verify the user's identity
pub methods: Vec<MfaMethod>,
}

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]
Expand All @@ -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<String>,

Expand Down Expand Up @@ -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,
}
Expand Down Expand Up @@ -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.
///
Expand All @@ -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 <https://docs.discord.sex/resources/user#create-webauthn-authenticator>
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.
///
Expand Down Expand Up @@ -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,
}
Expand All @@ -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,
Expand Down

0 comments on commit ae2042f

Please sign in to comment.