this repo has no description
1mod common;
2mod helpers;
3
4use common::*;
5use helpers::*;
6use reqwest::StatusCode;
7use serde_json::Value;
8
9#[tokio::test]
10async fn test_get_repo_takendown_returns_error() {
11 let client = client();
12 let (_, did) = create_account_and_login(&client).await;
13
14 set_account_takedown(&did, Some("test-takedown-ref")).await;
15
16 let res = client
17 .get(format!(
18 "{}/xrpc/com.atproto.sync.getRepo",
19 base_url().await
20 ))
21 .query(&[("did", did.as_str())])
22 .send()
23 .await
24 .expect("Failed to send request");
25
26 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
27 let body: Value = res.json().await.expect("Response was not valid JSON");
28 assert_eq!(body["error"], "RepoTakendown");
29}
30
31#[tokio::test]
32async fn test_get_repo_deactivated_returns_error() {
33 let client = client();
34 let (_, did) = create_account_and_login(&client).await;
35
36 set_account_deactivated(&did, true).await;
37
38 let res = client
39 .get(format!(
40 "{}/xrpc/com.atproto.sync.getRepo",
41 base_url().await
42 ))
43 .query(&[("did", did.as_str())])
44 .send()
45 .await
46 .expect("Failed to send request");
47
48 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
49 let body: Value = res.json().await.expect("Response was not valid JSON");
50 assert_eq!(body["error"], "RepoDeactivated");
51}
52
53#[tokio::test]
54async fn test_get_latest_commit_takendown_returns_error() {
55 let client = client();
56 let (_, did) = create_account_and_login(&client).await;
57
58 set_account_takedown(&did, Some("test-takedown-ref")).await;
59
60 let res = client
61 .get(format!(
62 "{}/xrpc/com.atproto.sync.getLatestCommit",
63 base_url().await
64 ))
65 .query(&[("did", did.as_str())])
66 .send()
67 .await
68 .expect("Failed to send request");
69
70 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
71 let body: Value = res.json().await.expect("Response was not valid JSON");
72 assert_eq!(body["error"], "RepoTakendown");
73}
74
75#[tokio::test]
76async fn test_get_blocks_takendown_returns_error() {
77 let client = client();
78 let (_, did) = create_account_and_login(&client).await;
79
80 let commit_res = client
81 .get(format!(
82 "{}/xrpc/com.atproto.sync.getLatestCommit",
83 base_url().await
84 ))
85 .query(&[("did", did.as_str())])
86 .send()
87 .await
88 .expect("Failed to get commit");
89 let commit_body: Value = commit_res.json().await.unwrap();
90 let cid = commit_body["cid"].as_str().unwrap();
91
92 set_account_takedown(&did, Some("test-takedown-ref")).await;
93
94 let res = client
95 .get(format!(
96 "{}/xrpc/com.atproto.sync.getBlocks",
97 base_url().await
98 ))
99 .query(&[("did", did.as_str()), ("cids", cid)])
100 .send()
101 .await
102 .expect("Failed to send request");
103
104 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
105 let body: Value = res.json().await.expect("Response was not valid JSON");
106 assert_eq!(body["error"], "RepoTakendown");
107}
108
109#[tokio::test]
110async fn test_get_repo_status_shows_takendown_status() {
111 let client = client();
112 let (_, did) = create_account_and_login(&client).await;
113
114 set_account_takedown(&did, Some("test-takedown-ref")).await;
115
116 let res = client
117 .get(format!(
118 "{}/xrpc/com.atproto.sync.getRepoStatus",
119 base_url().await
120 ))
121 .query(&[("did", did.as_str())])
122 .send()
123 .await
124 .expect("Failed to send request");
125
126 assert_eq!(res.status(), StatusCode::OK);
127 let body: Value = res.json().await.expect("Response was not valid JSON");
128 assert_eq!(body["active"], false);
129 assert_eq!(body["status"], "takendown");
130 assert!(body.get("rev").is_none() || body["rev"].is_null());
131}
132
133#[tokio::test]
134async fn test_get_repo_status_shows_deactivated_status() {
135 let client = client();
136 let (_, did) = create_account_and_login(&client).await;
137
138 set_account_deactivated(&did, true).await;
139
140 let res = client
141 .get(format!(
142 "{}/xrpc/com.atproto.sync.getRepoStatus",
143 base_url().await
144 ))
145 .query(&[("did", did.as_str())])
146 .send()
147 .await
148 .expect("Failed to send request");
149
150 assert_eq!(res.status(), StatusCode::OK);
151 let body: Value = res.json().await.expect("Response was not valid JSON");
152 assert_eq!(body["active"], false);
153 assert_eq!(body["status"], "deactivated");
154}
155
156#[tokio::test]
157async fn test_list_repos_shows_status_field() {
158 let client = client();
159 let (_, did) = create_account_and_login(&client).await;
160
161 set_account_takedown(&did, Some("test-takedown-ref")).await;
162
163 let res = client
164 .get(format!(
165 "{}/xrpc/com.atproto.sync.listRepos?limit=1000",
166 base_url().await
167 ))
168 .send()
169 .await
170 .expect("Failed to send request");
171
172 assert_eq!(res.status(), StatusCode::OK);
173 let body: Value = res.json().await.expect("Response was not valid JSON");
174 let repos = body["repos"].as_array().unwrap();
175
176 let takendown_repo = repos.iter().find(|r| r["did"] == did);
177 assert!(takendown_repo.is_some(), "Takendown repo should be in list");
178 let repo = takendown_repo.unwrap();
179 assert_eq!(repo["active"], false);
180 assert_eq!(repo["status"], "takendown");
181}
182
183#[tokio::test]
184async fn test_get_blob_takendown_returns_error() {
185 let client = client();
186 let (jwt, did) = create_account_and_login(&client).await;
187
188 let blob_res = client
189 .post(format!(
190 "{}/xrpc/com.atproto.repo.uploadBlob",
191 base_url().await
192 ))
193 .header("Content-Type", "image/png")
194 .bearer_auth(&jwt)
195 .body(vec![0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])
196 .send()
197 .await
198 .expect("Failed to upload blob");
199 let blob_body: Value = blob_res.json().await.unwrap();
200 let cid = blob_body["blob"]["ref"]["$link"].as_str().unwrap();
201
202 set_account_takedown(&did, Some("test-takedown-ref")).await;
203
204 let res = client
205 .get(format!(
206 "{}/xrpc/com.atproto.sync.getBlob",
207 base_url().await
208 ))
209 .query(&[("did", did.as_str()), ("cid", cid)])
210 .send()
211 .await
212 .expect("Failed to send request");
213
214 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
215 let body: Value = res.json().await.expect("Response was not valid JSON");
216 assert_eq!(body["error"], "RepoTakendown");
217}
218
219#[tokio::test]
220async fn test_get_blob_has_security_headers() {
221 let client = client();
222 let (jwt, did) = create_account_and_login(&client).await;
223
224 let blob_res = client
225 .post(format!(
226 "{}/xrpc/com.atproto.repo.uploadBlob",
227 base_url().await
228 ))
229 .header("Content-Type", "image/png")
230 .bearer_auth(&jwt)
231 .body(vec![0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A])
232 .send()
233 .await
234 .expect("Failed to upload blob");
235 let blob_body: Value = blob_res.json().await.unwrap();
236 let cid = blob_body["blob"]["ref"]["$link"].as_str().unwrap();
237
238 let res = client
239 .get(format!(
240 "{}/xrpc/com.atproto.sync.getBlob",
241 base_url().await
242 ))
243 .query(&[("did", did.as_str()), ("cid", cid)])
244 .send()
245 .await
246 .expect("Failed to send request");
247
248 assert_eq!(res.status(), StatusCode::OK);
249
250 let headers = res.headers();
251 assert_eq!(
252 headers
253 .get("x-content-type-options")
254 .map(|v| v.to_str().unwrap()),
255 Some("nosniff"),
256 "Missing x-content-type-options: nosniff header"
257 );
258 assert_eq!(
259 headers
260 .get("content-security-policy")
261 .map(|v| v.to_str().unwrap()),
262 Some("default-src 'none'; sandbox"),
263 "Missing content-security-policy header"
264 );
265 assert!(
266 headers.get("content-length").is_some(),
267 "Missing content-length header"
268 );
269}
270
271#[tokio::test]
272async fn test_get_blocks_missing_cids_returns_error() {
273 let client = client();
274 let (_, did) = create_account_and_login(&client).await;
275
276 let fake_cid = "bafyreif2pall7dybz7vecqka3zo24irdwabwdi4wc55jznaq75q7eaavvu";
277
278 let res = client
279 .get(format!(
280 "{}/xrpc/com.atproto.sync.getBlocks",
281 base_url().await
282 ))
283 .query(&[("did", did.as_str()), ("cids", fake_cid)])
284 .send()
285 .await
286 .expect("Failed to send request");
287
288 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
289 let body: Value = res.json().await.expect("Response was not valid JSON");
290 assert_eq!(body["error"], "InvalidRequest");
291 assert!(
292 body["message"]
293 .as_str()
294 .unwrap()
295 .contains("Could not find blocks"),
296 "Error message should mention missing blocks"
297 );
298}
299
300#[tokio::test]
301async fn test_get_blocks_accepts_array_format() {
302 let client = client();
303 let (_, did) = create_account_and_login(&client).await;
304
305 let commit_res = client
306 .get(format!(
307 "{}/xrpc/com.atproto.sync.getLatestCommit",
308 base_url().await
309 ))
310 .query(&[("did", did.as_str())])
311 .send()
312 .await
313 .expect("Failed to get commit");
314 let commit_body: Value = commit_res.json().await.unwrap();
315 let cid = commit_body["cid"].as_str().unwrap();
316
317 let url = format!(
318 "{}/xrpc/com.atproto.sync.getBlocks?did={}&cids={}&cids={}",
319 base_url().await,
320 did,
321 cid,
322 cid
323 );
324 let res = client
325 .get(&url)
326 .send()
327 .await
328 .expect("Failed to send request");
329
330 assert_eq!(res.status(), StatusCode::OK);
331 let content_type = res.headers().get("content-type").unwrap().to_str().unwrap();
332 assert!(
333 content_type.contains("application/vnd.ipld.car"),
334 "Response should be a CAR file"
335 );
336}
337
338#[tokio::test]
339async fn test_get_repo_since_returns_partial() {
340 let client = client();
341 let (jwt, did) = create_account_and_login(&client).await;
342
343 let initial_commit_res = client
344 .get(format!(
345 "{}/xrpc/com.atproto.sync.getLatestCommit",
346 base_url().await
347 ))
348 .query(&[("did", did.as_str())])
349 .send()
350 .await
351 .expect("Failed to get initial commit");
352 let initial_body: Value = initial_commit_res.json().await.unwrap();
353 let initial_rev = initial_body["rev"].as_str().unwrap();
354
355 let full_repo_res = client
356 .get(format!(
357 "{}/xrpc/com.atproto.sync.getRepo",
358 base_url().await
359 ))
360 .query(&[("did", did.as_str())])
361 .send()
362 .await
363 .expect("Failed to get full repo");
364 assert_eq!(full_repo_res.status(), StatusCode::OK);
365 let full_repo_bytes = full_repo_res.bytes().await.unwrap();
366 let full_repo_size = full_repo_bytes.len();
367
368 create_post(&client, &did, &jwt, "Test post for since param").await;
369
370 let partial_repo_res = client
371 .get(format!(
372 "{}/xrpc/com.atproto.sync.getRepo",
373 base_url().await
374 ))
375 .query(&[("did", did.as_str()), ("since", initial_rev)])
376 .send()
377 .await
378 .expect("Failed to get partial repo");
379 assert_eq!(partial_repo_res.status(), StatusCode::OK);
380 let partial_repo_bytes = partial_repo_res.bytes().await.unwrap();
381 let partial_repo_size = partial_repo_bytes.len();
382
383 assert!(
384 partial_repo_size < full_repo_size,
385 "Partial export (since={}) should be smaller than full export: {} vs {}",
386 initial_rev,
387 partial_repo_size,
388 full_repo_size
389 );
390}
391
392#[tokio::test]
393async fn test_list_blobs_takendown_returns_error() {
394 let client = client();
395 let (_, did) = create_account_and_login(&client).await;
396
397 set_account_takedown(&did, Some("test-takedown-ref")).await;
398
399 let res = client
400 .get(format!(
401 "{}/xrpc/com.atproto.sync.listBlobs",
402 base_url().await
403 ))
404 .query(&[("did", did.as_str())])
405 .send()
406 .await
407 .expect("Failed to send request");
408
409 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
410 let body: Value = res.json().await.expect("Response was not valid JSON");
411 assert_eq!(body["error"], "RepoTakendown");
412}
413
414#[tokio::test]
415async fn test_get_record_takendown_returns_error() {
416 let client = client();
417 let (jwt, did) = create_account_and_login(&client).await;
418
419 let (uri, _cid) = create_post(&client, &did, &jwt, "Test post").await;
420 let parts: Vec<&str> = uri.split('/').collect();
421 let collection = parts[parts.len() - 2];
422 let rkey = parts[parts.len() - 1];
423
424 set_account_takedown(&did, Some("test-takedown-ref")).await;
425
426 let res = client
427 .get(format!(
428 "{}/xrpc/com.atproto.sync.getRecord",
429 base_url().await
430 ))
431 .query(&[
432 ("did", did.as_str()),
433 ("collection", collection),
434 ("rkey", rkey),
435 ])
436 .send()
437 .await
438 .expect("Failed to send request");
439
440 assert_eq!(res.status(), StatusCode::BAD_REQUEST);
441 let body: Value = res.json().await.expect("Response was not valid JSON");
442 assert_eq!(body["error"], "RepoTakendown");
443}