this repo has no description
1mod common;
2mod helpers;
3use reqwest::StatusCode;
4use serde_json::{json, Value};
5use sqlx::PgPool;
6use helpers::verify_new_account;
7
8async fn get_pool() -> PgPool {
9 let conn_str = common::get_db_connection_string().await;
10 sqlx::postgres::PgPoolOptions::new()
11 .max_connections(5)
12 .connect(&conn_str)
13 .await
14 .expect("Failed to connect to test database")
15}
16
17#[tokio::test]
18async fn test_reserve_signing_key_without_did() {
19 let client = common::client();
20 let base_url = common::base_url().await;
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 assert_eq!(res.status(), StatusCode::OK);
31 let body: Value = res.json().await.expect("Response was not valid JSON");
32 assert!(body["signingKey"].is_string());
33 let signing_key = body["signingKey"].as_str().unwrap();
34 assert!(
35 signing_key.starts_with("did:key:z"),
36 "Signing key should be in did:key format with multibase prefix"
37 );
38}
39
40#[tokio::test]
41async fn test_reserve_signing_key_with_did() {
42 let client = common::client();
43 let base_url = common::base_url().await;
44 let pool = get_pool().await;
45 let target_did = "did:plc:test123456";
46 let res = client
47 .post(format!(
48 "{}/xrpc/com.atproto.server.reserveSigningKey",
49 base_url
50 ))
51 .json(&json!({ "did": target_did }))
52 .send()
53 .await
54 .expect("Failed to send request");
55 assert_eq!(res.status(), StatusCode::OK);
56 let body: Value = res.json().await.expect("Response was not valid JSON");
57 let signing_key = body["signingKey"].as_str().unwrap();
58 assert!(signing_key.starts_with("did:key:z"));
59 let row = sqlx::query!(
60 "SELECT did, public_key_did_key FROM reserved_signing_keys WHERE public_key_did_key = $1",
61 signing_key
62 )
63 .fetch_one(&pool)
64 .await
65 .expect("Reserved key not found in database");
66 assert_eq!(row.did.as_deref(), Some(target_did));
67 assert_eq!(row.public_key_did_key, signing_key);
68}
69
70#[tokio::test]
71async fn test_reserve_signing_key_stores_private_key() {
72 let client = common::client();
73 let base_url = common::base_url().await;
74 let pool = get_pool().await;
75 let res = client
76 .post(format!(
77 "{}/xrpc/com.atproto.server.reserveSigningKey",
78 base_url
79 ))
80 .json(&json!({}))
81 .send()
82 .await
83 .expect("Failed to send request");
84 assert_eq!(res.status(), StatusCode::OK);
85 let body: Value = res.json().await.expect("Response was not valid JSON");
86 let signing_key = body["signingKey"].as_str().unwrap();
87 let row = sqlx::query!(
88 "SELECT private_key_bytes, expires_at, used_at FROM reserved_signing_keys WHERE public_key_did_key = $1",
89 signing_key
90 )
91 .fetch_one(&pool)
92 .await
93 .expect("Reserved key not found in database");
94 assert_eq!(row.private_key_bytes.len(), 32, "Private key should be 32 bytes for secp256k1");
95 assert!(row.used_at.is_none(), "Reserved key should not be marked as used yet");
96 assert!(row.expires_at > chrono::Utc::now(), "Key should expire in the future");
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 = get_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!("reserved_key_user_{}", uuid::Uuid::new_v4());
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": "password",
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!("bad_key_user_{}", uuid::Uuid::new_v4());
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": "password",
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!("reuse_key_user1_{}", uuid::Uuid::new_v4());
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": "password",
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!("reuse_key_user2_{}", uuid::Uuid::new_v4());
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": "password",
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"]
276 .as_str()
277 .unwrap()
278 .contains("already used"));
279}
280
281#[tokio::test]
282async fn test_reserved_key_tokens_work() {
283 let client = common::client();
284 let base_url = common::base_url().await;
285 let res = client
286 .post(format!(
287 "{}/xrpc/com.atproto.server.reserveSigningKey",
288 base_url
289 ))
290 .json(&json!({}))
291 .send()
292 .await
293 .expect("Failed to reserve signing key");
294 assert_eq!(res.status(), StatusCode::OK);
295 let body: Value = res.json().await.unwrap();
296 let signing_key = body["signingKey"].as_str().unwrap();
297 let handle = format!("token_test_user_{}", uuid::Uuid::new_v4());
298 let res = client
299 .post(format!(
300 "{}/xrpc/com.atproto.server.createAccount",
301 base_url
302 ))
303 .json(&json!({
304 "handle": handle,
305 "email": format!("{}@example.com", handle),
306 "password": "password",
307 "signingKey": signing_key
308 }))
309 .send()
310 .await
311 .expect("Failed to create account");
312 assert_eq!(res.status(), StatusCode::OK);
313 let body: Value = res.json().await.unwrap();
314 let did = body["did"].as_str().unwrap();
315 let access_jwt = verify_new_account(&client, did).await;
316 let res = client
317 .get(format!(
318 "{}/xrpc/com.atproto.server.getSession",
319 base_url
320 ))
321 .bearer_auth(&access_jwt)
322 .send()
323 .await
324 .expect("Failed to get session");
325 assert_eq!(res.status(), StatusCode::OK);
326 let body: Value = res.json().await.unwrap();
327 assert_eq!(body["handle"], handle);
328}