This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

core / knot2 / crates / knot-xrpc / src / blocklist.rs
3.6 kB 118 lines
1use std::sync::Arc; 2 3use axum::body::Bytes; 4use axum::extract::State; 5use axum::response::Response; 6use http::HeaderMap; 7use serde::Deserialize; 8 9use knot_acl::{KnotAcl, can_admin_knot}; 10use knot_cob::{CobHome, CobStore}; 11use knot_cobs::{BlocklistChange, BlocklistCob, Grant, Removal}; 12use knot_git::Repo; 13use knot_index::Resolved; 14use knot_runtime::{Clock, HttpTransport}; 15use knot_types::AccountDid; 16 17use crate::cob::grant_set_apply; 18use crate::error::XrpcError; 19use crate::{XrpcState, decode, ok_empty, run_blocking}; 20 21pub(crate) const BAN_ROUTE: &str = "/xrpc/sh.tangled.knot.ban"; 22pub(crate) const UNBAN_ROUTE: &str = "/xrpc/sh.tangled.knot.unban"; 23 24#[derive(Deserialize)] 25struct SubjectInput { 26 subject: AccountDid, 27} 28 29pub(crate) async fn ban<H: HttpTransport, C: Clock>( 30 State(state): State<Arc<XrpcState<H, C>>>, 31 headers: HeaderMap, 32 method: crate::Method, 33 body: Bytes, 34) -> Result<Response, XrpcError> { 35 let actor = state.authenticate(&headers, &method).await?; 36 let acl = KnotAcl::new(&state.admins, state.admission, &state.index); 37 if !can_admin_knot(&acl, &actor).is_allowed() { 38 return Err(XrpcError::forbidden("only knot admin may ban accounts")); 39 } 40 41 let SubjectInput { subject } = decode(&body)?; 42 if state.admins.contains(&subject) { 43 return Err(XrpcError::forbidden("admin cannot be banned")); 44 } 45 if matches!(state.index.is_blocked(&subject), Resolved::Ready(true)) { 46 return Ok(ok_empty()); 47 } 48 49 let now = state.now(); 50 let grant = Grant { 51 subject, 52 added_by: actor, 53 created_at: now, 54 }; 55 let signer = state.secrets.signer(&state.knot_did)?; 56 let meta_path = state.meta_path.clone(); 57 let index = Arc::clone(&state.index); 58 let cob_locks = Arc::clone(&state.cob_locks); 59 let home = CobHome::from(&state.knot_did); 60 run_blocking(move || { 61 let _guard = cob_locks.meta(); 62 let meta = Repo::open(&meta_path)?; 63 grant_set_apply::<BlocklistCob>( 64 &CobStore::new(&meta), 65 &home, 66 BlocklistChange::Add(grant), 67 &signer, 68 now, 69 true, 70 )?; 71 index.refresh_blocklist().map_err(XrpcError::from) 72 }) 73 .await?; 74 75 Ok(ok_empty()) 76} 77 78pub(crate) async fn unban<H: HttpTransport, C: Clock>( 79 State(state): State<Arc<XrpcState<H, C>>>, 80 headers: HeaderMap, 81 method: crate::Method, 82 body: Bytes, 83) -> Result<Response, XrpcError> { 84 let actor = state.authenticate(&headers, &method).await?; 85 let acl = KnotAcl::new(&state.admins, state.admission, &state.index); 86 if !can_admin_knot(&acl, &actor).is_allowed() { 87 return Err(XrpcError::forbidden("only knot admin may unban accounts")); 88 } 89 90 let SubjectInput { subject } = decode(&body)?; 91 if matches!(state.index.is_blocked(&subject), Resolved::Ready(false)) { 92 return Ok(ok_empty()); 93 } 94 95 let now = state.now(); 96 let removal = Removal { subject }; 97 let signer = state.secrets.signer(&state.knot_did)?; 98 let meta_path = state.meta_path.clone(); 99 let index = Arc::clone(&state.index); 100 let cob_locks = Arc::clone(&state.cob_locks); 101 let home = CobHome::from(&state.knot_did); 102 run_blocking(move || { 103 let _guard = cob_locks.meta(); 104 let meta = Repo::open(&meta_path)?; 105 grant_set_apply::<BlocklistCob>( 106 &CobStore::new(&meta), 107 &home, 108 BlocklistChange::Remove(removal), 109 &signer, 110 now, 111 false, 112 )?; 113 index.refresh_blocklist().map_err(XrpcError::from) 114 }) 115 .await?; 116 117 Ok(ok_empty()) 118}