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