shared/config/configuration/
validate.rs1use crate::config::{
2 AuthSecurity, AuthStrategy, Authentication, PasswordConfig, PasswordRequirements,
3 SameSiteConfig, Security, SessionConfig,
4};
5use crate::error::{CoreError, InternalError};
6
7pub trait Validate {
8 fn validate(&self) -> Result<(), Vec<CoreError>>;
9}
10
11impl Validate for Security {
15 fn validate(&self) -> Result<(), Vec<CoreError>> {
16 let mut errors = vec![];
17
18 if self.secret_key.len() < 32 {
19 errors.push(CoreError::Internal(InternalError::MissingField {
20 field: "security.secret_key".into(),
21 reason: "must be at least 32 characters".into(),
22 }));
23 }
24 if let Err(e) = self.auth.validate() {
25 errors.extend(e);
26 }
27
28 if errors.is_empty() {
29 Ok(())
30 } else {
31 Err(errors)
32 }
33 }
34}
35impl Validate for AuthSecurity {
36 fn validate(&self) -> Result<(), Vec<CoreError>> {
37 let mut errors = vec![];
38
39 if self.max_failed_attempts == 0 {
40 errors.push(CoreError::Internal(InternalError::MissingField {
41 field: "auth.password.security.max_failed_attempts".into(),
42 reason: "must be greater than 0".into(),
43 }));
44 }
45 if self.lockout_duration <= 0 {
46 errors.push(CoreError::Internal(InternalError::MissingField {
47 field: "auth.password.security.lockout_duration".into(),
48 reason: "must be greater than 0".into(),
49 }));
50 }
51
52 if errors.is_empty() {
53 Ok(())
54 } else {
55 Err(errors)
56 }
57 }
58}
59
60impl Validate for Authentication {
65 fn validate(&self) -> Result<(), Vec<CoreError>> {
66 let mut errors = vec![];
67
68 if let AuthStrategy::Jwt(jwt) = &self.strategy {
69 if jwt.issuer.is_empty() {
70 errors.push(CoreError::Internal(InternalError::MissingField {
71 field: "auth.jwt.issuer".into(),
72 reason: "must be set".into(),
73 }));
74 }
75 if jwt.audience.is_empty() {
76 errors.push(CoreError::Internal(InternalError::MissingField {
77 field: "auth.jwt.audience".into(),
78 reason: "must be set".into(),
79 }));
80 }
81 }
82
83 if let AuthStrategy::Session(session) = &self.strategy
84 && let Err(e) = session.validate()
85 {
86 errors.extend(e);
87 }
88
89 if let Err(e) = self.password.validate() {
91 errors.extend(e);
92 }
93
94 if errors.is_empty() {
95 Ok(())
96 } else {
97 Err(errors)
98 }
99 }
100}
101impl Validate for SessionConfig {
102 fn validate(&self) -> Result<(), Vec<CoreError>> {
103 let mut errors = vec![];
104
105 if self.name.is_empty() {
106 errors.push(CoreError::Internal(InternalError::MissingField {
107 field: "auth.session.name".into(),
108 reason: "must not be empty".into(),
109 }));
110 }
111 if self.max_age == 0 {
112 errors.push(CoreError::Internal(InternalError::MissingField {
113 field: "auth.session.max_age".into(),
114 reason: "must be greater than 0".into(),
115 }));
116 }
117 if let SameSiteConfig::None = self.same_site
118 && !self.secure
119 {
120 errors.push(CoreError::Internal(InternalError::MissingField {
121 field: "auth.session.secure".into(),
122 reason: "must be true when same_site is None".into(),
123 }));
124 }
125
126 if errors.is_empty() {
127 Ok(())
128 } else {
129 Err(errors)
130 }
131 }
132}
133
134impl Validate for PasswordConfig {
137 fn validate(&self) -> Result<(), Vec<CoreError>> {
138 let mut errors = vec![];
139
140 if let Err(e) = self.requirements.validate() {
141 errors.extend(e);
142 }
143
144 if errors.is_empty() {
145 Ok(())
146 } else {
147 Err(errors)
148 }
149 }
150}
151impl Validate for PasswordRequirements {
153 fn validate(&self) -> Result<(), Vec<CoreError>> {
154 let mut errors = vec![];
155
156 if self.min_length == 0 {
157 errors.push(CoreError::Internal(InternalError::MissingField {
158 field: "auth.password.requirements.min_length".into(),
159 reason: "must be greater than 0".into(),
160 }));
161 }
162 if self.max_length < self.min_length {
163 errors.push(CoreError::Internal(InternalError::MissingField {
164 field: "auth.password.requirements.max_length".into(),
165 reason: "must be greater than or equal to min_length".into(),
166 }));
167 }
168
169 if errors.is_empty() {
170 Ok(())
171 } else {
172 Err(errors)
173 }
174 }
175}