use jiff::Timestamp;
use crate::store::{Session, User};
#[cfg(feature = "cloudflare")]
use crate::types::CloudflareConfig;
use crate::types::{UserId, UserInfo};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum Actor {
User {
user: UserId,
impersonator: Option<UserId>,
},
System,
}
impl Actor {
pub fn of(user: &User, session: &Session) -> Self {
Self::User {
user: user.id,
impersonator: session.impersonator,
}
}
pub fn user(user: UserId) -> Self {
Self::User {
user,
impersonator: None,
}
}
pub fn responsible(&self) -> Option<UserId> {
match *self {
Self::User { user, impersonator } => Some(impersonator.unwrap_or(user)),
Self::System => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum AuditEvent {
UserCreated {
actor: Actor,
user: UserInfo,
},
UserUpdated {
actor: Actor,
before: UserInfo,
after: UserInfo,
},
AccessRevoked {
actor: Actor,
before: UserInfo,
after: UserInfo,
},
Activated {
actor: Actor,
user: UserInfo,
},
UserDeleted {
actor: Actor,
user: UserInfo,
},
SignedOutEverywhere {
actor: Actor,
user: UserId,
},
LinkIssued {
actor: Actor,
user: UserId,
expires_at: Timestamp,
},
LinkRevoked {
actor: Actor,
user: UserId,
},
LinkRedeemed {
actor: Actor,
user: UserInfo,
},
CredentialChanged {
actor: Actor,
user: UserInfo,
},
ImpersonationStarted {
admin: UserId,
user: UserId,
},
ImpersonationStopped {
admin: UserId,
user: UserId,
},
#[cfg(feature = "cloudflare")]
#[cfg_attr(watchword_docsrs, doc(cfg(feature = "cloudflare")))]
CloudflareChanged {
actor: Actor,
before: Option<CloudflareConfig>,
after: CloudflareConfig,
},
}
impl AuditEvent {
pub fn actor(&self) -> Actor {
match self {
Self::UserCreated { actor, .. }
| Self::UserUpdated { actor, .. }
| Self::AccessRevoked { actor, .. }
| Self::Activated { actor, .. }
| Self::UserDeleted { actor, .. }
| Self::SignedOutEverywhere { actor, .. }
| Self::LinkIssued { actor, .. }
| Self::LinkRevoked { actor, .. }
| Self::LinkRedeemed { actor, .. }
| Self::CredentialChanged { actor, .. } => *actor,
#[cfg(feature = "cloudflare")]
Self::CloudflareChanged { actor, .. } => *actor,
Self::ImpersonationStarted { admin, .. } | Self::ImpersonationStopped { admin, .. } => {
Actor::user(*admin)
}
}
}
pub fn user(&self) -> Option<UserId> {
match self {
Self::UserCreated { user, .. }
| Self::Activated { user, .. }
| Self::UserDeleted { user, .. }
| Self::LinkRedeemed { user, .. }
| Self::CredentialChanged { user, .. } => Some(user.id),
Self::UserUpdated { after, .. } | Self::AccessRevoked { after, .. } => Some(after.id),
Self::SignedOutEverywhere { user, .. }
| Self::LinkIssued { user, .. }
| Self::LinkRevoked { user, .. }
| Self::ImpersonationStarted { user, .. }
| Self::ImpersonationStopped { user, .. } => Some(*user),
#[cfg(feature = "cloudflare")]
Self::CloudflareChanged { .. } => None,
}
}
}