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 16#[tokio::test] 17async fn test_email_update_flow_success() { 18 let client = common::client(); 19 let base_url = common::base_url().await; 20 let pool = get_pool().await; 21 22 let handle = format!("emailup_{}", uuid::Uuid::new_v4()); 23 let email = format!("{}@example.com", handle); 24 let payload = json!({ 25 "handle": handle, 26 "email": email, 27 "password": "password" 28 }); 29 30 let res = client 31 .post(format!("{}/xrpc/com.atproto.server.createAccount", base_url)) 32 .json(&payload) 33 .send() 34 .await 35 .expect("Failed to create account"); 36 assert_eq!(res.status(), StatusCode::OK); 37 let body: Value = res.json().await.expect("Invalid JSON"); 38 let access_jwt = body["accessJwt"].as_str().expect("No accessJwt"); 39 40 let new_email = format!("new_{}@example.com", handle); 41 let res = client 42 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url)) 43 .bearer_auth(access_jwt) 44 .json(&json!({"email": new_email})) 45 .send() 46 .await 47 .expect("Failed to request email update"); 48 assert_eq!(res.status(), StatusCode::OK); 49 let body: Value = res.json().await.expect("Invalid JSON"); 50 assert_eq!(body["tokenRequired"], true); 51 52 let user = sqlx::query!( 53 "SELECT email_pending_verification, email_confirmation_code, email FROM users WHERE handle = $1", 54 handle 55 ) 56 .fetch_one(&pool) 57 .await 58 .expect("User not found"); 59 60 assert_eq!(user.email_pending_verification.as_deref(), Some(new_email.as_str())); 61 assert!(user.email_confirmation_code.is_some()); 62 let code = user.email_confirmation_code.unwrap(); 63 64 let res = client 65 .post(format!("{}/xrpc/com.atproto.server.confirmEmail", base_url)) 66 .bearer_auth(access_jwt) 67 .json(&json!({ 68 "email": new_email, 69 "token": code 70 })) 71 .send() 72 .await 73 .expect("Failed to confirm email"); 74 assert_eq!(res.status(), StatusCode::OK); 75 76 let user = sqlx::query!( 77 "SELECT email, email_pending_verification, email_confirmation_code FROM users WHERE handle = $1", 78 handle 79 ) 80 .fetch_one(&pool) 81 .await 82 .expect("User not found"); 83 84 assert_eq!(user.email, new_email); 85 assert!(user.email_pending_verification.is_none()); 86 assert!(user.email_confirmation_code.is_none()); 87} 88 89#[tokio::test] 90async fn test_request_email_update_taken_email() { 91 let client = common::client(); 92 let base_url = common::base_url().await; 93 94 let handle1 = format!("emailup_taken1_{}", uuid::Uuid::new_v4()); 95 let email1 = format!("{}@example.com", handle1); 96 let res = client 97 .post(format!("{}/xrpc/com.atproto.server.createAccount", base_url)) 98 .json(&json!({ 99 "handle": handle1, 100 "email": email1, 101 "password": "password" 102 })) 103 .send() 104 .await 105 .expect("Failed to create account 1"); 106 assert_eq!(res.status(), StatusCode::OK); 107 108 let handle2 = format!("emailup_taken2_{}", uuid::Uuid::new_v4()); 109 let email2 = format!("{}@example.com", handle2); 110 let res = client 111 .post(format!("{}/xrpc/com.atproto.server.createAccount", base_url)) 112 .json(&json!({ 113 "handle": handle2, 114 "email": email2, 115 "password": "password" 116 })) 117 .send() 118 .await 119 .expect("Failed to create account 2"); 120 assert_eq!(res.status(), StatusCode::OK); 121 let body: Value = res.json().await.expect("Invalid JSON"); 122 let access_jwt2 = body["accessJwt"].as_str().expect("No accessJwt"); 123 124 let res = client 125 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url)) 126 .bearer_auth(access_jwt2) 127 .json(&json!({"email": email1})) 128 .send() 129 .await 130 .expect("Failed to request email update"); 131 132 assert_eq!(res.status(), StatusCode::BAD_REQUEST); 133 let body: Value = res.json().await.expect("Invalid JSON"); 134 assert_eq!(body["error"], "EmailTaken"); 135} 136 137#[tokio::test] 138async fn test_confirm_email_invalid_token() { 139 let client = common::client(); 140 let base_url = common::base_url().await; 141 142 let handle = format!("emailup_inv_{}", uuid::Uuid::new_v4()); 143 let email = format!("{}@example.com", handle); 144 let res = client 145 .post(format!("{}/xrpc/com.atproto.server.createAccount", base_url)) 146 .json(&json!({ 147 "handle": handle, 148 "email": email, 149 "password": "password" 150 })) 151 .send() 152 .await 153 .expect("Failed to create account"); 154 assert_eq!(res.status(), StatusCode::OK); 155 let body: Value = res.json().await.expect("Invalid JSON"); 156 let access_jwt = body["accessJwt"].as_str().expect("No accessJwt"); 157 158 let new_email = format!("new_{}@example.com", handle); 159 let res = client 160 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url)) 161 .bearer_auth(access_jwt) 162 .json(&json!({"email": new_email})) 163 .send() 164 .await 165 .expect("Failed to request email update"); 166 assert_eq!(res.status(), StatusCode::OK); 167 168 let res = client 169 .post(format!("{}/xrpc/com.atproto.server.confirmEmail", base_url)) 170 .bearer_auth(access_jwt) 171 .json(&json!({ 172 "email": new_email, 173 "token": "wrong-token" 174 })) 175 .send() 176 .await 177 .expect("Failed to confirm email"); 178 179 assert_eq!(res.status(), StatusCode::BAD_REQUEST); 180 let body: Value = res.json().await.expect("Invalid JSON"); 181 assert_eq!(body["error"], "InvalidToken"); 182} 183 184#[tokio::test] 185async fn test_confirm_email_wrong_email() { 186 let client = common::client(); 187 let base_url = common::base_url().await; 188 let pool = get_pool().await; 189 190 let handle = format!("emailup_wrong_{}", uuid::Uuid::new_v4()); 191 let email = format!("{}@example.com", handle); 192 let res = client 193 .post(format!("{}/xrpc/com.atproto.server.createAccount", base_url)) 194 .json(&json!({ 195 "handle": handle, 196 "email": email, 197 "password": "password" 198 })) 199 .send() 200 .await 201 .expect("Failed to create account"); 202 assert_eq!(res.status(), StatusCode::OK); 203 let body: Value = res.json().await.expect("Invalid JSON"); 204 let access_jwt = body["accessJwt"].as_str().expect("No accessJwt"); 205 206 let new_email = format!("new_{}@example.com", handle); 207 let res = client 208 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url)) 209 .bearer_auth(access_jwt) 210 .json(&json!({"email": new_email})) 211 .send() 212 .await 213 .expect("Failed to request email update"); 214 assert_eq!(res.status(), StatusCode::OK); 215 216 let user = sqlx::query!("SELECT email_confirmation_code FROM users WHERE handle = $1", handle) 217 .fetch_one(&pool) 218 .await 219 .expect("User not found"); 220 let code = user.email_confirmation_code.unwrap(); 221 222 let res = client 223 .post(format!("{}/xrpc/com.atproto.server.confirmEmail", base_url)) 224 .bearer_auth(access_jwt) 225 .json(&json!({ 226 "email": "another_random@example.com", 227 "token": code 228 })) 229 .send() 230 .await 231 .expect("Failed to confirm email"); 232 233 assert_eq!(res.status(), StatusCode::BAD_REQUEST); 234 let body: Value = res.json().await.expect("Invalid JSON"); 235 assert_eq!(body["message"], "Email does not match pending update"); 236} 237 238#[tokio::test] 239async fn test_update_email_success_no_token_required() { 240 let client = common::client(); 241 let base_url = common::base_url().await; 242 let pool = get_pool().await; 243 244 let handle = format!("emailup_direct_{}", uuid::Uuid::new_v4()); 245 let email = format!("{}@example.com", handle); 246 let res = client 247 .post(format!("{}/xrpc/com.atproto.server.createAccount", base_url)) 248 .json(&json!({ 249 "handle": handle, 250 "email": email, 251 "password": "password" 252 })) 253 .send() 254 .await 255 .expect("Failed to create account"); 256 assert_eq!(res.status(), StatusCode::OK); 257 let body: Value = res.json().await.expect("Invalid JSON"); 258 let access_jwt = body["accessJwt"].as_str().expect("No accessJwt"); 259 260 let new_email = format!("direct_{}@example.com", handle); 261 let res = client 262 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url)) 263 .bearer_auth(access_jwt) 264 .json(&json!({ "email": new_email })) 265 .send() 266 .await 267 .expect("Failed to update email"); 268 269 assert_eq!(res.status(), StatusCode::OK); 270 271 let user = sqlx::query!("SELECT email FROM users WHERE handle = $1", handle) 272 .fetch_one(&pool) 273 .await 274 .expect("User not found"); 275 assert_eq!(user.email, new_email); 276} 277 278#[tokio::test] 279async fn test_update_email_same_email_noop() { 280 let client = common::client(); 281 let base_url = common::base_url().await; 282 283 let handle = format!("emailup_same_{}", uuid::Uuid::new_v4()); 284 let email = format!("{}@example.com", handle); 285 let res = client 286 .post(format!("{}/xrpc/com.atproto.server.createAccount", base_url)) 287 .json(&json!({ 288 "handle": handle, 289 "email": email, 290 "password": "password" 291 })) 292 .send() 293 .await 294 .expect("Failed to create account"); 295 assert_eq!(res.status(), StatusCode::OK); 296 let body: Value = res.json().await.expect("Invalid JSON"); 297 let access_jwt = body["accessJwt"].as_str().expect("No accessJwt"); 298 299 let res = client 300 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url)) 301 .bearer_auth(access_jwt) 302 .json(&json!({ "email": email })) 303 .send() 304 .await 305 .expect("Failed to update email"); 306 307 assert_eq!(res.status(), StatusCode::OK, "Updating to same email should succeed as no-op"); 308} 309 310#[tokio::test] 311async fn test_update_email_requires_token_after_pending() { 312 let client = common::client(); 313 let base_url = common::base_url().await; 314 315 let handle = format!("emailup_token_{}", uuid::Uuid::new_v4()); 316 let email = format!("{}@example.com", handle); 317 let res = client 318 .post(format!("{}/xrpc/com.atproto.server.createAccount", base_url)) 319 .json(&json!({ 320 "handle": handle, 321 "email": email, 322 "password": "password" 323 })) 324 .send() 325 .await 326 .expect("Failed to create account"); 327 assert_eq!(res.status(), StatusCode::OK); 328 let body: Value = res.json().await.expect("Invalid JSON"); 329 let access_jwt = body["accessJwt"].as_str().expect("No accessJwt"); 330 331 let new_email = format!("pending_{}@example.com", handle); 332 let res = client 333 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url)) 334 .bearer_auth(access_jwt) 335 .json(&json!({"email": new_email})) 336 .send() 337 .await 338 .expect("Failed to request email update"); 339 assert_eq!(res.status(), StatusCode::OK); 340 341 let res = client 342 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url)) 343 .bearer_auth(access_jwt) 344 .json(&json!({ "email": new_email })) 345 .send() 346 .await 347 .expect("Failed to attempt email update"); 348 349 assert_eq!(res.status(), StatusCode::BAD_REQUEST); 350 let body: Value = res.json().await.expect("Invalid JSON"); 351 assert_eq!(body["error"], "TokenRequired"); 352} 353 354#[tokio::test] 355async fn test_update_email_with_valid_token() { 356 let client = common::client(); 357 let base_url = common::base_url().await; 358 let pool = get_pool().await; 359 360 let handle = format!("emailup_valid_{}", uuid::Uuid::new_v4()); 361 let email = format!("{}@example.com", handle); 362 let res = client 363 .post(format!("{}/xrpc/com.atproto.server.createAccount", base_url)) 364 .json(&json!({ 365 "handle": handle, 366 "email": email, 367 "password": "password" 368 })) 369 .send() 370 .await 371 .expect("Failed to create account"); 372 assert_eq!(res.status(), StatusCode::OK); 373 let body: Value = res.json().await.expect("Invalid JSON"); 374 let access_jwt = body["accessJwt"].as_str().expect("No accessJwt"); 375 376 let new_email = format!("valid_{}@example.com", handle); 377 let res = client 378 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url)) 379 .bearer_auth(access_jwt) 380 .json(&json!({"email": new_email})) 381 .send() 382 .await 383 .expect("Failed to request email update"); 384 assert_eq!(res.status(), StatusCode::OK); 385 386 let user = sqlx::query!( 387 "SELECT email_confirmation_code FROM users WHERE handle = $1", 388 handle 389 ) 390 .fetch_one(&pool) 391 .await 392 .expect("User not found"); 393 let code = user.email_confirmation_code.unwrap(); 394 395 let res = client 396 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url)) 397 .bearer_auth(access_jwt) 398 .json(&json!({ 399 "email": new_email, 400 "token": code 401 })) 402 .send() 403 .await 404 .expect("Failed to update email"); 405 406 assert_eq!(res.status(), StatusCode::OK); 407 408 let user = sqlx::query!("SELECT email, email_pending_verification FROM users WHERE handle = $1", handle) 409 .fetch_one(&pool) 410 .await 411 .expect("User not found"); 412 assert_eq!(user.email, new_email); 413 assert!(user.email_pending_verification.is_none()); 414} 415 416#[tokio::test] 417async fn test_update_email_invalid_token() { 418 let client = common::client(); 419 let base_url = common::base_url().await; 420 421 let handle = format!("emailup_badtok_{}", uuid::Uuid::new_v4()); 422 let email = format!("{}@example.com", handle); 423 let res = client 424 .post(format!("{}/xrpc/com.atproto.server.createAccount", base_url)) 425 .json(&json!({ 426 "handle": handle, 427 "email": email, 428 "password": "password" 429 })) 430 .send() 431 .await 432 .expect("Failed to create account"); 433 assert_eq!(res.status(), StatusCode::OK); 434 let body: Value = res.json().await.expect("Invalid JSON"); 435 let access_jwt = body["accessJwt"].as_str().expect("No accessJwt"); 436 437 let new_email = format!("badtok_{}@example.com", handle); 438 let res = client 439 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url)) 440 .bearer_auth(access_jwt) 441 .json(&json!({"email": new_email})) 442 .send() 443 .await 444 .expect("Failed to request email update"); 445 assert_eq!(res.status(), StatusCode::OK); 446 447 let res = client 448 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url)) 449 .bearer_auth(access_jwt) 450 .json(&json!({ 451 "email": new_email, 452 "token": "wrong-token-12345" 453 })) 454 .send() 455 .await 456 .expect("Failed to attempt email update"); 457 458 assert_eq!(res.status(), StatusCode::BAD_REQUEST); 459 let body: Value = res.json().await.expect("Invalid JSON"); 460 assert_eq!(body["error"], "InvalidToken"); 461} 462 463#[tokio::test] 464async fn test_update_email_already_taken() { 465 let client = common::client(); 466 let base_url = common::base_url().await; 467 468 let handle1 = format!("emailup_dup1_{}", uuid::Uuid::new_v4()); 469 let email1 = format!("{}@example.com", handle1); 470 let res = client 471 .post(format!("{}/xrpc/com.atproto.server.createAccount", base_url)) 472 .json(&json!({ 473 "handle": handle1, 474 "email": email1, 475 "password": "password" 476 })) 477 .send() 478 .await 479 .expect("Failed to create account 1"); 480 assert_eq!(res.status(), StatusCode::OK); 481 482 let handle2 = format!("emailup_dup2_{}", uuid::Uuid::new_v4()); 483 let email2 = format!("{}@example.com", handle2); 484 let res = client 485 .post(format!("{}/xrpc/com.atproto.server.createAccount", base_url)) 486 .json(&json!({ 487 "handle": handle2, 488 "email": email2, 489 "password": "password" 490 })) 491 .send() 492 .await 493 .expect("Failed to create account 2"); 494 assert_eq!(res.status(), StatusCode::OK); 495 let body: Value = res.json().await.expect("Invalid JSON"); 496 let access_jwt2 = body["accessJwt"].as_str().expect("No accessJwt"); 497 498 let res = client 499 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url)) 500 .bearer_auth(access_jwt2) 501 .json(&json!({ "email": email1 })) 502 .send() 503 .await 504 .expect("Failed to attempt email update"); 505 506 assert_eq!(res.status(), StatusCode::BAD_REQUEST); 507 let body: Value = res.json().await.expect("Invalid JSON"); 508 assert!(body["message"].as_str().unwrap().contains("already in use") || body["error"] == "InvalidRequest"); 509} 510 511#[tokio::test] 512async fn test_update_email_no_auth() { 513 let client = common::client(); 514 let base_url = common::base_url().await; 515 516 let res = client 517 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url)) 518 .json(&json!({ "email": "test@example.com" })) 519 .send() 520 .await 521 .expect("Failed to send request"); 522 523 assert_eq!(res.status(), StatusCode::UNAUTHORIZED); 524 let body: Value = res.json().await.expect("Invalid JSON"); 525 assert_eq!(body["error"], "AuthenticationRequired"); 526} 527 528#[tokio::test] 529async fn test_update_email_invalid_format() { 530 let client = common::client(); 531 let base_url = common::base_url().await; 532 533 let handle = format!("emailup_fmt_{}", uuid::Uuid::new_v4()); 534 let email = format!("{}@example.com", handle); 535 let res = client 536 .post(format!("{}/xrpc/com.atproto.server.createAccount", base_url)) 537 .json(&json!({ 538 "handle": handle, 539 "email": email, 540 "password": "password" 541 })) 542 .send() 543 .await 544 .expect("Failed to create account"); 545 assert_eq!(res.status(), StatusCode::OK); 546 let body: Value = res.json().await.expect("Invalid JSON"); 547 let access_jwt = body["accessJwt"].as_str().expect("No accessJwt"); 548 549 let res = client 550 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url)) 551 .bearer_auth(access_jwt) 552 .json(&json!({ "email": "not-an-email" })) 553 .send() 554 .await 555 .expect("Failed to send request"); 556 557 assert_eq!(res.status(), StatusCode::BAD_REQUEST); 558 let body: Value = res.json().await.expect("Invalid JSON"); 559 assert_eq!(body["error"], "InvalidEmail"); 560}