diff --git a/.gitignore b/.gitignore index 2674b3d..995767b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target .idea -.vscode \ No newline at end of file +.vscode +/.env \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index d18aecd..e8f4c8d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -75,24 +75,85 @@ dependencies = [ "tower-service", ] +[[package]] +name = "base64ct" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" + [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + [[package]] name = "bytes" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "const-oid" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "const-oid", + "crypto-common", +] + [[package]] name = "dotenvy" version = "0.15.6" @@ -153,6 +214,27 @@ dependencies = [ "pin-utils", ] +[[package]] +name = "generic-array" +version = "0.14.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "h2" version = "0.3.15" @@ -277,11 +359,23 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440" +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] [[package]] name = "libc" @@ -289,6 +383,12 @@ version = "0.2.139" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" +[[package]] +name = "libm" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" + [[package]] name = "lock_api" version = "0.4.9" @@ -317,14 +417,23 @@ dependencies = [ "dotenvy", "hyper", "magnetar_core", + "rand", + "ring", + "rsa", "serde", + "serde_json", "tokio", + "toml", "tower", "tower-http", "tracing", "tracing-subscriber", ] +[[package]] +name = "magnetar_activity_pub" +version = "0.1.0" + [[package]] name = "magnetar_core" version = "0.1.0" @@ -334,6 +443,14 @@ dependencies = [ "url", ] +[[package]] +name = "magnetar_nodeinfo" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "matchers" version = "0.1.0" @@ -373,6 +490,15 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "nom8" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" +dependencies = [ + "memchr", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -383,6 +509,54 @@ dependencies = [ "winapi", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2399c9463abc5f909349d8aa9ba080e0b88b3ce2885389b60b993f39b1a56905" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", + "libm", +] + [[package]] name = "num_cpus" version = "1.15.0" @@ -428,6 +602,15 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "pem-rfc7468" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.2.0" @@ -466,6 +649,34 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff33bdbdfc54cc98a2eca766ebdec3e1b8fb7387523d5c9c9a2891da856f719" +dependencies = [ + "der", + "pkcs8", + "spki", + "zeroize", +] + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + [[package]] name = "proc-macro2" version = "1.0.51" @@ -484,6 +695,36 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + [[package]] name = "redox_syscall" version = "0.2.16" @@ -517,6 +758,41 @@ version = "0.6.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "rsa" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b3896c9b7790b70a9aa314a30e4ae114200992a19c96cbe0ca6070edd32ab8" +dependencies = [ + "byteorder", + "digest", + "num-bigint-dig", + "num-integer", + "num-iter", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "subtle", + "zeroize", +] + [[package]] name = "rustversion" version = "1.0.11" @@ -575,6 +851,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -605,6 +890,16 @@ dependencies = [ "libc", ] +[[package]] +name = "signature" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fe458c98333f9c8152221191a77e2a44e8325d0193484af2e9421a53019e57d" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "slab" version = "0.4.7" @@ -630,6 +925,28 @@ dependencies = [ "winapi", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + [[package]] name = "syn" version = "1.0.107" @@ -717,6 +1034,40 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7afcae9e3f0fe2c370fd4657108972cbb2fa9db1b9f84849cefd80741b01cb6" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6a7712b49e1775fb9a7b998de6635b299237f48b404dde71704f2e0e7f37e5" +dependencies = [ + "indexmap", + "nom8", + "serde", + "serde_spanned", + "toml_datetime", +] + [[package]] name = "tower" version = "0.4.13" @@ -834,6 +1185,12 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + [[package]] name = "unicode-bidi" version = "0.3.10" @@ -855,6 +1212,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "url" version = "2.3.1" @@ -873,6 +1236,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + [[package]] name = "want" version = "0.3.0" @@ -889,6 +1258,70 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasm-bindgen" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" @@ -991,3 +1424,9 @@ name = "windows_x86_64_msvc" version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" + +[[package]] +name = "zeroize" +version = "1.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" diff --git a/Cargo.toml b/Cargo.toml index 0a34aaa..e3c5621 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,8 @@ edition = "2021" [workspace] members = [ ".", + "ext_activity_pub", + "ext_nodeinfo", "core" ] @@ -27,4 +29,11 @@ tower-http = { version = "0.3", features = ["cors", "trace"] } tracing-subscriber = { version = "0.3", features = ["env-filter"] } tracing = "0.1" -serde = { version = "1.0", features = ["derive"] } \ No newline at end of file +ring = "0.16" +rand = { version = "0.8", features = ["getrandom"] } +rsa = "0.8" + +serde = { version = "1.0", features = ["derive"] } +toml = "0.7" + +serde_json = "1.0" \ No newline at end of file diff --git a/config/.gitignore b/config/.gitignore new file mode 100644 index 0000000..73ee336 --- /dev/null +++ b/config/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore +!default.toml \ No newline at end of file diff --git a/config/default.toml b/config/default.toml new file mode 100644 index 0000000..bba23f3 --- /dev/null +++ b/config/default.toml @@ -0,0 +1,47 @@ +# Primary Magnetar configuration. +# The location of the config to load may be overriden with MAG_CONFIG_PATH. + +# Please note options in this file take priority over environment variables. + +# Container quick start: +# Technically it's not necessary to edit this file at all. +# Set the following variables: +# - MAG_C_HOST (host) + + +# --------------------------------[ LOGGING ]---------------------------------- + +# Logging can be configured using the RUST_LOG environment variable. +# See https://docs.rs/env_logger/0.10.0/env_logger/#enabling-logging +# Default: "info" + +# -------------------------------[ NETWORKING ]-------------------------------- + +# Magnetar does not contain a TLS ingress, please use a reverse proxy like: +# - Nginx (https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) +# - Caddy (https://caddyserver.com/docs/quick-starts/reverse-proxy) +# - Traefik + +# [REQUIRED] +# The hostname the instance will run on. +# Environment variable: MAG_C_HOST +# networking.host = "example.com" + +# [Optional] +# The IP address the application will bind to. +# Default: "::" +# Environment variable: MAG_C_BIND_ADDR +# networking.bind_addr = "::" + +# [Optional] +# The port of the instance. +# Default: 4939 +# Environment variable: MAG_C_PORT +# networking.port = 4939 + +# ----------------------------------[ DATA ]----------------------------------- + + + +# -------------------------------[ FEDERATION ]-------------------------------- + diff --git a/ext_activity_pub/Cargo.toml b/ext_activity_pub/Cargo.toml new file mode 100644 index 0000000..d38ecba --- /dev/null +++ b/ext_activity_pub/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "magnetar_activity_pub" +version = "0.1.0" +edition = "2021" + + +[dependencies] diff --git a/ext_activity_pub/src/lib.rs b/ext_activity_pub/src/lib.rs new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/ext_activity_pub/src/lib.rs @@ -0,0 +1 @@ + diff --git a/ext_nodeinfo/Cargo.toml b/ext_nodeinfo/Cargo.toml new file mode 100644 index 0000000..8a9d91a --- /dev/null +++ b/ext_nodeinfo/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "magnetar_nodeinfo" +version = "0.1.0" +edition = "2021" + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/ext_nodeinfo/src/lib.rs b/ext_nodeinfo/src/lib.rs new file mode 100644 index 0000000..cb2dca1 --- /dev/null +++ b/ext_nodeinfo/src/lib.rs @@ -0,0 +1,169 @@ +use crate::version_1_0::NodeInfo10; +use crate::version_1_1::NodeInfo11; +use crate::version_2_0::NodeInfo20; +use crate::version_2_1::NodeInfo21; +use serde::{Deserialize, Serialize}; + +pub mod version_1_0; +pub mod version_1_1; +pub mod version_2_0; +pub mod version_2_1; + +#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] +#[serde(tag = "version")] +pub enum NodeInfo { + #[serde(rename = "1.0")] + V1_0(NodeInfo10), + #[serde(rename = "1.1")] + V1_1(NodeInfo11), + #[serde(rename = "2.0")] + V2_0(NodeInfo20), + #[serde(rename = "2.1")] + V2_1(NodeInfo21), +} + +#[cfg(test)] +mod test { + use crate::version_1_0::{ + NodeInfo10Services, NodeInfo10Software, NodeInfo10Usage, NodeInfo10UsageUsers, + }; + use crate::version_2_0::NodeInfo20; + use crate::version_2_1::{NodeInfo21, NodeInfo21Software}; + use crate::NodeInfo; + use serde_json::json; + use std::collections::{HashMap, HashSet}; + + fn json_mastodon() -> serde_json::Value { + json!({ + "version": "2.0", + "software": { + "name": "mastodon", + "version": "4.1.0" + }, + "protocols": [ + "activitypub" + ], + "services": { + "outbound": [], + "inbound": [] + }, + "usage": { + "users": { + "total": 10360, + "activeMonth": 4627, + "activeHalfyear": 10089 + }, + "localPosts": 1033206 + }, + "openRegistrations": true, + "metadata": {} + }) + } + + fn data_mastodon() -> NodeInfo20 { + NodeInfo20 { + software: NodeInfo10Software { + name: "mastodon".to_owned(), + version: "4.1.0".to_owned(), + }, + protocols: HashSet::from(["activitypub".to_owned()]), + services: NodeInfo10Services { + inbound: HashSet::new(), + outbound: HashSet::new(), + }, + open_registrations: true, + usage: NodeInfo10Usage { + users: NodeInfo10UsageUsers { + total: Some(10360), + active_halfyear: Some(10089), + active_month: Some(4627), + }, + local_posts: Some(1033206), + local_comments: None, + }, + metadata: HashMap::new(), + } + } + + #[test] + fn should_serialize_nodeinfo_20() { + let json = json_mastodon(); + + let node_info = serde_json::to_value(NodeInfo::V2_0(data_mastodon())).unwrap(); + + assert_eq!(node_info, json); + } + + #[test] + fn should_parse_nodeinfo_20() { + let json = json_mastodon(); + + let node_info: NodeInfo = serde_json::from_value(json).unwrap(); + + assert_eq!(node_info, NodeInfo::V2_0(data_mastodon())); + } + + #[test] + fn should_parse_nodeinfo_21() { + let json = json!({ + "version": "2.1", + "software": { + "name": "calckey", + "version": "13.1.2", + "repository": "https://github.com/misskey-dev/misskey", + "homepage": "https://calckey.cloud" + }, + "protocols": [ + "activitypub" + ], + "services": { + "inbound": [], + "outbound": [ + "atom1.0", + "rss2.0" + ] + }, + "openRegistrations": false, + "usage": { + "users": { + "total": 2, + "activeHalfyear": 1, + "activeMonth": 1 + }, + "localPosts": 1936, + "localComments": 0 + }, + "metadata": {} + }); + + let node_info: NodeInfo = serde_json::from_value(json).unwrap(); + + assert_eq!( + node_info, + NodeInfo::V2_1(NodeInfo21 { + software: NodeInfo21Software { + name: "calckey".to_owned(), + version: "13.1.2".to_owned(), + homepage: Some("https://calckey.cloud".to_owned()), + repository: Some("https://github.com/misskey-dev/misskey".to_owned()) + }, + protocols: HashSet::from(["activitypub".to_owned()]), + services: NodeInfo10Services { + inbound: HashSet::new(), + outbound: HashSet::from(["atom1.0".to_owned(), "rss2.0".to_owned()]) + }, + open_registrations: false, + usage: NodeInfo10Usage { + users: NodeInfo10UsageUsers { + total: Some(2), + active_halfyear: Some(1), + active_month: Some(1) + }, + local_posts: Some(1936), + local_comments: Some(0) + }, + metadata: HashMap::new() + }) + ); + } +} diff --git a/ext_nodeinfo/src/version_1_0.rs b/ext_nodeinfo/src/version_1_0.rs new file mode 100644 index 0000000..4cfcdeb --- /dev/null +++ b/ext_nodeinfo/src/version_1_0.rs @@ -0,0 +1,76 @@ +use serde::{Deserialize, Serialize}; +use std::collections::{HashMap, HashSet}; + +#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] +pub struct NodeInfo10Protocols { + #[doc = "The protocols this server can receive traffic for."] + pub inbound: HashSet, + #[doc = "The protocols this server can generate traffic for."] + pub outbound: HashSet, +} + +#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] +pub struct NodeInfo10Services { + #[doc = "The third party sites this server can retrieve messages from for combined display with "] + #[doc = "regular traffic."] + pub inbound: HashSet, + #[doc = "The third party sites this server can publish messages to on the behalf of a user."] + pub outbound: HashSet, +} + +#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] +pub struct NodeInfo10Software { + #[doc = "The canonical name of this server software."] + pub name: String, + #[doc = "The version of this server software."] + pub version: String, +} + +#[derive(Clone, PartialEq, Debug, Default, Deserialize, Serialize)] +pub struct NodeInfo10UsageUsers { + #[doc = "The amount of users that signed in at least once in the last 180 days."] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(rename = "activeHalfyear")] + pub active_halfyear: Option, + #[doc = "The amount of users that signed in at least once in the last 30 days."] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(rename = "activeMonth")] + pub active_month: Option, + #[doc = "The total amount of on this server registered users."] + #[serde(skip_serializing_if = "Option::is_none")] + pub total: Option, +} + +#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] +pub struct NodeInfo10Usage { + #[doc = "The amount of comments that were made by users that are registered on this server."] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(rename = "localComments")] + pub local_comments: Option, + #[doc = "The amount of posts that were made by users that are registered on this server."] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(rename = "localPosts")] + pub local_posts: Option, + #[doc = "statistics about the users of this server."] + pub users: NodeInfo10UsageUsers, +} + +#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] +pub struct NodeInfo10 { + #[doc = "The schema version, must be 1.0."] + pub version: String, + #[doc = "Free form key value pairs for software specific values. Clients should not rely on any "] + #[doc = "specific key present."] + pub metadata: HashMap, + #[doc = "Whether this server allows open self-registration."] + #[serde(rename = "openRegistrations")] + pub open_registrations: bool, + #[doc = "The protocols supported on this server."] + pub protocols: NodeInfo10Protocols, + #[doc = "The third party sites this server can connect to via their application API."] + pub services: NodeInfo10Services, + #[doc = "Metadata about server software in use."] + pub software: NodeInfo10Protocols, + #[doc = "Usage statistics for this server."] + pub usage: NodeInfo10Usage, +} diff --git a/ext_nodeinfo/src/version_1_1.rs b/ext_nodeinfo/src/version_1_1.rs new file mode 100644 index 0000000..a100bb6 --- /dev/null +++ b/ext_nodeinfo/src/version_1_1.rs @@ -0,0 +1,23 @@ +use crate::version_1_0::{ + NodeInfo10Protocols, NodeInfo10Services, NodeInfo10Software, NodeInfo10Usage, +}; +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] +pub struct NodeInfo11 { + #[doc = "Free form key value pairs for software specific values. Clients should not rely on any "] + #[doc = "specific key present."] + pub metadata: HashMap, + #[doc = "Whether this server allows open self-registration."] + #[serde(rename = "openRegistrations")] + pub open_registrations: bool, + #[doc = "The protocols supported on this server."] + pub protocols: NodeInfo10Protocols, + #[doc = "The third party sites this server can connect to via their application API."] + pub services: NodeInfo10Services, + #[doc = "Metadata about server software in use."] + pub software: NodeInfo10Software, + #[doc = "Usage statistics for this server."] + pub usage: NodeInfo10Usage, +} diff --git a/ext_nodeinfo/src/version_2_0.rs b/ext_nodeinfo/src/version_2_0.rs new file mode 100644 index 0000000..9bf18a8 --- /dev/null +++ b/ext_nodeinfo/src/version_2_0.rs @@ -0,0 +1,21 @@ +use crate::version_1_0::{NodeInfo10Services, NodeInfo10Software, NodeInfo10Usage}; +use serde::{Deserialize, Serialize}; +use std::collections::{HashMap, HashSet}; + +#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] +pub struct NodeInfo20 { + #[doc = "Free form key value pairs for software specific values. Clients should not rely on any "] + #[doc = "specific key present."] + pub metadata: HashMap, + #[doc = "Whether this server allows open self-registration."] + #[serde(rename = "openRegistrations")] + pub open_registrations: bool, + #[doc = "The protocols supported on this server."] + pub protocols: HashSet, + #[doc = "The third party sites this server can connect to via their application API."] + pub services: NodeInfo10Services, + #[doc = "Metadata about server software in use."] + pub software: NodeInfo10Software, + #[doc = "Usage statistics for this server."] + pub usage: NodeInfo10Usage, +} diff --git a/ext_nodeinfo/src/version_2_1.rs b/ext_nodeinfo/src/version_2_1.rs new file mode 100644 index 0000000..032bf88 --- /dev/null +++ b/ext_nodeinfo/src/version_2_1.rs @@ -0,0 +1,35 @@ +use crate::version_1_0::{NodeInfo10Services, NodeInfo10Usage}; +use serde::{Deserialize, Serialize}; +use std::collections::{HashMap, HashSet}; + +#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] +pub struct NodeInfo21Software { + #[doc = "The url of the homepage of this server software."] + #[serde(skip_serializing_if = "Option::is_none")] + pub homepage: Option, + #[doc = "The canonical name of this server software."] + pub name: String, + #[doc = "The url of the source code repository of this server software."] + #[serde(skip_serializing_if = "Option::is_none")] + pub repository: Option, + #[doc = "The version of this server software."] + pub version: String, +} + +#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)] +pub struct NodeInfo21 { + #[doc = "Free form key value pairs for software specific values. Clients should not rely on any "] + #[doc = "specific key present."] + pub metadata: HashMap, + #[doc = "Whether this server allows open self-registration."] + #[serde(rename = "openRegistrations")] + pub open_registrations: bool, + #[doc = "The protocols supported on this server."] + pub protocols: HashSet, + #[doc = "The third party sites this server can connect to via their application API."] + pub services: NodeInfo10Services, + #[doc = "Metadata about server software in use."] + pub software: NodeInfo21Software, + #[doc = "Usage statistics for this server."] + pub usage: NodeInfo10Usage, +} diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..df200f0 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,64 @@ +use anyhow::anyhow; +use serde::Deserialize; +use std::net::IpAddr; +use tracing::info; + +#[derive(Deserialize, Debug)] +#[non_exhaustive] +pub struct MagnetarNetworking { + pub host: String, + pub port: u16, + pub bind_addr: IpAddr, +} + +fn env_host() -> String { + std::env::var("MAG_C_HOST") + .expect("MAG_C_HOST or \"host\" in the default configuration must be set") +} + +fn env_bind_addr() -> IpAddr { + std::env::var("MAG_C_BIND_ADDR") + .unwrap_or_else(|_| "::".to_owned()) + .parse() + .map_err(|e| format!("Failed to parse \"MAG_C_BIND_ADDR\": {e}")) + .unwrap() +} + +fn env_port() -> u16 { + std::env::var("MAG_C_PORT") + .unwrap_or_else(|_| "4939".to_owned()) + .parse() + .expect("MAG_C_PORT must be a valid port number") +} + +impl Default for MagnetarNetworking { + fn default() -> Self { + MagnetarNetworking { + host: env_host(), + bind_addr: env_bind_addr(), + port: env_port(), + } + } +} + +#[derive(Deserialize, Debug, Default)] +#[non_exhaustive] +pub struct MagnetarConfig { + #[serde(default)] + pub networking: MagnetarNetworking, +} + +pub fn load_config() -> anyhow::Result { + let path = + std::env::var("MAG_CONFIG_PATH").unwrap_or_else(|_| "config/default.toml".to_owned()); + + let str_cfg = + std::fs::read_to_string(path).map_err(|e| anyhow!("Failed to load configuration: {e}"))?; + + let config = + toml::from_str(&str_cfg).map_err(|e| anyhow!("Failed to parse configuration: {e}"))?; + + info!("Loaded configuration: {config:#?}"); + + Ok(config) +} diff --git a/src/main.rs b/src/main.rs index f10a443..c400e7a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,4 @@ +pub mod config; pub mod webfinger; use anyhow::{anyhow, Context}; @@ -5,6 +6,7 @@ use axum::routing::get; use axum::Router; use dotenvy::dotenv; use std::net::SocketAddr; +use std::sync::Arc; use tower_http::cors::{Any, CorsLayer}; use tower_http::trace::TraceLayer; use tracing::info; @@ -23,15 +25,21 @@ async fn main() -> anyhow::Result<()> { .with_test_writer() .init(); - let port: u16 = std::env::var("SERVER_PORT") - .unwrap_or_else(|_| "4939".to_string()) - .parse() - .context("SERVER_PORT not a number")?; + let config = Arc::new(config::load_config()?); let well_known_router = Router::new().route("/webfinger", get(webfinger::handle_webfinger)); + /* + let activity_pub_router = Router::new() + .route("/@!:id/outbox", get(activity_pub::handle_actor_get)) + .route("/@:name/outbox", get(activity_pub::handle_actor_get)) + .route("/@!:id", get(activity_pub::handle_actor_get)) + .route("/@:name", get(activity_pub::handle_actor_get)); + */ let app = Router::new() .nest("/.well-known", well_known_router) + //.nest("/", activity_pub_router) + .with_state(config.clone()) .layer( CorsLayer::new() .allow_headers(Any) @@ -40,7 +48,7 @@ async fn main() -> anyhow::Result<()> { ) .layer(TraceLayer::new_for_http()); - let addr = SocketAddr::from(([0, 0, 0, 0], port)); + let addr = SocketAddr::from((config.networking.bind_addr, config.networking.port)); info!("Serving on: {addr}"); axum::Server::bind(&addr) .serve(app.into_make_service()) diff --git a/src/webfinger.rs b/src/webfinger.rs index 1923952..e38f57b 100644 --- a/src/webfinger.rs +++ b/src/webfinger.rs @@ -12,6 +12,7 @@ pub struct WebFingerQuery { rel: Option>, } +// TODO: Filter by rel pub async fn handle_webfinger( Query(WebFingerQuery { resource, rel, .. }): Query, ) -> Result, StatusCode> { @@ -24,8 +25,6 @@ pub async fn handle_webfinger( other => other, }; - println!("{resource:?}"); - Ok(Json(WebFinger { subject: WebFingerSubject::Acct("natty@tech.lgbt".into()), aliases: vec![