this repo has no description
1mod common;
2
3use reqwest::StatusCode;
4use serde_json::{json, Value};
5use sqlx::PgPool;
6
7async fn get_pool() -> PgPool {
8 let conn_str = common::get_db_connection_string().await;
9 sqlx::postgres::PgPoolOptions::new()
10 .max_connections(5)
11 .connect(&conn_str)
12 .await
13 .expect("Failed to connect to test database")
14}
15
16async fn create_verified_account(client: &reqwest::Client, base_url: &str, handle: &str, email: &str) -> String {
17 let res = client
18 .post(format!("{}/xrpc/com.atproto.server.createAccount", base_url))
19 .json(&json!({
20 "handle": handle,
21 "email": email,
22 "password": "password"
23 }))
24 .send()
25 .await
26 .expect("Failed to create account");
27 assert_eq!(res.status(), StatusCode::OK);
28 let body: Value = res.json().await.expect("Invalid JSON");
29 let did = body["did"].as_str().expect("No did");
30 common::verify_new_account(client, did).await
31}
32
33#[tokio::test]
34async fn test_email_update_flow_success() {
35 let client = common::client();
36 let base_url = common::base_url().await;
37 let pool = get_pool().await;
38
39 let handle = format!("emailup_{}", uuid::Uuid::new_v4());
40 let email = format!("{}@example.com", handle);
41 let access_jwt = create_verified_account(&client, &base_url, &handle, &email).await;
42
43 let new_email = format!("new_{}@example.com", handle);
44 let res = client
45 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url))
46 .bearer_auth(&access_jwt)
47 .json(&json!({"email": new_email}))
48 .send()
49 .await
50 .expect("Failed to request email update");
51 assert_eq!(res.status(), StatusCode::OK);
52 let body: Value = res.json().await.expect("Invalid JSON");
53 assert_eq!(body["tokenRequired"], true);
54
55 let user = sqlx::query!(
56 "SELECT email_pending_verification, email_confirmation_code, email FROM users WHERE handle = $1",
57 handle
58 )
59 .fetch_one(&pool)
60 .await
61 .expect("User not found");
62
63 assert_eq!(user.email_pending_verification.as_deref(), Some(new_email.as_str()));
64 assert!(user.email_confirmation_code.is_some());
65 let code = user.email_confirmation_code.unwrap();
66
67 let res = client
68 .post(format!("{}/xrpc/com.atproto.server.confirmEmail", base_url))
69 .bearer_auth(&access_jwt)
70 .json(&json!({
71 "email": new_email,
72 "token": code
73 }))
74 .send()
75 .await
76 .expect("Failed to confirm email");
77 assert_eq!(res.status(), StatusCode::OK);
78
79 let user = sqlx::query!(
80 "SELECT email, email_pending_verification, email_confirmation_code FROM users WHERE handle = $1",
81 handle
82 )
83 .fetch_one(&pool)
84 .await
85 .expect("User not found");
86
87 assert_eq!(user.email, Some(new_email));
88 assert!(user.email_pending_verification.is_none());
89 assert!(user.email_confirmation_code.is_none());
90}
91
92#[tokio::test]
93async fn test_request_email_update_taken_email() {
94 let client = common::client();
95 let base_url = common::base_url().await;
96
97 let handle1 = format!("emailup_taken1_{}", uuid::Uuid::new_v4());
98 let email1 = format!("{}@example.com", handle1);
99 let _ = create_verified_account(&client, &base_url, &handle1, &email1).await;
100
101 let handle2 = format!("emailup_taken2_{}", uuid::Uuid::new_v4());
102 let email2 = format!("{}@example.com", handle2);
103 let access_jwt2 = create_verified_account(&client, &base_url, &handle2, &email2).await;
104
105 let res = client
106 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url))
107 .bearer_auth(&access_jwt2)
108 .json(&json!({"email": email1}))
109 .send()
110 .await
111 .expect("Failed to request email update");
112
113 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
114 let body: Value = res.json().await.expect("Invalid JSON");
115 assert_eq!(body["error"], "EmailTaken");
116}
117
118#[tokio::test]
119async fn test_confirm_email_invalid_token() {
120 let client = common::client();
121 let base_url = common::base_url().await;
122
123 let handle = format!("emailup_inv_{}", uuid::Uuid::new_v4());
124 let email = format!("{}@example.com", handle);
125 let access_jwt = create_verified_account(&client, &base_url, &handle, &email).await;
126
127 let new_email = format!("new_{}@example.com", handle);
128 let res = client
129 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url))
130 .bearer_auth(&access_jwt)
131 .json(&json!({"email": new_email}))
132 .send()
133 .await
134 .expect("Failed to request email update");
135 assert_eq!(res.status(), StatusCode::OK);
136
137 let res = client
138 .post(format!("{}/xrpc/com.atproto.server.confirmEmail", base_url))
139 .bearer_auth(&access_jwt)
140 .json(&json!({
141 "email": new_email,
142 "token": "wrong-token"
143 }))
144 .send()
145 .await
146 .expect("Failed to confirm email");
147
148 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
149 let body: Value = res.json().await.expect("Invalid JSON");
150 assert_eq!(body["error"], "InvalidToken");
151}
152
153#[tokio::test]
154async fn test_confirm_email_wrong_email() {
155 let client = common::client();
156 let base_url = common::base_url().await;
157 let pool = get_pool().await;
158
159 let handle = format!("emailup_wrong_{}", uuid::Uuid::new_v4());
160 let email = format!("{}@example.com", handle);
161 let access_jwt = create_verified_account(&client, &base_url, &handle, &email).await;
162
163 let new_email = format!("new_{}@example.com", handle);
164 let res = client
165 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url))
166 .bearer_auth(&access_jwt)
167 .json(&json!({"email": new_email}))
168 .send()
169 .await
170 .expect("Failed to request email update");
171 assert_eq!(res.status(), StatusCode::OK);
172
173 let user = sqlx::query!("SELECT email_confirmation_code FROM users WHERE handle = $1", handle)
174 .fetch_one(&pool)
175 .await
176 .expect("User not found");
177 let code = user.email_confirmation_code.unwrap();
178
179 let res = client
180 .post(format!("{}/xrpc/com.atproto.server.confirmEmail", base_url))
181 .bearer_auth(&access_jwt)
182 .json(&json!({
183 "email": "another_random@example.com",
184 "token": code
185 }))
186 .send()
187 .await
188 .expect("Failed to confirm email");
189
190 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
191 let body: Value = res.json().await.expect("Invalid JSON");
192 assert_eq!(body["message"], "Email does not match pending update");
193}
194
195#[tokio::test]
196async fn test_update_email_success_no_token_required() {
197 let client = common::client();
198 let base_url = common::base_url().await;
199 let pool = get_pool().await;
200
201 let handle = format!("emailup_direct_{}", uuid::Uuid::new_v4());
202 let email = format!("{}@example.com", handle);
203 let access_jwt = create_verified_account(&client, &base_url, &handle, &email).await;
204
205 let new_email = format!("direct_{}@example.com", handle);
206 let res = client
207 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url))
208 .bearer_auth(&access_jwt)
209 .json(&json!({ "email": new_email }))
210 .send()
211 .await
212 .expect("Failed to update email");
213
214 assert_eq!(res.status(), StatusCode::OK);
215
216 let user = sqlx::query!("SELECT email FROM users WHERE handle = $1", handle)
217 .fetch_one(&pool)
218 .await
219 .expect("User not found");
220 assert_eq!(user.email, Some(new_email));
221}
222
223#[tokio::test]
224async fn test_update_email_same_email_noop() {
225 let client = common::client();
226 let base_url = common::base_url().await;
227
228 let handle = format!("emailup_same_{}", uuid::Uuid::new_v4());
229 let email = format!("{}@example.com", handle);
230 let access_jwt = create_verified_account(&client, &base_url, &handle, &email).await;
231
232 let res = client
233 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url))
234 .bearer_auth(&access_jwt)
235 .json(&json!({ "email": email }))
236 .send()
237 .await
238 .expect("Failed to update email");
239
240 assert_eq!(res.status(), StatusCode::OK, "Updating to same email should succeed as no-op");
241}
242
243#[tokio::test]
244async fn test_update_email_requires_token_after_pending() {
245 let client = common::client();
246 let base_url = common::base_url().await;
247
248 let handle = format!("emailup_token_{}", uuid::Uuid::new_v4());
249 let email = format!("{}@example.com", handle);
250 let access_jwt = create_verified_account(&client, &base_url, &handle, &email).await;
251
252 let new_email = format!("pending_{}@example.com", handle);
253 let res = client
254 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url))
255 .bearer_auth(&access_jwt)
256 .json(&json!({"email": new_email}))
257 .send()
258 .await
259 .expect("Failed to request email update");
260 assert_eq!(res.status(), StatusCode::OK);
261
262 let res = client
263 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url))
264 .bearer_auth(&access_jwt)
265 .json(&json!({ "email": new_email }))
266 .send()
267 .await
268 .expect("Failed to attempt email update");
269
270 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
271 let body: Value = res.json().await.expect("Invalid JSON");
272 assert_eq!(body["error"], "TokenRequired");
273}
274
275#[tokio::test]
276async fn test_update_email_with_valid_token() {
277 let client = common::client();
278 let base_url = common::base_url().await;
279 let pool = get_pool().await;
280
281 let handle = format!("emailup_valid_{}", uuid::Uuid::new_v4());
282 let email = format!("{}@example.com", handle);
283 let access_jwt = create_verified_account(&client, &base_url, &handle, &email).await;
284
285 let new_email = format!("valid_{}@example.com", handle);
286 let res = client
287 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url))
288 .bearer_auth(&access_jwt)
289 .json(&json!({"email": new_email}))
290 .send()
291 .await
292 .expect("Failed to request email update");
293 assert_eq!(res.status(), StatusCode::OK);
294
295 let user = sqlx::query!(
296 "SELECT email_confirmation_code FROM users WHERE handle = $1",
297 handle
298 )
299 .fetch_one(&pool)
300 .await
301 .expect("User not found");
302 let code = user.email_confirmation_code.unwrap();
303
304 let res = client
305 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url))
306 .bearer_auth(&access_jwt)
307 .json(&json!({
308 "email": new_email,
309 "token": code
310 }))
311 .send()
312 .await
313 .expect("Failed to update email");
314
315 assert_eq!(res.status(), StatusCode::OK);
316
317 let user = sqlx::query!("SELECT email, email_pending_verification FROM users WHERE handle = $1", handle)
318 .fetch_one(&pool)
319 .await
320 .expect("User not found");
321 assert_eq!(user.email, Some(new_email));
322 assert!(user.email_pending_verification.is_none());
323}
324
325#[tokio::test]
326async fn test_update_email_invalid_token() {
327 let client = common::client();
328 let base_url = common::base_url().await;
329
330 let handle = format!("emailup_badtok_{}", uuid::Uuid::new_v4());
331 let email = format!("{}@example.com", handle);
332 let access_jwt = create_verified_account(&client, &base_url, &handle, &email).await;
333
334 let new_email = format!("badtok_{}@example.com", handle);
335 let res = client
336 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url))
337 .bearer_auth(&access_jwt)
338 .json(&json!({"email": new_email}))
339 .send()
340 .await
341 .expect("Failed to request email update");
342 assert_eq!(res.status(), StatusCode::OK);
343
344 let res = client
345 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url))
346 .bearer_auth(&access_jwt)
347 .json(&json!({
348 "email": new_email,
349 "token": "wrong-token-12345"
350 }))
351 .send()
352 .await
353 .expect("Failed to attempt email update");
354
355 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
356 let body: Value = res.json().await.expect("Invalid JSON");
357 assert_eq!(body["error"], "InvalidToken");
358}
359
360#[tokio::test]
361async fn test_update_email_already_taken() {
362 let client = common::client();
363 let base_url = common::base_url().await;
364
365 let handle1 = format!("emailup_dup1_{}", uuid::Uuid::new_v4());
366 let email1 = format!("{}@example.com", handle1);
367 let _ = create_verified_account(&client, &base_url, &handle1, &email1).await;
368
369 let handle2 = format!("emailup_dup2_{}", uuid::Uuid::new_v4());
370 let email2 = format!("{}@example.com", handle2);
371 let access_jwt2 = create_verified_account(&client, &base_url, &handle2, &email2).await;
372
373 let res = client
374 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url))
375 .bearer_auth(&access_jwt2)
376 .json(&json!({ "email": email1 }))
377 .send()
378 .await
379 .expect("Failed to attempt email update");
380
381 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
382 let body: Value = res.json().await.expect("Invalid JSON");
383 assert!(body["message"].as_str().unwrap().contains("already in use") || body["error"] == "InvalidRequest");
384}
385
386#[tokio::test]
387async fn test_update_email_no_auth() {
388 let client = common::client();
389 let base_url = common::base_url().await;
390
391 let res = client
392 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url))
393 .json(&json!({ "email": "test@example.com" }))
394 .send()
395 .await
396 .expect("Failed to send request");
397
398 assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
399 let body: Value = res.json().await.expect("Invalid JSON");
400 assert_eq!(body["error"], "AuthenticationRequired");
401}
402
403#[tokio::test]
404async fn test_update_email_invalid_format() {
405 let client = common::client();
406 let base_url = common::base_url().await;
407
408 let handle = format!("emailup_fmt_{}", uuid::Uuid::new_v4());
409 let email = format!("{}@example.com", handle);
410 let access_jwt = create_verified_account(&client, &base_url, &handle, &email).await;
411
412 let res = client
413 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url))
414 .bearer_auth(&access_jwt)
415 .json(&json!({ "email": "not-an-email" }))
416 .send()
417 .await
418 .expect("Failed to send request");
419
420 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
421 let body: Value = res.json().await.expect("Invalid JSON");
422 assert_eq!(body["error"], "InvalidEmail");
423}