mirror of
https://tangled.org/tranquil.farm/tranquil-pds
synced 2026-02-12 23:21:08 +00:00
268 lines
8.5 KiB
Rust
268 lines
8.5 KiB
Rust
mod common;
|
|
mod helpers;
|
|
use common::*;
|
|
use helpers::*;
|
|
use reqwest::StatusCode;
|
|
use serde_json::{Value, json};
|
|
|
|
#[tokio::test]
|
|
async fn test_moderation_report_lifecycle() {
|
|
let client = client();
|
|
let (alice_did, alice_jwt) = setup_new_user("alice-report").await;
|
|
let (bob_did, bob_jwt) = setup_new_user("bob-report").await;
|
|
let (post_uri, post_cid) =
|
|
create_post(&client, &bob_did, &bob_jwt, "This is a reportable post").await;
|
|
let report_payload = json!({
|
|
"reasonType": "com.atproto.moderation.defs#reasonSpam",
|
|
"reason": "This looks like spam to me",
|
|
"subject": {
|
|
"$type": "com.atproto.repo.strongRef",
|
|
"uri": post_uri,
|
|
"cid": post_cid
|
|
}
|
|
});
|
|
let report_res = client
|
|
.post(format!(
|
|
"{}/xrpc/com.atproto.moderation.createReport",
|
|
base_url().await
|
|
))
|
|
.bearer_auth(&alice_jwt)
|
|
.json(&report_payload)
|
|
.send()
|
|
.await
|
|
.expect("Failed to create report");
|
|
assert_eq!(report_res.status(), StatusCode::OK);
|
|
let report_body: Value = report_res.json().await.unwrap();
|
|
assert!(report_body["id"].is_number(), "Report should have an ID");
|
|
assert_eq!(
|
|
report_body["reasonType"],
|
|
"com.atproto.moderation.defs#reasonSpam"
|
|
);
|
|
assert_eq!(report_body["reportedBy"], alice_did);
|
|
let account_report_payload = json!({
|
|
"reasonType": "com.atproto.moderation.defs#reasonOther",
|
|
"reason": "Suspicious account activity",
|
|
"subject": {
|
|
"$type": "com.atproto.admin.defs#repoRef",
|
|
"did": bob_did
|
|
}
|
|
});
|
|
let account_report_res = client
|
|
.post(format!(
|
|
"{}/xrpc/com.atproto.moderation.createReport",
|
|
base_url().await
|
|
))
|
|
.bearer_auth(&alice_jwt)
|
|
.json(&account_report_payload)
|
|
.send()
|
|
.await
|
|
.expect("Failed to create account report");
|
|
assert_eq!(account_report_res.status(), StatusCode::OK);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_moderation_report_invalid_reason_type() {
|
|
let client = client();
|
|
let (alice_did, alice_jwt) = setup_new_user("alice-invalid-reason").await;
|
|
let report_payload = json!({
|
|
"reasonType": "invalid.reason.type",
|
|
"reason": "Testing invalid reason",
|
|
"subject": {
|
|
"$type": "com.atproto.admin.defs#repoRef",
|
|
"did": alice_did
|
|
}
|
|
});
|
|
let res = client
|
|
.post(format!(
|
|
"{}/xrpc/com.atproto.moderation.createReport",
|
|
base_url().await
|
|
))
|
|
.bearer_auth(&alice_jwt)
|
|
.json(&report_payload)
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
assert_eq!(res.status(), StatusCode::BAD_REQUEST);
|
|
let body: Value = res.json().await.unwrap();
|
|
assert_eq!(body["error"], "InvalidRequest");
|
|
assert!(body["message"].as_str().unwrap().contains("reasonType"));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_moderation_report_unauthenticated() {
|
|
let client = client();
|
|
let report_payload = json!({
|
|
"reasonType": "com.atproto.moderation.defs#reasonSpam",
|
|
"reason": "Spam report",
|
|
"subject": {
|
|
"$type": "com.atproto.admin.defs#repoRef",
|
|
"did": "did:plc:test"
|
|
}
|
|
});
|
|
let res = client
|
|
.post(format!(
|
|
"{}/xrpc/com.atproto.moderation.createReport",
|
|
base_url().await
|
|
))
|
|
.json(&report_payload)
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
assert_eq!(res.status(), StatusCode::UNAUTHORIZED);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_moderation_report_all_reason_types() {
|
|
let client = client();
|
|
let (alice_did, alice_jwt) = setup_new_user("alice-all-reasons").await;
|
|
let (bob_did, _) = setup_new_user("bob-all-reasons").await;
|
|
let reason_types = [
|
|
"com.atproto.moderation.defs#reasonSpam",
|
|
"com.atproto.moderation.defs#reasonViolation",
|
|
"com.atproto.moderation.defs#reasonMisleading",
|
|
"com.atproto.moderation.defs#reasonSexual",
|
|
"com.atproto.moderation.defs#reasonRude",
|
|
"com.atproto.moderation.defs#reasonOther",
|
|
"com.atproto.moderation.defs#reasonAppeal",
|
|
];
|
|
for reason_type in reason_types {
|
|
let report_payload = json!({
|
|
"reasonType": reason_type,
|
|
"subject": {
|
|
"$type": "com.atproto.admin.defs#repoRef",
|
|
"did": bob_did
|
|
}
|
|
});
|
|
let res = client
|
|
.post(format!(
|
|
"{}/xrpc/com.atproto.moderation.createReport",
|
|
base_url().await
|
|
))
|
|
.bearer_auth(&alice_jwt)
|
|
.json(&report_payload)
|
|
.send()
|
|
.await
|
|
.expect("Failed to send request");
|
|
assert_eq!(
|
|
res.status(),
|
|
StatusCode::OK,
|
|
"Failed for reason type: {}",
|
|
reason_type
|
|
);
|
|
let body: Value = res.json().await.unwrap();
|
|
assert_eq!(body["reasonType"], reason_type);
|
|
assert_eq!(body["reportedBy"], alice_did);
|
|
}
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_moderation_report_takendown_user_can_appeal() {
|
|
let client = client();
|
|
let (admin_jwt, _) = create_admin_account_and_login(&client).await;
|
|
let (target_jwt, target_did) = create_account_and_login(&client).await;
|
|
let takedown_payload = json!({
|
|
"subject": {
|
|
"$type": "com.atproto.admin.defs#repoRef",
|
|
"did": target_did
|
|
},
|
|
"takedown": {
|
|
"applied": true,
|
|
"ref": "mod-action-test"
|
|
}
|
|
});
|
|
let takedown_res = client
|
|
.post(format!(
|
|
"{}/xrpc/com.atproto.admin.updateSubjectStatus",
|
|
base_url().await
|
|
))
|
|
.bearer_auth(&admin_jwt)
|
|
.json(&takedown_payload)
|
|
.send()
|
|
.await
|
|
.expect("Failed to takedown");
|
|
assert_eq!(takedown_res.status(), StatusCode::OK);
|
|
let appeal_payload = json!({
|
|
"reasonType": "com.atproto.moderation.defs#reasonAppeal",
|
|
"reason": "I believe this takedown was a mistake",
|
|
"subject": {
|
|
"$type": "com.atproto.admin.defs#repoRef",
|
|
"did": target_did
|
|
}
|
|
});
|
|
let appeal_res = client
|
|
.post(format!(
|
|
"{}/xrpc/com.atproto.moderation.createReport",
|
|
base_url().await
|
|
))
|
|
.bearer_auth(&target_jwt)
|
|
.json(&appeal_payload)
|
|
.send()
|
|
.await
|
|
.expect("Failed to send appeal");
|
|
assert_eq!(
|
|
appeal_res.status(),
|
|
StatusCode::OK,
|
|
"Takendown user should be able to file appeal reports"
|
|
);
|
|
let appeal_body: Value = appeal_res.json().await.unwrap();
|
|
assert_eq!(
|
|
appeal_body["reasonType"],
|
|
"com.atproto.moderation.defs#reasonAppeal"
|
|
);
|
|
assert_eq!(appeal_body["reportedBy"], target_did);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_moderation_report_takendown_user_cannot_file_non_appeal() {
|
|
let client = client();
|
|
let (admin_jwt, _) = create_admin_account_and_login(&client).await;
|
|
let (target_jwt, target_did) = create_account_and_login(&client).await;
|
|
let takedown_payload = json!({
|
|
"subject": {
|
|
"$type": "com.atproto.admin.defs#repoRef",
|
|
"did": target_did
|
|
},
|
|
"takedown": {
|
|
"applied": true,
|
|
"ref": "mod-action-test-non-appeal"
|
|
}
|
|
});
|
|
let takedown_res = client
|
|
.post(format!(
|
|
"{}/xrpc/com.atproto.admin.updateSubjectStatus",
|
|
base_url().await
|
|
))
|
|
.bearer_auth(&admin_jwt)
|
|
.json(&takedown_payload)
|
|
.send()
|
|
.await
|
|
.expect("Failed to takedown");
|
|
assert_eq!(takedown_res.status(), StatusCode::OK);
|
|
let report_payload = json!({
|
|
"reasonType": "com.atproto.moderation.defs#reasonSpam",
|
|
"reason": "Trying to report spam",
|
|
"subject": {
|
|
"$type": "com.atproto.admin.defs#repoRef",
|
|
"did": "did:plc:test"
|
|
}
|
|
});
|
|
let report_res = client
|
|
.post(format!(
|
|
"{}/xrpc/com.atproto.moderation.createReport",
|
|
base_url().await
|
|
))
|
|
.bearer_auth(&target_jwt)
|
|
.json(&report_payload)
|
|
.send()
|
|
.await
|
|
.expect("Failed to send report");
|
|
assert_eq!(
|
|
report_res.status(),
|
|
StatusCode::BAD_REQUEST,
|
|
"Takendown user should not be able to file non-appeal reports"
|
|
);
|
|
let body: Value = report_res.json().await.unwrap();
|
|
assert_eq!(body["error"], "InvalidRequest");
|
|
assert!(body["message"].as_str().unwrap().contains("takendown"));
|
|
}
|