use crate::config::{
AuthSecurity, AuthStrategy, Authentication, PasswordConfig, PasswordRequirements,
SameSiteConfig, Security, SessionConfig,
};
use crate::error::{CoreError, InternalError};
pub trait Validate {
fn validate(&self) -> Result<(), Vec<CoreError>>;
}
impl Validate for Security {
fn validate(&self) -> Result<(), Vec<CoreError>> {
let mut errors = vec![];
if self.secret_key.len() < 32 {
errors.push(CoreError::Internal(InternalError::MissingField {
field: "security.secret_key".into(),
reason: "must be at least 32 characters".into(),
}));
}
if let Err(e) = self.auth.validate() {
errors.extend(e);
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
}
impl Validate for AuthSecurity {
fn validate(&self) -> Result<(), Vec<CoreError>> {
let mut errors = vec![];
if self.max_failed_attempts == 0 {
errors.push(CoreError::Internal(InternalError::MissingField {
field: "auth.password.security.max_failed_attempts".into(),
reason: "must be greater than 0".into(),
}));
}
if self.lockout_duration <= 0 {
errors.push(CoreError::Internal(InternalError::MissingField {
field: "auth.password.security.lockout_duration".into(),
reason: "must be greater than 0".into(),
}));
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
}
impl Validate for Authentication {
fn validate(&self) -> Result<(), Vec<CoreError>> {
let mut errors = vec![];
if let AuthStrategy::Jwt(jwt) = &self.strategy {
if jwt.issuer.is_empty() {
errors.push(CoreError::Internal(InternalError::MissingField {
field: "auth.jwt.issuer".into(),
reason: "must be set".into(),
}));
}
if jwt.audience.is_empty() {
errors.push(CoreError::Internal(InternalError::MissingField {
field: "auth.jwt.audience".into(),
reason: "must be set".into(),
}));
}
}
if let AuthStrategy::Session(session) = &self.strategy
&& let Err(e) = session.validate()
{
errors.extend(e);
}
if let Err(e) = self.password.validate() {
errors.extend(e);
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
}
impl Validate for SessionConfig {
fn validate(&self) -> Result<(), Vec<CoreError>> {
let mut errors = vec![];
if self.name.is_empty() {
errors.push(CoreError::Internal(InternalError::MissingField {
field: "auth.session.name".into(),
reason: "must not be empty".into(),
}));
}
if self.max_age == 0 {
errors.push(CoreError::Internal(InternalError::MissingField {
field: "auth.session.max_age".into(),
reason: "must be greater than 0".into(),
}));
}
if let SameSiteConfig::None = self.same_site
&& !self.secure
{
errors.push(CoreError::Internal(InternalError::MissingField {
field: "auth.session.secure".into(),
reason: "must be true when same_site is None".into(),
}));
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
}
impl Validate for PasswordConfig {
fn validate(&self) -> Result<(), Vec<CoreError>> {
let mut errors = vec![];
if let Err(e) = self.requirements.validate() {
errors.extend(e);
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
}
impl Validate for PasswordRequirements {
fn validate(&self) -> Result<(), Vec<CoreError>> {
let mut errors = vec![];
if self.min_length == 0 {
errors.push(CoreError::Internal(InternalError::MissingField {
field: "auth.password.requirements.min_length".into(),
reason: "must be greater than 0".into(),
}));
}
if self.max_length < self.min_length {
errors.push(CoreError::Internal(InternalError::MissingField {
field: "auth.password.requirements.max_length".into(),
reason: "must be greater than or equal to min_length".into(),
}));
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}
}