this repo has no description
1mod common;
2use reqwest::StatusCode;
3use serde_json::{json, Value};
4use sqlx::PgPool;
5async fn get_pool() -> PgPool {
6 let conn_str = common::get_db_connection_string().await;
7 sqlx::postgres::PgPoolOptions::new()
8 .max_connections(5)
9 .connect(&conn_str)
10 .await
11 .expect("Failed to connect to test database")
12}
13async fn create_verified_account(client: &reqwest::Client, base_url: &str, handle: &str, email: &str) -> String {
14 let res = client
15 .post(format!("{}/xrpc/com.atproto.server.createAccount", base_url))
16 .json(&json!({
17 "handle": handle,
18 "email": email,
19 "password": "password"
20 }))
21 .send()
22 .await
23 .expect("Failed to create account");
24 assert_eq!(res.status(), StatusCode::OK);
25 let body: Value = res.json().await.expect("Invalid JSON");
26 let did = body["did"].as_str().expect("No did");
27 common::verify_new_account(client, did).await
28}
29#[tokio::test]
30async fn test_email_update_flow_success() {
31 let client = common::client();
32 let base_url = common::base_url().await;
33 let pool = get_pool().await;
34 let handle = format!("emailup_{}", uuid::Uuid::new_v4());
35 let email = format!("{}@example.com", handle);
36 let access_jwt = create_verified_account(&client, &base_url, &handle, &email).await;
37 let new_email = format!("new_{}@example.com", handle);
38 let res = client
39 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url))
40 .bearer_auth(&access_jwt)
41 .json(&json!({"email": new_email}))
42 .send()
43 .await
44 .expect("Failed to request email update");
45 assert_eq!(res.status(), StatusCode::OK);
46 let body: Value = res.json().await.expect("Invalid JSON");
47 assert_eq!(body["tokenRequired"], true);
48 let user = sqlx::query!(
49 "SELECT email_pending_verification, email_confirmation_code, email FROM users WHERE handle = $1",
50 handle
51 )
52 .fetch_one(&pool)
53 .await
54 .expect("User not found");
55 assert_eq!(user.email_pending_verification.as_deref(), Some(new_email.as_str()));
56 assert!(user.email_confirmation_code.is_some());
57 let code = user.email_confirmation_code.unwrap();
58 let res = client
59 .post(format!("{}/xrpc/com.atproto.server.confirmEmail", base_url))
60 .bearer_auth(&access_jwt)
61 .json(&json!({
62 "email": new_email,
63 "token": code
64 }))
65 .send()
66 .await
67 .expect("Failed to confirm email");
68 assert_eq!(res.status(), StatusCode::OK);
69 let user = sqlx::query!(
70 "SELECT email, email_pending_verification, email_confirmation_code FROM users WHERE handle = $1",
71 handle
72 )
73 .fetch_one(&pool)
74 .await
75 .expect("User not found");
76 assert_eq!(user.email, Some(new_email));
77 assert!(user.email_pending_verification.is_none());
78 assert!(user.email_confirmation_code.is_none());
79}
80#[tokio::test]
81async fn test_request_email_update_taken_email() {
82 let client = common::client();
83 let base_url = common::base_url().await;
84 let handle1 = format!("emailup_taken1_{}", uuid::Uuid::new_v4());
85 let email1 = format!("{}@example.com", handle1);
86 let _ = create_verified_account(&client, &base_url, &handle1, &email1).await;
87 let handle2 = format!("emailup_taken2_{}", uuid::Uuid::new_v4());
88 let email2 = format!("{}@example.com", handle2);
89 let access_jwt2 = create_verified_account(&client, &base_url, &handle2, &email2).await;
90 let res = client
91 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url))
92 .bearer_auth(&access_jwt2)
93 .json(&json!({"email": email1}))
94 .send()
95 .await
96 .expect("Failed to request email update");
97 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
98 let body: Value = res.json().await.expect("Invalid JSON");
99 assert_eq!(body["error"], "EmailTaken");
100}
101#[tokio::test]
102async fn test_confirm_email_invalid_token() {
103 let client = common::client();
104 let base_url = common::base_url().await;
105 let handle = format!("emailup_inv_{}", uuid::Uuid::new_v4());
106 let email = format!("{}@example.com", handle);
107 let access_jwt = create_verified_account(&client, &base_url, &handle, &email).await;
108 let new_email = format!("new_{}@example.com", handle);
109 let res = client
110 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url))
111 .bearer_auth(&access_jwt)
112 .json(&json!({"email": new_email}))
113 .send()
114 .await
115 .expect("Failed to request email update");
116 assert_eq!(res.status(), StatusCode::OK);
117 let res = client
118 .post(format!("{}/xrpc/com.atproto.server.confirmEmail", base_url))
119 .bearer_auth(&access_jwt)
120 .json(&json!({
121 "email": new_email,
122 "token": "wrong-token"
123 }))
124 .send()
125 .await
126 .expect("Failed to confirm email");
127 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
128 let body: Value = res.json().await.expect("Invalid JSON");
129 assert_eq!(body["error"], "InvalidToken");
130}
131#[tokio::test]
132async fn test_confirm_email_wrong_email() {
133 let client = common::client();
134 let base_url = common::base_url().await;
135 let pool = get_pool().await;
136 let handle = format!("emailup_wrong_{}", uuid::Uuid::new_v4());
137 let email = format!("{}@example.com", handle);
138 let access_jwt = create_verified_account(&client, &base_url, &handle, &email).await;
139 let new_email = format!("new_{}@example.com", handle);
140 let res = client
141 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url))
142 .bearer_auth(&access_jwt)
143 .json(&json!({"email": new_email}))
144 .send()
145 .await
146 .expect("Failed to request email update");
147 assert_eq!(res.status(), StatusCode::OK);
148 let user = sqlx::query!("SELECT email_confirmation_code FROM users WHERE handle = $1", handle)
149 .fetch_one(&pool)
150 .await
151 .expect("User not found");
152 let code = user.email_confirmation_code.unwrap();
153 let res = client
154 .post(format!("{}/xrpc/com.atproto.server.confirmEmail", base_url))
155 .bearer_auth(&access_jwt)
156 .json(&json!({
157 "email": "another_random@example.com",
158 "token": code
159 }))
160 .send()
161 .await
162 .expect("Failed to confirm email");
163 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
164 let body: Value = res.json().await.expect("Invalid JSON");
165 assert_eq!(body["message"], "Email does not match pending update");
166}
167#[tokio::test]
168async fn test_update_email_success_no_token_required() {
169 let client = common::client();
170 let base_url = common::base_url().await;
171 let pool = get_pool().await;
172 let handle = format!("emailup_direct_{}", uuid::Uuid::new_v4());
173 let email = format!("{}@example.com", handle);
174 let access_jwt = create_verified_account(&client, &base_url, &handle, &email).await;
175 let new_email = format!("direct_{}@example.com", handle);
176 let res = client
177 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url))
178 .bearer_auth(&access_jwt)
179 .json(&json!({ "email": new_email }))
180 .send()
181 .await
182 .expect("Failed to update email");
183 assert_eq!(res.status(), StatusCode::OK);
184 let user = sqlx::query!("SELECT email FROM users WHERE handle = $1", handle)
185 .fetch_one(&pool)
186 .await
187 .expect("User not found");
188 assert_eq!(user.email, Some(new_email));
189}
190#[tokio::test]
191async fn test_update_email_same_email_noop() {
192 let client = common::client();
193 let base_url = common::base_url().await;
194 let handle = format!("emailup_same_{}", uuid::Uuid::new_v4());
195 let email = format!("{}@example.com", handle);
196 let access_jwt = create_verified_account(&client, &base_url, &handle, &email).await;
197 let res = client
198 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url))
199 .bearer_auth(&access_jwt)
200 .json(&json!({ "email": email }))
201 .send()
202 .await
203 .expect("Failed to update email");
204 assert_eq!(res.status(), StatusCode::OK, "Updating to same email should succeed as no-op");
205}
206#[tokio::test]
207async fn test_update_email_requires_token_after_pending() {
208 let client = common::client();
209 let base_url = common::base_url().await;
210 let handle = format!("emailup_token_{}", 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!("pending_{}@example.com", handle);
214 let res = client
215 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url))
216 .bearer_auth(&access_jwt)
217 .json(&json!({"email": new_email}))
218 .send()
219 .await
220 .expect("Failed to request email update");
221 assert_eq!(res.status(), StatusCode::OK);
222 let res = client
223 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url))
224 .bearer_auth(&access_jwt)
225 .json(&json!({ "email": new_email }))
226 .send()
227 .await
228 .expect("Failed to attempt email update");
229 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
230 let body: Value = res.json().await.expect("Invalid JSON");
231 assert_eq!(body["error"], "TokenRequired");
232}
233#[tokio::test]
234async fn test_update_email_with_valid_token() {
235 let client = common::client();
236 let base_url = common::base_url().await;
237 let pool = get_pool().await;
238 let handle = format!("emailup_valid_{}", uuid::Uuid::new_v4());
239 let email = format!("{}@example.com", handle);
240 let access_jwt = create_verified_account(&client, &base_url, &handle, &email).await;
241 let new_email = format!("valid_{}@example.com", handle);
242 let res = client
243 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url))
244 .bearer_auth(&access_jwt)
245 .json(&json!({"email": new_email}))
246 .send()
247 .await
248 .expect("Failed to request email update");
249 assert_eq!(res.status(), StatusCode::OK);
250 let user = sqlx::query!(
251 "SELECT email_confirmation_code FROM users WHERE handle = $1",
252 handle
253 )
254 .fetch_one(&pool)
255 .await
256 .expect("User not found");
257 let code = user.email_confirmation_code.unwrap();
258 let res = client
259 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url))
260 .bearer_auth(&access_jwt)
261 .json(&json!({
262 "email": new_email,
263 "token": code
264 }))
265 .send()
266 .await
267 .expect("Failed to update email");
268 assert_eq!(res.status(), StatusCode::OK);
269 let user = sqlx::query!("SELECT email, email_pending_verification FROM users WHERE handle = $1", handle)
270 .fetch_one(&pool)
271 .await
272 .expect("User not found");
273 assert_eq!(user.email, Some(new_email));
274 assert!(user.email_pending_verification.is_none());
275}
276#[tokio::test]
277async fn test_update_email_invalid_token() {
278 let client = common::client();
279 let base_url = common::base_url().await;
280 let handle = format!("emailup_badtok_{}", uuid::Uuid::new_v4());
281 let email = format!("{}@example.com", handle);
282 let access_jwt = create_verified_account(&client, &base_url, &handle, &email).await;
283 let new_email = format!("badtok_{}@example.com", handle);
284 let res = client
285 .post(format!("{}/xrpc/com.atproto.server.requestEmailUpdate", base_url))
286 .bearer_auth(&access_jwt)
287 .json(&json!({"email": new_email}))
288 .send()
289 .await
290 .expect("Failed to request email update");
291 assert_eq!(res.status(), StatusCode::OK);
292 let res = client
293 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url))
294 .bearer_auth(&access_jwt)
295 .json(&json!({
296 "email": new_email,
297 "token": "wrong-token-12345"
298 }))
299 .send()
300 .await
301 .expect("Failed to attempt email update");
302 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
303 let body: Value = res.json().await.expect("Invalid JSON");
304 assert_eq!(body["error"], "InvalidToken");
305}
306#[tokio::test]
307async fn test_update_email_already_taken() {
308 let client = common::client();
309 let base_url = common::base_url().await;
310 let handle1 = format!("emailup_dup1_{}", uuid::Uuid::new_v4());
311 let email1 = format!("{}@example.com", handle1);
312 let _ = create_verified_account(&client, &base_url, &handle1, &email1).await;
313 let handle2 = format!("emailup_dup2_{}", uuid::Uuid::new_v4());
314 let email2 = format!("{}@example.com", handle2);
315 let access_jwt2 = create_verified_account(&client, &base_url, &handle2, &email2).await;
316 let res = client
317 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url))
318 .bearer_auth(&access_jwt2)
319 .json(&json!({ "email": email1 }))
320 .send()
321 .await
322 .expect("Failed to attempt email update");
323 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
324 let body: Value = res.json().await.expect("Invalid JSON");
325 assert!(body["message"].as_str().unwrap().contains("already in use") || body["error"] == "InvalidRequest");
326}
327#[tokio::test]
328async fn test_update_email_no_auth() {
329 let client = common::client();
330 let base_url = common::base_url().await;
331 let res = client
332 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url))
333 .json(&json!({ "email": "test@example.com" }))
334 .send()
335 .await
336 .expect("Failed to send request");
337 assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
338 let body: Value = res.json().await.expect("Invalid JSON");
339 assert_eq!(body["error"], "AuthenticationRequired");
340}
341#[tokio::test]
342async fn test_update_email_invalid_format() {
343 let client = common::client();
344 let base_url = common::base_url().await;
345 let handle = format!("emailup_fmt_{}", 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 res = client
349 .post(format!("{}/xrpc/com.atproto.server.updateEmail", base_url))
350 .bearer_auth(&access_jwt)
351 .json(&json!({ "email": "not-an-email" }))
352 .send()
353 .await
354 .expect("Failed to send request");
355 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
356 let body: Value = res.json().await.expect("Invalid JSON");
357 assert_eq!(body["error"], "InvalidEmail");
358}