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