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