0.5.1: axum-only apub_federation, rustls ring-only, install ring provider

This commit is contained in:
2026-10-26 03:41:08 +01:00
parent b569efe715
commit b88a187749
10 changed files with 82 additions and 636 deletions

View File

@@ -1,5 +1,9 @@
# Changelog
## [0.5.1] — 2026-10-26
- build: axum-only activitypub_federation, rustls-ring only — drops actix-web and aws-lc from consumers' builds
## [0.5.0] — 2026-07-25
### Breaking changes

669
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
[package]
name = "k-ap"
version = "0.5.0"
version = "0.5.1"
edition = "2024"
description = "Generic ActivityPub protocol layer"
license = "MIT"
@@ -18,9 +18,10 @@ thiserror = "2"
tracing = "0.1"
async-trait = "0.1"
axum = { version = "0.8", features = ["macros"] }
reqwest = { version = "0.13", features = ["json"] }
reqwest = { version = "0.13", default-features = false, features = ["json", "charset", "http2", "system-proxy", "rustls-no-provider"] }
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12", "logging"] }
url = { version = "2", features = ["serde"] }
enum_delegate = "0.2"
activitypub_federation = "0.7.0-beta.11"
activitypub_federation = { version = "0.7.0-beta.11", default-features = false, features = ["axum"] }
zeroize = { version = "1", features = ["derive"] }
paste = "1"

View File

@@ -37,6 +37,7 @@ impl ApFederationConfig {
debug: bool,
signing_actor: Option<&DbActor>,
) -> anyhow::Result<Self> {
crate::tls::ensure_crypto_provider();
let config = if debug {
FederationConfig::builder()
.domain(&data.domain)

View File

@@ -11,6 +11,7 @@ pub mod service;
/// Mock builders for testing. Not behind `#[cfg(test)]` so downstream crates
/// can use them in their own test suites.
pub mod testing;
pub(crate) mod tls;
pub(crate) mod url_scheme;
pub(crate) mod urls;
pub(crate) mod user;

View File

@@ -21,6 +21,7 @@ impl ActivityPubService {
) -> anyhow::Result<()> {
let outbox_parsed = url::Url::parse(outbox_url)?;
crate::security::validate_url(&outbox_parsed).await?;
crate::tls::ensure_crypto_provider();
let client = reqwest::Client::builder()
.timeout(std::time::Duration::from_secs(
super::HTTP_FETCH_TIMEOUT_SECS,

View File

@@ -30,6 +30,7 @@ fn webfinger_url(handle: &ParsedHandle<'_>) -> String {
async fn fetch_webfinger(url: &str) -> anyhow::Result<serde_json::Value> {
let parsed = Url::parse(url)?;
crate::security::validate_url(&parsed).await?;
crate::tls::ensure_crypto_provider();
Ok(reqwest::Client::new()
.get(url)
.header("Accept", "application/jrd+json, application/json")

View File

@@ -279,6 +279,7 @@ async fn setup_with_blocklist(
Arc::new(crate::url_scheme::DefaultUrlScheme),
);
crate::tls::ensure_crypto_provider();
let config = FederationConfig::builder()
.domain(LOCAL_DOMAIN)
.app_data(data)

View File

@@ -103,6 +103,7 @@ async fn check_guards_idempotency() {
build_user_repo(uuid::Uuid::new_v4(), "alice"),
MockObjectHandlerBuilder::new().build(),
);
crate::tls::ensure_crypto_provider();
let config = FederationConfig::builder()
.domain("example.com")
.app_data(data_inner)
@@ -139,6 +140,7 @@ async fn check_guards_blocks_domain() {
build_user_repo(uuid::Uuid::new_v4(), "alice"),
MockObjectHandlerBuilder::new().build(),
);
crate::tls::ensure_crypto_provider();
let config = FederationConfig::builder()
.domain("example.com")
.app_data(data_inner)
@@ -170,6 +172,7 @@ async fn extract_and_dispatch_mentions_notifies_local_users() {
})
.build();
let data_inner = make_data(None, build_user_repo(local_user_id, "alice"), handler);
crate::tls::ensure_crypto_provider();
let config = FederationConfig::builder()
.domain("example.com")
.app_data(data_inner)

30
src/tls.rs Normal file
View File

@@ -0,0 +1,30 @@
//! rustls crypto provider setup.
//!
//! k-ap compiles rustls with the `ring` provider only (no aws-lc). reqwest 0.13
//! does not auto-select a provider in that configuration and panics
//! ("No provider set") on client construction, so we install ring as the
//! process default before any HTTP client is built. Idempotent; a provider
//! already installed by the host application wins.
pub(crate) fn ensure_crypto_provider() {
static ONCE: std::sync::Once = std::sync::Once::new();
ONCE.call_once(|| {
// Err means the application already installed a provider; keep theirs.
let _ = rustls::crypto::ring::default_provider().install_default();
});
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn installs_provider_and_client_builds() {
ensure_crypto_provider();
ensure_crypto_provider();
assert!(rustls::crypto::CryptoProvider::get_default().is_some());
reqwest::Client::builder()
.build()
.expect("reqwest client builds with ring-only rustls");
}
}