PDS software with bells & whistles you didn’t even know you needed. will move this to its own account when ready.
at main 11 kB view raw
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}