1use crate::profile::constants::{
2 EMAIL_MAX_LENGTH, LOCALE_MAX_LENGTH, NAME_MAX_LENGTH, SHORT_NAME_MAX_LENGTH,
3};
4use crate::profile::errors::{
5 JUNO_AUTH_ERROR_PROFILE_EMAIL_INVALID_LENGTH,
6 JUNO_AUTH_ERROR_PROFILE_FAMILY_NAME_INVALID_LENGTH,
7 JUNO_AUTH_ERROR_PROFILE_GIVEN_NAME_INVALID_LENGTH,
8 JUNO_AUTH_ERROR_PROFILE_LOCALE_INVALID_LENGTH, JUNO_AUTH_ERROR_PROFILE_NAME_INVALID_LENGTH,
9 JUNO_AUTH_ERROR_PROFILE_PICTURE_INVALID_SCHEME, JUNO_AUTH_ERROR_PROFILE_PICTURE_INVALID_URL,
10 JUNO_AUTH_ERROR_PROFILE_PREFERRED_USERNAME_INVALID_LENGTH,
11};
12use crate::profile::types::{OpenIdProfile, Validated};
13use url::Url;
14
15impl<T: OpenIdProfile> Validated for T {
16 fn validate(&self) -> Result<(), String> {
17 if let Some(email) = self.email().as_ref() {
18 if email.len() > EMAIL_MAX_LENGTH {
19 return Err(JUNO_AUTH_ERROR_PROFILE_EMAIL_INVALID_LENGTH.to_string());
20 }
21 }
22
23 if let Some(name) = self.name().as_ref() {
24 if name.chars().count() > NAME_MAX_LENGTH {
25 return Err(JUNO_AUTH_ERROR_PROFILE_NAME_INVALID_LENGTH.to_string());
26 }
27 }
28
29 if let Some(given_name) = self.given_name().as_ref() {
30 if given_name.chars().count() > SHORT_NAME_MAX_LENGTH {
31 return Err(JUNO_AUTH_ERROR_PROFILE_GIVEN_NAME_INVALID_LENGTH.to_string());
32 }
33 }
34
35 if let Some(family_name) = self.family_name().as_ref() {
36 if family_name.chars().count() > SHORT_NAME_MAX_LENGTH {
37 return Err(JUNO_AUTH_ERROR_PROFILE_FAMILY_NAME_INVALID_LENGTH.to_string());
38 }
39 }
40
41 if let Some(preferred_username) = self.preferred_username().as_ref() {
42 if preferred_username.chars().count() > SHORT_NAME_MAX_LENGTH {
43 return Err(JUNO_AUTH_ERROR_PROFILE_PREFERRED_USERNAME_INVALID_LENGTH.to_string());
44 }
45 }
46
47 if let Some(locale) = self.locale().as_ref() {
48 if locale.chars().count() > LOCALE_MAX_LENGTH {
49 return Err(JUNO_AUTH_ERROR_PROFILE_LOCALE_INVALID_LENGTH.to_string());
50 }
51 }
52
53 if let Some(picture) = self.picture().as_ref() {
54 let url = Url::parse(picture)
55 .map_err(|_| JUNO_AUTH_ERROR_PROFILE_PICTURE_INVALID_URL.to_string())?;
56
57 if url.scheme() != "https" {
58 return Err(JUNO_AUTH_ERROR_PROFILE_PICTURE_INVALID_SCHEME.to_string());
59 }
60 }
61
62 Ok(())
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 pub struct OpenIdDataTest {
71 pub email: Option<String>,
72 pub name: Option<String>,
73 pub given_name: Option<String>,
74 pub family_name: Option<String>,
75 pub preferred_username: Option<String>,
76 pub picture: Option<String>,
77 pub locale: Option<String>,
78 }
79
80 impl OpenIdProfile for OpenIdDataTest {
81 fn email(&self) -> Option<&str> {
82 self.email.as_deref()
83 }
84 fn name(&self) -> Option<&str> {
85 self.name.as_deref()
86 }
87 fn given_name(&self) -> Option<&str> {
88 self.given_name.as_deref()
89 }
90 fn family_name(&self) -> Option<&str> {
91 self.family_name.as_deref()
92 }
93 fn preferred_username(&self) -> Option<&str> {
94 self.preferred_username.as_deref()
95 }
96 fn picture(&self) -> Option<&str> {
97 self.picture.as_deref()
98 }
99 fn locale(&self) -> Option<&str> {
100 self.locale.as_deref()
101 }
102 }
103
104 #[test]
105 fn test_google_valid_data() {
106 let data = OpenIdDataTest {
107 email: Some("user@example.com".to_string()),
108 name: Some("Ada Lovelace".to_string()),
109 given_name: Some("Ada".to_string()),
110 family_name: Some("Lovelace".to_string()),
111 preferred_username: None,
112 picture: Some("https://example.com/avatar.png".to_string()),
113 locale: Some("en".to_string()),
114 };
115
116 assert!(data.validate().is_ok());
117 }
118
119 #[test]
120 fn test_google_invalid_email_length() {
121 let long_email = "a".repeat(EMAIL_MAX_LENGTH + 1);
122 let data = OpenIdDataTest {
123 email: Some(long_email),
124 name: None,
125 given_name: None,
126 family_name: None,
127 preferred_username: None,
128 picture: None,
129 locale: None,
130 };
131 assert!(data.validate().is_err());
132 }
133
134 #[test]
135 fn test_google_invalid_picture_url() {
136 let data = OpenIdDataTest {
137 email: None,
138 name: None,
139 given_name: None,
140 family_name: None,
141 preferred_username: None,
142 picture: Some("not-a-valid-url".to_string()),
143 locale: None,
144 };
145 assert!(data.validate().is_err());
146 }
147
148 #[test]
149 fn test_google_invalid_picture_scheme() {
150 let data = OpenIdDataTest {
151 email: None,
152 name: None,
153 given_name: None,
154 family_name: None,
155 preferred_username: None,
156 picture: Some("http://example.com/avatar.png".to_string()),
157 locale: None,
158 };
159 assert!(data.validate().is_err());
160 }
161
162 #[test]
163 fn test_google_invalid_name_length() {
164 let data = OpenIdDataTest {
165 email: None,
166 name: Some("a".repeat(NAME_MAX_LENGTH + 1)),
167 given_name: None,
168 family_name: None,
169 preferred_username: None,
170 picture: None,
171 locale: None,
172 };
173 assert!(data.validate().is_err());
174 }
175
176 #[test]
177 fn test_google_invalid_given_name_length() {
178 let data = OpenIdDataTest {
179 email: None,
180 name: None,
181 given_name: Some("a".repeat(SHORT_NAME_MAX_LENGTH + 1)),
182 family_name: None,
183 preferred_username: None,
184 picture: None,
185 locale: None,
186 };
187 assert!(data.validate().is_err());
188 }
189
190 #[test]
191 fn test_google_invalid_family_name_length() {
192 let data = OpenIdDataTest {
193 email: None,
194 name: None,
195 given_name: None,
196 family_name: Some("a".repeat(SHORT_NAME_MAX_LENGTH + 1)),
197 preferred_username: None,
198 picture: None,
199 locale: None,
200 };
201 assert!(data.validate().is_err());
202 }
203
204 #[test]
205 fn test_google_invalid_locale_length() {
206 let data = OpenIdDataTest {
207 email: None,
208 name: None,
209 given_name: None,
210 family_name: None,
211 preferred_username: None,
212 picture: None,
213 locale: Some("a".repeat(LOCALE_MAX_LENGTH + 1)),
214 };
215 assert!(data.validate().is_err());
216 }
217
218 #[test]
219 fn test_github_invalid_preferred_username_length() {
220 let data = OpenIdDataTest {
221 email: None,
222 name: None,
223 given_name: None,
224 family_name: None,
225 preferred_username: Some("a".repeat(SHORT_NAME_MAX_LENGTH + 1)),
226 picture: None,
227 locale: None,
228 };
229 assert!(data.validate().is_err());
230 }
231
232 #[test]
233 fn test_github_valid_data() {
234 let data = OpenIdDataTest {
235 email: Some("user@example.com".to_string()),
236 name: Some("Peter Peter Parker".to_string()),
237 given_name: None,
238 family_name: None,
239 preferred_username: Some("peterpeterparker".to_string()),
240 picture: Some("https://avatars.githubusercontent.com/u/16886711".to_string()),
241 locale: None,
242 };
243
244 assert!(data.validate().is_ok());
245 }
246}