Skip to main content

renox_core/auth/
events.rs

1//! Events the built-in auth pages emit, e.g. for a welcome mail or an audit
2//! log (`renox::audit` records them all). Listen like to any event:
3//!
4//! ```
5//! # use renox::prelude::*;
6//! use renox::auth::events::{LoggedIn, Registered};
7//!
8//! # let _ =
9//! App::new()
10//!     .module(Auth::new())
11//!     .listen(|e: Registered, state| async move {
12//!         tracing::info!(user = e.user_id, "welcome!"); // e.g. queue a welcome mail
13//!         let _ = state;
14//!         Ok(())
15//!     })
16//!     .listen(|e: LoggedIn, _state| async move {
17//!         tracing::info!(user = e.user_id, ip = ?e.ip, "logged in");
18//!         Ok(())
19//!     })
20//! # ;
21//! ```
22//!
23//! A listener's error is logged; it never fails the login itself. Your own
24//! login code (`auth::login`) emits nothing: emit these yourself if you need
25//! them.
26
27use crate::AppState;
28use crate::events::Event;
29
30/// A new account, after `on_registered` succeeded.
31#[derive(Debug, Clone)]
32#[non_exhaustive]
33pub struct Registered {
34    /// The new user's id.
35    pub user_id: i64,
36    /// The new user's email address (normalized).
37    pub email: String,
38}
39
40/// A successful login on the login page.
41#[derive(Debug, Clone)]
42#[non_exhaustive]
43pub struct LoggedIn {
44    /// The user who logged in.
45    pub user_id: i64,
46    /// The client's IP address (`ClientIp`), if known.
47    pub ip: Option<String>,
48}
49
50/// A wrong email or password on the login page.
51#[derive(Debug, Clone)]
52#[non_exhaustive]
53pub struct LoginFailed {
54    /// The email address that was entered.
55    pub email: String,
56    /// The client's IP address (`ClientIp`), if known.
57    pub ip: Option<String>,
58}
59
60/// Too many failed logins: this email (or address) must wait.
61#[derive(Debug, Clone)]
62#[non_exhaustive]
63pub struct LockedOut {
64    /// The email address that was entered.
65    pub email: String,
66    /// The client's IP address (`ClientIp`), if known.
67    pub ip: Option<String>,
68    /// Seconds left until another attempt is allowed.
69    pub seconds: u64,
70}
71
72/// A logout of one device.
73#[derive(Debug, Clone)]
74#[non_exhaustive]
75pub struct LoggedOut {
76    /// The user who logged out.
77    pub user_id: i64,
78}
79
80/// A password chosen through a reset link.
81#[derive(Debug, Clone)]
82#[non_exhaustive]
83pub struct PasswordReset {
84    /// The user whose password was reset.
85    pub user_id: i64,
86}
87
88/// A password changed on the account page.
89#[derive(Debug, Clone)]
90#[non_exhaustive]
91pub struct PasswordChanged {
92    /// The user whose password changed.
93    pub user_id: i64,
94}
95
96/// An email address confirmed through its link.
97#[derive(Debug, Clone)]
98#[non_exhaustive]
99pub struct EmailVerified {
100    /// The user whose email address was confirmed.
101    pub user_id: i64,
102}
103
104/// Name or email changed on the account page.
105#[derive(Debug, Clone)]
106#[non_exhaustive]
107pub struct ProfileUpdated {
108    /// The user whose profile changed.
109    pub user_id: i64,
110    /// Whether the email address changed.
111    pub email_changed: bool,
112}
113
114/// "Log out other devices" on the account page.
115#[derive(Debug, Clone)]
116#[non_exhaustive]
117pub struct OtherDevicesLoggedOut {
118    /// The user whose other sessions were ended.
119    pub user_id: i64,
120}
121
122/// An account deleted on the account page (the row is already gone).
123#[derive(Debug, Clone)]
124#[non_exhaustive]
125pub struct AccountDeleted {
126    /// The deleted user's id (no longer in `users`).
127    pub user_id: i64,
128    /// The deleted user's email address.
129    pub email: String,
130}
131
132impl Event for Registered {}
133impl Event for LoggedIn {}
134impl Event for LoginFailed {}
135impl Event for LockedOut {}
136impl Event for LoggedOut {}
137impl Event for PasswordReset {}
138impl Event for PasswordChanged {}
139impl Event for EmailVerified {}
140impl Event for ProfileUpdated {}
141impl Event for OtherDevicesLoggedOut {}
142impl Event for AccountDeleted {}
143
144/// Emits `event`; a listener's failure is logged, not returned.
145pub(crate) async fn announce<E: Event>(state: &AppState, event: E) {
146    if let Err(err) = state.emit(event).await {
147        tracing::error!(event = std::any::type_name::<E>(), error = ?err, "auth listener failed");
148    }
149}