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}