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