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