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