#15 @context security vocab: actor JSON now uses actor_ap_context() which includes W3C security vocab + Mastodon toot extensions (manuallyApprovesFollowers, discoverable, featured). Applied to actor_handler, actor_json(), broadcast_actor_update(). Activity JSON keeps plain AS context (no security vocab needed). #17 HTTP Digest (documented, no code change): production mode (debug=false) REQUIRES Digest header on inbound POSTs via require_digest() in the non-compat normalization config. Added doc comment to ApFederationConfig::new() to clarify. #26 Integration tests: 3 new tokio tests in src/tests/integration.rs using in-memory trait stubs. Tests cover: - check_guards idempotency (duplicate activity rejected) - check_guards domain block (blocked domain skipped) - extract_and_dispatch_mentions (on_mention called for local actor)
52 lines
1.8 KiB
Rust
52 lines
1.8 KiB
Rust
use url::Url;
|
|
|
|
use crate::error::Error;
|
|
|
|
pub const AS_PUBLIC: &str = "https://www.w3.org/ns/activitystreams#Public";
|
|
pub const AP_CONTEXT: &str = "https://www.w3.org/ns/activitystreams";
|
|
pub const AP_PAGE_SIZE: usize = 20;
|
|
|
|
/// Returns the `@context` array for actor AP JSON.
|
|
/// Includes the W3C security vocabulary (needed for `publicKey` resolution)
|
|
/// and common Mastodon/Toot extensions (`discoverable`, `featured`, etc.).
|
|
/// Activities use `WithContext::new_default` (plain AS context) — only actor
|
|
/// JSON needs the security vocab.
|
|
pub fn actor_ap_context() -> serde_json::Value {
|
|
serde_json::json!([
|
|
"https://www.w3.org/ns/activitystreams",
|
|
"https://w3id.org/security/v1",
|
|
{
|
|
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
|
|
"toot": "http://joinmastodon.org/ns#",
|
|
"discoverable": "toot:discoverable",
|
|
"featured": {"@id": "toot:featured", "@type": "@id"}
|
|
}
|
|
])
|
|
}
|
|
|
|
pub fn extract_user_id_from_url(url: &Url) -> Option<uuid::Uuid> {
|
|
let path = url.path();
|
|
path.strip_prefix("/users/")
|
|
.and_then(|s| s.split('/').next())
|
|
.and_then(|s| uuid::Uuid::parse_str(s).ok())
|
|
}
|
|
|
|
pub fn activity_url(base_url: &str) -> Result<Url, Error> {
|
|
Url::parse(&format!("{}/activities/{}", base_url, uuid::Uuid::new_v4()))
|
|
.map_err(|e| Error::bad_request(anyhow::anyhow!(e)))
|
|
}
|
|
|
|
pub fn actor_url(base_url: &str, user_id: uuid::Uuid) -> Url {
|
|
Url::parse(&format!("{}/users/{}", base_url, user_id))
|
|
.expect("base_url is always a valid URL prefix")
|
|
}
|
|
|
|
/// Extract the username segment from a /users/:username URL.
|
|
#[allow(dead_code)]
|
|
pub fn extract_username_from_url(url: &Url) -> Option<String> {
|
|
url.path()
|
|
.strip_prefix("/users/")
|
|
.and_then(|s| s.split('/').next())
|
|
.map(|s| s.to_string())
|
|
}
|