alibi-plugins 0.10.0

Built-in authentication plugins and API metadata for Alibi
Documentation
use super::PasskeyHandlerOutcome;
use super::PasskeyHandlerResult;
use super::registration_value;
use crate::StatusResponse;
use crate::passkey::types::DeletePasskeyRequest;
use crate::passkey::types::PasskeyResponse;
use crate::passkey::types::UpdatePasskeyRequest;
use alibi_core::AuthContext;
use alibi_core::AuthError;
use alibi_core::AuthPasskey;
use alibi_core::AuthResult;
use alibi_core::entity::AuthUser;
use alibi_core::error::codes;
use alibi_core::wire::PasskeyView;
use serde_json::Value;
use serde_json::json;
pub(in crate::passkey) async fn list_user_passkeys_core(
    user: &impl AuthUser,
    ctx: &AuthContext<impl alibi_core::AuthSchema>,
) -> AuthResult<Vec<Value>> {
    let passkeys = ctx.database.list_passkeys_by_user(&user.id()).await?;
    passkeys
        .iter()
        .map(|passkey| {
            let mut value = registration_value(passkey)?;
            // Source lists adapter rows, retaining an own SQL NULL property.
            if passkey.transports.is_none()
                && let Some(object) = value.as_object_mut()
            {
                _ = object.insert("transports".into(), Value::Null);
            }
            Ok(value)
        })
        .collect()
}

pub(in crate::passkey) async fn delete_passkey_core(
    body: &DeletePasskeyRequest,
    user: &impl AuthUser,
    ctx: &AuthContext<impl alibi_core::AuthSchema>,
) -> PasskeyHandlerResult<StatusResponse> {
    if body.id.is_empty() {
        return Err(AuthError::Api {
            status: 400,
            code: None,
            message: "Missing required parameter: id".into(),
        });
    }
    let passkey = ctx
        .database
        .get_passkey_by_id(&body.id)
        .await?
        .ok_or(AuthError::Upstream {
            status: 404,
            code: codes::PASSKEY_NOT_FOUND,
            message: "Passkey not found",
        })?;

    if passkey.user_id() != user.id() {
        return Ok(PasskeyHandlerOutcome::Response(
            alibi_core::AuthResponse::new(401).with_header("content-type", "application/json"),
        ));
    }

    ctx.database.delete_passkey(&body.id).await?;
    Ok(PasskeyHandlerOutcome::Success(StatusResponse {
        status: true,
    }))
}

pub(in crate::passkey) async fn update_passkey_core(
    body: &UpdatePasskeyRequest,
    user: &impl AuthUser,
    ctx: &AuthContext<impl alibi_core::AuthSchema>,
) -> PasskeyHandlerResult<PasskeyResponse> {
    if body.id.is_empty() {
        return Err(AuthError::Api {
            status: 400,
            code: None,
            message: "Missing required parameter: id".into(),
        });
    }
    let passkey = ctx
        .database
        .get_passkey_by_id(&body.id)
        .await?
        .ok_or(AuthError::Upstream {
            status: 404,
            code: codes::PASSKEY_NOT_FOUND,
            message: "Passkey not found",
        })?;

    if passkey.user_id() != user.id() {
        return Ok(PasskeyHandlerOutcome::Response(
            alibi_core::AuthResponse::json(
                401,
                &json!({ "code": codes::YOU_ARE_NOT_ALLOWED_TO_REGISTER_THIS_PASSKEY, "message": "You are not allowed to register this passkey" }),
            )?,
        ));
    }

    let updated = ctx
        .database
        .update_passkey_name(
            &body.id,
            crate::passkey::registration::trim_name(&body.name),
        )
        .await?;

    Ok(PasskeyHandlerOutcome::Success(PasskeyResponse {
        passkey: PasskeyView::from(&updated),
    }))
}