this repo has no description
1mod common;
2
3use reqwest::StatusCode;
4use serde_json::{json, Value};
5use sqlx::PgPool;
6
7async fn get_pool() -> PgPool {
8 let conn_str = common::get_db_connection_string().await;
9 sqlx::postgres::PgPoolOptions::new()
10 .max_connections(5)
11 .connect(&conn_str)
12 .await
13 .expect("Failed to connect to test database")
14}
15
16#[tokio::test]
17async fn test_reserve_signing_key_without_did() {
18 let client = common::client();
19 let base_url = common::base_url().await;
20
21 let res = client
22 .post(format!(
23 "{}/xrpc/com.atproto.server.reserveSigningKey",
24 base_url
25 ))
26 .json(&json!({}))
27 .send()
28 .await
29 .expect("Failed to send request");
30
31 assert_eq!(res.status(), StatusCode::OK);
32 let body: Value = res.json().await.expect("Response was not valid JSON");
33
34 assert!(body["signingKey"].is_string());
35 let signing_key = body["signingKey"].as_str().unwrap();
36 assert!(
37 signing_key.starts_with("did:key:z"),
38 "Signing key should be in did:key format with multibase prefix"
39 );
40}
41
42#[tokio::test]
43async fn test_reserve_signing_key_with_did() {
44 let client = common::client();
45 let base_url = common::base_url().await;
46 let pool = get_pool().await;
47
48 let target_did = "did:plc:test123456";
49 let res = client
50 .post(format!(
51 "{}/xrpc/com.atproto.server.reserveSigningKey",
52 base_url
53 ))
54 .json(&json!({ "did": target_did }))
55 .send()
56 .await
57 .expect("Failed to send request");
58
59 assert_eq!(res.status(), StatusCode::OK);
60 let body: Value = res.json().await.expect("Response was not valid JSON");
61
62 let signing_key = body["signingKey"].as_str().unwrap();
63 assert!(signing_key.starts_with("did:key:z"));
64
65 let row = sqlx::query!(
66 "SELECT did, public_key_did_key FROM reserved_signing_keys WHERE public_key_did_key = $1",
67 signing_key
68 )
69 .fetch_one(&pool)
70 .await
71 .expect("Reserved key not found in database");
72
73 assert_eq!(row.did.as_deref(), Some(target_did));
74 assert_eq!(row.public_key_did_key, signing_key);
75}
76
77#[tokio::test]
78async fn test_reserve_signing_key_stores_private_key() {
79 let client = common::client();
80 let base_url = common::base_url().await;
81 let pool = get_pool().await;
82
83 let res = client
84 .post(format!(
85 "{}/xrpc/com.atproto.server.reserveSigningKey",
86 base_url
87 ))
88 .json(&json!({}))
89 .send()
90 .await
91 .expect("Failed to send request");
92
93 assert_eq!(res.status(), StatusCode::OK);
94 let body: Value = res.json().await.expect("Response was not valid JSON");
95 let signing_key = body["signingKey"].as_str().unwrap();
96
97 let row = sqlx::query!(
98 "SELECT private_key_bytes, expires_at, used_at FROM reserved_signing_keys WHERE public_key_did_key = $1",
99 signing_key
100 )
101 .fetch_one(&pool)
102 .await
103 .expect("Reserved key not found in database");
104
105 assert_eq!(row.private_key_bytes.len(), 32, "Private key should be 32 bytes for secp256k1");
106 assert!(row.used_at.is_none(), "Reserved key should not be marked as used yet");
107 assert!(row.expires_at > chrono::Utc::now(), "Key should expire in the future");
108}
109
110#[tokio::test]
111async fn test_reserve_signing_key_unique_keys() {
112 let client = common::client();
113 let base_url = common::base_url().await;
114
115 let res1 = client
116 .post(format!(
117 "{}/xrpc/com.atproto.server.reserveSigningKey",
118 base_url
119 ))
120 .json(&json!({}))
121 .send()
122 .await
123 .expect("Failed to send request 1");
124 assert_eq!(res1.status(), StatusCode::OK);
125 let body1: Value = res1.json().await.unwrap();
126 let key1 = body1["signingKey"].as_str().unwrap();
127
128 let res2 = client
129 .post(format!(
130 "{}/xrpc/com.atproto.server.reserveSigningKey",
131 base_url
132 ))
133 .json(&json!({}))
134 .send()
135 .await
136 .expect("Failed to send request 2");
137 assert_eq!(res2.status(), StatusCode::OK);
138 let body2: Value = res2.json().await.unwrap();
139 let key2 = body2["signingKey"].as_str().unwrap();
140
141 assert_ne!(key1, key2, "Each call should generate a unique signing key");
142}
143
144#[tokio::test]
145async fn test_reserve_signing_key_is_public() {
146 let client = common::client();
147 let base_url = common::base_url().await;
148
149 let res = client
150 .post(format!(
151 "{}/xrpc/com.atproto.server.reserveSigningKey",
152 base_url
153 ))
154 .json(&json!({}))
155 .send()
156 .await
157 .expect("Failed to send request");
158
159 assert_eq!(
160 res.status(),
161 StatusCode::OK,
162 "reserveSigningKey should work without authentication"
163 );
164}
165
166#[tokio::test]
167async fn test_create_account_with_reserved_signing_key() {
168 let client = common::client();
169 let base_url = common::base_url().await;
170 let pool = get_pool().await;
171
172 let res = client
173 .post(format!(
174 "{}/xrpc/com.atproto.server.reserveSigningKey",
175 base_url
176 ))
177 .json(&json!({}))
178 .send()
179 .await
180 .expect("Failed to reserve signing key");
181 assert_eq!(res.status(), StatusCode::OK);
182 let body: Value = res.json().await.unwrap();
183 let signing_key = body["signingKey"].as_str().unwrap();
184
185 let handle = format!("reserved_key_user_{}", uuid::Uuid::new_v4());
186 let res = client
187 .post(format!(
188 "{}/xrpc/com.atproto.server.createAccount",
189 base_url
190 ))
191 .json(&json!({
192 "handle": handle,
193 "email": format!("{}@example.com", handle),
194 "password": "password",
195 "signingKey": signing_key
196 }))
197 .send()
198 .await
199 .expect("Failed to create account");
200
201 assert_eq!(res.status(), StatusCode::OK);
202 let body: Value = res.json().await.unwrap();
203 assert!(body["accessJwt"].is_string());
204 assert!(body["did"].is_string());
205
206 let reserved = sqlx::query!(
207 "SELECT used_at FROM reserved_signing_keys WHERE public_key_did_key = $1",
208 signing_key
209 )
210 .fetch_one(&pool)
211 .await
212 .expect("Reserved key not found");
213 assert!(
214 reserved.used_at.is_some(),
215 "Reserved key should be marked as used"
216 );
217}
218
219#[tokio::test]
220async fn test_create_account_with_invalid_signing_key() {
221 let client = common::client();
222 let base_url = common::base_url().await;
223
224 let handle = format!("bad_key_user_{}", uuid::Uuid::new_v4());
225 let res = client
226 .post(format!(
227 "{}/xrpc/com.atproto.server.createAccount",
228 base_url
229 ))
230 .json(&json!({
231 "handle": handle,
232 "email": format!("{}@example.com", handle),
233 "password": "password",
234 "signingKey": "did:key:zNonExistentKey12345"
235 }))
236 .send()
237 .await
238 .expect("Failed to send request");
239
240 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
241 let body: Value = res.json().await.unwrap();
242 assert_eq!(body["error"], "InvalidSigningKey");
243}
244
245#[tokio::test]
246async fn test_create_account_cannot_reuse_signing_key() {
247 let client = common::client();
248 let base_url = common::base_url().await;
249
250 let res = client
251 .post(format!(
252 "{}/xrpc/com.atproto.server.reserveSigningKey",
253 base_url
254 ))
255 .json(&json!({}))
256 .send()
257 .await
258 .expect("Failed to reserve signing key");
259 assert_eq!(res.status(), StatusCode::OK);
260 let body: Value = res.json().await.unwrap();
261 let signing_key = body["signingKey"].as_str().unwrap();
262
263 let handle1 = format!("reuse_key_user1_{}", uuid::Uuid::new_v4());
264 let res = client
265 .post(format!(
266 "{}/xrpc/com.atproto.server.createAccount",
267 base_url
268 ))
269 .json(&json!({
270 "handle": handle1,
271 "email": format!("{}@example.com", handle1),
272 "password": "password",
273 "signingKey": signing_key
274 }))
275 .send()
276 .await
277 .expect("Failed to create first account");
278 assert_eq!(res.status(), StatusCode::OK);
279
280 let handle2 = format!("reuse_key_user2_{}", uuid::Uuid::new_v4());
281 let res = client
282 .post(format!(
283 "{}/xrpc/com.atproto.server.createAccount",
284 base_url
285 ))
286 .json(&json!({
287 "handle": handle2,
288 "email": format!("{}@example.com", handle2),
289 "password": "password",
290 "signingKey": signing_key
291 }))
292 .send()
293 .await
294 .expect("Failed to send second request");
295
296 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
297 let body: Value = res.json().await.unwrap();
298 assert_eq!(body["error"], "InvalidSigningKey");
299 assert!(body["message"]
300 .as_str()
301 .unwrap()
302 .contains("already used"));
303}
304
305#[tokio::test]
306async fn test_reserved_key_tokens_work() {
307 let client = common::client();
308 let base_url = common::base_url().await;
309
310 let res = client
311 .post(format!(
312 "{}/xrpc/com.atproto.server.reserveSigningKey",
313 base_url
314 ))
315 .json(&json!({}))
316 .send()
317 .await
318 .expect("Failed to reserve signing key");
319 assert_eq!(res.status(), StatusCode::OK);
320 let body: Value = res.json().await.unwrap();
321 let signing_key = body["signingKey"].as_str().unwrap();
322
323 let handle = format!("token_test_user_{}", uuid::Uuid::new_v4());
324 let res = client
325 .post(format!(
326 "{}/xrpc/com.atproto.server.createAccount",
327 base_url
328 ))
329 .json(&json!({
330 "handle": handle,
331 "email": format!("{}@example.com", handle),
332 "password": "password",
333 "signingKey": signing_key
334 }))
335 .send()
336 .await
337 .expect("Failed to create account");
338 assert_eq!(res.status(), StatusCode::OK);
339 let body: Value = res.json().await.unwrap();
340 let access_jwt = body["accessJwt"].as_str().unwrap();
341
342 let res = client
343 .get(format!(
344 "{}/xrpc/com.atproto.server.getSession",
345 base_url
346 ))
347 .bearer_auth(access_jwt)
348 .send()
349 .await
350 .expect("Failed to get session");
351
352 assert_eq!(res.status(), StatusCode::OK);
353 let body: Value = res.json().await.unwrap();
354 assert_eq!(body["handle"], handle);
355}