this repo has no description
1mod common; 2mod helpers; 3use chrono::Utc; 4use common::*; 5use reqwest::StatusCode; 6use serde_json::{Value, json}; 7 8async fn create_verified_account( 9 client: &reqwest::Client, 10 base_url: &str, 11 handle: &str, 12 email: &str, 13 password: &str, 14) -> (String, String) { 15 let res = client 16 .post(format!( 17 "{}/xrpc/com.atproto.server.createAccount", 18 base_url 19 )) 20 .json(&json!({ 21 "handle": handle, 22 "email": email, 23 "password": password 24 })) 25 .send() 26 .await 27 .expect("Failed to create account"); 28 assert_eq!(res.status(), StatusCode::OK); 29 let body: Value = res.json().await.expect("Invalid JSON"); 30 let did = body["did"].as_str().expect("No did").to_string(); 31 let jwt = verify_new_account(client, &did).await; 32 (did, jwt) 33} 34 35#[tokio::test] 36async fn test_delete_account_full_flow() { 37 let client = client(); 38 let base_url = base_url().await; 39 let ts = Utc::now().timestamp_millis(); 40 let handle = format!("delete-test-{}.test", ts); 41 let email = format!("delete-test-{}@test.com", ts); 42 let password = "Delete123pass!"; 43 let (did, jwt) = create_verified_account(&client, base_url, &handle, &email, password).await; 44 let request_delete_res = client 45 .post(format!( 46 "{}/xrpc/com.atproto.server.requestAccountDelete", 47 base_url 48 )) 49 .bearer_auth(&jwt) 50 .send() 51 .await 52 .expect("Failed to request account deletion"); 53 assert_eq!(request_delete_res.status(), StatusCode::OK); 54 let pool = get_test_db_pool().await; 55 let row = sqlx::query!( 56 "SELECT token FROM account_deletion_requests WHERE did = $1", 57 did 58 ) 59 .fetch_one(pool) 60 .await 61 .expect("Failed to query deletion token"); 62 let token = row.token; 63 let delete_payload = json!({ 64 "did": did, 65 "password": password, 66 "token": token 67 }); 68 let delete_res = client 69 .post(format!( 70 "{}/xrpc/com.atproto.server.deleteAccount", 71 base_url 72 )) 73 .json(&delete_payload) 74 .send() 75 .await 76 .expect("Failed to delete account"); 77 assert_eq!(delete_res.status(), StatusCode::OK); 78 let user_row = sqlx::query!("SELECT id FROM users WHERE did = $1", did) 79 .fetch_optional(pool) 80 .await 81 .expect("Failed to query user"); 82 assert!(user_row.is_none(), "User should be deleted from database"); 83 let session_res = client 84 .get(format!("{}/xrpc/com.atproto.server.getSession", base_url)) 85 .bearer_auth(&jwt) 86 .send() 87 .await 88 .expect("Failed to check session"); 89 assert_eq!(session_res.status(), StatusCode::UNAUTHORIZED); 90} 91 92#[tokio::test] 93async fn test_delete_account_wrong_password() { 94 let client = client(); 95 let base_url = base_url().await; 96 let ts = Utc::now().timestamp_millis(); 97 let handle = format!("delete-wrongpw-{}.test", ts); 98 let email = format!("delete-wrongpw-{}@test.com", ts); 99 let password = "Correct123!"; 100 let (did, jwt) = create_verified_account(&client, base_url, &handle, &email, password).await; 101 let request_delete_res = client 102 .post(format!( 103 "{}/xrpc/com.atproto.server.requestAccountDelete", 104 base_url 105 )) 106 .bearer_auth(&jwt) 107 .send() 108 .await 109 .expect("Failed to request account deletion"); 110 assert_eq!(request_delete_res.status(), StatusCode::OK); 111 let pool = get_test_db_pool().await; 112 let row = sqlx::query!( 113 "SELECT token FROM account_deletion_requests WHERE did = $1", 114 did 115 ) 116 .fetch_one(pool) 117 .await 118 .expect("Failed to query deletion token"); 119 let token = row.token; 120 let delete_payload = json!({ 121 "did": did, 122 "password": "wrong-password", 123 "token": token 124 }); 125 let delete_res = client 126 .post(format!( 127 "{}/xrpc/com.atproto.server.deleteAccount", 128 base_url 129 )) 130 .json(&delete_payload) 131 .send() 132 .await 133 .expect("Failed to send delete request"); 134 assert_eq!(delete_res.status(), StatusCode::UNAUTHORIZED); 135 let body: Value = delete_res.json().await.unwrap(); 136 assert_eq!(body["error"], "AuthenticationFailed"); 137} 138 139#[tokio::test] 140async fn test_delete_account_invalid_token() { 141 let client = client(); 142 let base_url = base_url().await; 143 let ts = Utc::now().timestamp_millis(); 144 let handle = format!("delete-badtoken-{}.test", ts); 145 let email = format!("delete-badtoken-{}@test.com", ts); 146 let password = "Delete123!"; 147 let create_res = client 148 .post(format!( 149 "{}/xrpc/com.atproto.server.createAccount", 150 base_url 151 )) 152 .json(&json!({ 153 "handle": handle, 154 "email": email, 155 "password": password 156 })) 157 .send() 158 .await 159 .expect("Failed to create account"); 160 assert_eq!(create_res.status(), StatusCode::OK); 161 let create_body: Value = create_res.json().await.unwrap(); 162 let did = create_body["did"].as_str().unwrap().to_string(); 163 let delete_payload = json!({ 164 "did": did, 165 "password": password, 166 "token": "invalid-token-12345" 167 }); 168 let delete_res = client 169 .post(format!( 170 "{}/xrpc/com.atproto.server.deleteAccount", 171 base_url 172 )) 173 .json(&delete_payload) 174 .send() 175 .await 176 .expect("Failed to send delete request"); 177 assert_eq!(delete_res.status(), StatusCode::UNAUTHORIZED); 178 let body: Value = delete_res.json().await.unwrap(); 179 assert_eq!(body["error"], "InvalidToken"); 180} 181 182#[tokio::test] 183async fn test_delete_account_expired_token() { 184 let client = client(); 185 let base_url = base_url().await; 186 let ts = Utc::now().timestamp_millis(); 187 let handle = format!("delete-expired-{}.test", ts); 188 let email = format!("delete-expired-{}@test.com", ts); 189 let password = "Delete123!"; 190 let (did, jwt) = create_verified_account(&client, base_url, &handle, &email, password).await; 191 let request_delete_res = client 192 .post(format!( 193 "{}/xrpc/com.atproto.server.requestAccountDelete", 194 base_url 195 )) 196 .bearer_auth(&jwt) 197 .send() 198 .await 199 .expect("Failed to request account deletion"); 200 assert_eq!(request_delete_res.status(), StatusCode::OK); 201 let pool = get_test_db_pool().await; 202 let row = sqlx::query!( 203 "SELECT token FROM account_deletion_requests WHERE did = $1", 204 did 205 ) 206 .fetch_one(pool) 207 .await 208 .expect("Failed to query deletion token"); 209 let token = row.token; 210 sqlx::query!( 211 "UPDATE account_deletion_requests SET expires_at = NOW() - INTERVAL '1 hour' WHERE token = $1", 212 token 213 ) 214 .execute(pool) 215 .await 216 .expect("Failed to expire token"); 217 let delete_payload = json!({ 218 "did": did, 219 "password": password, 220 "token": token 221 }); 222 let delete_res = client 223 .post(format!( 224 "{}/xrpc/com.atproto.server.deleteAccount", 225 base_url 226 )) 227 .json(&delete_payload) 228 .send() 229 .await 230 .expect("Failed to send delete request"); 231 assert_eq!(delete_res.status(), StatusCode::UNAUTHORIZED); 232 let body: Value = delete_res.json().await.unwrap(); 233 assert_eq!(body["error"], "ExpiredToken"); 234} 235 236#[tokio::test] 237async fn test_delete_account_token_mismatch() { 238 let client = client(); 239 let base_url = base_url().await; 240 let ts = Utc::now().timestamp_millis(); 241 let handle1 = format!("delete-user1-{}.test", ts); 242 let email1 = format!("delete-user1-{}@test.com", ts); 243 let password1 = "User1pass123!"; 244 let (did1, jwt1) = 245 create_verified_account(&client, base_url, &handle1, &email1, password1).await; 246 let handle2 = format!("delete-user2-{}.test", ts); 247 let email2 = format!("delete-user2-{}@test.com", ts); 248 let password2 = "User2pass123!"; 249 let (did2, _) = create_verified_account(&client, base_url, &handle2, &email2, password2).await; 250 let request_delete_res = client 251 .post(format!( 252 "{}/xrpc/com.atproto.server.requestAccountDelete", 253 base_url 254 )) 255 .bearer_auth(&jwt1) 256 .send() 257 .await 258 .expect("Failed to request account deletion"); 259 assert_eq!(request_delete_res.status(), StatusCode::OK); 260 let pool = get_test_db_pool().await; 261 let row = sqlx::query!( 262 "SELECT token FROM account_deletion_requests WHERE did = $1", 263 did1 264 ) 265 .fetch_one(pool) 266 .await 267 .expect("Failed to query deletion token"); 268 let token = row.token; 269 let delete_payload = json!({ 270 "did": did2, 271 "password": password2, 272 "token": token 273 }); 274 let delete_res = client 275 .post(format!( 276 "{}/xrpc/com.atproto.server.deleteAccount", 277 base_url 278 )) 279 .json(&delete_payload) 280 .send() 281 .await 282 .expect("Failed to send delete request"); 283 assert_eq!(delete_res.status(), StatusCode::UNAUTHORIZED); 284 let body: Value = delete_res.json().await.unwrap(); 285 assert_eq!(body["error"], "InvalidToken"); 286} 287 288#[tokio::test] 289async fn test_delete_account_with_app_password() { 290 let client = client(); 291 let base_url = base_url().await; 292 let ts = Utc::now().timestamp_millis(); 293 let handle = format!("delete-apppw-{}.test", ts); 294 let email = format!("delete-apppw-{}@test.com", ts); 295 let main_password = "Mainpass123!"; 296 let (did, jwt) = 297 create_verified_account(&client, base_url, &handle, &email, main_password).await; 298 let app_password_res = client 299 .post(format!( 300 "{}/xrpc/com.atproto.server.createAppPassword", 301 base_url 302 )) 303 .bearer_auth(&jwt) 304 .json(&json!({ "name": "delete-test-app" })) 305 .send() 306 .await 307 .expect("Failed to create app password"); 308 assert_eq!(app_password_res.status(), StatusCode::OK); 309 let app_password_body: Value = app_password_res.json().await.unwrap(); 310 let app_password = app_password_body["password"].as_str().unwrap().to_string(); 311 let request_delete_res = client 312 .post(format!( 313 "{}/xrpc/com.atproto.server.requestAccountDelete", 314 base_url 315 )) 316 .bearer_auth(&jwt) 317 .send() 318 .await 319 .expect("Failed to request account deletion"); 320 assert_eq!(request_delete_res.status(), StatusCode::OK); 321 let pool = get_test_db_pool().await; 322 let row = sqlx::query!( 323 "SELECT token FROM account_deletion_requests WHERE did = $1", 324 did 325 ) 326 .fetch_one(pool) 327 .await 328 .expect("Failed to query deletion token"); 329 let token = row.token; 330 let delete_payload = json!({ 331 "did": did, 332 "password": app_password, 333 "token": token 334 }); 335 let delete_res = client 336 .post(format!( 337 "{}/xrpc/com.atproto.server.deleteAccount", 338 base_url 339 )) 340 .json(&delete_payload) 341 .send() 342 .await 343 .expect("Failed to delete account"); 344 assert_eq!(delete_res.status(), StatusCode::OK); 345 let user_row = sqlx::query!("SELECT id FROM users WHERE did = $1", did) 346 .fetch_optional(pool) 347 .await 348 .expect("Failed to query user"); 349 assert!(user_row.is_none(), "User should be deleted from database"); 350} 351 352#[tokio::test] 353async fn test_delete_account_missing_fields() { 354 let client = client(); 355 let base_url = base_url().await; 356 let res1 = client 357 .post(format!( 358 "{}/xrpc/com.atproto.server.deleteAccount", 359 base_url 360 )) 361 .json(&json!({ 362 "password": "test", 363 "token": "test" 364 })) 365 .send() 366 .await 367 .expect("Failed to send request"); 368 assert_eq!(res1.status(), StatusCode::UNPROCESSABLE_ENTITY); 369 let res2 = client 370 .post(format!( 371 "{}/xrpc/com.atproto.server.deleteAccount", 372 base_url 373 )) 374 .json(&json!({ 375 "did": "did:web:test", 376 "token": "test" 377 })) 378 .send() 379 .await 380 .expect("Failed to send request"); 381 assert_eq!(res2.status(), StatusCode::UNPROCESSABLE_ENTITY); 382 let res3 = client 383 .post(format!( 384 "{}/xrpc/com.atproto.server.deleteAccount", 385 base_url 386 )) 387 .json(&json!({ 388 "did": "did:web:test", 389 "password": "test" 390 })) 391 .send() 392 .await 393 .expect("Failed to send request"); 394 assert_eq!(res3.status(), StatusCode::UNPROCESSABLE_ENTITY); 395} 396 397#[tokio::test] 398async fn test_delete_account_nonexistent_user() { 399 let client = client(); 400 let base_url = base_url().await; 401 let delete_payload = json!({ 402 "did": "did:web:nonexistent.user", 403 "password": "any-password", 404 "token": "any-token" 405 }); 406 let delete_res = client 407 .post(format!( 408 "{}/xrpc/com.atproto.server.deleteAccount", 409 base_url 410 )) 411 .json(&delete_payload) 412 .send() 413 .await 414 .expect("Failed to send delete request"); 415 assert_eq!(delete_res.status(), StatusCode::BAD_REQUEST); 416 let body: Value = delete_res.json().await.unwrap(); 417 assert_eq!(body["error"], "InvalidRequest"); 418}