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