Implemented host-meta and some overdue fixes
ci/woodpecker/push/ociImagePush Pipeline is running Details

This commit is contained in:
Natty 2024-03-31 05:10:48 +02:00
parent a640890cad
commit 5aceca72bd
Signed by: natty
GPG Key ID: BF6CB659ADEE60EC
15 changed files with 687 additions and 145 deletions

View File

@ -3,6 +3,10 @@ magnetar-dev.local {
}
handle /.well-known/host-meta {
reverse_proxy 127.0.0.1:4939
}
handle /.well-known/webfinger {
reverse_proxy 127.0.0.1:4939
}

418
Cargo.lock generated
View File

@ -206,10 +206,10 @@ dependencies = [
"axum-macros",
"bytes",
"futures-util",
"http",
"http-body",
"http 1.0.0",
"http-body 1.0.0",
"http-body-util",
"hyper",
"hyper 1.1.0",
"hyper-util",
"itoa",
"matchit",
@ -239,8 +239,8 @@ dependencies = [
"async-trait",
"bytes",
"futures-util",
"http",
"http-body",
"http 1.0.0",
"http-body 1.0.0",
"http-body-util",
"mime",
"pin-project-lite",
@ -262,8 +262,8 @@ dependencies = [
"bytes",
"futures-util",
"headers",
"http",
"http-body",
"http 1.0.0",
"http-body 1.0.0",
"http-body-util",
"mime",
"pin-project-lite",
@ -636,6 +636,16 @@ version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
name = "core-foundation"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.6"
@ -819,6 +829,15 @@ dependencies = [
"phf",
]
[[package]]
name = "encoding_rs"
version = "0.8.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
dependencies = [
"cfg-if",
]
[[package]]
name = "equivalent"
version = "1.0.1"
@ -889,6 +908,21 @@ version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
[[package]]
name = "foreign-types"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
dependencies = [
"foreign-types-shared",
]
[[package]]
name = "foreign-types-shared"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "form_urlencoded"
version = "1.2.1"
@ -1061,6 +1095,25 @@ dependencies = [
"walkdir",
]
[[package]]
name = "h2"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9"
dependencies = [
"bytes",
"fnv",
"futures-core",
"futures-sink",
"futures-util",
"http 0.2.12",
"indexmap",
"slab",
"tokio",
"tokio-util",
"tracing",
]
[[package]]
name = "h2"
version = "0.4.2"
@ -1072,7 +1125,7 @@ dependencies = [
"futures-core",
"futures-sink",
"futures-util",
"http",
"http 1.0.0",
"indexmap",
"slab",
"tokio",
@ -1117,7 +1170,7 @@ dependencies = [
"base64",
"bytes",
"headers-core",
"http",
"http 1.0.0",
"httpdate",
"mime",
"sha1",
@ -1129,7 +1182,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4"
dependencies = [
"http",
"http 1.0.0",
]
[[package]]
@ -1180,6 +1233,17 @@ dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "http"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]]
name = "http"
version = "1.0.0"
@ -1191,6 +1255,17 @@ dependencies = [
"itoa",
]
[[package]]
name = "http-body"
version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
dependencies = [
"bytes",
"http 0.2.12",
"pin-project-lite",
]
[[package]]
name = "http-body"
version = "1.0.0"
@ -1198,7 +1273,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cac85db508abc24a2e48553ba12a996e87244a0395ce011e62b37158745d643"
dependencies = [
"bytes",
"http",
"http 1.0.0",
]
[[package]]
@ -1209,8 +1284,8 @@ checksum = "41cb79eb393015dadd30fc252023adb0b2400a0caee0fa2a077e6e21a551e840"
dependencies = [
"bytes",
"futures-util",
"http",
"http-body",
"http 1.0.0",
"http-body 1.0.0",
"pin-project-lite",
]
@ -1241,6 +1316,30 @@ dependencies = [
"libm",
]
[[package]]
name = "hyper"
version = "0.14.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80"
dependencies = [
"bytes",
"futures-channel",
"futures-core",
"futures-util",
"h2 0.3.24",
"http 0.2.12",
"http-body 0.4.6",
"httparse",
"httpdate",
"itoa",
"pin-project-lite",
"socket2 0.5.5",
"tokio",
"tower-service",
"tracing",
"want",
]
[[package]]
name = "hyper"
version = "1.1.0"
@ -1250,9 +1349,9 @@ dependencies = [
"bytes",
"futures-channel",
"futures-util",
"h2",
"http",
"http-body",
"h2 0.4.2",
"http 1.0.0",
"http-body 1.0.0",
"httparse",
"httpdate",
"itoa",
@ -1261,6 +1360,19 @@ dependencies = [
"want",
]
[[package]]
name = "hyper-tls"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
dependencies = [
"bytes",
"hyper 0.14.28",
"native-tls",
"tokio",
"tokio-native-tls",
]
[[package]]
name = "hyper-util"
version = "0.1.3"
@ -1269,9 +1381,9 @@ checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa"
dependencies = [
"bytes",
"futures-util",
"http",
"http-body",
"hyper",
"http 1.0.0",
"http-body 1.0.0",
"hyper 1.1.0",
"pin-project-lite",
"socket2 0.5.5",
"tokio",
@ -1362,6 +1474,12 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "ipnet"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
[[package]]
name = "is-terminal"
version = "0.4.12"
@ -1482,18 +1600,21 @@ dependencies = [
"futures",
"futures-util",
"headers",
"hyper",
"hyper 1.1.0",
"idna",
"itertools",
"lru",
"magnetar_calckey_model",
"magnetar_common",
"magnetar_core",
"magnetar_federation",
"magnetar_host_meta",
"magnetar_nodeinfo",
"magnetar_sdk",
"magnetar_webfinger",
"miette",
"percent-encoding",
"quick-xml",
"regex",
"serde",
"serde_json",
@ -1520,7 +1641,7 @@ dependencies = [
"chrono",
"dotenvy",
"headers",
"hyper",
"hyper 1.1.0",
"magnetar_common",
"miette",
"percent-encoding",
@ -1582,6 +1703,42 @@ dependencies = [
"serde_json",
]
[[package]]
name = "magnetar_federation"
version = "0.3.0-alpha"
dependencies = [
"async-stream",
"chrono",
"futures",
"futures-core",
"futures-util",
"headers",
"http 1.0.0",
"hyper 1.1.0",
"magnetar_common",
"magnetar_core",
"magnetar_host_meta",
"magnetar_webfinger",
"miette",
"percent-encoding",
"quick-xml",
"reqwest",
"serde",
"serde_json",
"thiserror",
"tokio",
"url",
]
[[package]]
name = "magnetar_host_meta"
version = "0.3.0-alpha"
dependencies = [
"magnetar_core",
"quick-xml",
"serde",
]
[[package]]
name = "magnetar_mmm_parser"
version = "0.3.0-alpha"
@ -1611,7 +1768,7 @@ name = "magnetar_sdk"
version = "0.3.0-alpha"
dependencies = [
"chrono",
"http",
"http 1.0.0",
"magnetar_mmm_parser",
"magnetar_sdk_macros",
"serde",
@ -1744,6 +1901,24 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "native-tls"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
dependencies = [
"lazy_static",
"libc",
"log",
"openssl",
"openssl-probe",
"openssl-sys",
"schannel",
"security-framework",
"security-framework-sys",
"tempfile",
]
[[package]]
name = "nix"
version = "0.27.1"
@ -1875,6 +2050,50 @@ version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
name = "openssl"
version = "0.10.64"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f"
dependencies = [
"bitflags 2.4.2",
"cfg-if",
"foreign-types",
"libc",
"once_cell",
"openssl-macros",
"openssl-sys",
]
[[package]]
name = "openssl-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.49",
]
[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]]
name = "openssl-sys"
version = "0.9.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dda2b0f344e78efc2facf7d195d098df0dd72151b26ab98da807afc26c198dff"
dependencies = [
"cc",
"libc",
"pkg-config",
"vcpkg",
]
[[package]]
name = "ordered-float"
version = "3.9.2"
@ -2329,6 +2548,48 @@ dependencies = [
"bytecheck",
]
[[package]]
name = "reqwest"
version = "0.11.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78bf93c4af7a8bb7d879d51cebe797356ff10ae8516ace542b5182d9dcac10b2"
dependencies = [
"base64",
"bytes",
"encoding_rs",
"futures-core",
"futures-util",
"h2 0.3.24",
"http 0.2.12",
"http-body 0.4.6",
"hyper 0.14.28",
"hyper-tls",
"ipnet",
"js-sys",
"log",
"mime",
"native-tls",
"once_cell",
"percent-encoding",
"pin-project-lite",
"rustls-pemfile",
"serde",
"serde_json",
"serde_urlencoded",
"sync_wrapper",
"system-configuration",
"tokio",
"tokio-native-tls",
"tokio-util",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
"winreg",
]
[[package]]
name = "ring"
version = "0.17.7"
@ -2478,6 +2739,15 @@ dependencies = [
"winapi-util",
]
[[package]]
name = "schannel"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534"
dependencies = [
"windows-sys 0.52.0",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
@ -2659,6 +2929,29 @@ version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
[[package]]
name = "security-framework"
version = "2.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "serde"
version = "1.0.196"
@ -3220,6 +3513,27 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
[[package]]
name = "system-configuration"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
dependencies = [
"bitflags 1.3.2",
"core-foundation",
"system-configuration-sys",
]
[[package]]
name = "system-configuration-sys"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "tap"
version = "1.0.1"
@ -3396,6 +3710,16 @@ dependencies = [
"syn 2.0.49",
]
[[package]]
name = "tokio-native-tls"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
dependencies = [
"native-tls",
"tokio",
]
[[package]]
name = "tokio-stream"
version = "0.1.14"
@ -3491,8 +3815,8 @@ dependencies = [
"bitflags 2.4.2",
"bytes",
"futures-util",
"http",
"http-body",
"http 1.0.0",
"http-body 1.0.0",
"http-body-util",
"http-range-header",
"httpdate",
@ -3742,6 +4066,7 @@ dependencies = [
"form_urlencoded",
"idna",
"percent-encoding",
"serde",
]
[[package]]
@ -3833,6 +4158,18 @@ dependencies = [
"wasm-bindgen-shared",
]
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97"
dependencies = [
"cfg-if",
"js-sys",
"wasm-bindgen",
"web-sys",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.91"
@ -3862,6 +4199,29 @@ version = "0.2.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
[[package]]
name = "wasm-streams"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b65dc4c90b63b118468cf747d8bf3566c1913ef60be765b5730ead9e0a3ba129"
dependencies = [
"futures-util",
"js-sys",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]]
name = "web-sys"
version = "0.3.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "webpki-roots"
version = "0.25.4"
@ -4064,6 +4424,16 @@ dependencies = [
"memchr",
]
[[package]]
name = "winreg"
version = "0.50.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
dependencies = [
"cfg-if",
"windows-sys 0.48.0",
]
[[package]]
name = "wyz"
version = "0.5.1"

View File

@ -8,6 +8,7 @@ license = "AGPL-3.0-only"
[workspace]
members = [
".",
"ext_federation",
"ext_nodeinfo",
"ext_webfinger",
"ext_calckey_model",
@ -75,6 +76,8 @@ walkdir = "2.3"
[dependencies]
magnetar_core = { path = "./core" }
magnetar_common = { path = "./magnetar_common" }
magnetar_federation = { path = "./ext_federation" }
magnetar_host_meta = { path = "./ext_host_meta" }
magnetar_webfinger = { path = "./ext_webfinger" }
magnetar_nodeinfo = { path = "./ext_nodeinfo" }
magnetar_calckey_model = { path = "./ext_calckey_model" }
@ -96,7 +99,6 @@ tokio-stream = { workspace = true }
tower = { workspace = true }
tower-http = { workspace = true, features = ["cors", "trace", "fs"] }
url = { workspace = true }
idna = { workspace = true }
regex = { workspace = true }
@ -121,6 +123,7 @@ serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
serde_urlencoded = { workspace = true }
toml = { workspace = true }
quick-xml = { workspace = true, features = ["serialize", "overlapped-lists"] }
unicode-segmentation = { workspace = true }

View File

@ -248,7 +248,6 @@ impl NoteResolver {
.add(join_columns_default(
note::Relation::SelfRef2.with_alias(note_tbl, &reply_tbl),
))
.add(note_tbl.col(note::Column::IsQuote).not())
.add(visibility_filter);
q.join_columns_on(
JoinType::LeftJoin,

38
ext_federation/Cargo.toml Normal file
View File

@ -0,0 +1,38 @@
[package]
name = "magnetar_federation"
version.workspace = true
edition.workspace = true
license = "MIT OR Apache-2.0"
[lib]
crate-type = ["rlib"]
[dependencies]
magnetar_core = { path = "../core" }
magnetar_common = { path = "../magnetar_common" }
magnetar_host_meta = { path = "../ext_host_meta" }
magnetar_webfinger = { path = "../ext_webfinger" }
async-stream = { workspace = true }
futures = { workspace = true }
futures-core = { workspace = true }
futures-util = { workspace = true }
quick-xml = { workspace = true, features = ["serialize"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
url = { workspace = true, features = ["serde"] }
chrono = { workspace = true, features = ["serde"] }
thiserror = { workspace = true }
http = { workspace = true }
headers = { workspace = true }
hyper = { workspace = true, features = ["full"] }
percent-encoding = { workspace = true }
reqwest = { workspace = true, features = ["stream"] }
tokio = { workspace = true, features = ["full"] }
[dev-dependencies]
miette = { workspace = true, features = ["fancy"] }

View File

@ -1,12 +1,9 @@
use std::io::Cursor;
use async_stream::stream;
use futures_util::{select, stream::StreamExt, FutureExt, Stream, TryStreamExt};
use headers::Header;
use hyper::body::Bytes;
use magnetar_common::config::MagnetarNetworkingProtocol;
use magnetar_core::web_model::content_type::ContentActivityStreams;
use magnetar_host_meta::Xrd;
use reqwest::{Client, RequestBuilder};
use magnetar_core::web_model::{content_type::ContentActivityStreams, ContentType};
use reqwest::{redirect::Policy, Client, RequestBuilder};
use serde_json::Value;
use thiserror::Error;
use tokio::pin;
@ -55,7 +52,10 @@ impl FederationClient {
body_limit: usize,
timeout_seconds: u64,
) -> Result<FederationClient, FederationClientBuilderError> {
let client = Client::builder().https_only(force_https).build()?;
let client = Client::builder()
.https_only(force_https)
.redirect(Policy::limited(5))
.build()?;
Ok(FederationClient {
client,
@ -66,7 +66,7 @@ impl FederationClient {
pub fn builder(&self, method: reqwest::Method, url: Url) -> FederationRequestBuilder<'_> {
FederationRequestBuilder {
client: &self,
client: self,
builder: self.client.request(method, url),
}
}
@ -74,28 +74,19 @@ impl FederationClient {
pub fn get(&self, url: Url) -> FederationRequestBuilder<'_> {
self.builder(reqwest::Method::GET, url)
}
pub async fn host_meta(
&self,
protocol: MagnetarNetworkingProtocol,
host: &str,
) -> Result<Xrd, FederationClientError> {
let host_meta_xml = self
.get(Url::parse(&format!(
"{}://{}/.well-known/host-meta",
protocol.as_ref(),
host
))?)
.send()
.await?;
let reader = quick_xml::de::from_reader(Cursor::new(host_meta_xml))?;
Ok(reader)
}
}
impl FederationRequestBuilder<'_> {
pub fn content_type(self, content_type: impl ContentType) -> Self {
Self {
client: self.client,
builder: self.builder.header(
headers::ContentType::name().to_string(),
content_type.mime_type().to_string(),
),
}
}
pub fn headers(self, headers: reqwest::header::HeaderMap) -> Self {
Self {
client: self.client,
@ -129,7 +120,7 @@ impl FederationRequestBuilder<'_> {
})
}
async fn send(self) -> Result<Vec<u8>, FederationClientError> {
pub async fn send(self) -> Result<Vec<u8>, FederationClientError> {
let sleep = tokio::time::sleep(tokio::time::Duration::from_secs(
self.client.timeout_seconds,
))
@ -164,28 +155,8 @@ impl FederationRequestBuilder<'_> {
);
let data = self.send().await?;
let json =
serde_json::from_slice::<Value>(&data).map_err(FederationClientError::JsonError)?;
let json = serde_json::from_slice::<Value>(&data)?;
Ok(json)
}
}
#[cfg(test)]
mod test {
use magnetar_common::config::MagnetarNetworkingProtocol;
use miette::IntoDiagnostic;
use super::FederationClient;
#[tokio::test]
async fn test() -> miette::Result<()> {
let client = FederationClient::new(true, 1024 * 1024, 30).into_diagnostic()?;
let host_meta = client
.host_meta(MagnetarNetworkingProtocol::Https, "astolfo.social")
.await
.into_diagnostic()?;
Ok(())
}
}

102
ext_federation/src/lib.rs Normal file
View File

@ -0,0 +1,102 @@
use std::{io::Cursor, sync::Arc};
use client::federation_client::{FederationClient, FederationClientError};
use magnetar_common::{config::MagnetarNetworkingProtocol, util::FediverseTag};
use magnetar_host_meta::{Xrd, XrdXml};
use magnetar_webfinger::webfinger::WebFinger;
use serde::{Deserialize, Serialize};
use url::Url;
pub mod client;
/// The *visible* domain of fediverse handles, that gets resolved by WebFinger
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(transparent)]
pub struct HostUnmapped(String);
/// The real domain of fediverse handles used for federation
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(transparent)]
pub struct HostMapped(String);
pub trait HostMetaResolverService {
type Error;
async fn resolve(&self, host: &HostUnmapped) -> Result<Xrd, Self::Error>;
}
pub struct HostMetaResolverProviderDefault {
client: Arc<FederationClient>,
protocol: MagnetarNetworkingProtocol,
}
impl HostMetaResolverService for HostMetaResolverProviderDefault {
type Error = FederationClientError;
async fn resolve(&self, HostUnmapped(host): &HostUnmapped) -> Result<Xrd, Self::Error> {
let host_meta_xml = self
.client
.get(Url::parse(&format!(
"{}://{}/.well-known/host-meta",
self.protocol.as_ref(),
host
))?)
.send()
.await?;
let XrdXml::Xrd(xrd) = quick_xml::de::from_reader(Cursor::new(host_meta_xml))?;
Ok(xrd)
}
}
pub trait WebFingerResolverService {
type Error;
async fn resolve_url(&self, url: &str) -> Result<WebFinger, Self::Error>;
async fn resolve(
&self,
template_url: &str,
resolved_uri: &str,
) -> Result<WebFinger, Self::Error> {
self.resolve_url(
&template_url.replace(
"{}",
&percent_encoding::utf8_percent_encode(
resolved_uri,
percent_encoding::NON_ALPHANUMERIC,
)
.to_string(),
),
)
.await
}
}
pub struct WebFingerResolverProviderDefault {
client: Arc<FederationClient>,
}
impl WebFingerResolverService for WebFingerResolverProviderDefault {
type Error = FederationClientError;
async fn resolve_url(&self, url: &str) -> Result<WebFinger, Self::Error> {
let host_meta_xml = self.client.get(Url::parse(url)?).send().await?;
let webfinger = serde_json::from_reader(Cursor::new(host_meta_xml))?;
Ok(webfinger)
}
}
#[derive(Debug)]
pub struct MappedUser {
pub host_meta: Xrd,
pub webfinger: WebFinger,
pub tag_mapped: FediverseTag,
}
pub trait FederationService {
type Error;
async fn map_fedi_tag(&self, host: &HostUnmapped) -> Result<MappedUser, Self::Error>;
}

View File

@ -30,6 +30,13 @@ impl Xrd {
}],
}
}
pub fn get_webfinger_template(&self) -> Option<&str> {
self.links
.iter()
.find(|l| l.rel.as_deref() == Some(ContentXrdXml.as_ref()))
.and_then(|l| l.template.as_deref())
}
}
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq)]

12
src/host_meta.rs Normal file
View File

@ -0,0 +1,12 @@
use axum::{extract::State, response::IntoResponse};
use magnetar_common::config::MagnetarConfig;
use magnetar_host_meta::Xrd;
use crate::web::extractors::XrdXmlExt;
pub async fn handle_host_meta(State(config): State<&'static MagnetarConfig>) -> impl IntoResponse {
XrdXmlExt(magnetar_host_meta::XrdXml::Xrd(Xrd::default_host_meta(
config.networking.protocol.as_ref(),
&config.networking.host,
)))
}

View File

@ -1,4 +1,5 @@
mod api_v1;
pub mod host_meta;
pub mod model;
pub mod nodeinfo;
pub mod service;
@ -7,6 +8,7 @@ pub mod web;
pub mod webfinger;
use crate::api_v1::create_api_router;
use crate::host_meta::handle_host_meta;
use crate::nodeinfo::{handle_nodeinfo, handle_nodeinfo_20, handle_nodeinfo_21};
use crate::service::MagnetarService;
use axum::routing::get;
@ -66,6 +68,7 @@ async fn main() -> miette::Result<()> {
"/webfinger",
get(webfinger::handle_webfinger).with_state((config, db)),
)
.route("/host-meta", get(handle_host_meta))
.route("/nodeinfo", get(handle_nodeinfo));
let nodeinfo_router = Router::new()

View File

@ -6,7 +6,7 @@ use crate::model::processing::{get_mm_token_emoji, PackError, PackResult};
use crate::model::{PackType, PackingContext};
use compact_str::CompactString;
use either::Either;
use futures_util::future::{try_join_all, BoxFuture};
use futures_util::future::try_join_all;
use futures_util::{FutureExt, StreamExt, TryStreamExt};
use magnetar_calckey_model::ck::sea_orm_active_enums::NoteVisibilityEnum;
use magnetar_calckey_model::model_ext::AliasColumnExt;
@ -446,19 +446,18 @@ impl NoteModel {
)))
}
pub fn pack_full_single<'b, 'a: 'b>(
&'a self,
ctx: &'a PackingContext,
note: &'b (dyn NoteShapedData<'a> + 'b),
) -> BoxFuture<'b, PackResult<PackNoteMaybeFull>> {
async move {
pub async fn pack_full_single(
&self,
ctx: &PackingContext,
note: &dyn NoteShapedData<'_>,
) -> PackResult<PackNoteMaybeFull> {
let drive_model = DriveModel;
let reply_target = async {
match note.reply() {
Some(r) if self.with_context => {
self.pack_full_single(ctx, r.as_ref()).await.map(Some)
}
Some(r) if self.with_context => Box::pin(self.pack_full_single(ctx, r.as_ref()))
.await
.map(Some),
_ => Ok(None),
}
};
@ -466,9 +465,13 @@ impl NoteModel {
let renote_target = async {
match (note.renote(), &note.note().renote_id, note.note().is_quote) {
(Some(r), _, _) if self.with_context => {
self.pack_full_single(ctx, r.as_ref()).await.map(Some)
Box::pin(self.pack_full_single(ctx, r.as_ref()))
.await
.map(Some)
}
(_, Some(renote_id), Some(true)) => {
Box::pin(self.fetch_single(ctx, renote_id)).await
}
(_, Some(renote_id), Some(true)) => self.fetch_single(ctx, renote_id).await,
_ => Ok(None),
}
};
@ -506,8 +509,6 @@ impl NoteModel {
Optional(detail),
)))
}
.boxed()
}
pub async fn fetch_single(
&self,

View File

@ -26,7 +26,7 @@ use magnetar_sdk::types::{Id, MmXml};
use magnetar_sdk::{mmm, Optional, Packed, Required};
use serde::{Deserialize, Serialize};
use tokio::{join, try_join};
use tracing::{instrument, warn};
use tracing::warn;
use url::Url;
pub trait UserShapedData<'a>: Send + Sync {
@ -227,12 +227,8 @@ impl UserModel {
let moved = ctx.service.db.get_user_by_uri(uri).await?;
moved.and_then(|m| {
let Some(uri) = m.uri else {
return None;
};
Some(MovedTo {
moved_to_uri: uri,
moved_to_uri: m.uri?,
username: m.username,
host: m
.host

35
src/web/extractors.rs Normal file
View File

@ -0,0 +1,35 @@
use axum::{http::HeaderValue, response::IntoResponse};
use hyper::{header, StatusCode};
use magnetar_core::web_model::{content_type::ContentXrdXml, ContentType};
use serde::Serialize;
use crate::web::{ApiError, ErrorCode};
pub struct XrdXmlExt<T>(pub T);
impl<T: Serialize> IntoResponse for XrdXmlExt<T> {
fn into_response(self) -> axum::response::Response {
let mut buf = r#"<?xml version="1.0" encoding="UTF-8"?>"#.to_string();
match quick_xml::se::to_writer(&mut buf, &self.0) {
Ok(()) => (
[(
header::CONTENT_TYPE,
HeaderValue::from_static(ContentXrdXml.mime_type()),
)],
buf.into_bytes(),
)
.into_response(),
Err(e) => ApiError {
status: StatusCode::INTERNAL_SERVER_ERROR,
code: ErrorCode("XmlSerializationError".into()),
message: if cfg!(debug_assertions) {
format!("Serialization error: {}", e)
} else {
"Serialization error".to_string()
},
}
.into_response(),
}
}
}

View File

@ -10,6 +10,7 @@ use std::fmt::{Display, Formatter};
use thiserror::Error;
pub mod auth;
pub mod extractors;
pub mod pagination;
#[derive(Debug, Clone, Serialize)]