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