actpub_webfinger/lib.rs
1//! `WebFinger` (RFC 7033) primitives for `ActivityPub` account discovery.
2//!
3//! `WebFinger` is the discovery mechanism used across the Fediverse to map
4//! `acct:user@host` identifiers to `ActivityPub` actor URLs via a
5//! [`/.well-known/webfinger`][endpoint] endpoint returning a JSON Resource
6//! Descriptor (JRD).
7//!
8//! # Example (client)
9//!
10//! ```no_run
11//! # #[cfg(feature = "client")]
12//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
13//! use actpub_webfinger::{Account, resolve};
14//!
15//! let client = reqwest::Client::new();
16//! let account = Account::parse("acct:gargron@mastodon.social")?;
17//! let jrd = resolve(&account, &client).await?;
18//!
19//! if let Some(link) = jrd.activitypub_actor() {
20//! println!("Actor URL: {}", link.href.as_ref().unwrap());
21//! }
22//! # Ok(()) }
23//! ```
24//!
25//! # Example (server)
26//!
27//! ```
28//! use actpub_webfinger::{Jrd, JrdLink, rels};
29//!
30//! let jrd = Jrd::builder("acct:alice@example.com")
31//! .alias("https://example.com/@alice")
32//! .link(
33//! JrdLink::builder(rels::ACTIVITYPUB_ACTOR)
34//! .href("https://example.com/users/alice".parse().unwrap())
35//! .media_type("application/activity+json")
36//! .build(),
37//! )
38//! .build();
39//!
40//! let json = serde_json::to_string(&jrd).unwrap();
41//! assert!(json.contains(r#""subject":"acct:alice@example.com""#));
42//! ```
43//!
44//! [endpoint]: https://datatracker.ietf.org/doc/html/rfc7033#section-4
45#![cfg_attr(docsrs, feature(doc_cfg))]
46#![allow(
47 clippy::error_impl_error,
48 reason = "`Error` is the idiomatic name for the crate's top-level error enum, matching the `thiserror` convention used pervasively in the Rust ecosystem"
49)]
50#![cfg_attr(
51 test,
52 allow(
53 clippy::indexing_slicing,
54 reason = "JSON field indexing via `Value[\"key\"]` is ergonomic inside tests and its panic-on-missing behaviour is the desired failure mode when fixtures are wrong"
55 )
56)]
57
58mod account;
59#[cfg(feature = "client")]
60#[cfg_attr(docsrs, doc(cfg(feature = "client")))]
61mod client;
62mod error;
63mod jrd;
64
65pub mod rels;
66
67pub use self::account::Account;
68#[cfg(feature = "client")]
69#[cfg_attr(docsrs, doc(cfg(feature = "client")))]
70pub use self::client::{
71 DEFAULT_CONNECT_TIMEOUT, DEFAULT_MAX_BODY_BYTES, DEFAULT_REQUEST_TIMEOUT, fetch_at,
72 fetch_at_with_limit, recommended_client, resolve,
73};
74pub use self::error::Error;
75pub use self::jrd::{Jrd, JrdBuilder, JrdLink, JrdLinkBuilder};
76
77/// Crate [`Result`] alias with the default error type set to [`Error`].
78pub type Result<T, E = Error> = core::result::Result<T, E>;
79
80/// The IANA-registered media type for a `WebFinger` JRD response.
81pub const MEDIA_TYPE: &str = "application/jrd+json";
82
83/// The well-known URI path for the `WebFinger` endpoint (RFC 7033 ยง4).
84pub const WELL_KNOWN_PATH: &str = "/.well-known/webfinger";