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(¶ms)
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(¶ms)
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!(res.status(), StatusCode::OK);
147 let doc: Value = res.json().await.expect("DID doc was not JSON");
148 assert_eq!(doc["id"], did);
149 assert_eq!(doc["alsoKnownAs"][0], format!("at://{}", handle));
150 assert_eq!(doc["verificationMethod"][0]["controller"], did);
151 assert!(doc["verificationMethod"][0]["publicKeyJwk"].is_object());
152}
153
154#[tokio::test]
155async fn test_create_account_duplicate_handle() {
156 let client = client();
157 let handle = format!("dupe_{}", uuid::Uuid::new_v4());
158 let email = format!("{}@example.com", handle);
159 let payload = json!({
160 "handle": handle,
161 "email": email,
162 "password": "password"
163 });
164 let res = client
165 .post(format!(
166 "{}/xrpc/com.atproto.server.createAccount",
167 base_url().await
168 ))
169 .json(&payload)
170 .send()
171 .await
172 .expect("Failed to send request");
173 assert_eq!(res.status(), StatusCode::OK);
174 let res = client
175 .post(format!(
176 "{}/xrpc/com.atproto.server.createAccount",
177 base_url().await
178 ))
179 .json(&payload)
180 .send()
181 .await
182 .expect("Failed to send request");
183 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
184 let body: Value = res.json().await.expect("Response was not JSON");
185 assert_eq!(body["error"], "HandleTaken");
186}
187
188#[tokio::test]
189async fn test_did_web_lifecycle() {
190 let client = client();
191 let mock_server = MockServer::start().await;
192 let mock_uri = mock_server.uri();
193 let mock_addr = mock_uri.trim_start_matches("http://");
194 let handle = format!("lifecycle_{}", uuid::Uuid::new_v4());
195 let did = format!("did:web:{}:u:{}", mock_addr.replace(":", "%3A"), handle);
196 let email = format!("{}@test.com", handle);
197 let pds_endpoint = base_url().await.replace("http://", "https://");
198 let did_doc = json!({
199 "@context": ["https://www.w3.org/ns/did/v1"],
200 "id": did,
201 "service": [{
202 "id": "#atproto_pds",
203 "type": "AtprotoPersonalDataServer",
204 "serviceEndpoint": pds_endpoint
205 }]
206 });
207 Mock::given(method("GET"))
208 .and(path(format!("/u/{}/did.json", handle)))
209 .respond_with(ResponseTemplate::new(200).set_body_json(did_doc))
210 .mount(&mock_server)
211 .await;
212 let create_payload = json!({
213 "handle": handle,
214 "email": email,
215 "password": "password",
216 "did": did
217 });
218 let res = client
219 .post(format!(
220 "{}/xrpc/com.atproto.server.createAccount",
221 base_url().await
222 ))
223 .json(&create_payload)
224 .send()
225 .await
226 .expect("Failed createAccount");
227 if res.status() != StatusCode::OK {
228 let body: Value = res.json().await.unwrap();
229 println!("createAccount failed: {:?}", body);
230 panic!("createAccount returned non-200");
231 }
232 assert_eq!(res.status(), StatusCode::OK);
233 let create_body: Value = res.json().await.expect("Not JSON");
234 assert_eq!(create_body["did"], did);
235 let _jwt = verify_new_account(&client, &did).await;
236 /*
237 let profile_payload = json!({
238 "repo": did,
239 "collection": "app.bsky.actor.profile",
240 "rkey": "self",
241 "record": {
242 "$type": "app.bsky.actor.profile",
243 "displayName": "DID Web User",
244 "description": "Testing lifecycle"
245 }
246 });
247 let res = client.post(format!("{}/xrpc/com.atproto.repo.putRecord", base_url().await))
248 .bearer_auth(_jwt)
249 .json(&profile_payload)
250 .send()
251 .await
252 .expect("Failed putRecord");
253 if res.status() != StatusCode::OK {
254 let body: Value = res.json().await.unwrap();
255 println!("putRecord failed: {:?}", body);
256 panic!("putRecord returned non-200");
257 }
258 assert_eq!(res.status(), StatusCode::OK);
259 let res = client.get(format!("{}/xrpc/com.atproto.repo.getRecord", base_url().await))
260 .query(&[
261 ("repo", &handle),
262 ("collection", &"app.bsky.actor.profile".to_string()),
263 ("rkey", &"self".to_string())
264 ])
265 .send()
266 .await
267 .expect("Failed getRecord");
268 if res.status() != StatusCode::OK {
269 let body: Value = res.json().await.unwrap();
270 println!("getRecord failed: {:?}", body);
271 panic!("getRecord returned non-200");
272 }
273 let record_body: Value = res.json().await.expect("Not JSON");
274 assert_eq!(record_body["value"]["displayName"], "DID Web User");
275 */
276}
277
278#[tokio::test]
279async fn test_get_recommended_did_credentials_success() {
280 let client = client();
281 let (access_jwt, _) = create_account_and_login(&client).await;
282 let res = client
283 .get(format!(
284 "{}/xrpc/com.atproto.identity.getRecommendedDidCredentials",
285 base_url().await
286 ))
287 .bearer_auth(&access_jwt)
288 .send()
289 .await
290 .expect("Failed to send request");
291 assert_eq!(res.status(), StatusCode::OK);
292 let body: Value = res.json().await.expect("Response was not valid JSON");
293 assert!(body["rotationKeys"].is_array());
294 assert!(body["alsoKnownAs"].is_array());
295 assert!(body["verificationMethods"].is_object());
296 assert!(body["services"].is_object());
297 let rotation_keys = body["rotationKeys"].as_array().unwrap();
298 assert!(!rotation_keys.is_empty());
299 assert!(rotation_keys[0].as_str().unwrap().starts_with("did:key:"));
300 let also_known_as = body["alsoKnownAs"].as_array().unwrap();
301 assert!(!also_known_as.is_empty());
302 assert!(also_known_as[0].as_str().unwrap().starts_with("at://"));
303 assert!(body["verificationMethods"]["atproto"].is_string());
304 assert_eq!(
305 body["services"]["atprotoPds"]["type"],
306 "AtprotoPersonalDataServer"
307 );
308 assert!(body["services"]["atprotoPds"]["endpoint"].is_string());
309}
310
311#[tokio::test]
312async fn test_get_recommended_did_credentials_no_auth() {
313 let client = client();
314 let res = client
315 .get(format!(
316 "{}/xrpc/com.atproto.identity.getRecommendedDidCredentials",
317 base_url().await
318 ))
319 .send()
320 .await
321 .expect("Failed to send request");
322 assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
323 let body: Value = res.json().await.expect("Response was not valid JSON");
324 assert_eq!(body["error"], "AuthenticationRequired");
325}