this repo has no description
1mod common; 2use common::*; 3use reqwest::StatusCode; 4use serde_json::{Value, json}; 5use wiremock::matchers::{method, path}; 6use wiremock::{Mock, MockServer, ResponseTemplate}; 7 8#[tokio::test] 9async fn test_resolve_handle_success() { 10 let client = client(); 11 let handle = format!("resolvetest_{}", uuid::Uuid::new_v4()); 12 let payload = json!({ 13 "handle": handle, 14 "email": format!("{}@example.com", handle), 15 "password": "password" 16 }); 17 18 let res = client 19 .post(format!( 20 "{}/xrpc/com.atproto.server.createAccount", 21 base_url().await 22 )) 23 .json(&payload) 24 .send() 25 .await 26 .expect("Failed to create account"); 27 28 assert_eq!(res.status(), StatusCode::OK); 29 let body: Value = res.json().await.expect("Invalid JSON"); 30 let did = body["did"].as_str().expect("No DID").to_string(); 31 32 let params = [("handle", handle.as_str())]; 33 let res = client 34 .get(format!( 35 "{}/xrpc/com.atproto.identity.resolveHandle", 36 base_url().await 37 )) 38 .query(&params) 39 .send() 40 .await 41 .expect("Failed to send request"); 42 43 assert_eq!(res.status(), StatusCode::OK); 44 let body: Value = res.json().await.expect("Response was not valid JSON"); 45 assert_eq!(body["did"], did); 46} 47 48#[tokio::test] 49async fn test_resolve_handle_not_found() { 50 let client = client(); 51 let params = [("handle", "nonexistent_handle_12345")]; 52 let res = client 53 .get(format!( 54 "{}/xrpc/com.atproto.identity.resolveHandle", 55 base_url().await 56 )) 57 .query(&params) 58 .send() 59 .await 60 .expect("Failed to send request"); 61 62 assert_eq!(res.status(), StatusCode::NOT_FOUND); 63 let body: Value = res.json().await.expect("Response was not valid JSON"); 64 assert_eq!(body["error"], "HandleNotFound"); 65} 66 67#[tokio::test] 68async fn test_resolve_handle_missing_param() { 69 let client = client(); 70 let res = client 71 .get(format!( 72 "{}/xrpc/com.atproto.identity.resolveHandle", 73 base_url().await 74 )) 75 .send() 76 .await 77 .expect("Failed to send request"); 78 79 assert_eq!(res.status(), StatusCode::BAD_REQUEST); 80} 81 82#[tokio::test] 83async fn test_well_known_did() { 84 let client = client(); 85 let res = client 86 .get(format!("{}/.well-known/did.json", base_url().await)) 87 .send() 88 .await 89 .expect("Failed to send request"); 90 91 assert_eq!(res.status(), StatusCode::OK); 92 let body: Value = res.json().await.expect("Response was not valid JSON"); 93 assert!(body["id"].as_str().unwrap().starts_with("did:web:")); 94 assert_eq!(body["service"][0]["type"], "AtprotoPersonalDataServer"); 95} 96 97#[tokio::test] 98async fn test_create_did_web_account_and_resolve() { 99 let client = client(); 100 101 let mock_server = MockServer::start().await; 102 let mock_uri = mock_server.uri(); 103 let mock_addr = mock_uri.trim_start_matches("http://"); 104 105 let did = format!("did:web:{}", mock_addr.replace(":", "%3A")); 106 107 let handle = format!("webuser_{}", uuid::Uuid::new_v4()); 108 109 let pds_endpoint = base_url().await.replace("http://", "https://"); 110 111 let did_doc = json!({ 112 "@context": ["https://www.w3.org/ns/did/v1"], 113 "id": did, 114 "service": [{ 115 "id": "#atproto_pds", 116 "type": "AtprotoPersonalDataServer", 117 "serviceEndpoint": pds_endpoint 118 }] 119 }); 120 121 Mock::given(method("GET")) 122 .and(path("/.well-known/did.json")) 123 .respond_with(ResponseTemplate::new(200).set_body_json(did_doc)) 124 .mount(&mock_server) 125 .await; 126 127 let payload = json!({ 128 "handle": handle, 129 "email": format!("{}@example.com", handle), 130 "password": "password", 131 "did": did 132 }); 133 134 let res = client 135 .post(format!( 136 "{}/xrpc/com.atproto.server.createAccount", 137 base_url().await 138 )) 139 .json(&payload) 140 .send() 141 .await 142 .expect("Failed to send request"); 143 144 if res.status() != StatusCode::OK { 145 let status = res.status(); 146 let body: Value = res 147 .json() 148 .await 149 .unwrap_or(json!({"error": "could not parse body"})); 150 panic!("createAccount failed with status {}: {:?}", status, body); 151 } 152 let body: Value = res 153 .json() 154 .await 155 .expect("createAccount response was not JSON"); 156 assert_eq!(body["did"], did); 157 158 let res = client 159 .get(format!("{}/u/{}/did.json", base_url().await, handle)) 160 .send() 161 .await 162 .expect("Failed to fetch DID doc"); 163 164 assert_eq!(res.status(), StatusCode::OK); 165 let doc: Value = res.json().await.expect("DID doc was not JSON"); 166 167 assert_eq!(doc["id"], did); 168 assert_eq!(doc["alsoKnownAs"][0], format!("at://{}", handle)); 169 assert_eq!(doc["verificationMethod"][0]["controller"], did); 170 assert!(doc["verificationMethod"][0]["publicKeyJwk"].is_object()); 171} 172 173#[tokio::test] 174async fn test_create_account_duplicate_handle() { 175 let client = client(); 176 let handle = format!("dupe_{}", uuid::Uuid::new_v4()); 177 let email = format!("{}@example.com", handle); 178 179 let payload = json!({ 180 "handle": handle, 181 "email": email, 182 "password": "password" 183 }); 184 185 let res = client 186 .post(format!( 187 "{}/xrpc/com.atproto.server.createAccount", 188 base_url().await 189 )) 190 .json(&payload) 191 .send() 192 .await 193 .expect("Failed to send request"); 194 assert_eq!(res.status(), StatusCode::OK); 195 196 let res = client 197 .post(format!( 198 "{}/xrpc/com.atproto.server.createAccount", 199 base_url().await 200 )) 201 .json(&payload) 202 .send() 203 .await 204 .expect("Failed to send request"); 205 206 assert_eq!(res.status(), StatusCode::BAD_REQUEST); 207 let body: Value = res.json().await.expect("Response was not JSON"); 208 assert_eq!(body["error"], "HandleTaken"); 209} 210 211#[tokio::test] 212async fn test_did_web_lifecycle() { 213 let client = client(); 214 215 let mock_server = MockServer::start().await; 216 let mock_uri = mock_server.uri(); 217 let mock_addr = mock_uri.trim_start_matches("http://"); 218 219 let handle = format!("lifecycle_{}", uuid::Uuid::new_v4()); 220 let did = format!("did:web:{}:u:{}", mock_addr.replace(":", "%3A"), handle); 221 let email = format!("{}@test.com", handle); 222 223 let pds_endpoint = base_url().await.replace("http://", "https://"); 224 225 let did_doc = json!({ 226 "@context": ["https://www.w3.org/ns/did/v1"], 227 "id": did, 228 "service": [{ 229 "id": "#atproto_pds", 230 "type": "AtprotoPersonalDataServer", 231 "serviceEndpoint": pds_endpoint 232 }] 233 }); 234 235 Mock::given(method("GET")) 236 .and(path(format!("/u/{}/did.json", handle))) 237 .respond_with(ResponseTemplate::new(200).set_body_json(did_doc)) 238 .mount(&mock_server) 239 .await; 240 241 let create_payload = json!({ 242 "handle": handle, 243 "email": email, 244 "password": "password", 245 "did": did 246 }); 247 248 let res = client 249 .post(format!( 250 "{}/xrpc/com.atproto.server.createAccount", 251 base_url().await 252 )) 253 .json(&create_payload) 254 .send() 255 .await 256 .expect("Failed createAccount"); 257 258 if res.status() != StatusCode::OK { 259 let body: Value = res.json().await.unwrap(); 260 println!("createAccount failed: {:?}", body); 261 panic!("createAccount returned non-200"); 262 } 263 assert_eq!(res.status(), StatusCode::OK); 264 let create_body: Value = res.json().await.expect("Not JSON"); 265 assert_eq!(create_body["did"], did); 266 267 let login_payload = json!({ 268 "identifier": handle, 269 "password": "password" 270 }); 271 let res = client 272 .post(format!( 273 "{}/xrpc/com.atproto.server.createSession", 274 base_url().await 275 )) 276 .json(&login_payload) 277 .send() 278 .await 279 .expect("Failed createSession"); 280 281 assert_eq!(res.status(), StatusCode::OK); 282 let session_body: Value = res.json().await.expect("Not JSON"); 283 let _jwt = session_body["accessJwt"].as_str().unwrap(); 284 285 /* 286 let profile_payload = json!({ 287 "repo": did, 288 "collection": "app.bsky.actor.profile", 289 "rkey": "self", 290 "record": { 291 "$type": "app.bsky.actor.profile", 292 "displayName": "DID Web User", 293 "description": "Testing lifecycle" 294 } 295 }); 296 297 let res = client.post(format!("{}/xrpc/com.atproto.repo.putRecord", base_url().await)) 298 .bearer_auth(_jwt) 299 .json(&profile_payload) 300 .send() 301 .await 302 .expect("Failed putRecord"); 303 304 if res.status() != StatusCode::OK { 305 let body: Value = res.json().await.unwrap(); 306 println!("putRecord failed: {:?}", body); 307 panic!("putRecord returned non-200"); 308 } 309 assert_eq!(res.status(), StatusCode::OK); 310 311 let res = client.get(format!("{}/xrpc/com.atproto.repo.getRecord", base_url().await)) 312 .query(&[ 313 ("repo", &handle), 314 ("collection", &"app.bsky.actor.profile".to_string()), 315 ("rkey", &"self".to_string()) 316 ]) 317 .send() 318 .await 319 .expect("Failed getRecord"); 320 321 if res.status() != StatusCode::OK { 322 let body: Value = res.json().await.unwrap(); 323 println!("getRecord failed: {:?}", body); 324 panic!("getRecord returned non-200"); 325 } 326 let record_body: Value = res.json().await.expect("Not JSON"); 327 assert_eq!(record_body["value"]["displayName"], "DID Web User"); 328 */ 329} 330 331#[tokio::test] 332async fn test_get_recommended_did_credentials_success() { 333 let client = client(); 334 let (access_jwt, _) = create_account_and_login(&client).await; 335 336 let res = client 337 .get(format!( 338 "{}/xrpc/com.atproto.identity.getRecommendedDidCredentials", 339 base_url().await 340 )) 341 .bearer_auth(&access_jwt) 342 .send() 343 .await 344 .expect("Failed to send request"); 345 346 assert_eq!(res.status(), StatusCode::OK); 347 let body: Value = res.json().await.expect("Response was not valid JSON"); 348 assert!(body["rotationKeys"].is_array()); 349 assert!(body["alsoKnownAs"].is_array()); 350 assert!(body["verificationMethods"].is_object()); 351 assert!(body["services"].is_object()); 352 353 let rotation_keys = body["rotationKeys"].as_array().unwrap(); 354 assert!(!rotation_keys.is_empty()); 355 assert!(rotation_keys[0].as_str().unwrap().starts_with("did:key:")); 356 357 let also_known_as = body["alsoKnownAs"].as_array().unwrap(); 358 assert!(!also_known_as.is_empty()); 359 assert!(also_known_as[0].as_str().unwrap().starts_with("at://")); 360 361 assert!(body["verificationMethods"]["atproto"].is_string()); 362 assert_eq!(body["services"]["atprotoPds"]["type"], "AtprotoPersonalDataServer"); 363 assert!(body["services"]["atprotoPds"]["endpoint"].is_string()); 364} 365 366#[tokio::test] 367async fn test_get_recommended_did_credentials_no_auth() { 368 let client = client(); 369 let res = client 370 .get(format!( 371 "{}/xrpc/com.atproto.identity.getRecommendedDidCredentials", 372 base_url().await 373 )) 374 .send() 375 .await 376 .expect("Failed to send request"); 377 378 assert_eq!(res.status(), StatusCode::UNAUTHORIZED); 379 let body: Value = res.json().await.expect("Response was not valid JSON"); 380 assert_eq!(body["error"], "AuthenticationRequired"); 381}