Skip to main content

ojak/federation/
mod.rs

1//! Serving: what Ojak answers when another server, or a person, sends a
2//! GET.
3//!
4//! An application builds one [`Federation`] at start-up, registering a
5//! dispatcher for each kind of actor, object and collection it serves, each
6//! with the URI template that both routes requests to it and builds its URIs.
7//! WebFinger and host-meta follow from the actors, and NodeInfo from one more
8//! dispatcher. *docs/guide/serving.md* explains it.
9//!
10//! [`Federation::handle`] answers a request in `http` types, so that it works
11//! under any server framework; *ojak-axum* adapts it to axum.
12
13mod collection;
14mod inbox;
15mod negotiate;
16mod nodeinfo;
17mod signer;
18mod webfinger;
19
20pub use crate::template::Values;
21pub use collection::{Collection, CollectionDocument, First, Page};
22pub use inbox::{
23    CollectionRef, Forward, ForwardTo, GatewayInbox, InboxWorker, InboxWorkerConfig,
24    MAX_BODY as MAX_INBOX_BODY, Received, VouchedBy,
25};
26pub use nodeinfo::{NodeInfo, Software, Usage};
27pub use signer::{KnownKey, Signing};
28
29use crate::fetch::Fetcher;
30use crate::kv::{KvError, KvStore};
31use crate::portable::{ApUri, Hashlink, Media};
32use crate::template::{Template, TemplateError};
33use chrono::{DateTime, SecondsFormat, Utc};
34use http::{HeaderName, HeaderValue, Method, StatusCode, header};
35use serde_json::{Value, json};
36use std::fmt;
37use std::future::Future;
38use std::pin::Pin;
39use std::sync::Arc;
40use std::time::Duration;
41use url::Url;
42
43/// What a dispatcher's error is turned into: anything that is an error, a
44/// `String`, or an `anyhow::Error`.
45pub type Error = Box<dyn std::error::Error + Send + Sync>;
46
47type BoxFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
48
49/// The media type every ActivityPub document is served as.
50pub const ACTIVITY_JSON: &str = "application/activity+json";
51
52/// The `@context` a document gets when its dispatcher gave it none:
53/// ActivityStreams, with the security and Multikey vocabularies that keys
54/// are written in.
55#[must_use]
56pub fn default_context() -> Value {
57    json!([
58        "https://www.w3.org/ns/activitystreams",
59        "https://w3id.org/security/v1",
60        "https://w3id.org/security/multikey/v1",
61    ])
62}
63
64/// What a guard ([`Builder::guard`]) makes of a request.
65#[derive(Clone, Copy, Debug, PartialEq, Eq)]
66pub enum Access {
67    /// Serve it.
68    Allow,
69    /// Refuse it as unauthorized, 401: it has to be signed, or signed by
70    /// someone else.
71    Unauthorized,
72    /// Refuse it as forbidden, 403: whoever signed it is refused.
73    Forbidden,
74    /// Answer it as if nothing were there, 404.
75    NotFound,
76}
77
78/// What a dispatcher found.
79#[derive(Clone, Debug, PartialEq)]
80pub enum Found<T> {
81    Found(T),
82    /// It existed and was deleted: served as a Tombstone with 410, with when
83    /// it was deleted if that is known.
84    Gone(Option<DateTime<Utc>>),
85    NotFound,
86    /// It is served elsewhere: answered with a `302 Found` to this URL, as
87    /// Mastodon sends whoever asks for a boost to the post it boosted.
88    Redirect(Url),
89}
90
91/// An actor, as the application names it: its kind and its identifier.
92#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
93pub struct ActorRef {
94    pub kind: String,
95    pub identifier: String,
96}
97
98impl ActorRef {
99    #[must_use]
100    pub fn new(kind: impl Into<String>, identifier: impl Into<String>) -> Self {
101        Self {
102            kind: kind.into(),
103            identifier: identifier.into(),
104        }
105    }
106}
107
108/// What an IRI of ours is, from [`Context::parse_uri`].
109#[derive(Clone, Debug, Eq, PartialEq)]
110pub enum Route {
111    Actor(ActorRef),
112    Object { kind: String, values: Values },
113    Collection { kind: String, identifier: String },
114}
115
116/// A public key an actor publishes.
117#[derive(Clone, Debug, Eq, PartialEq)]
118pub enum PublicKey {
119    /// An RSA key, published as `publicKey`, which HTTP signatures verify
120    /// with. The first one an actor has is the one published.
121    Rsa { id: String, pem: String },
122    /// A key published in `assertionMethod` as a Multikey (FEP-521a), which
123    /// integrity proofs verify with.
124    Multikey { id: String, multibase: String },
125}
126
127/// Put `keys` into `actor`, a document whose `id` is set: the first RSA key
128/// as `publicKey`, and every Multikey in `assertionMethod`.
129pub fn with_keys(actor: &mut Value, keys: &[PublicKey]) {
130    let Some(members) = actor.as_object_mut() else {
131        return;
132    };
133    let id = members.get("id").cloned().unwrap_or(Value::Null);
134    if let Some((key_id, pem)) = keys.iter().find_map(|key| match key {
135        PublicKey::Rsa { id, pem } => Some((id, pem)),
136        PublicKey::Multikey { .. } => None,
137    }) {
138        members.insert(
139            "publicKey".into(),
140            json!({"id": key_id, "owner": id, "publicKeyPem": pem}),
141        );
142    }
143    let methods: Vec<Value> = keys
144        .iter()
145        .filter_map(|key| match key {
146            PublicKey::Multikey {
147                id: key_id,
148                multibase,
149            } => Some(json!({
150                "id": key_id,
151                "type": "Multikey",
152                "controller": id,
153                "publicKeyMultibase": multibase,
154            })),
155            PublicKey::Rsa { .. } => None,
156        })
157        .collect();
158    if !methods.is_empty() {
159        members.insert("assertionMethod".into(), Value::Array(methods));
160    }
161}
162
163/// What [`Federation::handle`] made of a request.
164#[derive(Debug)]
165pub enum Handled {
166    /// Ojak's answer.
167    Response(http::Response<Vec<u8>>),
168    /// A route of Ojak's matched, but the request did not ask for
169    /// ActivityPub: the application serves its page at this URL, or 406.
170    NotAcceptable,
171    /// Nothing of Ojak's is at this URL, or on this host.
172    NotFound,
173}
174
175/// Why a URI could not be built.
176#[derive(Clone, Debug, Eq, PartialEq)]
177pub enum UriError {
178    /// No dispatcher of this kind is registered.
179    UnknownKind(String),
180    /// The values do not fill the template.
181    Template(TemplateError),
182}
183
184impl fmt::Display for UriError {
185    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186        match self {
187            Self::UnknownKind(kind) => write!(f, "no dispatcher of kind {kind:?}"),
188            Self::Template(error) => error.fmt(f),
189        }
190    }
191}
192
193impl std::error::Error for UriError {}
194
195/// Why a federation could not be built.
196#[derive(Clone, Debug, Eq, PartialEq)]
197pub struct BuildError(pub Vec<String>);
198
199impl fmt::Display for BuildError {
200    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
201        f.write_str(&self.0.join("; "))
202    }
203}
204
205impl std::error::Error for BuildError {}
206
207type ActorFn<D> = Arc<
208    dyn Fn(Context<D>, String) -> BoxFuture<'static, Result<Found<Value>, Error>> + Send + Sync,
209>;
210type ObjectFn<D> = Arc<
211    dyn Fn(Context<D>, Values) -> BoxFuture<'static, Result<Found<Value>, Error>> + Send + Sync,
212>;
213type AuthorizeFn<D> =
214    Arc<dyn Fn(Context<D>, Values) -> BoxFuture<'static, Result<Access, Error>> + Send + Sync>;
215type KeysFn<D> = Arc<
216    dyn Fn(Context<D>, ActorRef) -> BoxFuture<'static, Result<Vec<PublicKey>, Error>> + Send + Sync,
217>;
218type LookupFn<D, A> =
219    Arc<dyn Fn(Context<D>, A) -> BoxFuture<'static, Result<Option<ActorRef>, Error>> + Send + Sync>;
220type LinksFn<D> = Arc<dyn Fn(&Context<D>, &ActorRef, &Value) -> Vec<Value> + Send + Sync>;
221type NodeInfoFn<D> =
222    Arc<dyn Fn(Context<D>) -> BoxFuture<'static, Result<NodeInfo, Error>> + Send + Sync>;
223type OriginFn<D> = Arc<dyn Fn(&str, &D) -> Option<Url> + Send + Sync>;
224type ErrorFn = Arc<dyn Fn(&Error) + Send + Sync>;
225type GatewayFn<D> =
226    Arc<dyn Fn(Context<D>, ApUri) -> BoxFuture<'static, Result<Found<Value>, Error>> + Send + Sync>;
227type GatewayMediaFn<D> = Arc<
228    dyn Fn(Context<D>, Hashlink) -> BoxFuture<'static, Result<Option<Media>, Error>> + Send + Sync,
229>;
230type GatewayInboxFn<D> = Arc<
231    dyn Fn(Context<D>, ApUri) -> BoxFuture<'static, Result<Option<GatewayInbox>, Error>>
232        + Send
233        + Sync,
234>;
235
236enum Dispatcher<D> {
237    Actor(ActorFn<D>),
238    Object(ObjectFn<D>),
239    Collection(Collection<D>),
240}
241
242struct Entry<D> {
243    kind: String,
244    template: Template,
245    dispatcher: Dispatcher<D>,
246    authorize: Option<AuthorizeFn<D>>,
247    /// Another path the kind is served and recognised at, never built.
248    alias: bool,
249}
250
251impl<D> Entry<D> {
252    fn noun(&self) -> &'static str {
253        match self.dispatcher {
254            Dispatcher::Actor(_) => "actor",
255            Dispatcher::Object(_) => "object",
256            Dispatcher::Collection(_) => "collection",
257        }
258    }
259}
260
261enum OriginRule<D> {
262    Fixed(Url),
263    PerHost(OriginFn<D>),
264}
265
266struct Inner<D> {
267    origin: OriginRule<D>,
268    entries: Vec<Entry<D>>,
269    templates: Arc<Templates>,
270    key_pairs: Option<KeysFn<D>>,
271    handle: Option<LookupFn<D, String>>,
272    map_alias: Option<LookupFn<D, Url>>,
273    webfinger_links: Option<LinksFn<D>>,
274    nodeinfo: Option<NodeInfoFn<D>>,
275    signed_fetch: Option<signer::SignedFetch<D>>,
276    on_error: Option<ErrorFn>,
277    inboxes: Vec<(String, Template)>,
278    shared_inbox: Option<Template>,
279    listeners: std::collections::HashMap<&'static str, inbox::ListenerFn<D>>,
280    fallback_listener: Option<inbox::ListenerFn<D>>,
281    blocked: Option<inbox::BlockedFn<D>>,
282    on_unverified: Option<inbox::UnverifiedFn<D>>,
283    inbox_queue: Option<inbox::QueueFn<D>>,
284    gateway: Option<GatewayFn<D>>,
285    gateway_media: Option<GatewayMediaFn<D>>,
286    gateway_inbox: Option<GatewayInboxFn<D>>,
287    forward: Option<inbox::ForwardFn<D>>,
288    read_as_written: bool,
289    linked_data_first: bool,
290    remote_contexts: Option<RemoteContexts<D>>,
291}
292
293/// How contexts ojak does not ship are loaded to check a Linked Data
294/// Signature: [`Builder::remote_contexts`].
295pub(super) struct RemoteContexts<D> {
296    pub(super) limits: crate::contexts::Limits,
297    pub(super) load: LoadContextFn<D>,
298}
299
300/// A loader of the context an IRI names.
301type LoadContextFn<D> =
302    Arc<dyn Fn(Context<D>, String) -> BoxFuture<'static, Result<String, Error>> + Send + Sync>;
303
304impl<D> Inner<D> {
305    /// The entry `path` is routed to, with its values: of every template it
306    /// matches, the most specific, as `build` made sure there is one.
307    fn route(&self, path: &str) -> Option<(usize, Values)> {
308        self.entries
309            .iter()
310            .enumerate()
311            .filter_map(|(index, entry)| Some((index, entry.template.matches(path)?)))
312            .max_by(|(a, _), (b, _)| {
313                self.entries[*a]
314                    .template
315                    .specificity(&self.entries[*b].template)
316            })
317    }
318}
319
320/// Everything Ojak serves, and the URIs it builds. Cheap to clone.
321pub struct Federation<D> {
322    inner: Arc<Inner<D>>,
323}
324
325impl<D> Clone for Federation<D> {
326    fn clone(&self) -> Self {
327        Self {
328            inner: self.inner.clone(),
329        }
330    }
331}
332
333/// Wrap an application's async function as a stored dispatcher.
334fn boxed<A, T, E, F, Fut>(
335    f: F,
336) -> Arc<dyn Fn(A) -> BoxFuture<'static, Result<T, Error>> + Send + Sync>
337where
338    F: Fn(A) -> Fut + Send + Sync + 'static,
339    Fut: Future<Output = Result<T, E>> + Send + 'static,
340    E: Into<Error>,
341{
342    Arc::new(move |a| {
343        let future = f(a);
344        Box::pin(async move { future.await.map_err(Into::into) })
345    })
346}
347
348/// Builds a [`Federation`].
349pub struct Builder<D> {
350    origin: Option<OriginRule<D>>,
351    entries: Vec<Entry<D>>,
352    authorize: Vec<(String, AuthorizeFn<D>)>,
353    key_pairs: Option<KeysFn<D>>,
354    handle: Option<LookupFn<D, String>>,
355    map_alias: Option<LookupFn<D, Url>>,
356    webfinger_links: Option<LinksFn<D>>,
357    nodeinfo: Option<NodeInfoFn<D>>,
358    signed_fetch: Option<signer::SignedFetch<D>>,
359    on_error: Option<ErrorFn>,
360    inboxes: Vec<(String, String)>,
361    shared_inbox: Option<String>,
362    aliases: Vec<(String, &'static str, String)>,
363    listeners: std::collections::HashMap<&'static str, inbox::ListenerFn<D>>,
364    fallback_listener: Option<inbox::ListenerFn<D>>,
365    blocked: Option<inbox::BlockedFn<D>>,
366    on_unverified: Option<inbox::UnverifiedFn<D>>,
367    inbox_queue: Option<inbox::QueueFn<D>>,
368    gateway: Option<GatewayFn<D>>,
369    gateway_media: Option<GatewayMediaFn<D>>,
370    gateway_inbox: Option<GatewayInboxFn<D>>,
371    forward: Option<inbox::ForwardFn<D>>,
372    read_as_written: bool,
373    linked_data_first: bool,
374    remote_contexts: Option<RemoteContexts<D>>,
375    errors: Vec<String>,
376}
377
378impl<D: Clone + Send + Sync + 'static> Federation<D> {
379    #[must_use]
380    pub fn builder() -> Builder<D> {
381        Builder {
382            origin: None,
383            entries: Vec::new(),
384            authorize: Vec::new(),
385            key_pairs: None,
386            handle: None,
387            map_alias: None,
388            webfinger_links: None,
389            nodeinfo: None,
390            signed_fetch: None,
391            on_error: None,
392            inboxes: Vec::new(),
393            shared_inbox: None,
394            aliases: Vec::new(),
395            listeners: std::collections::HashMap::new(),
396            fallback_listener: None,
397            blocked: None,
398            on_unverified: None,
399            inbox_queue: None,
400            gateway: None,
401            gateway_media: None,
402            gateway_inbox: None,
403            forward: None,
404            read_as_written: false,
405            linked_data_first: false,
406            remote_contexts: None,
407            errors: Vec::new(),
408        }
409    }
410
411    /// The URIs of what is registered, in `origin`, with no request and no
412    /// data: for what has to be named before the application's data
413    /// exists, such as the ID of the key an actor signs with.
414    #[must_use]
415    pub fn uris(&self, origin: Url) -> Uris {
416        Uris {
417            templates: self.inner.templates.clone(),
418            origin,
419        }
420    }
421
422    /// A context outside any request, for building URIs in a background job:
423    /// `origin` is the canonical origin they are built in.
424    #[must_use]
425    pub fn context(&self, origin: Url, data: D) -> Context<D> {
426        Context::new(self.inner.clone(), data, origin, None)
427    }
428
429    /// The canonical origin for a request to `host`, if Ojak serves it.
430    fn origin_for(&self, host: &str, data: &D) -> Option<Url> {
431        match &self.inner.origin {
432            OriginRule::Fixed(origin) => Some(origin.clone()),
433            OriginRule::PerHost(origin) => origin(host, data),
434        }
435    }
436
437    /// The inbox `path` is, if it is one: `Some(Some(actor))` for an actor's,
438    /// `Some(None)` for the shared inbox.
439    fn inbox_at(&self, path: &str) -> Option<Option<ActorRef>> {
440        if self
441            .inner
442            .shared_inbox
443            .as_ref()
444            .is_some_and(|shared| shared.matches(path).is_some())
445        {
446            return Some(None);
447        }
448        self.inner.inboxes.iter().find_map(|(kind, template)| {
449            let values = template.matches(path)?;
450            Some(Some(ActorRef::new(
451                kind.clone(),
452                values.single().unwrap_or_default(),
453            )))
454        })
455    }
456
457    /// Whether `path` is an inbox, whose POSTs [`Federation::handle_with_body`]
458    /// answers: what an adapter asks before reading a request's body. Every
459    /// gateway path is one when the application accepts portable
460    /// deliveries, since which of them are inboxes is the application's to
461    /// say.
462    #[must_use]
463    pub fn is_inbox(&self, path: &str) -> bool {
464        self.inbox_at(path).is_some()
465            || (self.inner.gateway_inbox.is_some() && is_gateway_path(path))
466    }
467
468    /// Answer a request to `/.well-known/apgateway/{did}/{+path}`: a GET for
469    /// a portable object, a POST to a portable inbox.
470    async fn gateway(&self, request: &http::request::Parts, body: &[u8], data: D) -> Handled {
471        let host = request_host(request);
472        let Some(origin) = self.origin_for(&host, &data) else {
473            return Handled::NotFound;
474        };
475        if let Some(hashlink) = request
476            .uri
477            .path()
478            .strip_prefix(crate::portable::GATEWAY_PATH)
479            .filter(|rest| rest.starts_with("hl:"))
480        {
481            let context = Context::new(
482                self.inner.clone(),
483                data,
484                origin,
485                Some(RequestInfo::of(request, host)),
486            );
487            return Handled::Response(self.media(context, request, hashlink).await);
488        }
489        let compatible = format!(
490            "{}{}",
491            origin.as_str().trim_end_matches('/'),
492            request.uri.path()
493        );
494        let Some(uri) = ApUri::parse(&compatible) else {
495            return Handled::NotFound;
496        };
497        let context = Context::new(
498            self.inner.clone(),
499            data,
500            origin,
501            Some(RequestInfo::of(request, host)),
502        );
503        let head = request.method == Method::HEAD;
504        let response = if request.method == Method::GET || head {
505            let Some(load) = &self.inner.gateway else {
506                return Handled::NotFound;
507            };
508            match load(context.clone(), uri.clone()).await {
509                Ok(Found::Found(document)) => match servable(&context, &document, &uri).await {
510                    Ok(()) => without_body_if(head, portable_found(Found::Found(document), &uri)),
511                    Err(refused) => {
512                        context.report(&refused.to_string().into());
513                        empty(refused.status())
514                    }
515                },
516                Ok(found) => without_body_if(head, portable_found(found, &uri)),
517                Err(error) => {
518                    context.report(&error);
519                    empty(StatusCode::INTERNAL_SERVER_ERROR)
520                }
521            }
522        } else if request.method == Method::POST {
523            let Some(inbox_for) = &self.inner.gateway_inbox else {
524                return Handled::Response(method_not_allowed());
525            };
526            match inbox_for(context.clone(), uri.clone()).await {
527                Ok(Some(gateway)) => inbox::receive_at_gateway(context, uri, gateway, body).await,
528                // Not an inbox this server accepts deliveries for.
529                Ok(None) => empty(StatusCode::NOT_FOUND),
530                Err(error) => {
531                    context.report(&error);
532                    empty(StatusCode::INTERNAL_SERVER_ERROR)
533                }
534            }
535        } else {
536            let mut response = empty(StatusCode::METHOD_NOT_ALLOWED);
537            response
538                .headers_mut()
539                .insert(header::ALLOW, HeaderValue::from_static("GET, HEAD, POST"));
540            response
541        };
542        Handled::Response(response)
543    }
544
545    /// Answer a request for media by its hashlink,
546    /// `/.well-known/apgateway/hl:zQm…`.
547    async fn media(
548        &self,
549        context: Context<D>,
550        request: &http::request::Parts,
551        hashlink: &str,
552    ) -> http::Response<Vec<u8>> {
553        let head = request.method == Method::HEAD;
554        if request.method != Method::GET && !head {
555            return method_not_allowed();
556        }
557        let (Some(load), Some(hashlink)) = (&self.inner.gateway_media, Hashlink::parse(hashlink))
558        else {
559            return empty(StatusCode::NOT_FOUND);
560        };
561        match load(context.clone(), hashlink.clone()).await {
562            // What the hashlink names, and nothing else: whoever fetches it
563            // checks it against the digest, and would refuse anything else.
564            Ok(Some(media)) if hashlink.matches(&media.bytes) => {
565                let mut response = response(StatusCode::OK, &media.content_type, media.bytes);
566                // Whatever is served at a digest is always the same.
567                response.headers_mut().insert(
568                    header::CACHE_CONTROL,
569                    HeaderValue::from_static("public, max-age=31536000, immutable"),
570                );
571                without_body_if(head, response)
572            }
573            Ok(Some(_)) => {
574                context.report(
575                    &format!("gateway: media found for {hashlink} is not what it names").into(),
576                );
577                empty(StatusCode::INTERNAL_SERVER_ERROR)
578            }
579            Ok(None) => empty(StatusCode::NOT_FOUND),
580            Err(error) => {
581                context.report(&error);
582                empty(StatusCode::INTERNAL_SERVER_ERROR)
583            }
584        }
585    }
586
587    /// Answer `request` with its `body`: an activity POSTed to an inbox is
588    /// received; anything else is answered as [`Federation::handle`] does.
589    pub async fn handle_with_body(
590        &self,
591        request: &http::request::Parts,
592        body: &[u8],
593        data: D,
594    ) -> Handled {
595        if self.serves_gateway() && is_gateway_path(request.uri.path()) {
596            return self.gateway(request, body, data).await;
597        }
598        let Some(recipient) = self.inbox_at(request.uri.path()) else {
599            return self.handle(request, data).await;
600        };
601        let host = request_host(request);
602        let Some(origin) = self.origin_for(&host, &data) else {
603            return Handled::NotFound;
604        };
605        if request.method != Method::POST {
606            let mut response = empty(StatusCode::METHOD_NOT_ALLOWED);
607            response
608                .headers_mut()
609                .insert(header::ALLOW, HeaderValue::from_static("POST"));
610            return Handled::Response(response);
611        }
612        let context = Context::new(
613            self.inner.clone(),
614            data,
615            origin,
616            Some(RequestInfo::of(request, host)),
617        );
618        Handled::Response(inbox::receive(context, recipient, body).await)
619    }
620
621    /// Answer `request`, or say why it is not Ojak's to answer. An inbox's
622    /// POST needs its body: [`Federation::handle_with_body`].
623    pub async fn handle(&self, request: &http::request::Parts, data: D) -> Handled {
624        let path = request.uri.path();
625        if self.serves_gateway() && is_gateway_path(path) {
626            return self.gateway(request, b"", data).await;
627        }
628        if self.is_inbox(path) {
629            return Box::pin(self.handle_with_body(request, b"", data)).await;
630        }
631        let special = self.special(path);
632        let matched = if special.is_some() {
633            None
634        } else {
635            let found = self.inner.route(path);
636            if found.is_none() {
637                return Handled::NotFound;
638            }
639            found
640        };
641
642        let host = request_host(request);
643        let Some(origin) = self.origin_for(&host, &data) else {
644            return Handled::NotFound;
645        };
646        let head = request.method == Method::HEAD;
647        // An alias is a path the application serves too, such as a post's
648        // page, whose other methods are the application's.
649        let alias = matched
650            .as_ref()
651            .is_some_and(|(index, _)| self.inner.entries[*index].alias);
652        if request.method != Method::GET && !head {
653            if alias {
654                return Handled::NotFound;
655            }
656            return Handled::Response(method_not_allowed());
657        }
658
659        if let Some(special) = special {
660            let context = Context::new(
661                self.inner.clone(),
662                data,
663                origin,
664                Some(RequestInfo::of(request, host)),
665            );
666            let response = match special {
667                Special::WebFinger => webfinger::webfinger(&context, request.uri.query()).await,
668                Special::HostMeta => webfinger::host_meta(&context),
669                Special::NodeInfoLinks => nodeinfo::links(&context),
670                Special::NodeInfo(version) => nodeinfo::document(&context, version).await,
671            };
672            return Handled::Response(without_body_if(head, response));
673        }
674
675        let Some((index, values)) = matched else {
676            return Handled::NotFound;
677        };
678        let accept = request
679            .headers
680            .get(header::ACCEPT)
681            .and_then(|value| value.to_str().ok());
682        if !negotiate::wants_activity(accept) {
683            return Handled::NotAcceptable;
684        }
685        let context = Context::new(
686            self.inner.clone(),
687            data,
688            origin,
689            Some(RequestInfo::of(request, host)),
690        );
691        let entry = &self.inner.entries[index];
692        let response = self
693            .dispatch(&context, entry, values, request.uri.query())
694            .await
695            .unwrap_or_else(|error| {
696                context.report(&error);
697                empty(StatusCode::INTERNAL_SERVER_ERROR)
698            });
699        // What an alias's dispatcher does not find is the application's to
700        // answer at that path, as if the alias did not match.
701        if entry.alias && response.status() == StatusCode::NOT_FOUND {
702            return Handled::NotFound;
703        }
704        let response = context.with_response_headers(response);
705        Handled::Response(without_body_if(head, response))
706    }
707
708    async fn dispatch(
709        &self,
710        context: &Context<D>,
711        entry: &Entry<D>,
712        values: Values,
713        query: Option<&str>,
714    ) -> Result<http::Response<Vec<u8>>, Error> {
715        let url = context.request_url();
716        if let Some(authorize) = &entry.authorize {
717            match authorize(context.clone(), values.clone()).await? {
718                Access::Allow => {}
719                Access::Unauthorized => {
720                    return Ok(unauthorized(context.signer().await.is_some()));
721                }
722                Access::Forbidden => return Ok(forbidden()),
723                Access::NotFound => return Ok(found(Found::NotFound, &url)),
724            }
725        }
726        match &entry.dispatcher {
727            Dispatcher::Actor(load) => {
728                let identifier = values.single().unwrap_or_default().to_owned();
729                Ok(found(load(context.clone(), identifier).await?, &url))
730            }
731            Dispatcher::Object(load) => {
732                // A Tombstone names the object, and an alias is not its name.
733                let url = if entry.alias {
734                    let values: Vec<(&str, &str)> = values.iter().collect();
735                    context.object_uri(&entry.kind, &values).unwrap_or(url)
736                } else {
737                    url
738                };
739                Ok(found(load(context.clone(), values).await?, &url))
740            }
741            Dispatcher::Collection(collection) => {
742                let identifier = values.single().unwrap_or_default().to_owned();
743                collection
744                    .serve(context, &entry.kind, &identifier, query)
745                    .await
746            }
747        }
748    }
749
750    fn serves_gateway(&self) -> bool {
751        self.inner.gateway.is_some()
752            || self.inner.gateway_media.is_some()
753            || self.inner.gateway_inbox.is_some()
754    }
755
756    fn special(&self, path: &str) -> Option<Special> {
757        let serves_webfinger = self
758            .inner
759            .entries
760            .iter()
761            .any(|entry| matches!(entry.dispatcher, Dispatcher::Actor(_)));
762        match path {
763            webfinger::WEBFINGER_PATH if serves_webfinger => Some(Special::WebFinger),
764            webfinger::HOST_META_PATH if serves_webfinger => Some(Special::HostMeta),
765            nodeinfo::LINKS_PATH if self.inner.nodeinfo.is_some() => Some(Special::NodeInfoLinks),
766            nodeinfo::PATH_2_0 if self.inner.nodeinfo.is_some() => {
767                Some(Special::NodeInfo(nodeinfo::Version::V2_0))
768            }
769            nodeinfo::PATH_2_1 if self.inner.nodeinfo.is_some() => {
770                Some(Special::NodeInfo(nodeinfo::Version::V2_1))
771            }
772            _ => None,
773        }
774    }
775}
776
777enum Special {
778    WebFinger,
779    HostMeta,
780    NodeInfoLinks,
781    NodeInfo(nodeinfo::Version),
782}
783
784/// The paths Ojak serves itself, which no template may claim.
785const RESERVED: [&str; 5] = [
786    webfinger::WEBFINGER_PATH,
787    webfinger::HOST_META_PATH,
788    nodeinfo::LINKS_PATH,
789    nodeinfo::PATH_2_0,
790    nodeinfo::PATH_2_1,
791];
792
793impl<D: Clone + Send + Sync + 'static> Builder<D> {
794    /// Serve every request in `origin`'s URIs, whatever host it came to: for
795    /// an application with one host.
796    #[must_use]
797    pub fn origin(mut self, origin: Url) -> Self {
798        self.origin = Some(OriginRule::Fixed(origin));
799        self
800    }
801
802    /// The canonical origin for a request to a host, or `None` for a host
803    /// Ojak should not answer for. A host this maps to the canonical origin
804    /// is one of its aliases: its IRIs are ours, and its handles are.
805    #[must_use]
806    pub fn origin_with(
807        mut self,
808        origin: impl Fn(&str, &D) -> Option<Url> + Send + Sync + 'static,
809    ) -> Self {
810        self.origin = Some(OriginRule::PerHost(Arc::new(origin)));
811        self
812    }
813
814    fn add(&mut self, kind: &str, template: &str, dispatcher: Dispatcher<D>) {
815        match Template::parse(template) {
816            Ok(template) => self.entries.push(Entry {
817                kind: kind.to_owned(),
818                template,
819                dispatcher,
820                authorize: None,
821                alias: false,
822            }),
823            Err(error) => self.errors.push(error.to_string()),
824        }
825    }
826
827    /// Serve actors of `kind` at `template`, whose one expression, if it has
828    /// one, is the actor's identifier.
829    #[must_use]
830    pub fn actor<F, Fut, E>(mut self, kind: &str, template: &str, load: F) -> Self
831    where
832        F: Fn(Context<D>, String) -> Fut + Send + Sync + 'static,
833        Fut: Future<Output = Result<Found<Value>, E>> + Send + 'static,
834        E: Into<Error>,
835    {
836        let load = boxed(move |(context, identifier)| load(context, identifier));
837        self.add(
838            kind,
839            template,
840            Dispatcher::Actor(Arc::new(move |context, identifier| {
841                load((context, identifier))
842            })),
843        );
844        self
845    }
846
847    /// Serve objects of `kind` at `template`, whose expressions the
848    /// dispatcher receives by name.
849    #[must_use]
850    pub fn object<F, Fut, E>(mut self, kind: &str, template: &str, load: F) -> Self
851    where
852        F: Fn(Context<D>, Values) -> Fut + Send + Sync + 'static,
853        Fut: Future<Output = Result<Found<Value>, E>> + Send + 'static,
854        E: Into<Error>,
855    {
856        let load = boxed(move |(context, values)| load(context, values));
857        self.add(
858            kind,
859            template,
860            Dispatcher::Object(Arc::new(move |context, values| load((context, values)))),
861        );
862        self
863    }
864
865    /// Serve the objects of `kind` at `template` as well, and recognise it
866    /// in [`Context::parse_uri`] and [`Context::parse_object`]: another path
867    /// the same objects are known by, such as Mastodon's `/@{username}/{id}`
868    /// beside `/users/{username}/statuses/{id}`. URIs are still built from
869    /// the template `kind` was registered with. The dispatcher receives this
870    /// template's values, so it has to name every expression the first
871    /// template does, and may name more.
872    #[must_use]
873    pub fn object_alias(mut self, kind: &str, template: &str) -> Self {
874        self.aliases
875            .push((kind.to_owned(), "object", template.to_owned()));
876        self
877    }
878
879    /// Serve the collection `kind` at `template` as well, and recognise it in
880    /// [`Context::parse_uri`]: another path the same collection is known by,
881    /// such as Mastodon's `/@{username}/followers` beside
882    /// `/users/{username}/followers`. The collection is still named by the
883    /// template `kind` was registered with, in its `id` and its pages'
884    /// links. The alias names the owner in as many expressions as that
885    /// template does: one, or none.
886    #[must_use]
887    pub fn collection_alias(mut self, kind: &str, template: &str) -> Self {
888        self.aliases
889            .push((kind.to_owned(), "collection", template.to_owned()));
890        self
891    }
892
893    /// Serve the collection `kind` at `template`, whose one expression, if it
894    /// has one, is the identifier of what it belongs to.
895    #[must_use]
896    pub fn collection(mut self, kind: &str, template: &str, collection: Collection<D>) -> Self {
897        self.add(kind, template, Dispatcher::Collection(collection));
898        self
899    }
900
901    /// Serve what is registered as `kind` only to requests `authorize` allows.
902    /// It receives the verified signer of the request, if it was signed and
903    /// signed fetches are configured. A request it refuses is 401.
904    #[must_use]
905    pub fn authorize<F, Fut, E>(self, kind: &str, authorize: F) -> Self
906    where
907        F: Fn(Context<D>, Values, Option<Url>) -> Fut + Send + Sync + 'static,
908        Fut: Future<Output = Result<bool, E>> + Send + 'static,
909        E: Into<Error>,
910    {
911        let authorize = Arc::new(authorize);
912        self.guard(kind, move |context: Context<D>, values| {
913            let authorize = authorize.clone();
914            async move {
915                let signer = context.signer().await;
916                Ok::<_, Error>(
917                    if authorize(context, values, signer)
918                        .await
919                        .map_err(Into::into)?
920                    {
921                        Access::Allow
922                    } else {
923                        Access::Unauthorized
924                    },
925                )
926            }
927        })
928    }
929
930    /// Serve what is registered as `kind` only as `guard` says: to all, or
931    /// refused as unauthorized (401), forbidden (403) or not there (404).
932    /// Unlike [`Builder::authorize`], nothing is verified before it is asked:
933    /// the guard asks [`Context::signing`] or [`Context::signer`] when it
934    /// needs to know who signed, so a guard that lets everyone through costs
935    /// no signature check, nor a key fetched to make one.
936    #[must_use]
937    pub fn guard<F, Fut, E>(mut self, kind: &str, guard: F) -> Self
938    where
939        F: Fn(Context<D>, Values) -> Fut + Send + Sync + 'static,
940        Fut: Future<Output = Result<Access, E>> + Send + 'static,
941        E: Into<Error>,
942    {
943        let guard = boxed(move |(context, values)| guard(context, values));
944        self.authorize.push((
945            kind.to_owned(),
946            Arc::new(move |context, values| guard((context, values))),
947        ));
948        self
949    }
950
951    /// Where actors' public keys come from, read by [`Context::actor_keys`].
952    #[must_use]
953    pub fn key_pairs<F, Fut, E>(mut self, keys: F) -> Self
954    where
955        F: Fn(Context<D>, ActorRef) -> Fut + Send + Sync + 'static,
956        Fut: Future<Output = Result<Vec<PublicKey>, E>> + Send + 'static,
957        E: Into<Error>,
958    {
959        let keys = boxed(move |(context, actor)| keys(context, actor));
960        self.key_pairs = Some(Arc::new(move |context, actor| keys((context, actor))));
961        self
962    }
963
964    /// Which actor a WebFinger handle's username names.
965    #[must_use]
966    pub fn handle<F, Fut, E>(mut self, lookup: F) -> Self
967    where
968        F: Fn(Context<D>, String) -> Fut + Send + Sync + 'static,
969        Fut: Future<Output = Result<Option<ActorRef>, E>> + Send + 'static,
970        E: Into<Error>,
971    {
972        let lookup = boxed(move |(context, username)| lookup(context, username));
973        self.handle = Some(Arc::new(move |context, username| {
974            lookup((context, username))
975        }));
976        self
977    }
978
979    /// Which actor another URL of ours, such as a profile page, names, for
980    /// WebFinger.
981    #[must_use]
982    pub fn map_alias<F, Fut, E>(mut self, lookup: F) -> Self
983    where
984        F: Fn(Context<D>, Url) -> Fut + Send + Sync + 'static,
985        Fut: Future<Output = Result<Option<ActorRef>, E>> + Send + 'static,
986        E: Into<Error>,
987    {
988        let lookup = boxed(move |(context, url)| lookup(context, url));
989        self.map_alias = Some(Arc::new(move |context, url| lookup((context, url))));
990        self
991    }
992
993    /// Links a WebFinger answer carries beside `self` and `profile-page`,
994    /// such as Mastodon's `subscribe` template.
995    #[must_use]
996    pub fn webfinger_links(
997        mut self,
998        links: impl Fn(&Context<D>, &ActorRef, &Value) -> Vec<Value> + Send + Sync + 'static,
999    ) -> Self {
1000        self.webfinger_links = Some(Arc::new(links));
1001        self
1002    }
1003
1004    /// Serve NodeInfo, 2.0 and 2.1, from `nodeinfo`.
1005    #[must_use]
1006    pub fn nodeinfo<F, Fut, E>(mut self, nodeinfo: F) -> Self
1007    where
1008        F: Fn(Context<D>) -> Fut + Send + Sync + 'static,
1009        Fut: Future<Output = Result<NodeInfo, E>> + Send + 'static,
1010        E: Into<Error>,
1011    {
1012        self.nodeinfo = Some(boxed(nodeinfo));
1013        self
1014    }
1015
1016    /// Verify signed GETs, for [`Context::signer`] and `authorize`: keys are
1017    /// fetched with `fetcher`, signed with the key `key` returns when there is
1018    /// one, and kept in `kv` for `key_ttl`.
1019    #[must_use]
1020    pub fn signed_fetch<K, F, Fut, E>(
1021        mut self,
1022        fetcher: Arc<Fetcher>,
1023        kv: K,
1024        key_ttl: Duration,
1025        key: F,
1026    ) -> Self
1027    where
1028        K: KvStore,
1029        F: Fn(Context<D>) -> Fut + Send + Sync + 'static,
1030        Fut: Future<Output = Result<Option<crate::sig::SenderKey>, E>> + Send + 'static,
1031        E: Into<Error>,
1032    {
1033        self.signed_fetch = Some(signer::SignedFetch {
1034            fetcher,
1035            kv: Arc::new(kv),
1036            key_ttl,
1037            key: boxed(key),
1038            fetcher_for: None,
1039            kv_for: None,
1040            known_key: None,
1041            key_fetched: None,
1042        });
1043        self
1044    }
1045
1046    /// The fetcher for a request's data, in place of the one given to
1047    /// [`Builder::signed_fetch`]: an application serving several instances
1048    /// fetches with each one's own. Call after `signed_fetch`.
1049    #[must_use]
1050    pub fn fetcher_for(
1051        mut self,
1052        fetcher: impl Fn(&D) -> Arc<Fetcher> + Send + Sync + 'static,
1053    ) -> Self {
1054        match &mut self.signed_fetch {
1055            Some(settings) => settings.fetcher_for = Some(Arc::new(fetcher)),
1056            None => self.errors.push("fetcher_for before signed_fetch".into()),
1057        }
1058        self
1059    }
1060
1061    /// The key-value store for a request's data, in place of the one given
1062    /// to [`Builder::signed_fetch`]: an application serving several
1063    /// instances keeps each one's cached keys and the activities it has seen
1064    /// in that instance's own store, such as its own namespace of a shared
1065    /// Redis. Call after `signed_fetch`.
1066    #[must_use]
1067    pub fn kv_for<K: KvStore>(mut self, kv: impl Fn(&D) -> Arc<K> + Send + Sync + 'static) -> Self {
1068        match &mut self.signed_fetch {
1069            Some(settings) => {
1070                settings.kv_for = Some(Arc::new(move |data: &D| -> Arc<dyn DynKv> { kv(data) }));
1071            }
1072            None => self.errors.push("kv_for before signed_fetch".into()),
1073        }
1074        self
1075    }
1076
1077    /// A key the application already holds for a key ID, tried before the
1078    /// key-value store and a fetch: an application that stores remote
1079    /// actors' keys, as Mastodon's schema does, need not fetch them again. A
1080    /// key that does not verify is fetched fresh. Call after `signed_fetch`.
1081    #[must_use]
1082    pub fn known_key<F, Fut, E>(mut self, known: F) -> Self
1083    where
1084        F: Fn(Context<D>, String) -> Fut + Send + Sync + 'static,
1085        Fut: Future<Output = Result<Option<KnownKey>, E>> + Send + 'static,
1086        E: Into<Error>,
1087    {
1088        let known = boxed(move |(context, key_id)| known(context, key_id));
1089        match &mut self.signed_fetch {
1090            Some(settings) => {
1091                settings.known_key =
1092                    Some(Arc::new(move |context, key_id| known((context, key_id))));
1093            }
1094            None => self.errors.push("known_key before signed_fetch".into()),
1095        }
1096        self
1097    }
1098
1099    /// See the document of an actor Ojak fetched for its key, once the key
1100    /// has verified a request: an application that stores actors stores this
1101    /// one, so a new actor's first activity does not fetch it twice. Call
1102    /// after `signed_fetch`.
1103    #[must_use]
1104    pub fn key_fetched<F, Fut>(mut self, hook: F) -> Self
1105    where
1106        F: Fn(Context<D>, Value) -> Fut + Send + Sync + 'static,
1107        Fut: Future<Output = ()> + Send + 'static,
1108    {
1109        match &mut self.signed_fetch {
1110            Some(settings) => {
1111                settings.key_fetched = Some(Arc::new(move |context, document| {
1112                    Box::pin(hook(context, document))
1113                }));
1114            }
1115            None => self.errors.push("key_fetched before signed_fetch".into()),
1116        }
1117        self
1118    }
1119
1120    /// Run `listen` for every activity no typed listener is registered for,
1121    /// read as whatever it is: for an application with a dispatcher of its
1122    /// own, which reads [`Received::vouched`].
1123    #[must_use]
1124    pub fn on_any<F, Fut, E>(mut self, listen: F) -> Self
1125    where
1126        F: Fn(Context<D>, Received<ojak_vocab::generated::AnyObject>) -> Fut
1127            + Send
1128            + Sync
1129            + 'static,
1130        Fut: Future<Output = Result<(), E>> + Send + 'static,
1131        E: Into<Error>,
1132    {
1133        self.fallback_listener = Some(inbox::any_listener(listen));
1134        self
1135    }
1136
1137    /// Receive activities at `template`, the inbox of the actors of `kind`,
1138    /// whose one expression is the actor's identifier; or, for an actor
1139    /// whose own template has no expression, such as an instance actor at
1140    /// `/actor`, with none.
1141    #[must_use]
1142    pub fn inbox(mut self, kind: &str, template: &str) -> Self {
1143        self.inboxes.push((kind.to_owned(), template.to_owned()));
1144        self
1145    }
1146
1147    /// Receive activities at `path`, the shared inbox.
1148    #[must_use]
1149    pub fn shared_inbox(mut self, path: &str) -> Self {
1150        self.shared_inbox = Some(path.to_owned());
1151        self
1152    }
1153
1154    /// Run `listen` for every activity of type `T` an inbox receives from a
1155    /// sender Ojak has authenticated. Types with no listener are accepted
1156    /// and dropped.
1157    #[must_use]
1158    pub fn on<T, F, Fut, E>(mut self, listen: F) -> Self
1159    where
1160        T: ojak_vocab::json::Typed
1161            + ojak_vocab::json::FromJson
1162            + ojak_vocab::json::ToJson
1163            + Send
1164            + 'static,
1165        F: Fn(Context<D>, Received<T>) -> Fut + Send + Sync + 'static,
1166        Fut: Future<Output = Result<(), E>> + Send + 'static,
1167        E: Into<Error>,
1168    {
1169        if self
1170            .listeners
1171            .insert(T::TYPE, inbox::listener(listen))
1172            .is_some()
1173        {
1174            self.errors.push(format!("two listeners for {}", T::TYPE));
1175        }
1176        self
1177    }
1178
1179    /// Hand listeners each activity as its sender wrote it, without JSON-LD
1180    /// processing: its `@context` removed and what it embeds reduced to what
1181    /// the sender can vouch for, as always, but its terms left as spelled.
1182    ///
1183    /// By default an activity is expanded and compacted against ojak's
1184    /// context first, so that a sender's aliases, prefixes and extension terms
1185    /// read as ojak's vocabulary expects. That is what a listener typed to a
1186    /// vocabulary type relies on. An application that reads the JSON itself,
1187    /// as Mastodon reads it, needs none of it, and this skips the work — and
1188    /// the refusal of a document whose context cannot be processed.
1189    #[must_use]
1190    pub fn read_inbox_as_written(mut self) -> Self {
1191        self.read_as_written = true;
1192        self
1193    }
1194
1195    /// Check a forwarded activity's Linked Data signature before its
1196    /// FEP-8b32 proof, rather than after.
1197    ///
1198    /// An activity signed by a server other than its actor's is taken on its
1199    /// actor's proof by default, and on its Linked Data signature only when it
1200    /// has no proof that holds: a proof is the cheaper check, needing no
1201    /// JSON-LD processing. Mastodon and Fedify check the signature first, and
1202    /// what an activity is taken on decides whether it can be passed on
1203    /// (`Received::vouched_by`): Mastodon passes on only an activity taken on
1204    /// its Linked Data signature. An application that forwards as Mastodon
1205    /// does asks for this, so that an activity carrying both is taken on its
1206    /// signature. A request signed by the actor's own server, and one whose
1207    /// signature does not verify, are unaffected.
1208    #[must_use]
1209    pub fn linked_data_before_proof(mut self) -> Self {
1210        self.linked_data_first = true;
1211        self
1212    }
1213
1214    /// Whether activities from `host` are refused, asked before any key is
1215    /// fetched for them. A refused activity is answered 202 and dropped.
1216    ///
1217    /// A request signed with a key on `host` is refused too, before the key
1218    /// is looked for: its signer is not verified, an inbox POST is answered
1219    /// as one that does not verify, and a GET's signing is
1220    /// [`Signing::Blocked`].
1221    #[must_use]
1222    pub fn blocked<F, Fut, E>(mut self, blocked: F) -> Self
1223    where
1224        F: Fn(Context<D>, String) -> Fut + Send + Sync + 'static,
1225        Fut: Future<Output = Result<bool, E>> + Send + 'static,
1226        E: Into<Error>,
1227    {
1228        let blocked = boxed(move |(context, host)| blocked(context, host));
1229        self.blocked = Some(Arc::new(move |context, host| blocked((context, host))));
1230        self
1231    }
1232
1233    /// Check a Linked Data Signature over contexts ojak does not ship, as
1234    /// Mastodon does: `load` returns the context an IRI names, the body
1235    /// [`crate::contexts::fetch`] returns, from the application's cache or
1236    /// fetched with its client ([`crate::contexts::fetch_cached`] does both).
1237    /// Without it, an activity naming such a context is not taken on its
1238    /// signature, and is fetched from its origin instead.
1239    ///
1240    /// Only that check loads contexts, and only within `limits`; the
1241    /// activity is then read over the same contexts, so that what it is
1242    /// taken to say is what was signed.
1243    #[must_use]
1244    pub fn remote_contexts<F, Fut, E>(mut self, limits: crate::contexts::Limits, load: F) -> Self
1245    where
1246        F: Fn(Context<D>, String) -> Fut + Send + Sync + 'static,
1247        Fut: Future<Output = Result<String, E>> + Send + 'static,
1248        E: Into<Error>,
1249    {
1250        let load = boxed(move |(context, iri)| load(context, iri));
1251        self.remote_contexts = Some(RemoteContexts {
1252            limits,
1253            load: Arc::new(move |context, iri| load((context, iri))),
1254        });
1255        self
1256    }
1257
1258    /// See every activity whose sender could not be authenticated, which is
1259    /// where an application removes an actor whose Delete it could not
1260    /// verify because the actor, key and all, is gone.
1261    #[must_use]
1262    pub fn on_unverified<F, Fut>(mut self, hook: F) -> Self
1263    where
1264        F: Fn(Context<D>, Value) -> Fut + Send + Sync + 'static,
1265        Fut: Future<Output = ()> + Send + 'static,
1266    {
1267        self.on_unverified = Some(Arc::new(move |context, document| {
1268            Box::pin(hook(context, document))
1269        }));
1270        self
1271    }
1272
1273    /// The queue activities wait in for an [`InboxWorker`], for the data of a
1274    /// request: an application with a database per tenant has a queue per
1275    /// tenant. Without one, or when it gives `None`, listeners run inside the
1276    /// request.
1277    #[must_use]
1278    pub fn inbox_queue(
1279        mut self,
1280        queue: impl Fn(&D) -> Option<crate::queue::SharedQueue> + Send + Sync + 'static,
1281    ) -> Self {
1282        self.inbox_queue = Some(Arc::new(queue));
1283        self
1284    }
1285
1286    /// Serve the portable objects (FEP-ef61) this server is a gateway for,
1287    /// at `/.well-known/apgateway/{did}/{+path}`. `load` returns the object
1288    /// an `ap` URI names, as the signed document the application stored: its
1289    /// proof covers it, and Ojak serves it as it is. An object that is not
1290    /// public is the application's to refuse, as for any dispatcher.
1291    ///
1292    /// What is served is checked first, as whoever fetches it will check it:
1293    /// a document whose `id` is another object is answered 404, and one
1294    /// whose proof does not verify, 500, both reported to `on_error`. A
1295    /// collection may have no proof. A signed Tombstone is served with 410;
1296    /// `Found::Gone` serves an unsigned one, which says the object is gone
1297    /// but that nobody can take for its owner's word.
1298    #[must_use]
1299    pub fn gateway<F, Fut, E>(mut self, load: F) -> Self
1300    where
1301        F: Fn(Context<D>, ApUri) -> Fut + Send + Sync + 'static,
1302        Fut: Future<Output = Result<Found<Value>, E>> + Send + 'static,
1303        E: Into<Error>,
1304    {
1305        let load = boxed(move |(context, uri)| load(context, uri));
1306        self.gateway = Some(Arc::new(move |context, uri| load((context, uri))));
1307        self
1308    }
1309
1310    /// Serve the media portable objects refer to by hashlink (FEP-ef61), at
1311    /// `/.well-known/apgateway/hl:zQm…`. `load` returns what the hashlink
1312    /// names; it is served only if it is that, since it is checked against
1313    /// the digest wherever it is fetched, and a mismatch is reported to
1314    /// `on_error` and answered 500. Anyone who knows a digest can fetch what
1315    /// it names: media with an audience is the application's to refuse.
1316    #[must_use]
1317    pub fn gateway_media<F, Fut, E>(mut self, load: F) -> Self
1318    where
1319        F: Fn(Context<D>, Hashlink) -> Fut + Send + Sync + 'static,
1320        Fut: Future<Output = Result<Option<Media>, E>> + Send + 'static,
1321        E: Into<Error>,
1322    {
1323        let load = boxed(move |(context, hashlink)| load(context, hashlink));
1324        self.gateway_media = Some(Arc::new(move |context, hashlink| load((context, hashlink))));
1325        self
1326    }
1327
1328    /// Accept deliveries to portable inboxes: `inbox_for` maps the `ap` URI
1329    /// of an inbox POSTed to at `/.well-known/apgateway/…` to the actor the
1330    /// application hosts it for, who the listeners see as the recipient, and
1331    /// the gateways that actor lists, which what arrives is forwarded to.
1332    /// An inbox it maps to `None` is answered 404.
1333    #[must_use]
1334    pub fn gateway_inbox<F, Fut, E>(mut self, inbox_for: F) -> Self
1335    where
1336        F: Fn(Context<D>, ApUri) -> Fut + Send + Sync + 'static,
1337        Fut: Future<Output = Result<Option<GatewayInbox>, E>> + Send + 'static,
1338        E: Into<Error>,
1339    {
1340        let inbox_for = boxed(move |(context, uri)| inbox_for(context, uri));
1341        self.gateway_inbox = Some(Arc::new(move |context, uri| inbox_for((context, uri))));
1342        self
1343    }
1344
1345    /// Forward what arrives to where it has to go on to: a portable actor's
1346    /// other gateways, as FEP-ef61 asks, and the members of collections of
1347    /// ours an activity concerning something of ours is addressed to, as
1348    /// ActivityPub asks (§7.1.2). `forward` is called once for each activity
1349    /// and kind of forward, however many times it arrives, and sends it.
1350    /// Without it, nothing is forwarded.
1351    #[must_use]
1352    pub fn forward<F, Fut, E>(mut self, forward: F) -> Self
1353    where
1354        F: Fn(Context<D>, Forward) -> Fut + Send + Sync + 'static,
1355        Fut: Future<Output = Result<(), E>> + Send + 'static,
1356        E: Into<Error>,
1357    {
1358        let forward = boxed(move |(context, activity)| forward(context, activity));
1359        self.forward = Some(Arc::new(move |context, activity| {
1360            forward((context, activity))
1361        }));
1362        self
1363    }
1364
1365    /// See every error a dispatcher returns, which is otherwise a bare 500.
1366    #[must_use]
1367    pub fn on_error(mut self, report: impl Fn(&Error) + Send + Sync + 'static) -> Self {
1368        self.on_error = Some(Arc::new(report));
1369        self
1370    }
1371
1372    /// The federation.
1373    ///
1374    /// # Errors
1375    ///
1376    /// When there is no origin, a template is malformed, two templates could
1377    /// match one path, a template claims a path Ojak serves itself, two
1378    /// dispatchers share a kind, an actor or collection template has more
1379    /// than one expression, or `authorize` names no kind.
1380    pub fn build(mut self) -> Result<Federation<D>, BuildError> {
1381        let mut errors = std::mem::take(&mut self.errors);
1382        let origin = self.origin.take();
1383        if origin.is_none() {
1384            errors.push("no origin: call origin or origin_with".into());
1385        }
1386        for (kind, noun, template) in std::mem::take(&mut self.aliases) {
1387            let template = match Template::parse(&template) {
1388                Ok(template) => template,
1389                Err(error) => {
1390                    errors.push(error.to_string());
1391                    continue;
1392                }
1393            };
1394            let Some(primary) = self
1395                .entries
1396                .iter()
1397                .find(|entry| entry.kind == kind && entry.noun() == noun && !entry.alias)
1398            else {
1399                errors.push(format!(
1400                    "{noun}_alias for {kind:?}, which is no {noun} kind"
1401                ));
1402                continue;
1403            };
1404            let problem = match &primary.dispatcher {
1405                // An object's dispatcher reads its values by name.
1406                Dispatcher::Object(_) => primary
1407                    .template
1408                    .names()
1409                    .find(|name| !template.names().any(|alias| alias == *name))
1410                    .map(|missing| {
1411                        format!(
1412                            "object_alias {} does not name {missing}, which {} does",
1413                            template.as_str(),
1414                            primary.template.as_str()
1415                        )
1416                    }),
1417                // A collection's reads its one expression, whatever its name.
1418                _ => (template.names().count() != primary.template.names().count()).then(|| {
1419                    format!(
1420                        "collection_alias {} has to name its owner as {} does",
1421                        template.as_str(),
1422                        primary.template.as_str()
1423                    )
1424                }),
1425            };
1426            if let Some(problem) = problem {
1427                errors.push(problem);
1428                continue;
1429            }
1430            let dispatcher = match &primary.dispatcher {
1431                Dispatcher::Object(load) => Dispatcher::Object(load.clone()),
1432                Dispatcher::Collection(collection) => Dispatcher::Collection(collection.clone()),
1433                Dispatcher::Actor(load) => Dispatcher::Actor(load.clone()),
1434            };
1435            self.entries.push(Entry {
1436                kind,
1437                template,
1438                dispatcher,
1439                authorize: None,
1440                alias: true,
1441            });
1442        }
1443        for (index, entry) in self.entries.iter().enumerate() {
1444            let expressions = entry.template.names().count();
1445            if !matches!(entry.dispatcher, Dispatcher::Object(_)) && expressions > 1 {
1446                errors.push(format!(
1447                    "{} {:?}: {} has more than one expression",
1448                    entry.noun(),
1449                    entry.kind,
1450                    entry.template.as_str()
1451                ));
1452            }
1453            for reserved in RESERVED {
1454                if entry.template.matches(reserved).is_some() {
1455                    errors.push(format!(
1456                        "{} claims {reserved}, which Ojak serves",
1457                        entry.template.as_str()
1458                    ));
1459                }
1460            }
1461            for other in &self.entries[index + 1..] {
1462                if entry.kind == other.kind && !entry.alias && !other.alias {
1463                    errors.push(format!("two dispatchers of kind {:?}", entry.kind));
1464                }
1465                // A path both match goes to the more specific; two that
1466                // nothing tells apart are ambiguous.
1467                if entry.template.overlaps(&other.template)
1468                    && entry.template.specificity(&other.template).is_eq()
1469                {
1470                    errors.push(format!(
1471                        "{} and {} could match one path",
1472                        entry.template.as_str(),
1473                        other.template.as_str()
1474                    ));
1475                }
1476            }
1477        }
1478        let mut inboxes = Vec::new();
1479        for (kind, template) in std::mem::take(&mut self.inboxes) {
1480            match Template::parse(&template) {
1481                Ok(template) => {
1482                    // One expression, or none for an actor whose template
1483                    // has none, such as an instance actor at `/actor` with
1484                    // its inbox at `/actor/inbox`.
1485                    match self.entries.iter().find(|entry| {
1486                        entry.kind == kind && matches!(entry.dispatcher, Dispatcher::Actor(_))
1487                    }) {
1488                        Some(actor) => {
1489                            let expected = actor.template.names().count().min(1);
1490                            if template.names().count() != expected {
1491                                errors.push(format!(
1492                                    "inbox {}: has to name its actor in as many expressions \
1493                                     as its actor's template does",
1494                                    template.as_str()
1495                                ));
1496                            }
1497                        }
1498                        None => {
1499                            errors.push(format!("inbox for {kind:?}, which is no actor kind"));
1500                        }
1501                    }
1502                    inboxes.push((kind, template));
1503                }
1504                Err(error) => errors.push(error.to_string()),
1505            }
1506        }
1507        let shared_inbox = match self.shared_inbox.take().map(|path| Template::parse(&path)) {
1508            Some(Ok(template)) if template.names().count() == 0 => Some(template),
1509            Some(Ok(template)) => {
1510                errors.push(format!(
1511                    "shared inbox {} has an expression",
1512                    template.as_str()
1513                ));
1514                None
1515            }
1516            Some(Err(error)) => {
1517                errors.push(error.to_string());
1518                None
1519            }
1520            None => None,
1521        };
1522        let inbox_templates: Vec<&Template> = inboxes
1523            .iter()
1524            .map(|(_, template)| template)
1525            .chain(shared_inbox.as_ref())
1526            .collect();
1527        for (n, template) in inbox_templates.iter().enumerate() {
1528            for other in self
1529                .entries
1530                .iter()
1531                .map(|entry| &entry.template)
1532                .chain(inbox_templates[n + 1..].iter().copied())
1533            {
1534                if template.overlaps(other) {
1535                    errors.push(format!(
1536                        "{} and {} could match one path",
1537                        template.as_str(),
1538                        other.as_str()
1539                    ));
1540                }
1541            }
1542            for reserved in RESERVED {
1543                if template.matches(reserved).is_some() {
1544                    errors.push(format!(
1545                        "{} claims {reserved}, which Ojak serves",
1546                        template.as_str()
1547                    ));
1548                }
1549            }
1550        }
1551        if !inbox_templates.is_empty() && self.signed_fetch.is_none() {
1552            errors.push("an inbox needs signed_fetch, to fetch and cache senders' keys".into());
1553        }
1554        for (kind, authorize) in std::mem::take(&mut self.authorize) {
1555            let mut found = false;
1556            for entry in self.entries.iter_mut().filter(|entry| entry.kind == kind) {
1557                entry.authorize = Some(authorize.clone());
1558                found = true;
1559            }
1560            if !found {
1561                errors.push(format!("authorize names no dispatcher of kind {kind:?}"));
1562            }
1563        }
1564        let templates = Arc::new(Templates {
1565            routes: self
1566                .entries
1567                .iter()
1568                .filter(|entry| !entry.alias)
1569                .map(|entry| (entry.kind.clone(), entry.noun(), entry.template.clone()))
1570                .collect(),
1571            inboxes: inboxes.clone(),
1572            shared_inbox: shared_inbox.clone(),
1573        });
1574        match origin {
1575            Some(origin) if errors.is_empty() => Ok(Federation {
1576                inner: Arc::new(Inner {
1577                    origin,
1578                    entries: self.entries,
1579                    templates,
1580                    key_pairs: self.key_pairs,
1581                    handle: self.handle,
1582                    map_alias: self.map_alias,
1583                    webfinger_links: self.webfinger_links,
1584                    nodeinfo: self.nodeinfo,
1585                    signed_fetch: self.signed_fetch,
1586                    on_error: self.on_error,
1587                    inboxes,
1588                    shared_inbox,
1589                    listeners: self.listeners,
1590                    fallback_listener: self.fallback_listener,
1591                    blocked: self.blocked,
1592                    on_unverified: self.on_unverified,
1593                    inbox_queue: self.inbox_queue,
1594                    gateway: self.gateway,
1595                    gateway_media: self.gateway_media,
1596                    gateway_inbox: self.gateway_inbox,
1597                    forward: self.forward,
1598                    read_as_written: self.read_as_written,
1599                    linked_data_first: self.linked_data_first,
1600                    remote_contexts: self.remote_contexts,
1601                }),
1602            }),
1603            _ => Err(BuildError(errors)),
1604        }
1605    }
1606}
1607
1608/// What a context remembers of the request it was made for.
1609struct RequestInfo {
1610    method: String,
1611    path_and_query: String,
1612    host: String,
1613    headers: Vec<(String, String)>,
1614}
1615
1616impl RequestInfo {
1617    fn of(request: &http::request::Parts, host: String) -> Self {
1618        Self {
1619            method: request.method.as_str().to_owned(),
1620            path_and_query: request.uri.path_and_query().map_or_else(
1621                || request.uri.path().to_owned(),
1622                |pq| pq.as_str().to_owned(),
1623            ),
1624            host,
1625            headers: request
1626                .headers
1627                .iter()
1628                .filter_map(|(name, value)| {
1629                    Some((name.as_str().to_owned(), value.to_str().ok()?.to_owned()))
1630                })
1631                .collect(),
1632        }
1633    }
1634}
1635
1636struct ContextInner<D> {
1637    federation: Arc<Inner<D>>,
1638    data: D,
1639    origin: Url,
1640    request: Option<RequestInfo>,
1641    signer: tokio::sync::OnceCell<Signing>,
1642    /// Headers the application set on the response, in the order set: a
1643    /// value, or `None` to send none.
1644    response_headers: std::sync::Mutex<Vec<(HeaderName, Option<HeaderValue>)>>,
1645}
1646
1647/// The templates URIs are built from, apart from what serves them.
1648#[derive(Debug)]
1649struct Templates {
1650    /// Each kind's template, by kind and noun; aliases are not built.
1651    routes: Vec<(String, &'static str, Template)>,
1652    inboxes: Vec<(String, Template)>,
1653    shared_inbox: Option<Template>,
1654}
1655
1656/// The fragment of an actor's IRI its key is named by, as Mastodon names
1657/// it.
1658const KEY_FRAGMENT: &str = "main-key";
1659
1660/// The URIs of what a federation serves, in one origin, built from the
1661/// templates their routes were registered with.
1662///
1663/// [`Federation::uris`] gives them where there is no request, and
1664/// [`Context::uris`] within one. They carry none of the application's data
1665/// and are cheap to clone, so an application can keep them in its own
1666/// state, for code that runs outside any request: creating an account,
1667/// sending a post from a background job. An application serving several
1668/// hosts keeps one and takes each tenant's with [`Uris::with_origin`].
1669#[derive(Clone, Debug)]
1670pub struct Uris {
1671    templates: Arc<Templates>,
1672    origin: Url,
1673}
1674
1675impl Uris {
1676    /// The origin these URIs are in.
1677    #[must_use]
1678    pub fn origin(&self) -> &Url {
1679        &self.origin
1680    }
1681
1682    /// The same URIs, in `origin`.
1683    #[must_use]
1684    pub fn with_origin(&self, origin: Url) -> Self {
1685        Self {
1686            templates: self.templates.clone(),
1687            origin,
1688        }
1689    }
1690
1691    fn template(&self, kind: &str, noun: &str) -> Result<&Template, UriError> {
1692        self.templates
1693            .routes
1694            .iter()
1695            .find_map(|(k, n, template)| (k == kind && *n == noun).then_some(template))
1696            .ok_or_else(|| UriError::UnknownKind(kind.to_owned()))
1697    }
1698
1699    fn uri(&self, template: &Template, values: &Values) -> Result<Url, UriError> {
1700        let path = template.expand(values).map_err(UriError::Template)?;
1701        let mut url = self.origin.clone();
1702        url.set_path(&path);
1703        url.set_query(None);
1704        url.set_fragment(None);
1705        Ok(url)
1706    }
1707
1708    fn single(template: &Template, identifier: &str) -> Values {
1709        template
1710            .names()
1711            .map(|name| (name.to_owned(), identifier.to_owned()))
1712            .collect()
1713    }
1714
1715    /// The URI of the actor of `kind` with `identifier`.
1716    ///
1717    /// # Errors
1718    ///
1719    /// When no actor dispatcher is of `kind`, or `identifier` is empty for a
1720    /// template that needs one.
1721    pub fn actor_uri(&self, kind: &str, identifier: &str) -> Result<Url, UriError> {
1722        let template = self.template(kind, "actor")?;
1723        self.uri(template, &Self::single(template, identifier))
1724    }
1725
1726    /// The ID of the key the actor of `kind` with `identifier` signs with:
1727    /// its IRI with the fragment `main-key`, as Mastodon names it, and as
1728    /// the actor document should publish it.
1729    ///
1730    /// # Errors
1731    ///
1732    /// As [`Uris::actor_uri`].
1733    pub fn key_id(&self, kind: &str, identifier: &str) -> Result<Url, UriError> {
1734        let mut uri = self.actor_uri(kind, identifier)?;
1735        uri.set_fragment(Some(KEY_FRAGMENT));
1736        Ok(uri)
1737    }
1738
1739    /// The URI of the object of `kind` with `values`.
1740    ///
1741    /// # Errors
1742    ///
1743    /// When no object dispatcher is of `kind`, or `values` do not fill its
1744    /// template.
1745    pub fn object_uri(&self, kind: &str, values: &[(&str, &str)]) -> Result<Url, UriError> {
1746        let template = self.template(kind, "object")?;
1747        self.uri(template, &values.iter().copied().collect())
1748    }
1749
1750    /// The URI of the collection `kind` of what `identifier` names.
1751    ///
1752    /// # Errors
1753    ///
1754    /// As [`Uris::actor_uri`], for collections.
1755    pub fn collection_uri(&self, kind: &str, identifier: &str) -> Result<Url, UriError> {
1756        let template = self.template(kind, "collection")?;
1757        self.uri(template, &Self::single(template, identifier))
1758    }
1759
1760    /// The URI of the inbox of the actor of `kind` with `identifier`.
1761    ///
1762    /// # Errors
1763    ///
1764    /// When no inbox is registered for `kind`, or `identifier` does not fill
1765    /// its template.
1766    pub fn inbox_uri(&self, kind: &str, identifier: &str) -> Result<Url, UriError> {
1767        let template = self
1768            .templates
1769            .inboxes
1770            .iter()
1771            .find_map(|(inbox, template)| (inbox == kind).then_some(template))
1772            .ok_or_else(|| UriError::UnknownKind(kind.to_owned()))?;
1773        self.uri(template, &Self::single(template, identifier))
1774    }
1775
1776    /// The URI of the shared inbox.
1777    ///
1778    /// # Errors
1779    ///
1780    /// When no shared inbox is registered.
1781    pub fn shared_inbox_uri(&self) -> Result<Url, UriError> {
1782        let template = self
1783            .templates
1784            .shared_inbox
1785            .as_ref()
1786            .ok_or_else(|| UriError::UnknownKind("shared inbox".to_owned()))?;
1787        self.uri(template, &Values::new())
1788    }
1789}
1790
1791/// What every callback receives: the application's data, the canonical
1792/// origin, and the request, if there is one. Cheap to clone.
1793pub struct Context<D> {
1794    inner: Arc<ContextInner<D>>,
1795}
1796
1797impl<D> Clone for Context<D> {
1798    fn clone(&self) -> Self {
1799        Self {
1800            inner: self.inner.clone(),
1801        }
1802    }
1803}
1804
1805impl<D: Clone + Send + Sync + 'static> Context<D> {
1806    fn new(federation: Arc<Inner<D>>, data: D, origin: Url, request: Option<RequestInfo>) -> Self {
1807        Self {
1808            inner: Arc::new(ContextInner {
1809                federation,
1810                data,
1811                origin,
1812                request,
1813                signer: tokio::sync::OnceCell::new(),
1814                response_headers: std::sync::Mutex::new(Vec::new()),
1815            }),
1816        }
1817    }
1818
1819    /// The application's data.
1820    #[must_use]
1821    pub fn data(&self) -> &D {
1822        &self.inner.data
1823    }
1824
1825    /// The canonical origin every URI is built in.
1826    #[must_use]
1827    pub fn origin(&self) -> &Url {
1828        &self.inner.origin
1829    }
1830
1831    /// The URIs of what is registered, in the canonical origin.
1832    #[must_use]
1833    pub fn uris(&self) -> Uris {
1834        Uris {
1835            templates: self.inner.federation.templates.clone(),
1836            origin: self.inner.origin.clone(),
1837        }
1838    }
1839
1840    /// The URI of the actor of `kind` with `identifier`.
1841    ///
1842    /// # Errors
1843    ///
1844    /// When no actor dispatcher is of `kind`, or `identifier` is empty for a
1845    /// template that needs one.
1846    pub fn actor_uri(&self, kind: &str, identifier: &str) -> Result<Url, UriError> {
1847        self.uris().actor_uri(kind, identifier)
1848    }
1849
1850    /// The ID of the key the actor of `kind` with `identifier` signs with;
1851    /// see [`Uris::key_id`].
1852    ///
1853    /// # Errors
1854    ///
1855    /// As [`Context::actor_uri`].
1856    pub fn key_id(&self, kind: &str, identifier: &str) -> Result<Url, UriError> {
1857        self.uris().key_id(kind, identifier)
1858    }
1859
1860    /// The URI of the object of `kind` with `values`.
1861    ///
1862    /// # Errors
1863    ///
1864    /// When no object dispatcher is of `kind`, or `values` do not fill its
1865    /// template.
1866    pub fn object_uri(&self, kind: &str, values: &[(&str, &str)]) -> Result<Url, UriError> {
1867        self.uris().object_uri(kind, values)
1868    }
1869
1870    /// The URI of the collection `kind` of what `identifier` names.
1871    ///
1872    /// # Errors
1873    ///
1874    /// As [`Context::actor_uri`], for collections.
1875    pub fn collection_uri(&self, kind: &str, identifier: &str) -> Result<Url, UriError> {
1876        self.uris().collection_uri(kind, identifier)
1877    }
1878
1879    /// The URI of the inbox of the actor of `kind` with `identifier`.
1880    ///
1881    /// # Errors
1882    ///
1883    /// As [`Context::actor_uri`], for inboxes.
1884    pub fn inbox_uri(&self, kind: &str, identifier: &str) -> Result<Url, UriError> {
1885        self.uris().inbox_uri(kind, identifier)
1886    }
1887
1888    /// The URI of the shared inbox.
1889    ///
1890    /// # Errors
1891    ///
1892    /// When no shared inbox is registered.
1893    pub fn shared_inbox_uri(&self) -> Result<Url, UriError> {
1894        self.uris().shared_inbox_uri()
1895    }
1896
1897    /// Whether `host`, with its port if it has one, is the canonical
1898    /// origin's or one of its aliases.
1899    #[must_use]
1900    pub fn is_our_host(&self, host: &str) -> bool {
1901        let host = normalize_host(host);
1902        match &self.inner.federation.origin {
1903            OriginRule::Fixed(origin) => authority(origin) == host,
1904            OriginRule::PerHost(origin_for) => {
1905                origin_for(&host, &self.inner.data).as_ref() == Some(&self.inner.origin)
1906            }
1907        }
1908    }
1909
1910    /// What `iri` is, if it is ours: on the canonical origin or an alias, and
1911    /// matching a registered template.
1912    #[must_use]
1913    pub fn parse_uri(&self, iri: &str) -> Option<Route> {
1914        let url = Url::parse(iri).ok()?;
1915        if url.scheme() != self.inner.origin.scheme() || !self.is_our_host(&authority(&url)) {
1916            return None;
1917        }
1918        let (index, values) = self.inner.federation.route(url.path())?;
1919        let entry = &self.inner.federation.entries[index];
1920        Some(match entry.dispatcher {
1921            Dispatcher::Actor(_) => Route::Actor(ActorRef::new(
1922                entry.kind.clone(),
1923                values.single().unwrap_or_default(),
1924            )),
1925            Dispatcher::Object(_) => Route::Object {
1926                kind: entry.kind.clone(),
1927                values,
1928            },
1929            Dispatcher::Collection(_) => Route::Collection {
1930                kind: entry.kind.clone(),
1931                identifier: values.single().unwrap_or_default().to_owned(),
1932            },
1933        })
1934    }
1935
1936    /// The identifier of the actor of `kind` that `iri` is, if it is one of
1937    /// ours: what a listener checks a `Follow`'s object against.
1938    #[must_use]
1939    pub fn parse_actor(&self, kind: &str, iri: &str) -> Option<String> {
1940        match self.parse_uri(iri)? {
1941            Route::Actor(actor) if actor.kind == kind => Some(actor.identifier),
1942            _ => None,
1943        }
1944    }
1945
1946    /// The values of the object of `kind` that `iri` is, if it is one of
1947    /// ours: what a listener checks an `inReplyTo` or a `Like`'s object
1948    /// against.
1949    #[must_use]
1950    pub fn parse_object(&self, kind: &str, iri: &str) -> Option<Values> {
1951        match self.parse_uri(iri)? {
1952            Route::Object {
1953                kind: found,
1954                values,
1955            } if found == kind => Some(values),
1956            _ => None,
1957        }
1958    }
1959
1960    /// The public keys `actor` publishes, from the key-pairs dispatcher; none
1961    /// when there is no such dispatcher.
1962    ///
1963    /// # Errors
1964    ///
1965    /// What the dispatcher returns.
1966    pub async fn actor_keys(&self, actor: &ActorRef) -> Result<Vec<PublicKey>, Error> {
1967        match &self.inner.federation.key_pairs {
1968            Some(keys) => keys(self.clone(), actor.clone()).await,
1969            None => Ok(Vec::new()),
1970        }
1971    }
1972
1973    /// The actor who signed the request, verified: the signature is sound,
1974    /// made for this host and recently, and made with a key its actor
1975    /// publishes. `None` when the request is unsigned, the signature fails,
1976    /// there is no request, or signed fetches are not configured. Verified
1977    /// once per request, however often it is asked.
1978    pub async fn signer(&self) -> Option<Url> {
1979        match self.signing().await {
1980            Signing::Verified(signer) => Some(signer),
1981            _ => None,
1982        }
1983    }
1984
1985    /// How the request was signed: not at all, by an actor whose signature
1986    /// verifies, with a key on a server [`Builder::blocked`] refuses, or with
1987    /// a signature that does not hold. Verified once per request, however
1988    /// often it is asked, and as [`Context::signer`] verifies it.
1989    pub async fn signing(&self) -> Signing {
1990        self.inner
1991            .signer
1992            .get_or_init(|| signer::verify(self))
1993            .await
1994            .clone()
1995    }
1996
1997    /// Load the actor `actor` through its dispatcher.
1998    async fn load_actor(&self, actor: &ActorRef) -> Result<Found<Value>, Error> {
1999        let Some(entry) = self
2000            .inner
2001            .federation
2002            .entries
2003            .iter()
2004            .find(|entry| entry.kind == actor.kind && entry.noun() == "actor")
2005        else {
2006            return Ok(Found::NotFound);
2007        };
2008        match &entry.dispatcher {
2009            Dispatcher::Actor(load) => load(self.clone(), actor.identifier.clone()).await,
2010            _ => Ok(Found::NotFound),
2011        }
2012    }
2013
2014    /// The query of the request, if there is a request and it has one: for a
2015    /// dispatcher that reads parameters of its own, such as how a collection
2016    /// it writes itself is paged.
2017    #[must_use]
2018    pub fn query(&self) -> Option<&str> {
2019        let request = self.inner.request.as_ref()?;
2020        request
2021            .path_and_query
2022            .split_once('?')
2023            .map(|(_, query)| query)
2024    }
2025
2026    /// The value of the query parameter `name`, decoded, if the request has
2027    /// it: the first, when it has it more than once.
2028    #[must_use]
2029    pub fn query_value(&self, name: &str) -> Option<String> {
2030        url::form_urlencoded::parse(self.query()?.as_bytes())
2031            .find(|(key, _)| key == name)
2032            .map(|(_, value)| value.into_owned())
2033    }
2034
2035    /// The value of the request's header `name`, if it has one and it is
2036    /// text.
2037    #[must_use]
2038    pub fn request_header(&self, name: &str) -> Option<String> {
2039        let request = self.inner.request.as_ref()?;
2040        request
2041            .headers
2042            .iter()
2043            .find(|(header, _)| header.eq_ignore_ascii_case(name))
2044            .map(|(_, value)| value.clone())
2045    }
2046
2047    /// Send `value` as the response's header `name`, or no such header
2048    /// when it is `None`, in place of what Ojak would send: for a
2049    /// dispatcher or guard saying how the response may be cached, such as
2050    /// its `Cache-Control` and the request headers it `Vary`s on. It
2051    /// applies to whatever the request is answered with, a refusal or a 404
2052    /// included. A name or value that is no header is ignored.
2053    pub fn set_response_header(&self, name: &str, value: Option<&str>) {
2054        let Ok(name) = HeaderName::try_from(name) else {
2055            return;
2056        };
2057        let value = match value.map(HeaderValue::try_from) {
2058            Some(Ok(value)) => Some(value),
2059            Some(Err(_)) => return,
2060            None => None,
2061        };
2062        if let Ok(mut headers) = self.inner.response_headers.lock() {
2063            headers.push((name, value));
2064        }
2065    }
2066
2067    /// `response` with the headers the application set.
2068    fn with_response_headers(
2069        &self,
2070        mut response: http::Response<Vec<u8>>,
2071    ) -> http::Response<Vec<u8>> {
2072        if let Ok(headers) = self.inner.response_headers.lock() {
2073            for (name, value) in headers.iter() {
2074                match value {
2075                    Some(value) => {
2076                        response.headers_mut().insert(name.clone(), value.clone());
2077                    }
2078                    None => {
2079                        response.headers_mut().remove(name);
2080                    }
2081                }
2082            }
2083        }
2084        response
2085    }
2086
2087    /// The URL the request was for, in the canonical origin.
2088    fn request_url(&self) -> Url {
2089        let mut url = self.inner.origin.clone();
2090        if let Some(request) = &self.inner.request {
2091            let (path, query) = request
2092                .path_and_query
2093                .split_once('?')
2094                .map_or((request.path_and_query.as_str(), None), |(p, q)| {
2095                    (p, Some(q))
2096                });
2097            url.set_path(path);
2098            url.set_query(query);
2099        }
2100        url
2101    }
2102
2103    fn report(&self, error: &Error) {
2104        if let Some(report) = &self.inner.federation.on_error {
2105            report(error);
2106        }
2107    }
2108}
2109
2110/// `host` lower-cased, without a trailing dot on its name.
2111fn normalize_host(host: &str) -> String {
2112    let host = host.to_ascii_lowercase();
2113    if host.starts_with('[') {
2114        // An IPv6 literal, whose colons are not a port's.
2115        return host;
2116    }
2117    match host.rsplit_once(':') {
2118        Some((name, port)) if port.chars().all(|c| c.is_ascii_digit()) => {
2119            format!("{}:{port}", name.trim_end_matches('.'))
2120        }
2121        _ => host.trim_end_matches('.').to_owned(),
2122    }
2123}
2124
2125/// The host a request was sent to: `Host`, or the URI's authority, as
2126/// HTTP/2 sends it.
2127fn request_host(request: &http::request::Parts) -> String {
2128    let host = request
2129        .headers
2130        .get(header::HOST)
2131        .and_then(|value| value.to_str().ok())
2132        .or_else(|| request.uri.authority().map(http::uri::Authority::as_str))
2133        .unwrap_or_default();
2134    normalize_host(host)
2135}
2136
2137/// A URL's host, with its port when it has one other than its scheme's.
2138fn authority(url: &Url) -> String {
2139    let host = url.host_str().unwrap_or_default();
2140    match url.port() {
2141        Some(port) => format!("{host}:{port}"),
2142        None => host.to_owned(),
2143    }
2144}
2145
2146fn response(status: StatusCode, content_type: &str, body: Vec<u8>) -> http::Response<Vec<u8>> {
2147    let mut response = http::Response::new(body);
2148    *response.status_mut() = status;
2149    if let Ok(value) = HeaderValue::from_str(content_type) {
2150        response.headers_mut().insert(header::CONTENT_TYPE, value);
2151    }
2152    response
2153}
2154
2155fn empty(status: StatusCode) -> http::Response<Vec<u8>> {
2156    let mut response = http::Response::new(Vec::new());
2157    *response.status_mut() = status;
2158    response
2159}
2160
2161fn method_not_allowed() -> http::Response<Vec<u8>> {
2162    let mut response = empty(StatusCode::METHOD_NOT_ALLOWED);
2163    response
2164        .headers_mut()
2165        .insert(header::ALLOW, HeaderValue::from_static("GET, HEAD"));
2166    response
2167}
2168
2169fn unauthorized(signed: bool) -> http::Response<Vec<u8>> {
2170    let mut response = empty(StatusCode::UNAUTHORIZED);
2171    if !signed {
2172        // What a peer needs to know to try again, signed.
2173        response.headers_mut().insert(
2174            header::WWW_AUTHENTICATE,
2175            HeaderValue::from_static("Signature realm=\"ActivityPub\""),
2176        );
2177    }
2178    response
2179        .headers_mut()
2180        .insert(header::VARY, HeaderValue::from_static("Accept, Signature"));
2181    response
2182}
2183
2184fn forbidden() -> http::Response<Vec<u8>> {
2185    let mut response = empty(StatusCode::FORBIDDEN);
2186    response
2187        .headers_mut()
2188        .insert(header::VARY, HeaderValue::from_static("Accept, Signature"));
2189    response
2190}
2191
2192fn without_body_if(head: bool, mut response: http::Response<Vec<u8>>) -> http::Response<Vec<u8>> {
2193    if head {
2194        let length = response.body().len();
2195        response.body_mut().clear();
2196        response
2197            .headers_mut()
2198            .insert(header::CONTENT_LENGTH, HeaderValue::from(length));
2199    }
2200    response
2201}
2202
2203/// An ActivityPub document, with the default `@context` when it has none.
2204pub(crate) fn activity(status: StatusCode, mut document: Value) -> http::Response<Vec<u8>> {
2205    if let Some(members) = document.as_object_mut()
2206        && !members.contains_key("@context")
2207    {
2208        let mut with_context = serde_json::Map::new();
2209        with_context.insert("@context".into(), default_context());
2210        with_context.append(members);
2211        *members = with_context;
2212    }
2213    let mut response = response(
2214        status,
2215        ACTIVITY_JSON,
2216        serde_json::to_vec(&document).unwrap_or_default(),
2217    );
2218    response
2219        .headers_mut()
2220        .insert(header::VARY, HeaderValue::from_static("Accept"));
2221    response
2222}
2223
2224/// Whether `path` is under the well-known path gateways serve at.
2225fn is_gateway_path(path: &str) -> bool {
2226    path.starts_with(crate::portable::GATEWAY_PATH)
2227}
2228
2229/// The media type a gateway serves portable objects as (FEP-ef61).
2230pub const PORTABLE_JSON: &str =
2231    "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"";
2232
2233/// Why a gateway does not serve what the application found.
2234#[derive(Debug)]
2235enum Unservable {
2236    /// It is another object than the one asked for: answered as one the
2237    /// gateway does not have.
2238    Another { id: Option<String>, uri: String },
2239    /// It is not authentic, and anyone it was served to would refuse it.
2240    Unproven {
2241        uri: String,
2242        why: crate::portable::PortableError,
2243    },
2244}
2245
2246impl Unservable {
2247    fn status(&self) -> StatusCode {
2248        match self {
2249            Self::Another { .. } => StatusCode::NOT_FOUND,
2250            Self::Unproven { .. } => StatusCode::INTERNAL_SERVER_ERROR,
2251        }
2252    }
2253}
2254
2255impl std::fmt::Display for Unservable {
2256    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2257        match self {
2258            Self::Another { id: Some(id), uri } => {
2259                write!(f, "gateway: found {id} for {uri}, not serving it")
2260            }
2261            Self::Another { id: None, uri } => {
2262                write!(
2263                    f,
2264                    "gateway: found a document with no id for {uri}, not serving it"
2265                )
2266            }
2267            Self::Unproven { uri, why } => write!(f, "gateway: not serving {uri}: {why}"),
2268        }
2269    }
2270}
2271
2272/// Whether `document` may be served as `uri`: it is that object, and it is
2273/// authentic, as whoever it is served to will check. A collection needs no
2274/// proof, as FEP-ef61 has it, since its consumers take it only from its
2275/// owner's gateways; one with a proof is held to it.
2276async fn servable<D: Clone + Send + Sync + 'static>(
2277    context: &Context<D>,
2278    document: &Value,
2279    uri: &ApUri,
2280) -> Result<(), Unservable> {
2281    let id = document.get("id").and_then(Value::as_str);
2282    if id.and_then(ApUri::parse).as_ref() != Some(uri) {
2283        return Err(Unservable::Another {
2284            id: id.map(str::to_owned),
2285            uri: uri.canonical(),
2286        });
2287    }
2288    if document.get("proof").is_none() && is_collection(document) {
2289        return Ok(());
2290    }
2291    let fetcher = context
2292        .inner
2293        .federation
2294        .signed_fetch
2295        .as_ref()
2296        .map(|settings| settings.fetcher(context.data()));
2297    let resolver = fetcher.as_deref().and_then(crate::fetch::Fetcher::resolver);
2298    crate::portable::verify(document, resolver)
2299        .await
2300        .map(drop)
2301        .map_err(|why| Unservable::Unproven {
2302            uri: uri.canonical(),
2303            why,
2304        })
2305}
2306
2307fn is_collection(document: &Value) -> bool {
2308    const COLLECTIONS: [&str; 4] = [
2309        "Collection",
2310        "OrderedCollection",
2311        "CollectionPage",
2312        "OrderedCollectionPage",
2313    ];
2314    crate::portable::has_type(document, &COLLECTIONS)
2315}
2316
2317/// A portable object as a gateway serves it: the document as the
2318/// application stored it, since its proof covers it. A signed Tombstone is
2319/// served as what is gone.
2320fn portable_found(found: Found<Value>, uri: &ApUri) -> http::Response<Vec<u8>> {
2321    match found {
2322        Found::Found(document) => {
2323            let status = if crate::portable::has_type(&document, &["Tombstone"]) {
2324                StatusCode::GONE
2325            } else {
2326                StatusCode::OK
2327            };
2328            let body = serde_json::to_vec(&document).unwrap_or_default();
2329            response(status, PORTABLE_JSON, body)
2330        }
2331        Found::Gone(deleted) => {
2332            let mut tombstone = json!({
2333                "@context": "https://www.w3.org/ns/activitystreams",
2334                "id": uri.canonical(),
2335                "type": "Tombstone",
2336            });
2337            if let Some(deleted) = deleted {
2338                tombstone["deleted"] = deleted.to_rfc3339_opts(SecondsFormat::Secs, true).into();
2339            }
2340            let body = serde_json::to_vec(&tombstone).unwrap_or_default();
2341            response(StatusCode::GONE, PORTABLE_JSON, body)
2342        }
2343        Found::NotFound => empty(StatusCode::NOT_FOUND),
2344        Found::Redirect(location) => redirect(&location),
2345    }
2346}
2347
2348/// A `302 Found` to `location`.
2349fn redirect(location: &Url) -> http::Response<Vec<u8>> {
2350    let mut response = empty(StatusCode::FOUND);
2351    if let Ok(value) = HeaderValue::from_str(location.as_str()) {
2352        response.headers_mut().insert(header::LOCATION, value);
2353    }
2354    response
2355        .headers_mut()
2356        .insert(header::VARY, HeaderValue::from_static("Accept"));
2357    response
2358}
2359
2360fn found(found: Found<Value>, url: &Url) -> http::Response<Vec<u8>> {
2361    match found {
2362        Found::Found(document) => activity(StatusCode::OK, document),
2363        Found::Gone(deleted) => {
2364            let mut tombstone = json!({
2365                "@context": "https://www.w3.org/ns/activitystreams",
2366                "id": url.as_str(),
2367                "type": "Tombstone",
2368            });
2369            if let Some(deleted) = deleted {
2370                tombstone["deleted"] = deleted.to_rfc3339_opts(SecondsFormat::Secs, true).into();
2371            }
2372            activity(StatusCode::GONE, tombstone)
2373        }
2374        Found::NotFound => {
2375            let mut response = empty(StatusCode::NOT_FOUND);
2376            response
2377                .headers_mut()
2378                .insert(header::VARY, HeaderValue::from_static("Accept"));
2379            response
2380        }
2381        Found::Redirect(location) => redirect(&location),
2382    }
2383}
2384
2385/// A key-value store, object-safe, for what the federation keeps.
2386trait DynKv: Send + Sync {
2387    fn get<'a>(&'a self, key: &'a [&'a str]) -> BoxFuture<'a, Result<Option<Value>, KvError>>;
2388    fn set<'a>(
2389        &'a self,
2390        key: &'a [&'a str],
2391        value: Value,
2392        ttl: Option<Duration>,
2393    ) -> BoxFuture<'a, Result<(), KvError>>;
2394    fn insert<'a>(
2395        &'a self,
2396        key: &'a [&'a str],
2397        value: Value,
2398        ttl: Option<Duration>,
2399    ) -> BoxFuture<'a, Result<bool, KvError>>;
2400    fn delete<'a>(&'a self, key: &'a [&'a str]) -> BoxFuture<'a, Result<(), KvError>>;
2401}
2402
2403impl<K: KvStore> DynKv for K {
2404    fn get<'a>(&'a self, key: &'a [&'a str]) -> BoxFuture<'a, Result<Option<Value>, KvError>> {
2405        Box::pin(KvStore::get(self, key))
2406    }
2407
2408    fn set<'a>(
2409        &'a self,
2410        key: &'a [&'a str],
2411        value: Value,
2412        ttl: Option<Duration>,
2413    ) -> BoxFuture<'a, Result<(), KvError>> {
2414        Box::pin(KvStore::set(self, key, value, ttl))
2415    }
2416
2417    fn insert<'a>(
2418        &'a self,
2419        key: &'a [&'a str],
2420        value: Value,
2421        ttl: Option<Duration>,
2422    ) -> BoxFuture<'a, Result<bool, KvError>> {
2423        Box::pin(KvStore::insert(self, key, value, ttl))
2424    }
2425
2426    fn delete<'a>(&'a self, key: &'a [&'a str]) -> BoxFuture<'a, Result<(), KvError>> {
2427        Box::pin(KvStore::delete(self, key))
2428    }
2429}
2430
2431#[cfg(test)]
2432mod tests {
2433    use super::*;
2434
2435    #[test]
2436    fn hosts_are_compared_without_case_or_a_trailing_dot() {
2437        assert_eq!(normalize_host("Oeee.Cafe."), "oeee.cafe");
2438        assert_eq!(normalize_host("oeee.cafe.:8443"), "oeee.cafe:8443");
2439        assert_eq!(normalize_host("127.0.0.1:3000"), "127.0.0.1:3000");
2440        assert_eq!(normalize_host("[::1]:3000"), "[::1]:3000");
2441        assert_eq!(normalize_host("[::1]"), "[::1]");
2442    }
2443
2444    #[test]
2445    fn keys_go_where_each_is_read() {
2446        let mut actor = json!({"id": "https://a.example/users/1", "type": "Person"});
2447        with_keys(
2448            &mut actor,
2449            &[
2450                PublicKey::Multikey {
2451                    id: "https://a.example/users/1#ed25519-key".into(),
2452                    multibase: "z6Mk".into(),
2453                },
2454                PublicKey::Rsa {
2455                    id: "https://a.example/users/1#main-key".into(),
2456                    pem: "PEM".into(),
2457                },
2458            ],
2459        );
2460        assert_eq!(
2461            actor["publicKey"],
2462            json!({"id": "https://a.example/users/1#main-key", "owner": "https://a.example/users/1", "publicKeyPem": "PEM"})
2463        );
2464        assert_eq!(
2465            actor["assertionMethod"][0]["controller"],
2466            "https://a.example/users/1"
2467        );
2468        assert_eq!(actor["assertionMethod"][0]["type"], "Multikey");
2469    }
2470}