apibrasil 1.0.0

SDK oficial Rust da plataforma APIBrasil: WhatsApp, SMS, consultas de CPF/CNPJ, veiculos, CEP, correios, pagamentos PIX/boleto e mais.
Documentation
use crate::core::{IntoBody, Json, Result};

platform_service! {
    /// Autenticação e conta (`/auth/*`, `/profile*`, `/password/*`).
    ///
    /// [`login`](AuthService::login), [`verify_2fa`](AuthService::verify_2fa)
    /// e [`refresh`](AuthService::refresh) guardam automaticamente o Bearer
    /// Token retornado no cliente, deixando as próximas chamadas
    /// autenticadas.
    ///
    /// ```no_run
    /// # use apibrasil::ApiBrasil;
    /// # use serde_json::json;
    /// # async fn exemplo(api: ApiBrasil) -> apibrasil::Result<()> {
    /// let sessao = api.auth().login(json!({
    ///     "email": "voce@empresa.com.br",
    ///     "password": "******",
    /// })).await?;
    ///
    /// if apibrasil::requires_2fa(&sessao) {
    ///     let challenge = sessao["challenge"].clone();
    ///     api.auth().send_2fa(json!({ "challenge": challenge, "method": "email" })).await?;
    ///     api.auth().verify_2fa(json!({ "challenge": challenge, "code": "000000" })).await?;
    /// }
    /// # Ok(())
    /// # }
    /// ```
    AuthService
}

impl AuthService {
    /// Autentica com email/senha: `POST /auth/login`.
    ///
    /// `body` aceita `email`, `password` e `turnstile_token`. Se a conta
    /// tiver 2FA, a resposta traz `requires_2fa` e `challenge` — use
    /// [`send_2fa`](Self::send_2fa) + [`verify_2fa`](Self::verify_2fa)
    /// para concluir.
    pub async fn login(&self, body: impl IntoBody) -> Result<Json> {
        let response = self.base.post("auth/login", body).await?;
        self.store_token(&response);
        Ok(response)
    }

    /// Conclui o login com o código 2FA:
    /// `POST /auth/login/verify-2fa`.
    pub async fn verify_2fa(&self, body: impl IntoBody) -> Result<Json> {
        let response = self.base.post("auth/login/verify-2fa", body).await?;
        self.store_token(&response);
        Ok(response)
    }

    /// Renova o JWT: `POST /refresh`.
    pub async fn refresh(&self) -> Result<Json> {
        let response = self.base.post("refresh", None).await?;
        self.store_token(&response);
        Ok(response)
    }

    /// Encerra a sessão e limpa o Bearer Token do cliente:
    /// `POST /auth/logout`.
    pub async fn logout(&self) -> Result<Json> {
        let response = self.base.post("auth/logout", None).await;
        self.base.http().set_bearer_token(None);
        response
    }

    /// Guarda no cliente o token devolvido pela plataforma
    /// (`authorization.token` ou `token`, conforme a rota).
    fn store_token(&self, response: &Json) {
        if let Some(token) = extract_token(response) {
            self.base.http().set_bearer_token(Some(token));
        }
    }
}

json_body! {
    AuthService {
        /// Envia o código 2FA pelo método escolhido (`email`, `sms`,
        /// `whatsapp`, `call`): `POST /auth/2fa/send`.
        send_2fa => post "auth/2fa/send",
        /// Cria uma conta: `POST /auth/register`.
        register => post "auth/register",
        /// Cadastro simplificado: `POST /auth/register/simple`.
        register_simple => post "auth/register/simple",
        /// Dispara a verificação de email/celular:
        /// `POST /auth/verification/send`.
        verification_send => post "auth/verification/send",
        /// Confirma o código de verificação:
        /// `POST /auth/verification/verify`.
        verification_verify => post "auth/verification/verify",
        /// Inicia a recuperação de senha: `POST /auth/password/forgot`.
        password_forgot => post "auth/password/forgot",
        /// Valida o código de recuperação:
        /// `POST /auth/password/verify-code`.
        password_verify_code => post "auth/password/verify-code",
        /// Redefine a senha: `POST /auth/password/reset`.
        password_reset => post "auth/password/reset",
        /// Reenvia o código de recuperação:
        /// `POST /auth/password/resend`.
        password_resend => post "auth/password/resend",
        /// Troca a senha com a sessão ativa: `POST /password/change`.
        change_password => post "password/change",
        /// Atualiza o perfil: `PUT /profile/me`.
        update_me => put "profile/me",
    }
}

json_get! {
    AuthService {
        /// Lista os métodos 2FA ativos da conta: `GET /auth/2fa/methods`.
        two_factor_methods => "auth/2fa/methods",
        /// Perfil atual: `GET /profile/me`.
        me => "profile/me",
        /// Valida o token atual: `GET /auth/verify`.
        verify => "auth/verify",
    }
}

json_empty! {
    AuthService {
        /// Perfil completo, com estatísticas: `POST /profile`.
        profile => post "profile",
        /// Rotaciona o token: `POST /auth/token/rotate`.
        token_rotate => post "auth/token/rotate",
        /// Revoga o token atual: `POST /auth/token/revoke`.
        token_revoke => post "auth/token/revoke",
    }
}

/// Lê o Bearer Token de uma resposta de autenticação
/// (`authorization.token` ou `token`).
pub fn extract_token(response: &Json) -> Option<String> {
    if let Some(token) = response
        .get("authorization")
        .and_then(|authorization| authorization.get("token"))
        .and_then(Json::as_str)
    {
        if !token.is_empty() {
            return Some(token.to_string());
        }
    }

    let token = response.get("token")?.as_str()?;
    if token.is_empty() {
        None
    } else {
        Some(token.to_string())
    }
}

/// Informa se a resposta de login exige segundo fator.
pub fn requires_2fa(response: &Json) -> bool {
    response.get("requires_2fa") == Some(&Json::Bool(true))
}