Skip to main content

rustauth_plugins/email_otp/
mod.rs

1//! Email OTP plugin.
2
3mod change_email;
4mod endpoints;
5mod errors;
6mod helpers;
7mod hooks;
8mod otp;
9mod password;
10mod registry;
11mod response;
12mod schema;
13mod server;
14mod types;
15
16pub use types::{
17    ChangeEmailOptions, EmailOtpEncryptor, EmailOtpGenerator, EmailOtpHasher, EmailOtpOptions,
18    EmailOtpOptionsBuilder, EmailOtpPayload, EmailOtpType, OtpStorage, ResendStrategy,
19    SendEmailOtp,
20};
21
22use rustauth_core::error::RustAuthError;
23use rustauth_core::options::RateLimitRule;
24use rustauth_core::plugin::{AuthPlugin, PluginRateLimitRule};
25
26pub const UPSTREAM_PLUGIN_ID: &str = "email-otp";
27
28/// Build the Email OTP plugin.
29pub fn email_otp(options: EmailOtpOptions) -> Result<AuthPlugin, RustAuthError> {
30    options.validate()?;
31    Ok(build_email_otp_plugin(options))
32}
33
34fn build_email_otp_plugin(options: EmailOtpOptions) -> AuthPlugin {
35    let rate_limit = options.rate_limit.clone().unwrap_or(RateLimitRule {
36        window: time::Duration::seconds(60),
37        max: 3,
38    });
39    let hook_options = std::sync::Arc::new(options.clone());
40    let plugin = errors::error_codes().fold(
41        registry::register(
42            AuthPlugin::new(UPSTREAM_PLUGIN_ID).with_version(crate::VERSION),
43            options,
44        ),
45        AuthPlugin::with_error_code,
46    );
47    let plugin = if hook_options.send_verification_on_sign_up
48        && !hook_options.override_default_email_verification
49    {
50        plugin.with_async_after_hook("/sign-up/email", {
51            let options = std::sync::Arc::clone(&hook_options);
52            move |context, request, response| {
53                let options = std::sync::Arc::clone(&options);
54                Box::pin(async move {
55                    hooks::send_verification_after_sign_up(context, request, response, options)
56                        .await
57                })
58            }
59        })
60    } else {
61        plugin
62    };
63    let plugin = if hook_options.override_default_email_verification {
64        plugin.with_async_after_hook("/send-verification-email", {
65            let options = std::sync::Arc::clone(&hook_options);
66            move |context, request, response| {
67                let options = std::sync::Arc::clone(&options);
68                Box::pin(async move {
69                    hooks::override_send_verification_email(context, request, response, options)
70                        .await
71                })
72            }
73        })
74    } else {
75        plugin
76    };
77    registry::paths()
78        .iter()
79        .fold(plugin, |plugin: AuthPlugin, path| {
80            plugin.with_rate_limit(PluginRateLimitRule::new(*path, rate_limit.clone()))
81        })
82}