Something went wrong. Try again.
A lexicon-driven AppView for ATProto.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141mod common;
use axum::body::Body;use axum::http::{Request, StatusCode};use happyview::db::now_rfc3339;use happyview::spaces::db as spaces_db;use happyview::spaces::types::*;use serde_json::json;use serial_test::serial;use tower::ServiceExt;use uuid::Uuid;
use common::app::TestApp;
const SPACE_DID: &str = "did:plc:spacehost";const SPACE_TYPE: &str = "com.example.notify";const SPACE_SKEY: &str = "main";
fn space_uri() -> String { format!("at://{SPACE_DID}/space/{SPACE_TYPE}/{SPACE_SKEY}")}
async fn enable_spaces(app: &TestApp) { let (name, value) = app.admin_cookie(); let req = Request::builder() .method("PUT") .uri("/admin/settings/feature.spaces_enabled") .header(name, value) .header("content-type", "application/json") .body(Body::from(json!({ "value": "true" }).to_string())) .unwrap(); let resp = app.router.clone().oneshot(req).await.unwrap(); assert!(resp.status().is_success(), "failed to enable spaces flag");}
async fn create_space(app: &TestApp) { let now = now_rfc3339(); let space = Space { id: Uuid::new_v4().to_string(), did: SPACE_DID.to_string(), authority_did: SPACE_DID.to_string(), creator_did: SPACE_DID.to_string(), type_nsid: SPACE_TYPE.to_string(), skey: SPACE_SKEY.to_string(), display_name: Some("Notify Space".to_string()), description: None, mint_policy: MintPolicy::MemberList, app_access: AppAccess::Open, managing_app_did: None, config: SpaceConfig::default(), revision: None, created_at: now.clone(), updated_at: now, }; spaces_db::create_space(&app.state.db, app.state.db_backend, &space) .await .expect("create_space failed");}
fn notify_write_req( auth_cookie: Option<(axum::http::HeaderName, axum::http::HeaderValue)>,) -> Request<Body> { let mut b = Request::builder() .method("POST") .uri("/xrpc/com.atproto.space.notifyWrite") .header("content-type", "application/json"); if let Some((name, value)) = auth_cookie { b = b.header(name, value); } b.body(Body::from( json!({ "space": space_uri(), "did": "did:plc:someauthor", "collection": "com.example.post", "rkey": "rk1", }) .to_string(), )) .unwrap()}
/// An unauthenticated caller must NOT be able to fire write notifications./// Before the fix this returned success (the caller was ignored entirely).#[tokio::test]#[serial]async fn notify_write_rejects_unauthenticated() { common::require_db!(); let app = TestApp::new().await; enable_spaces(&app).await; create_space(&app).await;
let resp = app .router .clone() .oneshot(notify_write_req(None)) .await .unwrap(); assert_eq!( resp.status(), StatusCode::UNAUTHORIZED, "unauthenticated notifyWrite must be rejected" );}
/// A super admin is allowed (require_space_admin accepts authority or super).#[tokio::test]#[serial]async fn notify_write_allows_super_admin() { common::require_db!(); let app = TestApp::new().await; enable_spaces(&app).await; create_space(&app).await;
let resp = app .router .clone() .oneshot(notify_write_req(Some(app.admin_cookie()))) .await .unwrap(); assert_eq!(resp.status(), StatusCode::OK);}
/// notifySpaceDeleted is likewise gated.#[tokio::test]#[serial]async fn notify_space_deleted_rejects_unauthenticated() { common::require_db!(); let app = TestApp::new().await; enable_spaces(&app).await; create_space(&app).await;
let req = Request::builder() .method("POST") .uri("/xrpc/com.atproto.space.notifySpaceDeleted") .header("content-type", "application/json") .body(Body::from(json!({ "space": space_uri() }).to_string())) .unwrap(); let resp = app.router.clone().oneshot(req).await.unwrap(); assert_eq!(resp.status(), StatusCode::UNAUTHORIZED);}