diff --git a/.env b/.env index a9465f8..9eefcbb 100644 --- a/.env +++ b/.env @@ -9,3 +9,5 @@ FOOTER_BLURB="Opéré par @max" LOCAL_DOMAINS="xolus.net" LOCAL_BLURB="

Relais ActivityPub francophone

" # OPENTELEMETRY_URL=http://localhost:4317 +PROMETHEUS_ADDR=127.0.0.1 +PROMETHEUS_PORT=9000 diff --git a/.gitignore b/.gitignore index 1ce4608..447738f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ /target /artifacts /sled +/.direnv +/.envrc +/result diff --git a/Cargo.lock b/Cargo.lock index 5bd9064..0a02148 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "activitystreams" -version = "0.7.0-alpha.20" +version = "0.7.0-alpha.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "459a89e7d449cf49e57044d59dcf637d2927362b7a75737c90bd3679ba476a78" +checksum = "1e673a517c3cd11c3b1870be31f2c95580e30f9ca79e89082ba94325097ed9c4" dependencies = [ "activitystreams-kinds", "iri-string", @@ -18,9 +18,9 @@ dependencies = [ [[package]] name = "activitystreams-ext" -version = "0.1.0-alpha.2" +version = "0.1.0-alpha.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb8e19a0810cc25df3535061a08b7d8f8a734d309ea4411c57a9767e4a2ffa0e" +checksum = "cd4cc5f95aabf2bc2e0672400f7494094ffae30b597317cb825b4ac5c8a405b3" dependencies = [ "activitystreams", "serde", @@ -29,9 +29,9 @@ dependencies = [ [[package]] name = "activitystreams-kinds" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d014a4fb8828870b7b46bee6257b9a89d06188ae8d435381ba94f14c8c697d8" +checksum = "e97dfe76efd8c0b113cc3580a6b5f4acba47662e3cfbbfcce081c9ac89798990" dependencies = [ "iri-string", "serde", @@ -39,34 +39,34 @@ dependencies = [ [[package]] name = "actix-codec" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57a7559404a7f3573127aab53c08ce37a6c6a315c374a31070f3c91cd1b4a7fe" +checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" dependencies = [ "bitflags", "bytes", "futures-core", "futures-sink", - "log", "memchr", "pin-project-lite", "tokio", "tokio-util", + "tracing", ] [[package]] name = "actix-http" -version = "3.2.2" +version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c83abf9903e1f0ad9973cc4f7b9767fd5a03a583f51a5b7a339e07987cd2724" +checksum = "c2079246596c18b4a33e274ae10c0e50613f4d32a4198e09c7b93771013fed74" dependencies = [ "actix-codec", "actix-rt", "actix-service", "actix-tls", "actix-utils", - "ahash", - "base64", + "ahash 0.8.3", + "base64 0.21.2", "bitflags", "brotli", "bytes", @@ -88,6 +88,8 @@ dependencies = [ "rand", "sha1", "smallvec", + "tokio", + "tokio-util", "tracing", ] @@ -98,7 +100,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" dependencies = [ "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -116,9 +118,9 @@ dependencies = [ [[package]] name = "actix-rt" -version = "2.7.0" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ea16c295198e958ef31930a6ef37d0fb64e9ca3b6116e6b93a8bdae96ee1000" +checksum = "15265b6b8e2347670eb363c47fc8c75208b4a4994b27192f345fcbe707804f3e" dependencies = [ "actix-macros", "futures-core", @@ -127,9 +129,9 @@ dependencies = [ [[package]] name = "actix-server" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0da34f8e659ea1b077bb4637948b815cd3768ad5a188fdcd74ff4d84240cd824" +checksum = "3e8613a75dd50cc45f473cee3c34d59ed677c0f7b44480ce3b8247d7dc519327" dependencies = [ "actix-rt", "actix-service", @@ -168,7 +170,7 @@ dependencies = [ "http", "log", "pin-project-lite", - "tokio-rustls", + "tokio-rustls 0.23.4", "tokio-util", "webpki-roots", ] @@ -185,9 +187,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.2.1" +version = "4.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d48f7b6534e06c7bfc72ee91db7917d4af6afe23e7d223b51e68fffbb21e96b9" +checksum = "cd3cb42f9566ab176e1ef0b8b3a896529062b4efc6be0123046095914c4c1c96" dependencies = [ "actix-codec", "actix-http", @@ -197,7 +199,7 @@ dependencies = [ "actix-service", "actix-tls", "actix-utils", - "ahash", + "ahash 0.7.6", "bytes", "bytestring", "cfg-if", @@ -253,6 +255,18 @@ dependencies = [ "version_check", ] +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "0.7.20" @@ -262,6 +276,15 @@ dependencies = [ "memchr", ] +[[package]] +name = "aho-corasick" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +dependencies = [ + "memchr", +] + [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -279,9 +302,9 @@ dependencies = [ [[package]] name = "ammonia" -version = "3.2.1" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b477377562f3086b7778d241786e9406b883ccfaa03557c0fe0924b9349f13a" +checksum = "64e6d1c7838db705c9b756557ee27c384ce695a1c51a6fe528784cb1c6840170" dependencies = [ "html5ever", "maplit", @@ -291,14 +314,69 @@ dependencies = [ ] [[package]] -name = "anyhow" -version = "1.0.66" +name = "android-tzdata" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "anstream" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd" + +[[package]] +name = "anstyle-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" [[package]] name = "ap-relay" -version = "0.3.66" +version = "0.3.85" dependencies = [ "activitystreams", "activitystreams-ext", @@ -309,7 +387,7 @@ dependencies = [ "anyhow", "awc", "background-jobs", - "base64", + "base64 0.21.2", "bcrypt", "clap", "config", @@ -320,6 +398,7 @@ dependencies = [ "http-signature-normalization-actix", "lru", "metrics", + "metrics-exporter-prometheus", "metrics-util", "mime", "minify-html", @@ -331,17 +410,16 @@ dependencies = [ "rsa", "rsa-magic-public-key", "ructe", - "rustls", + "rustls 0.20.8", "rustls-pemfile", "serde", "serde_json", - "sha2", - "signature", "sled", "teloxide", "thiserror", + "time", "tokio", - "toml", + "toml 0.7.4", "tracing", "tracing-actix-web", "tracing-awc", @@ -363,71 +441,46 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "arc-swap" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "983cd8b9d4b02a6dc6ffa557262eb5858a27a0038ffffe21a0f133eaa819a164" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - -[[package]] -name = "async-mutex" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" -dependencies = [ - "event-listener", -] +checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" [[package]] name = "async-stream" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dad5c83079eae9969be7fadefe640a1c566901f05ff91ab221de4b6f68d9507e" +checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" dependencies = [ "async-stream-impl", "futures-core", + "pin-project-lite", ] [[package]] name = "async-stream-impl" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f203db73a71dfa2fb6dd22763990fa26f3d2625a6da2da900d23b87d26be27" +checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "async-trait" -version = "0.1.58" +version = "0.1.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c" +checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", + "syn 2.0.18", ] [[package]] @@ -438,9 +491,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "awc" -version = "3.0.1" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80ca7ff88063086d2e2c70b9f3b29b2fcd999bac68ac21731e66781970d68519" +checksum = "87ef547a81796eb2dfe9b345aba34c2e08391a0502493711395b36dd64052b69" dependencies = [ "actix-codec", "actix-http", @@ -448,8 +501,8 @@ dependencies = [ "actix-service", "actix-tls", "actix-utils", - "ahash", - "base64", + "ahash 0.7.6", + "base64 0.21.2", "bytes", "cfg-if", "derive_more", @@ -463,7 +516,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rand", - "rustls", + "rustls 0.20.8", "serde", "serde_json", "serde_urlencoded", @@ -472,9 +525,9 @@ dependencies = [ [[package]] name = "axum" -version = "0.5.17" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acee9fd5073ab6b045a275b3e709c163dd36c90685219cb21804a147b58dba43" +checksum = "f8175979259124331c1d7bf6586ee7e0da434155e4b2d48ec2c8386281d8df39" dependencies = [ "async-trait", "axum-core", @@ -490,20 +543,19 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", + "rustversion", "serde", "sync_wrapper", - "tokio", "tower", - "tower-http", "tower-layer", "tower-service", ] [[package]] name = "axum-core" -version = "0.2.9" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e5939e02c56fecd5c017c37df4238c0a839fa76b7f97acdd7efb804fd181cc" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" dependencies = [ "async-trait", "bytes", @@ -511,15 +563,16 @@ dependencies = [ "http", "http-body", "mime", + "rustversion", "tower-layer", "tower-service", ] [[package]] name = "background-jobs" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62dc7cfc967d6714768097a876ca2941a54a26976c6d3c95ea6da48974890970" +checksum = "a0788884be043a6ea4812f533b53f47180f1fb68a45d6a1e7c9f55369f187bd9" dependencies = [ "background-jobs-actix", "background-jobs-core", @@ -527,13 +580,12 @@ dependencies = [ [[package]] name = "background-jobs-actix" -version = "0.14.2" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99f8bfe0a984c8d0bc7e67b376cc05e0b9015fdd3ee878900046120ef781c47e" +checksum = "6918aac07d254c283e83e74d94d2a4137eb8eb2bb35749553b2aeedefc13243d" dependencies = [ "actix-rt", "anyhow", - "async-mutex", "async-trait", "background-jobs-core", "metrics", @@ -548,9 +600,9 @@ dependencies = [ [[package]] name = "background-jobs-core" -version = "0.14.1" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1274e49ae8eff1fc6b4943660e59ce2f2e13e65a23a707924a50a40c7b94fc4d" +checksum = "19188ccc4964d2d7ac0349ec05290b079c49a6218dc9a70516c9084790efc039" dependencies = [ "actix-rt", "anyhow", @@ -573,20 +625,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] -name = "base64ct" -version = "1.5.3" +name = "base64" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bcrypt" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7e7c93a3fb23b2fdde989b2c9ec4dd153063ec81f408507f84c090cd91c6641" +checksum = "9df288bec72232f78c1ec5fe4e8f1d108aa0265476e93097593c803c8c02062a" dependencies = [ - "base64", + "base64 0.21.2", "blowfish", "getrandom", + "subtle", "zeroize", ] @@ -596,23 +655,11 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" -[[package]] -name = "bitvec" -version = "0.19.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55f93d0ef3363c364d5976646a38f04cf67cfe1d4c8d160cdea02cab2c116b33" -dependencies = [ - "funty", - "radium", - "tap", - "wyz", -] - [[package]] name = "block-buffer" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] @@ -640,9 +687,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.3.2" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80" +checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -650,9 +697,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.11.1" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "bytecount" @@ -668,24 +715,24 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "bytes" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "bytestring" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7f83e57d9154148e355404702e2694463241880b939570d7c97c014da7a69a1" +checksum = "238e4886760d98c4f899360c834fa93e62cf7f721ac3c2da375cbdf4b8679aae" dependencies = [ "bytes", ] [[package]] name = "cc" -version = "1.0.77" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" [[package]] name = "cfg-if" @@ -695,19 +742,19 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.23" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f" +checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5" dependencies = [ - "num-integer", + "android-tzdata", "num-traits", ] [[package]] name = "cipher" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", @@ -715,77 +762,88 @@ dependencies = [ [[package]] name = "clap" -version = "4.0.26" +version = "4.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2148adefda54e14492fb9bddcc600b4344c5d1a3123bd666dcb939c6f0e0e57e" +checksum = "6320c6d1c98b6981da7bb2dcecbd0be9dc98d42165fa8326b21000f7dbfde6d0" dependencies = [ - "atty", - "bitflags", + "clap_builder", "clap_derive", - "clap_lex", "once_cell", +] + +[[package]] +name = "clap_builder" +version = "4.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e53afce1efce6ed1f633cf0e57612fe51db54a1ee4fd8f8503d078fe02d69ae" +dependencies = [ + "anstream", + "anstyle", + "bitflags", + "clap_lex", "strsim", - "termcolor", ] [[package]] name = "clap_derive" -version = "4.0.21" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014" +checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f" dependencies = [ "heck", - "proc-macro-error", "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "clap_lex" -version = "0.3.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8" -dependencies = [ - "os_str_bytes", -] +checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" [[package]] name = "config" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f1667b8320afa80d69d8bbe40830df2c8a06003d86f73d8e003b2c48df416d" +checksum = "d379af7f68bfc21714c6c7dea883544201741d2ce8274bb12fa54f89507f52a7" dependencies = [ "async-trait", "json5", "lazy_static", - "nom 7.1.1", + "nom", "pathdiff", "ron", "rust-ini", "serde", "serde_json", - "toml", + "toml 0.5.11", "yaml-rust", ] [[package]] name = "console-api" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e57ff02e8ad8e06ab9731d5dc72dc23bef9200778eae1a89d555d8c42e5d4a86" +checksum = "c2895653b4d9f1538a83970077cb01dfc77a4810524e51a110944688e916b18e" dependencies = [ "prost", "prost-types", - "tonic", + "tonic 0.9.2", "tracing-core", ] [[package]] name = "console-subscriber" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a3a81dfaf6b66bce5d159eddae701e3a002f194d378cbf7be5f053c281d9be" +checksum = "57ab2224a0311582eb03adba4caaf18644f7b1f10a760803a803b9b605187fc7" dependencies = [ "console-api", "crossbeam-channel", @@ -799,7 +857,7 @@ dependencies = [ "thread_local", "tokio", "tokio-stream", - "tonic", + "tonic 0.9.2", "tracing", "tracing-core", "tracing-subscriber", @@ -807,9 +865,9 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cec318a675afcb6a1ea1d4340e2d377e56e47c266f28043ceccbf4412ddfdd3b" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" [[package]] name = "convert_case" @@ -819,9 +877,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "cpufeatures" -version = "0.2.5" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320" +checksum = "03e69e28e9f7f77debdedbaafa2866e1de9ba56df55a8bd7cfc724c25a09987c" dependencies = [ "libc", ] @@ -837,9 +895,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.6" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" dependencies = [ "cfg-if", "crossbeam-utils", @@ -847,9 +905,9 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.13" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", "cfg-if", @@ -860,9 +918,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.14" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -879,13 +937,13 @@ dependencies = [ [[package]] name = "css-minify" -version = "0.2.2" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692b185e3b7c9af96b3195f3021f53a931d896968ed2ad3fb1cdb6558b30c9ab" +checksum = "874c6e2d19f8d4a285083b11a3241bfbe01ac3ed85f26e1e6b34888d960552bd" dependencies = [ "derive_more", "indexmap", - "nom 6.1.2", + "nom", ] [[package]] @@ -909,7 +967,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn", + "syn 1.0.109", ] [[package]] @@ -920,7 +978,7 @@ checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" dependencies = [ "darling_core", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -930,17 +988,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "907076dfda823b0b36d2a1bb5f90c96660a5bbcd7729e10727f07858f22c4edc" dependencies = [ "cfg-if", - "hashbrown", + "hashbrown 0.12.3", "lock_api", "once_cell", - "parking_lot_core 0.9.4", + "parking_lot_core 0.9.8", ] [[package]] name = "der" -version = "0.6.0" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dd2ae565c0a381dde7fade45fce95984c568bdcb4700a4fdbe3175e0380b2f" +checksum = "56acb310e15652100da43d130af8d97b509e95af61aab1c5a7939ef24337ee17" dependencies = [ "const-oid", "pem-rfc7468", @@ -957,14 +1015,14 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn", + "syn 1.0.109", ] [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "const-oid", @@ -994,15 +1052,15 @@ dependencies = [ [[package]] name = "either" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" [[package]] name = "encoding_rs" -version = "0.8.31" +version = "0.8.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" dependencies = [ "cfg-if", ] @@ -1023,6 +1081,27 @@ dependencies = [ "scopeguard", ] +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "event-listener" version = "2.5.3" @@ -1031,24 +1110,18 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "fastrand" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" dependencies = [ "instant", ] -[[package]] -name = "fixedbitset" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" - [[package]] name = "flate2" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" dependencies = [ "crc32fast", "miniz_oxide", @@ -1062,9 +1135,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -1079,12 +1152,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "funty" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed34cd105917e91daa4da6b3728c47b068749d6a62c59811f06ed2ac71d9da7" - [[package]] name = "futf" version = "0.1.5" @@ -1097,9 +1164,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38390104763dc37a5145a53c29c63c1290b5d316d6086ec32c293f6736051bb0" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -1112,9 +1179,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ba265a92256105f45b719605a571ffe2d1f0fea3807304b522c1d778f79eed" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -1122,15 +1189,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7acc85df6714c176ab5edf386123fafe217be88c0840ec11f199441134a074e2" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -1139,38 +1206,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00f5fb52a06bdcadeb54e8d3671f8888a39697dcb0b81b23b55174030427f4eb" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-macro" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "futures-sink" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39c15cf1a4aa79df40f1bb462fb39676d0ad9e366c2a33b590d7c66f4f81fcf9" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-util" -version = "0.3.25" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", @@ -1195,9 +1262,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -1205,20 +1272,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "h2" -version = "0.3.15" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4" +checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" dependencies = [ "bytes", "fnv", @@ -1239,7 +1306,16 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash", + "ahash 0.7.6", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.3", ] [[package]] @@ -1248,28 +1324,34 @@ version = "7.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f19b9f54f7c7f55e31401bb647626ce0cf0f67b0004982ce815b3ee72a02aa8" dependencies = [ - "base64", + "base64 0.13.1", "byteorder", "flate2", - "nom 7.1.1", + "nom", "num-traits", ] [[package]] name = "heck" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" -version = "0.1.19" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + [[package]] name = "html5ever" version = "0.26.0" @@ -1281,14 +1363,14 @@ dependencies = [ "markup5ever", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "http" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75f43d41e26995c17e71ee126451dd3941010b0514a81a9d11f3b341debc2399" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" dependencies = [ "bytes", "fnv", @@ -1306,32 +1388,26 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "http-range-header" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" - [[package]] name = "http-signature-normalization" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8f45adbef81d7ea3bd7e9bcc6734b7245dad05a14abdcc7ddc0988791d63515" +checksum = "b95e3149194de5f3f9d5225bcc6a8677979f8ff8ce39c85654730ad4824f101e" dependencies = [ "httpdate", ] [[package]] name = "http-signature-normalization-actix" -version = "0.6.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7483d0ee4d093fa4bfe5956cd405492c07808a5064a29cfe3960d474f21f39c2" +checksum = "1dc95d9ca3b4e2f93a97e5ccf9f26992c69a272e0abad8807180f0a9e9b59e31" dependencies = [ "actix-http", "actix-rt", "actix-web", "awc", - "base64", + "base64 0.13.1", "futures-util", "http-signature-normalization", "sha2", @@ -1362,9 +1438,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.23" +version = "0.14.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "034711faac9d2166cb1baf1a2fb0b60b1f277f8492fd72176c17f3515e1abd3c" +checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" dependencies = [ "bytes", "futures-channel", @@ -1386,15 +1462,15 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59df7c4e19c950e6e0e868dcc0a300b09a9b88e9ec55bd879ca819087a77355d" +checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7" dependencies = [ "http", "hyper", - "rustls", + "rustls 0.21.2", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", ] [[package]] @@ -1417,9 +1493,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1427,12 +1503,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -1454,20 +1530,44 @@ dependencies = [ ] [[package]] -name = "ipnet" -version = "2.5.1" +name = "io-lifetimes" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys", +] + +[[package]] +name = "ipnet" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" [[package]] name = "iri-string" -version = "0.5.6" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf071934ee7ee97e52fa1868a9540a7885eab75926bd70794030304a9797cea1" +checksum = "21859b667d66a4c1dacd9df0863b3efb65785474255face87f5bca39dd8407c0" dependencies = [ + "memchr", "serde", ] +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys", +] + [[package]] name = "itertools" version = "0.9.0" @@ -1488,15 +1588,15 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" [[package]] name = "js-sys" -version = "0.3.60" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -1527,30 +1627,17 @@ dependencies = [ "spin", ] -[[package]] -name = "lexical-core" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6607c62aa161d23d17a9072cc5da0be67cdfc89d3afb1e8d9c842bebc2525ffe" -dependencies = [ - "arrayvec", - "bitflags", - "cfg-if", - "ryu", - "static_assertions", -] - [[package]] name = "libc" -version = "0.2.137" +version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" [[package]] name = "libm" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" [[package]] name = "linked-hash-map" @@ -1558,6 +1645,12 @@ version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + [[package]] name = "local-channel" version = "0.1.3" @@ -1578,9 +1671,9 @@ checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -1588,20 +1681,17 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "lru" -version = "0.8.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6e8aaa3f231bb4bd57b84b2d5dc3ae7f350265df8aa96492e0bc394a1571909" +checksum = "03f1160296536f10c833a82dca22267d5486734230d47bf00bf435885814ba1e" dependencies = [ - "hashbrown", + "hashbrown 0.13.2", ] [[package]] @@ -1611,10 +1701,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" [[package]] -name = "mach" -version = "0.3.2" +name = "mach2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" dependencies = [ "libc", ] @@ -1650,9 +1740,9 @@ dependencies = [ [[package]] name = "matchit" -version = "0.5.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" +checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" [[package]] name = "md5" @@ -1668,51 +1758,66 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" dependencies = [ "autocfg", ] [[package]] name = "metrics" -version = "0.20.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b9b8653cec6897f73b519a43fba5ee3d50f62fe9af80b428accdcc093b4a849" +checksum = "aa8ebbd1a9e57bbab77b9facae7f5136aea44c356943bf9a198f647da64285d6" dependencies = [ - "ahash", + "ahash 0.8.3", "metrics-macros", "portable-atomic", ] [[package]] -name = "metrics-macros" -version = "0.6.0" +name = "metrics-exporter-prometheus" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "731f8ecebd9f3a4aa847dfe75455e4757a45da40a7793d2f0b1f9b6ed18b23f3" +checksum = "8a4964177ddfdab1e3a2b37aec7cf320e14169abb0ed73999f558136409178d5" +dependencies = [ + "base64 0.21.2", + "hyper", + "indexmap", + "ipnet", + "metrics", + "metrics-util", + "quanta", + "thiserror", + "tokio", +] + +[[package]] +name = "metrics-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddece26afd34c31585c74a4db0630c376df271c285d682d1e55012197830b6df" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "metrics-util" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d24dc2dbae22bff6f1f9326ffce828c9f07ef9cc1e8002e5279f845432a30a" +checksum = "111cb375987443c3de8d503580b536f77dc8416d32db62d9456db5d93bd7ac47" dependencies = [ - "aho-corasick", + "aho-corasick 0.7.20", "crossbeam-epoch", "crossbeam-utils", - "hashbrown", + "hashbrown 0.13.2", "indexmap", "metrics", "num_cpus", "ordered-float", - "parking_lot 0.12.1", - "portable-atomic", "quanta", "radix_trie", "sketches-ddsketch", @@ -1720,9 +1825,9 @@ dependencies = [ [[package]] name = "mime" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "mime_guess" @@ -1736,22 +1841,23 @@ dependencies = [ [[package]] name = "minify-html" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f84854d62363972a73c3d8331b85a479366a0871a83f2a01ac11b9ba787c10" +checksum = "fc4d9147754a49e80557df835eb59e743eab1bf75410a134f55dc4b9dbb692ad" dependencies = [ - "aho-corasick", + "aho-corasick 0.7.20", "css-minify", "lazy_static", "memchr", "minify-js", + "rustc-hash", ] [[package]] name = "minify-js" -version = "0.2.9" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe033709f5a1159736cf7e22748518ffb75af26f3a6264d52ecc8bb38c68c36" +checksum = "c300f90ba1138b5c5daf5d9441dc9bdc67b808aac22cf638362a2647bc213be4" dependencies = [ "lazy_static", "parse-js", @@ -1765,31 +1871,25 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.5.4" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "log", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", "windows-sys", ] -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - [[package]] name = "never" version = "0.1.0" @@ -1813,38 +1913,14 @@ dependencies = [ [[package]] name = "nom" -version = "6.1.2" +version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7413f999671bd4745a7b624bd370a569fb6bc574b23c83a3c5ed2e453f3d5e2" -dependencies = [ - "bitvec", - "funty", - "lexical-core", - "memchr", - "version_check", -] - -[[package]] -name = "nom" -version = "7.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", ] -[[package]] -name = "nom_locate" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37794436ca3029a3089e0b95d42da1f0b565ad271e4d3bb4bad0c7bb70b10605" -dependencies = [ - "bytecount", - "memchr", - "nom 7.1.1", -] - [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -1912,6 +1988,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" dependencies = [ "autocfg", + "num-bigint", "num-integer", "num-traits", ] @@ -1928,25 +2005,25 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "libc", ] [[package]] name = "once_cell" -version = "1.16.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "opentelemetry" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d6c3d7288a106c0a363e4b0e8d308058d56902adefb16f4936f417ffef086e" +checksum = "5f4b8347cc26099d3aeee044065ecc3ae11469796b4d65d065a23a584ed92a6f" dependencies = [ "opentelemetry_api", "opentelemetry_sdk", @@ -1954,9 +2031,9 @@ dependencies = [ [[package]] name = "opentelemetry-otlp" -version = "0.11.0" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1c928609d087790fc936a1067bdc310ae702bdf3b090c3f281b713622c8bbde" +checksum = "8af72d59a4484654ea8eb183fea5ae4eb6a41d7ac3e3bae5f4d2a282a3a7d3ca" dependencies = [ "async-trait", "futures", @@ -1967,44 +2044,43 @@ dependencies = [ "prost", "thiserror", "tokio", - "tonic", + "tonic 0.8.3", ] [[package]] name = "opentelemetry-proto" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61a2f56df5574508dd86aaca016c917489e589ece4141df1b5e349af8d66c28" +checksum = "045f8eea8c0fa19f7d48e7bc3128a39c2e5c533d5c61298c548dfefc1064474c" dependencies = [ "futures", "futures-util", "opentelemetry", "prost", - "tonic", - "tonic-build", + "tonic 0.8.3", ] [[package]] name = "opentelemetry_api" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c24f96e21e7acc813c7a8394ee94978929db2bcc46cf6b5014fc612bf7760c22" +checksum = "ed41783a5bf567688eb38372f2b7a8530f5a607a4b49d38dd7573236c23ca7e2" dependencies = [ "fnv", "futures-channel", "futures-util", "indexmap", - "js-sys", "once_cell", "pin-project-lite", "thiserror", + "urlencoding", ] [[package]] name = "opentelemetry_sdk" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ca41c4933371b61c2a2f214bf16931499af4ec90543604ec828f7a625c09113" +checksum = "8b3a2a91fdbfdd4d212c0dcc2ab540de2c2bcbbd90be17de7a7daf8822d010c1" dependencies = [ "async-trait", "crossbeam-channel", @@ -2024,9 +2100,9 @@ dependencies = [ [[package]] name = "ordered-float" -version = "2.10.0" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" +checksum = "2fc2dbde8f8a79f2102cc474ceb0ad68e3b80b85289ea62389b60e66777e4213" dependencies = [ "num-traits", ] @@ -2038,15 +2114,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccd746e37177e1711c20dd619a1620f34f5c8b569c53590a72dedd5344d8924a" dependencies = [ "dlv-list", - "hashbrown", + "hashbrown 0.12.3", ] -[[package]] -name = "os_str_bytes" -version = "6.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee" - [[package]] name = "overload" version = "0.1.1" @@ -2061,7 +2131,7 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core 0.8.5", + "parking_lot_core 0.8.6", ] [[package]] @@ -2071,52 +2141,52 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.4", + "parking_lot_core 0.9.8", ] [[package]] name = "parking_lot_core" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ "cfg-if", "instant", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", "winapi", ] [[package]] name = "parking_lot_core" -version = "0.9.4" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.3.5", "smallvec", - "windows-sys", + "windows-targets", ] [[package]] name = "parse-js" -version = "0.3.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66bb85ec60d22b9e6d4adac1e3dbdaf3903a4485f476c5f4dd7ed1285cbf4dad" +checksum = "30534759e6ad87aa144c396544747e1c25b1020bd133356fd758c8facec764e5" dependencies = [ - "aho-corasick", + "aho-corasick 0.7.20", "lazy_static", "memchr", ] [[package]] name = "paste" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1de2e551fb905ac83f73f7aedf2f0cb4a0da7e35efa24a202a936269f1f18e1" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" [[package]] name = "pathdiff" @@ -2126,24 +2196,24 @@ checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" [[package]] name = "pem-rfc7468" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" dependencies = [ "base64ct", ] [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "pest" -version = "2.4.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a528564cc62c19a7acac4d81e01f39e53e25e17b934878f4c6d25cc2836e62f8" +checksum = "f73935e4d55e2abf7f130186537b19e7a4abc886a0252380b59248af473a3fc9" dependencies = [ "thiserror", "ucd-trie", @@ -2151,9 +2221,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.4.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fd9bc6500181952d34bd0b2b0163a54d794227b498be0b7afa7698d0a7b18f" +checksum = "aef623c9bbfa0eedf5a0efba11a5ee83209c326653ca31ff019bec3a95bfff2b" dependencies = [ "pest", "pest_generator", @@ -2161,36 +2231,26 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.4.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2610d5ac5156217b4ff8e46ddcef7cdf44b273da2ac5bca2ecbfa86a330e7c4" +checksum = "b3e8cba4ec22bada7fc55ffe51e2deb6a0e0db2d0b7ab0b103acc80d2510c190" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "pest_meta" -version = "2.4.1" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824749bf7e21dd66b36fbe26b3f45c713879cccd4a009a917ab8e045ca8246fe" +checksum = "a01f71cb40bd8bb94232df14b946909e14660e33fc05db3e50ae2a82d7ea0ca0" dependencies = [ "once_cell", "pest", - "sha1", -] - -[[package]] -name = "petgraph" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5014253a1331579ce62aa67443b4a658c5e7dd03d4bc6d302b94474888143" -dependencies = [ - "fixedbitset", - "indexmap", + "sha2", ] [[package]] @@ -2233,22 +2293,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" +checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.12" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" +checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] @@ -2265,21 +2325,20 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkcs1" -version = "0.4.1" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eff33bdbdfc54cc98a2eca766ebdec3e1b8fb7387523d5c9c9a2891da856f719" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" dependencies = [ "der", "pkcs8", "spki", - "zeroize", ] [[package]] name = "pkcs8" -version = "0.9.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ "der", "spki", @@ -2287,9 +2346,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "0.3.15" +version = "1.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15eb2c6e362923af47e13c23ca5afb859e83d54452c55b0b9ac763b8f7c1ac16" +checksum = "767eb9f07d4a5ebcb39bbf2d452058a93c011373abf6832e24194a1c3f004794" [[package]] name = "ppv-lite86" @@ -2303,16 +2362,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" -[[package]] -name = "prettyplease" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c142c0e46b57171fe0c528bee8c5b7569e80f0c17e377cd0e30ea57dbc11bb51" -dependencies = [ - "proc-macro2", - "syn", -] - [[package]] name = "proc-macro-error" version = "1.0.4" @@ -2322,7 +2371,7 @@ dependencies = [ "proc-macro-error-attr", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "version_check", ] @@ -2339,99 +2388,70 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.47" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" +checksum = "dec2b086b7a862cf4de201096214fa870344cf922b2b30c167badb3af3195406" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.11.2" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0841812012b2d4a6145fae9a6af1534873c32aa67fff26bd09f8fa42c83f95a" +checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" dependencies = [ "bytes", "prost-derive", ] -[[package]] -name = "prost-build" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d8b442418ea0822409d9e7d047cbf1e7e9e1760b172bf9982cf29d517c93511" -dependencies = [ - "bytes", - "heck", - "itertools 0.10.5", - "lazy_static", - "log", - "multimap", - "petgraph", - "prettyplease", - "prost", - "prost-types", - "regex", - "syn", - "tempfile", - "which", -] - [[package]] name = "prost-derive" -version = "0.11.2" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164ae68b6587001ca506d3bf7f1000bfa248d0e1217b618108fba4ec1d0cc306" +checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" dependencies = [ "anyhow", "itertools 0.10.5", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "prost-types" -version = "0.11.2" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "747761bc3dc48f9a34553bf65605cf6cb6288ba219f3450b4275dbd81539551a" +checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" dependencies = [ - "bytes", "prost", ] [[package]] name = "quanta" -version = "0.10.1" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e31331286705f455e56cca62e0e717158474ff02b7936c1fa596d983f4ae27" +checksum = "a17e662a7a8291a865152364c20c7abc5e60486ab2001e8ec10b24862de0b9ab" dependencies = [ "crossbeam-utils", "libc", - "mach", + "mach2", "once_cell", "raw-cpuid", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi", "web-sys", "winapi", ] [[package]] name = "quote" -version = "1.0.21" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] -[[package]] -name = "radium" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941ba9d78d8e2f7ce474c015eea4d9c6d25b6a3327f9832ee29a4de27f91bbb8" - [[package]] name = "radix_trie" version = "0.2.1" @@ -2474,9 +2494,9 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "10.6.0" +version = "10.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6823ea29436221176fe662da99998ad3b4db2c7f31e7b6f5fe43adccd6320bb" +checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" dependencies = [ "bitflags", ] @@ -2500,14 +2520,23 @@ dependencies = [ ] [[package]] -name = "regex" -version = "1.7.0" +name = "redox_syscall" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e076559ef8e241f2ae3479e36f97bd5741c0330689e217ad51ce2c76808b868a" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" dependencies = [ - "aho-corasick", + "bitflags", +] + +[[package]] +name = "regex" +version = "1.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" +dependencies = [ + "aho-corasick 1.0.2", "memchr", - "regex-syntax", + "regex-syntax 0.7.2", ] [[package]] @@ -2516,31 +2545,28 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax", + "regex-syntax 0.6.29", ] [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] -name = "remove_dir_all" -version = "0.5.3" +name = "regex-syntax" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "reqwest" -version = "0.11.13" +version = "0.11.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" dependencies = [ - "base64", + "base64 0.21.2", "bytes", "encoding_rs", "futures-core", @@ -2558,18 +2584,19 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "rustls", + "rustls 0.21.2", "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tokio-util", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", "webpki-roots", "winreg", @@ -2596,18 +2623,19 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a" dependencies = [ - "base64", + "base64 0.13.1", "bitflags", "serde", ] [[package]] name = "rsa" -version = "0.7.2" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "094052d5470cbcef561cb848a7209968c9f12dfa6d668f4bca048ac5de51099c" +checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8" dependencies = [ "byteorder", + "const-oid", "digest", "num-bigint-dig", "num-integer", @@ -2616,19 +2644,20 @@ dependencies = [ "pkcs1", "pkcs8", "rand_core", + "sha2", "signature", - "smallvec", + "spki", "subtle", "zeroize", ] [[package]] name = "rsa-magic-public-key" -version = "0.6.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8dc035c92400b90ee471e0ea7e041bfadd4da26dd3e716a84053d0075ed9c159" +checksum = "88ca6a6947c6fe6454c93c3bb65b92f9680e6f9e906e75e30631110f2227344c" dependencies = [ - "base64", + "base64 0.21.2", "num-bigint-dig", "rsa", "thiserror", @@ -2636,15 +2665,14 @@ dependencies = [ [[package]] name = "rsass" -version = "0.26.0" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "665387d3be91521de331a04cc7118c8c129ffe43c5f4e8a61e78990850046b5a" +checksum = "a43695dd28122f6c684273de89796a56a98e02e9694b8ab57b160fdc6e6d69af" dependencies = [ "arc-swap", "fastrand", "lazy_static", - "nom 7.1.1", - "nom_locate", + "nom", "num-bigint", "num-integer", "num-rational", @@ -2654,16 +2682,16 @@ dependencies = [ [[package]] name = "ructe" -version = "0.15.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85517cd381cf0c34694881d8aaf173107c6af7670e66cec18d7a1a8bfce3b758" +checksum = "79c86c1631418815c5947a34be5872806586c65398754ec91cc2df35a8e26ba8" dependencies = [ - "base64", + "base64 0.21.2", "bytecount", "itertools 0.10.5", "md5", "mime", - "nom 7.1.1", + "nom", "rsass", ] @@ -2677,6 +2705,12 @@ dependencies = [ "ordered-multimap", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc_version" version = "0.4.0" @@ -2687,10 +2721,24 @@ dependencies = [ ] [[package]] -name = "rustls" -version = "0.20.7" +name = "rustix" +version = "0.37.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "539a2bfe908f471bfa933876bd1eb6a19cf2176d375f82ef7f99530a40e48c2c" +checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustls" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" dependencies = [ "log", "ring", @@ -2699,19 +2747,47 @@ dependencies = [ ] [[package]] -name = "rustls-pemfile" -version = "1.0.1" +name = "rustls" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55" +checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f" dependencies = [ - "base64", + "log", + "ring", + "rustls-webpki", + "sct", ] [[package]] -name = "ryu" -version = "1.0.11" +name = "rustls-pemfile" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +dependencies = [ + "base64 0.21.2", +] + +[[package]] +name = "rustls-webpki" +version = "0.100.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" [[package]] name = "scopeguard" @@ -2731,41 +2807,50 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.147" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.147" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "serde_json" -version = "1.0.89" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db" +checksum = "bdf3bf93142acad5821c99197022e170842cdbc1c30482b98750c688c640842a" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -2787,7 +2872,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -2803,9 +2888,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8" dependencies = [ "cfg-if", "cpufeatures", @@ -2823,18 +2908,18 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" dependencies = [ "libc", ] [[package]] name = "signature" -version = "1.6.4" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" dependencies = [ "digest", "rand_core", @@ -2848,15 +2933,15 @@ checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "sketches-ddsketch" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceb945e54128e09c43d8e4f1277851bd5044c6fc540bbaa2ad888f60b3da9ae7" +checksum = "68a406c1882ed7f29cd5e248c9848a80e7cb6ae0fea82346d2746f2f941c07e1" [[package]] name = "slab" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg", ] @@ -2885,9 +2970,9 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" [[package]] name = "socket2" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" dependencies = [ "libc", "winapi", @@ -2901,25 +2986,19 @@ checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spki" -version = "0.6.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" dependencies = [ "base64ct", "der", ] -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "string_cache" -version = "0.8.4" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213494b7a2b503146286049378ce02b482200519accc31872ee8be91fa820a08" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ "new_debug_unreachable", "once_cell", @@ -2949,15 +3028,26 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "subtle" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "1.0.103" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" dependencies = [ "proc-macro2", "quote", @@ -2966,9 +3056,9 @@ dependencies = [ [[package]] name = "sync_wrapper" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "take_mut" @@ -2982,17 +3072,11 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20f34339676cdcab560c9a82300c4c2581f68b9369aedf0fae86f2ff9565ff3e" -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - [[package]] name = "teloxide" -version = "0.11.2" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19017dde82bddcbbdf8e40484f23985f4097b1baef4f7c0e006195ad1e6d4e3c" +checksum = "c63345cf32a8850ebddcdd769dc2d5193d5e231262d5dada264b79da01a664da" dependencies = [ "aquamarine", "bytes", @@ -3016,9 +3100,9 @@ dependencies = [ [[package]] name = "teloxide-core" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9243a720aa9bddda324a7f90b4ab42887425524bf4d5d24a56b50bccb984b7c4" +checksum = "303db260110c238e3af77bb9dff18bf7a5b5196f783059b0852aab75f91d5a16" dependencies = [ "bitflags", "bytes", @@ -3047,28 +3131,14 @@ dependencies = [ [[package]] name = "teloxide-macros" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40a5fc46d9004706ee23e3b73a0f53518f28498f7297813fa9a505a29638ffd6" +checksum = "0f1d653b093dba5e44cada57a516f572167df37b8a619443e59c8c517bb6d804" dependencies = [ "heck", "proc-macro2", "quote", - "syn", -] - -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", + "syn 1.0.109", ] [[package]] @@ -3082,49 +3152,41 @@ dependencies = [ "utf-8", ] -[[package]] -name = "termcolor" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" -dependencies = [ - "winapi-util", -] - [[package]] name = "thiserror" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.37" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" dependencies = [ + "cfg-if", "once_cell", ] [[package]] name = "time" -version = "0.3.17" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd" dependencies = [ "itoa", "serde", @@ -3134,15 +3196,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" [[package]] name = "time-macros" -version = "0.2.6" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d967f99f534ca7e495c575c62638eebc2898a8c84c119b89e250477bc4ba16b2" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" dependencies = [ "time-core", ] @@ -3158,20 +3220,19 @@ dependencies = [ [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.22.0" +version = "1.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3" +checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" dependencies = [ "autocfg", "bytes", "libc", - "memchr", "mio", "parking_lot 0.12.1", "pin-project-lite", @@ -3179,7 +3240,7 @@ dependencies = [ "socket2", "tokio-macros", "tracing", - "winapi", + "windows-sys", ] [[package]] @@ -3194,13 +3255,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "1.8.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] @@ -3209,16 +3270,26 @@ version = "0.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" dependencies = [ - "rustls", + "rustls 0.20.8", "tokio", "webpki", ] [[package]] -name = "tokio-stream" -version = "0.1.11" +name = "tokio-rustls" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d660770404473ccd7bc9f8b28494a811bc18542b915c0855c51e8f419d5223ce" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.2", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ "futures-core", "pin-project-lite", @@ -3227,9 +3298,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.4" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb2e075f03b3d66d8d8785356224ba688d2906a371015e225beeb65ca92c740" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes", "futures-core", @@ -3241,23 +3312,57 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] [[package]] -name = "tonic" -version = "0.8.2" +name = "toml" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55b9af819e54b8f33d453655bef9b9acc171568fb49523078d0cc4e7484200ec" +checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tonic" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb" dependencies = [ "async-stream", "async-trait", "axum", - "base64", + "base64 0.13.1", "bytes", "futures-core", "futures-util", @@ -3281,16 +3386,31 @@ dependencies = [ ] [[package]] -name = "tonic-build" -version = "0.8.2" +name = "tonic" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c6fd7c2581e36d63388a9e04c350c21beb7a8b059580b2e93993c526899ddc" +checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a" dependencies = [ - "prettyplease", - "proc-macro2", - "prost-build", - "quote", - "syn", + "async-trait", + "axum", + "base64 0.21.2", + "bytes", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-timeout", + "percent-encoding", + "pin-project", + "prost", + "tokio", + "tokio-stream", + "tower", + "tower-layer", + "tower-service", + "tracing", ] [[package]] @@ -3313,25 +3433,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "tower-http" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c530c8675c1dbf98facee631536fa116b5fb6382d7dd6dc1b118d970eafe3ba" -dependencies = [ - "bitflags", - "bytes", - "futures-core", - "futures-util", - "http", - "http-body", - "http-range-header", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", -] - [[package]] name = "tower-layer" version = "0.3.2" @@ -3359,9 +3460,9 @@ dependencies = [ [[package]] name = "tracing-actix-web" -version = "0.6.2" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d725b8fa6ef307b3f4856913523337de45c47cc79271bafd7acfb39559e3a2da" +checksum = "ce52ffaf2d544e317d3bef63f49a6a22022866505fa4840a4339b1756834a2a9" dependencies = [ "actix-web", "pin-project", @@ -3371,20 +3472,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.23" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a" +checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", ] [[package]] name = "tracing-awc" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab0b57d9e4b25f3d5f17d705c11c13c333b26dc062c02a9dedfe6a26f750a99e" +checksum = "eaa1a68fce4d1a7fad459f81ddcafbdd7c6f6bcda5c7e07d5f42db637931fac7" dependencies = [ "actix-http", "actix-service", @@ -3397,9 +3498,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", "valuable", @@ -3438,9 +3539,9 @@ dependencies = [ [[package]] name = "tracing-opentelemetry" -version = "0.18.0" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21ebb87a95ea13271332df069020513ab70bdb5637ca42d6e492dc3bbbad48de" +checksum = "00a39dcf9bfc1742fa4d6215253b33a6e474be78275884c216fc2a06267b3600" dependencies = [ "once_cell", "opentelemetry", @@ -3452,9 +3553,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6176eae26dd70d0c919749377897b54a9276bd7061339665dd68777926b5a70" +checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77" dependencies = [ "matchers", "nu-ansi-term", @@ -3470,15 +3571,15 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" [[package]] name = "typenum" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" [[package]] name = "ucd-trie" @@ -3497,15 +3598,15 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" [[package]] name = "unicode-ident" -version = "1.0.5" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "unicode-normalization" @@ -3524,9 +3625,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", "idna", @@ -3534,6 +3635,12 @@ dependencies = [ "serde", ] +[[package]] +name = "urlencoding" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8db7427f936968176eaa7cdf81b7f98b980b18495ec28f1b5791ac3bfe3eea9" + [[package]] name = "utf-8" version = "0.7.6" @@ -3541,10 +3648,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" [[package]] -name = "uuid" -version = "1.2.2" +name = "utf8parse" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "uuid" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa2982af2eec27de306107c027578ff7f423d65f7250e40ce0fea8f45248b81" dependencies = [ "getrandom", "serde", @@ -3564,20 +3677,13 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] -[[package]] -name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" @@ -3586,9 +3692,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.83" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3596,24 +3702,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.83" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.18", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.33" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23639446165ca5a5de86ae1d8896b737ae80319560fbaa4c2887b7da6e7ebd7d" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" dependencies = [ "cfg-if", "js-sys", @@ -3623,9 +3729,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.83" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3633,28 +3739,41 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.83" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.18", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.83" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" + +[[package]] +name = "wasm-streams" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bbae3363c08332cadccd13b67db371814cd214c2524020932f0804b8cf7c078" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] [[package]] name = "web-sys" -version = "0.3.60" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", @@ -3672,24 +3791,13 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.22.5" +version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368bfe657969fb01238bb756d351dcade285e0f6fcbd36dcb23359a5169975be" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" dependencies = [ "webpki", ] -[[package]] -name = "which" -version = "4.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c831fbbee9e129a8cf93e7747a82da9d95ba8e16621cae60ec2cdc849bacb7b" -dependencies = [ - "either", - "libc", - "once_cell", -] - [[package]] name = "winapi" version = "0.3.9" @@ -3706,15 +3814,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -3723,9 +3822,18 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", @@ -3738,45 +3846,54 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" [[package]] name = "windows_aarch64_msvc" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" [[package]] name = "windows_i686_gnu" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" [[package]] name = "windows_i686_msvc" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" [[package]] name = "windows_x86_64_gnu" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" [[package]] name = "windows_x86_64_msvc" -version = "0.42.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winnow" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +dependencies = [ + "memchr", +] [[package]] name = "winreg" @@ -3787,12 +3904,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "wyz" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85e60b0d1b5f99db2556934e21937020776a5d31520bf169e851ac44e6420214" - [[package]] name = "yaml-rust" version = "0.4.5" @@ -3804,6 +3915,6 @@ dependencies = [ [[package]] name = "zeroize" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c394b5bd0c6f669e7275d9c20aa90ae064cb22e75a1cad54e1b34088034b149f" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/Cargo.toml b/Cargo.toml index fbc9e5f..d6358f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "ap-relay" description = "A simple activitypub relay" -version = "0.3.66" +version = "0.3.85" authors = ["asonix "] license = "AGPL-3.0" readme = "README.md" @@ -29,49 +29,51 @@ actix-web = { version = "4.0.1", default-features = false, features = [ "compress-gzip", ] } actix-webfinger = "0.4.0" -activitystreams = "0.7.0-alpha.19" -activitystreams-ext = "0.1.0-alpha.2" +activitystreams = "0.7.0-alpha.21" +activitystreams-ext = "0.1.0-alpha.3" ammonia = "3.1.0" awc = { version = "3.0.0", default-features = false, features = ["rustls"] } -bcrypt = "0.13" -base64 = "0.13" +bcrypt = "0.14" +base64 = "0.21" clap = { version = "4.0.0", features = ["derive"] } config = "0.13.0" console-subscriber = { version = "0.1", optional = true } dashmap = "5.1.0" dotenv = "0.15.0" futures-util = "0.3.17" -lru = "0.8.0" -metrics = "0.20.1" -metrics-util = "0.14.0" +lru = "0.10.0" +metrics = "0.21.0" +metrics-exporter-prometheus = { version = "0.12.0", default-features = false, features = [ + "http-listener", +] } +metrics-util = "0.15.0" mime = "0.3.16" -minify-html = "0.10.0" -opentelemetry = { version = "0.18", features = ["rt-tokio"] } -opentelemetry-otlp = "0.11" +minify-html = "0.11.0" +opentelemetry = { version = "0.19", features = ["rt-tokio"] } +opentelemetry-otlp = "0.12" pin-project-lite = "0.2.9" -quanta = "0.10.1" +quanta = "0.11.0" rand = "0.8" -rsa = "0.7" -rsa-magic-public-key = "0.6.0" +rsa = { version = "0.9", features = ["sha2"] } +rsa-magic-public-key = "0.8.0" rustls = "0.20.7" rustls-pemfile = "1.0.1" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -sha2 = { version = "0.10", features = ["oid"] } -signature = "1.6.4" sled = "0.34.7" -teloxide = { version = "0.11.1", default-features = false, features = [ +teloxide = { version = "0.12.0", default-features = false, features = [ "ctrlc_handler", "macros", "rustls", ] } thiserror = "1.0" +time = { version = "0.3.17", features = ["serde"] } tracing = "0.1" -tracing-awc = "0.1.6" +tracing-awc = "0.1.7" tracing-error = "0.2" tracing-futures = "0.2" tracing-log = "0.1" -tracing-opentelemetry = "0.18" +tracing-opentelemetry = "0.19" tracing-subscriber = { version = "0.3", features = [ "ansi", "env-filter", @@ -81,23 +83,23 @@ tokio = { version = "1", features = ["macros", "sync"] } uuid = { version = "1", features = ["v4", "serde"] } [dependencies.background-jobs] -version = "0.14.0" +version = "0.15.0" default-features = false features = ["background-jobs-actix", "error-logging"] [dependencies.http-signature-normalization-actix] -version = "0.6.0" +version = "0.8.0" default-features = false features = ["client", "server", "sha-2"] [dependencies.tracing-actix-web] -version = "0.6.1" +version = "0.7.5" [build-dependencies] anyhow = "1.0" dotenv = "0.15.0" -ructe = { version = "0.15.0", features = ["sass", "mime03"] } -toml = "0.5.8" +ructe = { version = "0.16.0", features = ["sass", "mime03"] } +toml = "0.7.0" [profile.dev.package.rsa] opt-level = 3 diff --git a/README.md b/README.md index 64d873e..66a6544 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,11 @@ _A simple and efficient activitypub relay_ If running docker, you can start the relay with the following command: ``` $ sudo docker run --rm -it \ - -v "./:/mnt/" \ + -v "$(pwd):/mnt/" \ -e ADDR=0.0.0.0 \ -e SLED_PATH=/mnt/sled/db-0.34 \ -p 8080:8080 \ - asonix/relay:0.3.52 + asonix/relay:0.3.85 ``` This will launch the relay with the database stored in "./sled/db-0.34" and listening on port 8080 #### Cargo @@ -103,6 +103,9 @@ TLS_CERT=/path/to/cert FOOTER_BLURB="Contact @asonix for inquiries" LOCAL_DOMAINS=masto.asonix.dog LOCAL_BLURB="

Welcome to my cool relay where I have cool relay things happening. I hope you enjoy your stay!

" +PROMETHEUS_ADDR=0.0.0.0 +PROMETHEUS_PORT=9000 +CLIENT_POOL_SIZE=20 ``` #### Descriptions @@ -128,6 +131,8 @@ Where to store the on-disk database of connected servers. This defaults to `./sl The log level to print. Available levels are `ERROR`, `WARN`, `INFO`, `DEBUG`, and `TRACE`. You can also specify module paths to enable some logs but not others, such as `RUST_LOG=warn,tracing_actix_web=info,relay=info`. This defaults to `warn` ##### `SOURCE_REPO` The URL to the source code for the relay. This defaults to `https://git.asonix.dog/asonix/relay`, but should be changed if you're running a fork hosted elsewhere. +##### `REPOSITORY_COMMIT_BASE` +The base path of the repository commit hash reference. For example, `/src/commit/` for Gitea, `/tree/` for GitLab. ##### `API_TOKEN` The Secret token used to access the admin APIs. This must be set for the commandline to function ##### `OPENTELEMETRY_URL` @@ -146,6 +151,15 @@ Optional - Add custom notes in the footer of the page Optional - domains of mastodon servers run by the same admin as the relay ##### `LOCAL_BLURB` Optional - description for the relay +##### `PROMETHEUS_ADDR` +Optional - Address to bind to for serving the prometheus scrape endpoint +##### `PROMETHEUS_PORT` +Optional - Port to bind to for serving the prometheus scrape endpoint +##### `CLIENT_POOL_SIZE` +Optional - How many connections the relay should maintain per thread. This value will be multiplied +by the number of cores available to the relay. This defaults to 20, so a 4-core machine will have a +maximum of 160 simultaneous outbound connections. If you run into problems related to "Too many open +files", you can either decrease this number or increase the ulimit for your system. ### Subscribing Mastodon admins can subscribe to this relay by adding the `/inbox` route to their relay settings. @@ -165,10 +179,16 @@ example, if the server is `https://relay.my.tld`, the correct URL would be - Follow Public, become a listener of the relay - Undo Follow {self-actor}, stop listening on the relay, an Undo Follow will be sent back - Undo Follow Public, stop listening on the relay -- Delete {anything}, the Delete {anything} is relayed verbatim to listening servers +- Delete {anything}, the Delete {anything} is relayed verbatim to listening servers. Note that this activity will likely be rejected by the listening servers unless it has been signed with a JSON-LD signature -- Update {anything}, the Update {anything} is relayed verbatim to listening servers +- Update {anything}, the Update {anything} is relayed verbatim to listening servers. + Note that this activity will likely be rejected by the listening servers unless it has been + signed with a JSON-LD signature +- Add {anything}, the Add {anything} is relayed verbatim to listening servers. + Note that this activity will likely be rejected by the listening servers unless it has been + signed with a JSON-LD signature +- Remove {anything}, the Remove {anything} is relayed verbatim to listening servers. Note that this activity will likely be rejected by the listening servers unless it has been signed with a JSON-LD signature @@ -176,6 +196,9 @@ example, if the server is `https://relay.my.tld`, the correct URL would be - Webfinger - NodeInfo +### Known issues +Pleroma and Akkoma do not support validating JSON-LD signatures, meaning many activities such as Delete, Update, Add, and Remove will be rejected with a message similar to `WARN: Response from https://example.com/inbox, "Invalid HTTP Signature"`. This is normal and not an issue with the relay. + ### Contributing Feel free to open issues for anything you find an issue with. Please note that any contributed code will be licensed under the AGPLv3. diff --git a/docker/prod/Dockerfile b/docker/prod/Dockerfile deleted file mode 100644 index 280aa95..0000000 --- a/docker/prod/Dockerfile +++ /dev/null @@ -1,41 +0,0 @@ -ARG REPO_ARCH=amd64 - -# cross-build environment -FROM asonix/rust-builder:$REPO_ARCH-latest AS builder - -ARG TAG=main -ARG BINARY=relay -ARG PROJECT=relay -ARG GIT_REPOSITORY=https://git.asonix.dog/asonix/$PROJECT - -ENV \ - BINARY=${BINARY} - -ADD \ - --chown=build:build \ - $GIT_REPOSITORY/archive/$TAG.tar.gz \ - /opt/build/repo.tar.gz - -RUN \ - tar zxf repo.tar.gz - -WORKDIR /opt/build/$PROJECT - -RUN \ - build - -# production environment -FROM asonix/rust-runner:$REPO_ARCH-latest - -ARG BINARY=relay - -ENV \ - BINARY=${BINARY} - -COPY \ - --from=builder \ - /opt/build/binary \ - /usr/bin/${BINARY} - -ENTRYPOINT ["/sbin/tini", "--"] -CMD /usr/bin/${BINARY} diff --git a/docker/prod/build-image.sh b/docker/prod/build-image.sh deleted file mode 100755 index 2782f1e..0000000 --- a/docker/prod/build-image.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env bash - -function require() { - if [ "$1" = "" ]; then - echo "input '$2' required" - print_help - exit 1 - fi -} - -function print_help() { - echo "deploy.sh" - echo "" - echo "Usage:" - echo " deploy.sh [repo] [tag] [arch]" - echo "" - echo "Args:" - echo " repo: The docker repository to publish the image" - echo " tag: The tag applied to the docker image" - echo " arch: The architecuture of the doker image" -} - -REPO=$1 -TAG=$2 -ARCH=$3 - -require "$REPO" repo -require "$TAG" tag -require "$ARCH" arch - -sudo docker build \ - --pull \ - --build-arg TAG=$TAG \ - --build-arg REPO_ARCH=$ARCH \ - -t $REPO:$ARCH-$TAG \ - -f Dockerfile \ - . diff --git a/docker/prod/deploy.sh b/docker/prod/deploy.sh deleted file mode 100755 index fcd7539..0000000 --- a/docker/prod/deploy.sh +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env bash - -function require() { - if [ "$1" = "" ]; then - echo "input '$2' required" - print_help - exit 1 - fi -} - -function print_help() { - echo "deploy.sh" - echo "" - echo "Usage:" - echo " deploy.sh [tag] [branch] [push]" - echo "" - echo "Args:" - echo " tag: The git tag to be applied to the repository and docker build" - echo " branch: The git branch to use for tagging and publishing" - echo " push: Whether or not to push the image" - echo "" - echo "Examples:" - echo " ./deploy.sh v0.3.0-alpha.13 main true" - echo " ./deploy.sh v0.3.0-alpha.13-shell-out asonix/shell-out false" -} - -function build_image() { - tag=$1 - arch=$2 - push=$3 - - ./build-image.sh asonix/relay $tag $arch - - sudo docker tag asonix/relay:$arch-$tag asonix/relay:$arch-latest - - if [ "$push" == "true" ]; then - sudo docker push asonix/relay:$arch-$tag - sudo docker push asonix/relay:$arch-latest - fi -} - -# Creating the new tag -new_tag="$1" -branch="$2" -push=$3 - -require "$new_tag" "tag" -require "$branch" "branch" -require "$push" "push" - -if ! sudo docker run --rm -it arm64v8/alpine:3.11 /bin/sh -c 'echo "docker is configured correctly"' -then - echo "docker is not configured to run on qemu-emulated architectures, fixing will require sudo" - sudo docker run --rm --privileged multiarch/qemu-user-static --reset -p yes -fi - -set -xe - -git checkout $branch - -# Changing the docker-compose prod -sed -i "s/asonix\/relay:.*/asonix\/relay:$new_tag/" docker-compose.yml -git add ../prod/docker-compose.yml -# The commit -git commit -m"Version $new_tag" -git tag $new_tag - -# Push -git push origin $new_tag -git push - -# Build for arm64v8, arm32v7 and amd64 -build_image $new_tag arm64v8 $push -build_image $new_tag arm32v7 $push -build_image $new_tag amd64 $push - -# Build for other archs -# TODO - -if [ "$push" == "true" ]; then - ./manifest.sh relay $new_tag - ./manifest.sh relay latest - - # pushd ../../ - # cargo publish - # popd -fi diff --git a/docker/prod/docker-compose.yml b/docker/prod/docker-compose.yml index 7201789..54e2a11 100644 --- a/docker/prod/docker-compose.yml +++ b/docker/prod/docker-compose.yml @@ -2,7 +2,7 @@ version: '3.3' services: relay: - image: asonix/relay:v0.3.8 + image: asonix/relay:0.3.85 ports: - "8079:8079" restart: always @@ -14,6 +14,7 @@ services: - RESTRICTED_MODE=false - VALIDATE_SIGNATURES=true - HTTPS=true - - DATABASE_URL=postgres://pg_user:pg_pass@pg_host:pg_port/pg_database + - SLED_PATH=/mnt/sled/db-0.34 - PRETTY_LOG=false - PUBLISH_BLOCKS=true + - API_TOKEN=somepasswordishtoken diff --git a/docker/prod/manifest.sh b/docker/prod/manifest.sh deleted file mode 100755 index d426a97..0000000 --- a/docker/prod/manifest.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash - -function require() { - if [ "$1" = "" ]; then - echo "input '$2' required" - print_help - exit 1 - fi -} -function print_help() { - echo "deploy.sh" - echo "" - echo "Usage:" - echo " manifest.sh [repo] [tag]" - echo "" - echo "Args:" - echo " repo: The docker repository to update" - echo " tag: The git tag to be applied to the image manifest" -} - -REPO=$1 -TAG=$2 - -require "$REPO" "repo" -require "$TAG" "tag" - -set -xe - -sudo docker manifest create asonix/$REPO:$TAG \ - -a asonix/$REPO:arm64v8-$TAG \ - -a asonix/$REPO:arm32v7-$TAG \ - -a asonix/$REPO:amd64-$TAG - -sudo docker manifest annotate asonix/$REPO:$TAG \ - asonix/$REPO:arm64v8-$TAG --os linux --arch arm64 --variant v8 - -sudo docker manifest annotate asonix/$REPO:$TAG \ - asonix/$REPO:arm32v7-$TAG --os linux --arch arm --variant v7 - -sudo docker manifest annotate asonix/$REPO:$TAG \ - asonix/$REPO:amd64-$TAG --os linux --arch amd64 - -sudo docker manifest push asonix/$REPO:$TAG --purge diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..0cb587b --- /dev/null +++ b/flake.lock @@ -0,0 +1,61 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1687171271, + "narHash": "sha256-BJlq+ozK2B1sJDQXS3tzJM5a+oVZmi1q0FlBK/Xqv7M=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "abfb11bd1aec8ced1c9bb9adfe68018230f4fb3c", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1687412861, + "narHash": "sha256-Z/g0wbL68C+mSGerYS2quv9FXQ1RRP082cAC0Bh4vcs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e603dc5f061ca1d8a19b3ede6a8cf9c9fcba6cdc", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..70d1fe7 --- /dev/null +++ b/flake.nix @@ -0,0 +1,34 @@ +{ + description = "relay"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { + inherit system; + }; + in + { + packages = rec { + relay = pkgs.callPackage ./relay.nix { }; + + default = relay; + }; + + apps = rec { + dev = flake-utils.lib.mkApp { drv = self.packages.${system}.pict-rs-proxy; }; + default = dev; + }; + + devShell = with pkgs; mkShell { + nativeBuildInputs = [ cargo cargo-outdated cargo-zigbuild clippy gcc protobuf rust-analyzer rustc rustfmt ]; + + RUST_SRC_PATH = "${pkgs.rust.packages.stable.rustPlatform.rustLibSrc}"; + }; + }); +} diff --git a/relay.nix b/relay.nix new file mode 100644 index 0000000..08d4a73 --- /dev/null +++ b/relay.nix @@ -0,0 +1,25 @@ +{ lib +, nixosTests +, protobuf +, rustPlatform +}: + +rustPlatform.buildRustPackage { + pname = "relay"; + version = "0.3.85"; + src = ./.; + cargoLock.lockFile = ./Cargo.lock; + + PROTOC = "${protobuf}/bin/protoc"; + PROTOC_INCLUDE = "${protobuf}/include"; + + nativeBuildInputs = [ ]; + + passthru.tests = { inherit (nixosTests) relay; }; + + meta = with lib; { + description = "A simple image hosting service"; + homepage = "https://git.asonix.dog/asonix/relay"; + license = with licenses; [ agpl3Plus ]; + }; +} diff --git a/src/admin.rs b/src/admin.rs index e7fc665..156a5d9 100644 --- a/src/admin.rs +++ b/src/admin.rs @@ -1,4 +1,6 @@ use activitystreams::iri_string::types::IriString; +use std::collections::{BTreeMap, BTreeSet}; +use time::OffsetDateTime; pub mod client; pub mod routes; @@ -22,3 +24,9 @@ pub(crate) struct BlockedDomains { pub(crate) struct ConnectedActors { pub(crate) connected_actors: Vec, } + +#[derive(serde::Deserialize, serde::Serialize)] +pub(crate) struct LastSeen { + pub(crate) last_seen: BTreeMap>, + pub(crate) never: Vec, +} diff --git a/src/admin/client.rs b/src/admin/client.rs index 3602487..fdb1687 100644 --- a/src/admin/client.rs +++ b/src/admin/client.rs @@ -1,5 +1,5 @@ use crate::{ - admin::{AllowedDomains, BlockedDomains, ConnectedActors, Domains}, + admin::{AllowedDomains, BlockedDomains, ConnectedActors, Domains, LastSeen}, collector::Snapshot, config::{AdminUrlKind, Config}, error::{Error, ErrorKind}, @@ -55,6 +55,10 @@ pub(crate) async fn stats(client: &Client, config: &Config) -> Result Result { + get_results(client, config, AdminUrlKind::LastSeen).await +} + async fn get_results( client: &Client, config: &Config, diff --git a/src/admin/routes.rs b/src/admin/routes.rs index 6578bfd..c13a6e3 100644 --- a/src/admin/routes.rs +++ b/src/admin/routes.rs @@ -1,5 +1,5 @@ use crate::{ - admin::{AllowedDomains, BlockedDomains, ConnectedActors, Domains}, + admin::{AllowedDomains, BlockedDomains, ConnectedActors, Domains, LastSeen}, collector::{MemoryCollector, Snapshot}, error::Error, extractors::Admin, @@ -8,6 +8,8 @@ use actix_web::{ web::{Data, Json}, HttpResponse, }; +use std::collections::{BTreeMap, BTreeSet}; +use time::OffsetDateTime; pub(crate) async fn allow( admin: Admin, @@ -69,3 +71,20 @@ pub(crate) async fn stats( ) -> Result, Error> { Ok(Json(collector.snapshot())) } + +pub(crate) async fn last_seen(admin: Admin) -> Result, Error> { + let nodes = admin.db_ref().last_seen().await?; + + let mut last_seen: BTreeMap> = BTreeMap::new(); + let mut never = Vec::new(); + + for (domain, datetime) in nodes { + if let Some(datetime) = datetime { + last_seen.entry(datetime).or_default().insert(domain); + } else { + never.push(domain); + } + } + + Ok(Json(LastSeen { last_seen, never })) +} diff --git a/src/apub.rs b/src/apub.rs index 2b922e3..a99cacc 100644 --- a/src/apub.rs +++ b/src/apub.rs @@ -34,11 +34,13 @@ pub struct PublicKey { #[serde(rename_all = "PascalCase")] pub enum ValidTypes { Accept, + Add, Announce, Create, Delete, Follow, Reject, + Remove, Undo, Update, } diff --git a/src/args.rs b/src/args.rs index 18a4059..155b296 100644 --- a/src/args.rs +++ b/src/args.rs @@ -17,11 +17,22 @@ pub(crate) struct Args { #[arg(short, long, help = "Get statistics from the server")] stats: bool, + + #[arg( + short, + long, + help = "List domains by when they were last succesfully contacted" + )] + contacted: bool, } impl Args { pub(crate) fn any(&self) -> bool { - !self.blocks.is_empty() || !self.allowed.is_empty() || self.list || self.stats + !self.blocks.is_empty() + || !self.allowed.is_empty() + || self.list + || self.stats + || self.contacted } pub(crate) fn new() -> Self { @@ -47,4 +58,8 @@ impl Args { pub(crate) fn stats(&self) -> bool { self.stats } + + pub(crate) fn contacted(&self) -> bool { + self.contacted + } } diff --git a/src/build.rs b/src/build.rs index 8db87a2..f21d5bb 100644 --- a/src/build.rs +++ b/src/build.rs @@ -5,7 +5,8 @@ fn git_info() { if let Ok(output) = Command::new("git").args(["rev-parse", "HEAD"]).output() { if output.status.success() { let git_hash = String::from_utf8_lossy(&output.stdout); - println!("cargo:rustc-env=GIT_HASH={}", git_hash); + println!("cargo:rustc-env=GIT_HASH={git_hash}"); + println!("cargo:rustc-env=GIT_SHORT_HASH={}", &git_hash[..8]) } } @@ -15,7 +16,7 @@ fn git_info() { { if output.status.success() { let git_branch = String::from_utf8_lossy(&output.stdout); - println!("cargo:rustc-env=GIT_BRANCH={}", git_branch); + println!("cargo:rustc-env=GIT_BRANCH={git_branch}"); } } } @@ -23,7 +24,7 @@ fn git_info() { fn version_info() -> Result<(), anyhow::Error> { let cargo_toml = Path::new(&std::env::var("CARGO_MANIFEST_DIR")?).join("Cargo.toml"); - let mut file = File::open(&cargo_toml)?; + let mut file = File::open(cargo_toml)?; let mut cargo_data = String::new(); file.read_to_string(&mut cargo_data)?; @@ -31,11 +32,11 @@ fn version_info() -> Result<(), anyhow::Error> { let data: toml::Value = toml::from_str(&cargo_data)?; if let Some(version) = data["package"]["version"].as_str() { - println!("cargo:rustc-env=PKG_VERSION={}", version); + println!("cargo:rustc-env=PKG_VERSION={version}"); } if let Some(name) = data["package"]["name"].as_str() { - println!("cargo:rustc-env=PKG_NAME={}", name); + println!("cargo:rustc-env=PKG_NAME={name}"); } Ok(()) diff --git a/src/collector.rs b/src/collector.rs index 0d3536d..56a533d 100644 --- a/src/collector.rs +++ b/src/collector.rs @@ -40,11 +40,11 @@ impl std::fmt::Display for Counter { let labels = self .labels .iter() - .map(|(k, v)| format!("{}: {}", k, v)) + .map(|(k, v)| format!("{k}: {v}")) .collect::>() .join(", "); - write!(f, "{} - {}", labels, self.value) + write!(f, "{labels} - {}", self.value) } } @@ -59,11 +59,11 @@ impl std::fmt::Display for Gauge { let labels = self .labels .iter() - .map(|(k, v)| format!("{}: {}", k, v)) + .map(|(k, v)| format!("{k}: {v}")) .collect::>() .join(", "); - write!(f, "{} - {}", labels, self.value) + write!(f, "{labels} - {}", self.value) } } @@ -78,7 +78,7 @@ impl std::fmt::Display for Histogram { let labels = self .labels .iter() - .map(|(k, v)| format!("{}: {}", k, v)) + .map(|(k, v)| format!("{k}: {v}")) .collect::>() .join(", "); @@ -87,15 +87,15 @@ impl std::fmt::Display for Histogram { .iter() .map(|(k, v)| { if let Some(v) = v { - format!("{}: {:.6}", k, v) + format!("{k}: {v:.6}") } else { - format!("{}: None,", k) + format!("{k}: None,") } }) .collect::>() .join(", "); - write!(f, "{} - {}", labels, value) + write!(f, "{labels} - {value}") } } @@ -172,18 +172,18 @@ impl Snapshot { continue; } - println!("\t{}", key); + println!("\t{key}"); for counter in counters { - println!("\t\t{}", counter); + println!("\t\t{counter}"); } } for (key, counters) in merging { - println!("\t{}", key); + println!("\t{key}"); for (_, counter) in counters { if let Some(counter) = counter.merge() { - println!("\t\t{}", counter); + println!("\t\t{counter}"); } } } @@ -192,10 +192,10 @@ impl Snapshot { if !self.gauges.is_empty() { println!("Gauges"); for (key, gauges) in self.gauges { - println!("\t{}", key); + println!("\t{key}"); for gauge in gauges { - println!("\t\t{}", gauge); + println!("\t\t{gauge}"); } } } @@ -203,10 +203,10 @@ impl Snapshot { if !self.histograms.is_empty() { println!("Histograms"); for (key, histograms) in self.histograms { - println!("\t{}", key); + println!("\t{key}"); for histogram in histograms { - println!("\t\t{}", histogram); + println!("\t\t{histogram}"); } } } @@ -216,7 +216,6 @@ impl Snapshot { fn key_to_parts(key: &Key) -> (String, Vec<(String, String)>) { let labels = key .labels() - .into_iter() .map(|label| (label.key().to_string(), label.value().to_string())) .collect(); let name = key.name().to_string(); @@ -348,10 +347,6 @@ impl MemoryCollector { } } - pub(crate) fn install(&self) -> Result<(), SetRecorderError> { - metrics::set_boxed_recorder(Box::new(self.clone())) - } - pub(crate) fn snapshot(&self) -> Snapshot { self.inner.snapshot() } @@ -364,6 +359,10 @@ impl MemoryCollector { let mut d = self.inner.descriptions.write().unwrap(); d.entry(key.as_str().to_owned()).or_insert(description); } + + pub(crate) fn install(&self) -> Result<(), SetRecorderError> { + metrics::set_boxed_recorder(Box::new(self.clone())) + } } impl Recorder for MemoryCollector { diff --git a/src/config.rs b/src/config.rs index 1d4cf86..bf58533 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,22 +1,24 @@ use crate::{ - data::{ActorCache, State}, error::Error, extractors::{AdminConfig, XApiToken}, - middleware::MyVerify, - requests::Requests, }; use activitystreams::{ iri, iri_string::{ + format::ToDedicatedString, resolve::FixedBaseResolver, types::{IriAbsoluteString, IriFragmentStr, IriRelativeStr, IriString}, }, }; use config::Environment; -use http_signature_normalization_actix::prelude::{VerifyDigest, VerifySignature}; +use http_signature_normalization_actix::prelude::VerifyDigest; +use rsa::sha2::{Digest, Sha256}; use rustls::{Certificate, PrivateKey}; -use sha2::{Digest, Sha256}; -use std::{io::BufReader, net::IpAddr, path::PathBuf}; +use std::{ + io::BufReader, + net::{IpAddr, SocketAddr}, + path::PathBuf, +}; use uuid::Uuid; #[derive(Clone, Debug, serde::Deserialize)] @@ -31,6 +33,7 @@ pub(crate) struct ParsedConfig { publish_blocks: bool, sled_path: PathBuf, source_repo: IriString, + repository_commit_base: String, opentelemetry_url: Option, telegram_token: Option, telegram_admin_handle: Option, @@ -40,6 +43,9 @@ pub(crate) struct ParsedConfig { footer_blurb: Option, local_domains: Option, local_blurb: Option, + prometheus_addr: Option, + prometheus_port: Option, + client_pool_size: usize, } #[derive(Clone)] @@ -62,6 +68,8 @@ pub struct Config { footer_blurb: Option, local_domains: Vec, local_blurb: Option, + prometheus_config: Option, + client_pool_size: usize, } #[derive(Clone)] @@ -70,6 +78,12 @@ struct TlsConfig { cert: PathBuf, } +#[derive(Clone, Debug)] +struct PrometheusConfig { + addr: IpAddr, + port: u16, +} + #[derive(Debug)] pub enum UrlKind { Activity, @@ -94,6 +108,7 @@ pub enum AdminUrlKind { Blocked, Connected, Stats, + LastSeen, } impl std::fmt::Debug for Config { @@ -121,6 +136,8 @@ impl std::fmt::Debug for Config { .field("footer_blurb", &self.footer_blurb) .field("local_domains", &self.local_domains) .field("local_blurb", &self.local_blurb) + .field("prometheus_config", &self.prometheus_config) + .field("client_pool_size", &self.client_pool_size) .finish() } } @@ -138,6 +155,7 @@ impl Config { .set_default("publish_blocks", false)? .set_default("sled_path", "./sled/db-0-34")? .set_default("source_repo", "https://git.asonix.dog/asonix/relay")? + .set_default("repository_commit_base", "/src/commit/")? .set_default("opentelemetry_url", None as Option<&str>)? .set_default("telegram_token", None as Option<&str>)? .set_default("telegram_admin_handle", None as Option<&str>)? @@ -147,13 +165,16 @@ impl Config { .set_default("footer_blurb", None as Option<&str>)? .set_default("local_domains", None as Option<&str>)? .set_default("local_blurb", None as Option<&str>)? + .set_default("prometheus_addr", None as Option<&str>)? + .set_default("prometheus_port", None as Option)? + .set_default("client_pool_size", 20u64)? .add_source(Environment::default()) .build()?; let config: ParsedConfig = config.try_deserialize()?; let scheme = if config.https { "https" } else { "http" }; - let base_uri = iri!(format!("{}://{}", scheme, config.hostname)).into_absolute(); + let base_uri = iri!(format!("{scheme}://{}", config.hostname)).into_absolute(); let tls = match (config.tls_key, config.tls_cert) { (Some(key), Some(cert)) => Some(TlsConfig { key, cert }), @@ -175,6 +196,29 @@ impl Config { .map(|d| d.to_string()) .collect(); + let prometheus_config = match (config.prometheus_addr, config.prometheus_port) { + (Some(addr), Some(port)) => Some(PrometheusConfig { addr, port }), + (Some(_), None) => { + tracing::warn!("PROMETHEUS_ADDR is set but PROMETHEUS_PORT is not set, not building Prometheus config"); + None + } + (None, Some(_)) => { + tracing::warn!("PROMETHEUS_PORT is set but PROMETHEUS_ADDR is not set, not building Prometheus config"); + None + } + (None, None) => None, + }; + + let source_url = match Self::git_hash() { + Some(hash) => format!( + "{}{}{hash}", + config.source_repo, config.repository_commit_base + ) + .parse() + .expect("constructed source URL is valid"), + None => config.source_repo.clone(), + }; + Ok(Config { hostname: config.hostname, addr: config.addr, @@ -185,7 +229,7 @@ impl Config { publish_blocks: config.publish_blocks, base_uri, sled_path: config.sled_path, - source_repo: config.source_repo, + source_repo: source_url, opentelemetry_url: config.opentelemetry_url, telegram_token: config.telegram_token, telegram_admin_handle: config.telegram_admin_handle, @@ -194,9 +238,17 @@ impl Config { footer_blurb: config.footer_blurb, local_domains, local_blurb: config.local_blurb, + prometheus_config, + client_pool_size: config.client_pool_size, }) } + pub(crate) fn prometheus_bind_address(&self) -> Option { + let config = self.prometheus_config.as_ref()?; + + Some((config.addr, config.port).into()) + } + pub(crate) fn open_keys(&self) -> Result, PrivateKey)>, Error> { let tls = if let Some(tls) = &self.tls { tls @@ -276,19 +328,6 @@ impl Config { } } - pub(crate) fn signature_middleware( - &self, - requests: Requests, - actors: ActorCache, - state: State, - ) -> VerifySignature { - if self.validate_signatures { - VerifySignature::new(MyVerify(requests, actors, state), Default::default()) - } else { - VerifySignature::new(MyVerify(requests, actors, state), Default::default()).optional() - } - } - pub(crate) fn x_api_token(&self) -> Option { self.api_token.clone().map(XApiToken::new) } @@ -298,7 +337,7 @@ impl Config { match AdminConfig::build(api_token) { Ok(conf) => Some(actix_web::web::Data::new(conf)), Err(e) => { - tracing::error!("Error creating admin config: {}", e); + tracing::error!("Error creating admin config: {e}"); None } } @@ -337,7 +376,7 @@ impl Config { pub(crate) fn software_version() -> String { if let Some(git) = Self::git_version() { - return format!("v{}-{}", Self::version(), git); + return format!("v{}-{git}", Self::version()); } format!("v{}", Self::version()) @@ -345,9 +384,9 @@ impl Config { fn git_version() -> Option { let branch = Self::git_branch()?; - let hash = Self::git_hash()?; + let hash = Self::git_short_hash()?; - Some(format!("{}-{}", branch, hash)) + Some(format!("{branch}-{hash}")) } fn name() -> &'static str { @@ -366,6 +405,10 @@ impl Config { option_env!("GIT_HASH") } + fn git_short_hash() -> Option<&'static str> { + option_env!("GIT_SHORT_HASH") + } + pub(crate) fn user_agent(&self) -> String { format!( "{} ({}/{}; +{})", @@ -376,6 +419,10 @@ impl Config { ) } + pub(crate) fn client_pool_size(&self) -> usize { + self.client_pool_size + } + pub(crate) fn source_code(&self) -> &IriString { &self.source_repo } @@ -395,37 +442,44 @@ impl Config { self.do_generate_url(kind).expect("Generated valid IRI") } - #[tracing::instrument(level = "debug", skip_all, fields(base_uri = tracing::field::debug(&self.base_uri), kind = tracing::field::debug(&kind)))] fn do_generate_url(&self, kind: UrlKind) -> Result { let iri = match kind { - UrlKind::Activity => FixedBaseResolver::new(self.base_uri.as_ref()).try_resolve( - IriRelativeStr::new(&format!("activity/{}", Uuid::new_v4()))?.as_ref(), - )?, + UrlKind::Activity => FixedBaseResolver::new(self.base_uri.as_ref()) + .resolve(IriRelativeStr::new(&format!("activity/{}", Uuid::new_v4()))?.as_ref()) + .try_to_dedicated_string()?, UrlKind::Actor => FixedBaseResolver::new(self.base_uri.as_ref()) - .try_resolve(IriRelativeStr::new("actor")?.as_ref())?, + .resolve(IriRelativeStr::new("actor")?.as_ref()) + .try_to_dedicated_string()?, UrlKind::Followers => FixedBaseResolver::new(self.base_uri.as_ref()) - .try_resolve(IriRelativeStr::new("followers")?.as_ref())?, + .resolve(IriRelativeStr::new("followers")?.as_ref()) + .try_to_dedicated_string()?, UrlKind::Following => FixedBaseResolver::new(self.base_uri.as_ref()) - .try_resolve(IriRelativeStr::new("following")?.as_ref())?, + .resolve(IriRelativeStr::new("following")?.as_ref()) + .try_to_dedicated_string()?, UrlKind::Inbox => FixedBaseResolver::new(self.base_uri.as_ref()) - .try_resolve(IriRelativeStr::new("inbox")?.as_ref())?, + .resolve(IriRelativeStr::new("inbox")?.as_ref()) + .try_to_dedicated_string()?, UrlKind::Index => self.base_uri.clone().into(), UrlKind::MainKey => { let actor = IriRelativeStr::new("actor")?; let fragment = IriFragmentStr::new("main-key")?; - let mut resolved = - FixedBaseResolver::new(self.base_uri.as_ref()).try_resolve(actor.as_ref())?; + let mut resolved = FixedBaseResolver::new(self.base_uri.as_ref()) + .resolve(actor.as_ref()) + .try_to_dedicated_string()?; resolved.set_fragment(Some(fragment)); resolved } UrlKind::Media(uuid) => FixedBaseResolver::new(self.base_uri.as_ref()) - .try_resolve(IriRelativeStr::new(&format!("media/{}", uuid))?.as_ref())?, + .resolve(IriRelativeStr::new(&format!("media/{uuid}"))?.as_ref()) + .try_to_dedicated_string()?, UrlKind::NodeInfo => FixedBaseResolver::new(self.base_uri.as_ref()) - .try_resolve(IriRelativeStr::new("nodeinfo/2.0.json")?.as_ref())?, + .resolve(IriRelativeStr::new("nodeinfo/2.0.json")?.as_ref()) + .try_to_dedicated_string()?, UrlKind::Outbox => FixedBaseResolver::new(self.base_uri.as_ref()) - .try_resolve(IriRelativeStr::new("outbox")?.as_ref())?, + .resolve(IriRelativeStr::new("outbox")?.as_ref()) + .try_to_dedicated_string()?, }; Ok(iri) @@ -437,25 +491,22 @@ impl Config { } fn do_generate_admin_url(&self, kind: AdminUrlKind) -> Result { - let iri = match kind { - AdminUrlKind::Allow => FixedBaseResolver::new(self.base_uri.as_ref()) - .try_resolve(IriRelativeStr::new("api/v1/admin/allow")?.as_ref())?, - AdminUrlKind::Disallow => FixedBaseResolver::new(self.base_uri.as_ref()) - .try_resolve(IriRelativeStr::new("api/v1/admin/disallow")?.as_ref())?, - AdminUrlKind::Block => FixedBaseResolver::new(self.base_uri.as_ref()) - .try_resolve(IriRelativeStr::new("api/v1/admin/block")?.as_ref())?, - AdminUrlKind::Unblock => FixedBaseResolver::new(self.base_uri.as_ref()) - .try_resolve(IriRelativeStr::new("api/v1/admin/unblock")?.as_ref())?, - AdminUrlKind::Allowed => FixedBaseResolver::new(self.base_uri.as_ref()) - .try_resolve(IriRelativeStr::new("api/v1/admin/allowed")?.as_ref())?, - AdminUrlKind::Blocked => FixedBaseResolver::new(self.base_uri.as_ref()) - .try_resolve(IriRelativeStr::new("api/v1/admin/blocked")?.as_ref())?, - AdminUrlKind::Connected => FixedBaseResolver::new(self.base_uri.as_ref()) - .try_resolve(IriRelativeStr::new("api/v1/admin/connected")?.as_ref())?, - AdminUrlKind::Stats => FixedBaseResolver::new(self.base_uri.as_ref()) - .try_resolve(IriRelativeStr::new("api/v1/admin/stats")?.as_ref())?, + let path = match kind { + AdminUrlKind::Allow => "api/v1/admin/allow", + AdminUrlKind::Disallow => "api/v1/admin/disallow", + AdminUrlKind::Block => "api/v1/admin/block", + AdminUrlKind::Unblock => "api/v1/admin/unblock", + AdminUrlKind::Allowed => "api/v1/admin/allowed", + AdminUrlKind::Blocked => "api/v1/admin/blocked", + AdminUrlKind::Connected => "api/v1/admin/connected", + AdminUrlKind::Stats => "api/v1/admin/stats", + AdminUrlKind::LastSeen => "api/v1/admin/last_seen", }; + let iri = FixedBaseResolver::new(self.base_uri.as_ref()) + .resolve(IriRelativeStr::new(path)?.as_ref()) + .try_to_dedicated_string()?; + Ok(iri) } } diff --git a/src/data.rs b/src/data.rs index 918bdf7..1125149 100644 --- a/src/data.rs +++ b/src/data.rs @@ -1,9 +1,11 @@ mod actor; +mod last_online; mod media; mod node; mod state; pub(crate) use actor::ActorCache; +pub(crate) use last_online::LastOnline; pub(crate) use media::MediaCache; pub(crate) use node::{Node, NodeCache}; pub(crate) use state::State; diff --git a/src/data/actor.rs b/src/data/actor.rs index c0b3ddd..af6fb78 100644 --- a/src/data/actor.rs +++ b/src/data/actor.rs @@ -37,7 +37,7 @@ impl ActorCache { ActorCache { db } } - #[tracing::instrument(level = "debug" name = "Get Actor", skip_all, fields(id = id.to_string().as_str(), requests))] + #[tracing::instrument(level = "debug" name = "Get Actor", skip_all, fields(id = id.to_string().as_str()))] pub(crate) async fn get( &self, id: &IriString, @@ -56,12 +56,8 @@ impl ActorCache { #[tracing::instrument(level = "debug", name = "Add Connection", skip(self))] pub(crate) async fn add_connection(&self, actor: Actor) -> Result<(), Error> { - let add_connection = self.db.add_connection(actor.id.clone()); - let save_actor = self.db.save_actor(actor); - - tokio::try_join!(add_connection, save_actor)?; - - Ok(()) + self.db.add_connection(actor.id.clone()).await?; + self.db.save_actor(actor).await } #[tracing::instrument(level = "debug", name = "Remove Connection", skip(self))] @@ -69,13 +65,13 @@ impl ActorCache { self.db.remove_connection(actor.id.clone()).await } - #[tracing::instrument(level = "debug", name = "Fetch remote actor", skip_all, fields(id = id.to_string().as_str(), requests))] + #[tracing::instrument(level = "debug", name = "Fetch remote actor", skip_all, fields(id = id.to_string().as_str()))] pub(crate) async fn get_no_cache( &self, id: &IriString, requests: &Requests, ) -> Result { - let accepted_actor = requests.fetch::(id.as_str()).await?; + let accepted_actor = requests.fetch::(id).await?; let input_authority = id.authority_components().ok_or(ErrorKind::MissingDomain)?; let accepted_actor_id = accepted_actor diff --git a/src/data/last_online.rs b/src/data/last_online.rs new file mode 100644 index 0000000..889d804 --- /dev/null +++ b/src/data/last_online.rs @@ -0,0 +1,28 @@ +use activitystreams::iri_string::types::IriStr; +use std::{collections::HashMap, sync::Mutex}; +use time::OffsetDateTime; + +pub(crate) struct LastOnline { + domains: Mutex>, +} + +impl LastOnline { + pub(crate) fn mark_seen(&self, iri: &IriStr) { + if let Some(authority) = iri.authority_str() { + self.domains + .lock() + .unwrap() + .insert(authority.to_string(), OffsetDateTime::now_utc()); + } + } + + pub(crate) fn take(&self) -> HashMap { + std::mem::take(&mut *self.domains.lock().unwrap()) + } + + pub(crate) fn empty() -> Self { + Self { + domains: Mutex::new(HashMap::default()), + } + } +} diff --git a/src/data/node.rs b/src/data/node.rs index 815cc7c..ac89cdb 100644 --- a/src/data/node.rs +++ b/src/data/node.rs @@ -36,11 +36,9 @@ impl NodeCache { #[tracing::instrument(level = "debug", name = "Get nodes", skip(self))] pub(crate) async fn nodes(&self) -> Result, Error> { - let infos = self.db.connected_info(); - let instances = self.db.connected_instance(); - let contacts = self.db.connected_contact(); - - let (infos, instances, contacts) = tokio::try_join!(infos, instances, contacts)?; + let infos = self.db.connected_info().await?; + let instances = self.db.connected_instance().await?; + let contacts = self.db.connected_contact().await?; let vec = self .db @@ -184,7 +182,7 @@ impl Node { let authority = url.authority_str().ok_or(ErrorKind::MissingDomain)?; let scheme = url.scheme_str(); - let base = iri!(format!("{}://{}", scheme, authority)); + let base = iri!(format!("{scheme}://{authority}")); Ok(Node { base, diff --git a/src/data/state.rs b/src/data/state.rs index 93a3f9a..d6c484b 100644 --- a/src/data/state.rs +++ b/src/data/state.rs @@ -10,8 +10,9 @@ use actix_web::web; use lru::LruCache; use rand::thread_rng; use rsa::{RsaPrivateKey, RsaPublicKey}; -use std::sync::Arc; -use tokio::sync::RwLock; +use std::sync::{Arc, RwLock}; + +use super::LastOnline; #[derive(Clone)] pub struct State { @@ -20,6 +21,7 @@ pub struct State { object_cache: Arc>>, node_cache: NodeCache, breakers: Breakers, + pub(crate) last_online: Arc, pub(crate) db: Db, } @@ -44,6 +46,8 @@ impl State { self.private_key.clone(), config.user_agent(), self.breakers.clone(), + self.last_online.clone(), + config.client_pool_size(), ) } @@ -78,12 +82,12 @@ impl State { .collect()) } - pub(crate) async fn is_cached(&self, object_id: &IriString) -> bool { - self.object_cache.read().await.contains(object_id) + pub(crate) fn is_cached(&self, object_id: &IriString) -> bool { + self.object_cache.read().unwrap().contains(object_id) } - pub(crate) async fn cache(&self, object_id: IriString, actor_id: IriString) { - self.object_cache.write().await.put(object_id, actor_id); + pub(crate) fn cache(&self, object_id: IriString, actor_id: IriString) { + self.object_cache.write().unwrap().put(object_id, actor_id); } #[tracing::instrument(level = "debug", name = "Building state", skip_all)] @@ -115,6 +119,7 @@ impl State { node_cache: NodeCache::new(db.clone()), breakers: Breakers::default(), db, + last_online: Arc::new(LastOnline::empty()), }; Ok(state) diff --git a/src/db.rs b/src/db.rs index 685405f..edf00c1 100644 --- a/src/db.rs +++ b/src/db.rs @@ -7,8 +7,16 @@ use rsa::{ pkcs8::{DecodePrivateKey, EncodePrivateKey}, RsaPrivateKey, }; -use sled::Tree; -use std::{collections::HashMap, sync::Arc, time::SystemTime}; +use sled::{Batch, Tree}; +use std::{ + collections::{BTreeMap, HashMap}, + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, + }, + time::SystemTime, +}; +use time::OffsetDateTime; use uuid::Uuid; #[derive(Clone, Debug)] @@ -17,6 +25,8 @@ pub(crate) struct Db { } struct Inner { + healthz: Tree, + healthz_counter: Arc, actor_id_actor: Tree, public_key_id_actor_id: Tree, connected_actor_ids: Tree, @@ -28,6 +38,7 @@ struct Inner { actor_id_info: Tree, actor_id_instance: Tree, actor_id_contact: Tree, + last_seen: Tree, restricted_mode: bool, } @@ -236,6 +247,8 @@ impl Db { fn build_inner(restricted_mode: bool, db: sled::Db) -> Result { Ok(Db { inner: Arc::new(Inner { + healthz: db.open_tree("healthz")?, + healthz_counter: Arc::new(AtomicU64::new(0)), actor_id_actor: db.open_tree("actor-id-actor")?, public_key_id_actor_id: db.open_tree("public-key-id-actor-id")?, connected_actor_ids: db.open_tree("connected-actor-ids")?, @@ -247,6 +260,7 @@ impl Db { actor_id_info: db.open_tree("actor-id-info")?, actor_id_instance: db.open_tree("actor-id-instance")?, actor_id_contact: db.open_tree("actor-id-contact")?, + last_seen: db.open_tree("last-seen")?, restricted_mode, }), }) @@ -254,7 +268,7 @@ impl Db { async fn unblock( &self, - f: impl Fn(&Inner) -> Result + Send + 'static, + f: impl FnOnce(&Inner) -> Result + Send + 'static, ) -> Result where T: Send + 'static, @@ -266,6 +280,63 @@ impl Db { Ok(t) } + pub(crate) async fn check_health(&self) -> Result<(), Error> { + let next = self.inner.healthz_counter.fetch_add(1, Ordering::Relaxed); + self.unblock(move |inner| { + inner + .healthz + .insert("healthz", &next.to_be_bytes()[..]) + .map_err(Error::from) + }) + .await?; + self.inner.healthz.flush_async().await?; + self.unblock(move |inner| inner.healthz.get("healthz").map_err(Error::from)) + .await?; + Ok(()) + } + + pub(crate) async fn mark_last_seen( + &self, + nodes: HashMap, + ) -> Result<(), Error> { + let mut batch = Batch::default(); + + for (domain, datetime) in nodes { + let datetime_string = serde_json::to_vec(&datetime)?; + + batch.insert(domain.as_bytes(), datetime_string); + } + + self.unblock(move |inner| inner.last_seen.apply_batch(batch).map_err(Error::from)) + .await + } + + pub(crate) async fn last_seen( + &self, + ) -> Result>, Error> { + self.unblock(|inner| { + let mut map = BTreeMap::new(); + + for iri in inner.connected() { + let Some(authority_str) = iri.authority_str() else { + continue; + }; + + if let Some(datetime) = inner.last_seen.get(authority_str)? { + map.insert( + authority_str.to_string(), + Some(serde_json::from_slice(&datetime)?), + ); + } else { + map.insert(authority_str.to_string(), None); + } + } + + Ok(map) + }) + .await + } + pub(crate) async fn connected_ids(&self) -> Result, Error> { self.unblock(|inner| Ok(inner.connected().collect())).await } @@ -285,12 +356,12 @@ impl Db { pub(crate) async fn info(&self, actor_id: IriString) -> Result, Error> { self.unblock(move |inner| { - if let Some(ivec) = inner.actor_id_info.get(actor_id.as_str().as_bytes())? { - let info = serde_json::from_slice(&ivec)?; - Ok(Some(info)) - } else { - Ok(None) - } + inner + .actor_id_info + .get(actor_id.as_str().as_bytes())? + .map(|ivec| serde_json::from_slice(&ivec)) + .transpose() + .map_err(Error::from) }) .await } @@ -319,12 +390,12 @@ impl Db { pub(crate) async fn instance(&self, actor_id: IriString) -> Result, Error> { self.unblock(move |inner| { - if let Some(ivec) = inner.actor_id_instance.get(actor_id.as_str().as_bytes())? { - let instance = serde_json::from_slice(&ivec)?; - Ok(Some(instance)) - } else { - Ok(None) - } + inner + .actor_id_instance + .get(actor_id.as_str().as_bytes())? + .map(|ivec| serde_json::from_slice(&ivec)) + .transpose() + .map_err(Error::from) }) .await } @@ -353,12 +424,12 @@ impl Db { pub(crate) async fn contact(&self, actor_id: IriString) -> Result, Error> { self.unblock(move |inner| { - if let Some(ivec) = inner.actor_id_contact.get(actor_id.as_str().as_bytes())? { - let contact = serde_json::from_slice(&ivec)?; - Ok(Some(contact)) - } else { - Ok(None) - } + inner + .actor_id_contact + .get(actor_id.as_str().as_bytes())? + .map(|ivec| serde_json::from_slice(&ivec)) + .transpose() + .map_err(Error::from) }) .await } @@ -383,22 +454,20 @@ impl Db { pub(crate) async fn media_id(&self, url: IriString) -> Result, Error> { self.unblock(move |inner| { - if let Some(ivec) = inner.media_url_media_id.get(url.as_str().as_bytes())? { - Ok(uuid_from_ivec(ivec)) - } else { - Ok(None) - } + Ok(inner + .media_url_media_id + .get(url.as_str().as_bytes())? + .and_then(uuid_from_ivec)) }) .await } pub(crate) async fn media_url(&self, id: Uuid) -> Result, Error> { self.unblock(move |inner| { - if let Some(ivec) = inner.media_id_media_url.get(id.as_bytes())? { - Ok(url_from_ivec(ivec)) - } else { - Ok(None) - } + Ok(inner + .media_id_media_url + .get(id.as_bytes())? + .and_then(url_from_ivec)) }) .await } @@ -419,7 +488,7 @@ impl Db { pub(crate) async fn is_connected(&self, base_id: IriString) -> Result { let scheme = base_id.scheme_str(); let authority = base_id.authority_str().ok_or(ErrorKind::MissingDomain)?; - let prefix = format!("{}://{}", scheme, authority); + let prefix = format!("{scheme}://{authority}"); self.unblock(move |inner| { let connected = inner @@ -438,26 +507,22 @@ impl Db { public_key_id: IriString, ) -> Result, Error> { self.unblock(move |inner| { - if let Some(ivec) = inner + Ok(inner .public_key_id_actor_id .get(public_key_id.as_str().as_bytes())? - { - Ok(url_from_ivec(ivec)) - } else { - Ok(None) - } + .and_then(url_from_ivec)) }) .await } pub(crate) async fn actor(&self, actor_id: IriString) -> Result, Error> { self.unblock(move |inner| { - if let Some(ivec) = inner.actor_id_actor.get(actor_id.as_str().as_bytes())? { - let actor = serde_json::from_slice(&ivec)?; - Ok(Some(actor)) - } else { - Ok(None) - } + inner + .actor_id_actor + .get(actor_id.as_str().as_bytes())? + .map(|ivec| serde_json::from_slice(&ivec)) + .transpose() + .map_err(Error::from) }) .await } @@ -479,7 +544,7 @@ impl Db { } pub(crate) async fn remove_connection(&self, actor_id: IriString) -> Result<(), Error> { - tracing::debug!("Removing Connection: {}", actor_id); + tracing::debug!("Removing Connection: {actor_id}"); self.unblock(move |inner| { inner .connected_actor_ids @@ -491,7 +556,7 @@ impl Db { } pub(crate) async fn add_connection(&self, actor_id: IriString) -> Result<(), Error> { - tracing::debug!("Adding Connection: {}", actor_id); + tracing::debug!("Adding Connection: {actor_id}"); self.unblock(move |inner| { inner .connected_actor_ids diff --git a/src/error.rs b/src/error.rs index 8fcd05d..c72b8b5 100644 --- a/src/error.rs +++ b/src/error.rs @@ -10,7 +10,7 @@ use std::{convert::Infallible, fmt::Debug, io}; use tracing_error::SpanTrace; pub(crate) struct Error { - context: SpanTrace, + context: String, kind: ErrorKind, } @@ -26,6 +26,14 @@ impl Error { pub(crate) fn is_bad_request(&self) -> bool { matches!(self.kind, ErrorKind::Status(_, StatusCode::BAD_REQUEST)) } + + pub(crate) fn is_gone(&self) -> bool { + matches!(self.kind, ErrorKind::Status(_, StatusCode::GONE)) + } + + pub(crate) fn is_malformed_json(&self) -> bool { + matches!(self.kind, ErrorKind::Json(_)) + } } impl std::fmt::Debug for Error { @@ -53,7 +61,7 @@ where { fn from(error: T) -> Self { Error { - context: SpanTrace::capture(), + context: SpanTrace::capture().to_string(), kind: error.into(), } } @@ -77,10 +85,7 @@ pub(crate) enum ErrorKind { ParseIri(#[from] activitystreams::iri_string::validate::Error), #[error("Couldn't normalize IRI, {0}")] - NormalizeIri( - #[from] - activitystreams::iri_string::task::Error, - ), + NormalizeIri(#[from] std::collections::TryReserveError), #[error("Couldn't perform IO, {0}")] Io(#[from] io::Error), @@ -98,13 +103,13 @@ pub(crate) enum ErrorKind { PrepareSign(#[from] PrepareSignError), #[error("Couldn't sign digest")] - Signature(#[from] signature::Error), + Signature(#[from] rsa::signature::Error), #[error("Couldn't read signature")] - ReadSignature(signature::Error), + ReadSignature(rsa::signature::Error), #[error("Couldn't verify signature")] - VerifySignature(signature::Error), + VerifySignature(rsa::signature::Error), #[error("Couldn't parse the signature header")] HeaderValidation(#[from] actix_web::http::header::InvalidHeaderValue), @@ -125,7 +130,7 @@ pub(crate) enum ErrorKind { BadActor(String, String), #[error("Signature verification is required, but no signature was given")] - NoSignature(String), + NoSignature(Option), #[error("Wrong ActivityPub kind, {0}")] Kind(String), @@ -196,7 +201,8 @@ impl ResponseError for Error { ErrorKind::Kind(_) | ErrorKind::MissingKind | ErrorKind::MissingId - | ErrorKind::ObjectCount => StatusCode::BAD_REQUEST, + | ErrorKind::ObjectCount + | ErrorKind::NoSignature(_) => StatusCode::BAD_REQUEST, _ => StatusCode::INTERNAL_SERVER_ERROR, } } diff --git a/src/extractors.rs b/src/extractors.rs index 572da34..f56b9af 100644 --- a/src/extractors.rs +++ b/src/extractors.rs @@ -80,7 +80,7 @@ impl Admin { #[derive(Debug, thiserror::Error)] #[error("Failed authentication")] pub(crate) struct Error { - context: SpanTrace, + context: String, #[source] kind: ErrorKind, } @@ -88,49 +88,49 @@ pub(crate) struct Error { impl Error { fn invalid() -> Self { Error { - context: SpanTrace::capture(), + context: SpanTrace::capture().to_string(), kind: ErrorKind::Invalid, } } fn missing_config() -> Self { Error { - context: SpanTrace::capture(), + context: SpanTrace::capture().to_string(), kind: ErrorKind::MissingConfig, } } fn missing_db() -> Self { Error { - context: SpanTrace::capture(), + context: SpanTrace::capture().to_string(), kind: ErrorKind::MissingDb, } } fn bcrypt_verify(e: BcryptError) -> Self { Error { - context: SpanTrace::capture(), + context: SpanTrace::capture().to_string(), kind: ErrorKind::BCryptVerify(e), } } fn bcrypt_hash(e: BcryptError) -> Self { Error { - context: SpanTrace::capture(), + context: SpanTrace::capture().to_string(), kind: ErrorKind::BCryptHash(e), } } fn parse_header(e: ParseError) -> Self { Error { - context: SpanTrace::capture(), + context: SpanTrace::capture().to_string(), kind: ErrorKind::ParseHeader(e), } } fn canceled(_: BlockingError) -> Self { Error { - context: SpanTrace::capture(), + context: SpanTrace::capture().to_string(), kind: ErrorKind::Canceled, } } diff --git a/src/jobs.rs b/src/jobs.rs index 014bd72..e2b6aef 100644 --- a/src/jobs.rs +++ b/src/jobs.rs @@ -5,6 +5,7 @@ mod deliver_many; mod instance; mod nodeinfo; mod process_listeners; +mod record_last_online; pub(crate) use self::{ contact::QueryContact, deliver::Deliver, deliver_many::DeliverMany, instance::QueryInstance, @@ -15,14 +16,14 @@ use crate::{ config::Config, data::{ActorCache, MediaCache, NodeCache, State}, error::{Error, ErrorKind}, - jobs::process_listeners::Listeners, + jobs::{process_listeners::Listeners, record_last_online::RecordLastOnline}, requests::Requests, }; use background_jobs::{ memory_storage::{ActixTimer, Storage}, - Job, Manager, QueueHandle, WorkerConfig, + Job, QueueHandle, WorkerConfig, }; -use std::{convert::TryFrom, num::NonZeroUsize, time::Duration}; +use std::time::Duration; fn debug_object(activity: &serde_json::Value) -> &serde_json::Value { let mut object = &activity["object"]["type"]; @@ -43,11 +44,8 @@ pub(crate) fn create_workers( actors: ActorCache, media: MediaCache, config: Config, -) -> (Manager, JobServer) { - let parallelism = std::thread::available_parallelism() - .unwrap_or_else(|_| NonZeroUsize::try_from(1).expect("nonzero")); - - let shared = WorkerConfig::new_managed(Storage::new(ActixTimer), move |queue_handle| { +) -> JobServer { + let queue_handle = WorkerConfig::new(Storage::new(ActixTimer), move |queue_handle| { JobState::new( state.clone(), actors.clone(), @@ -62,6 +60,7 @@ pub(crate) fn create_workers( .register::() .register::() .register::() + .register::() .register::() .register::() .register::() @@ -70,13 +69,12 @@ pub(crate) fn create_workers( .set_worker_count("maintenance", 2) .set_worker_count("apub", 2) .set_worker_count("deliver", 8) - .start_with_threads(parallelism); + .start(); - shared.every(Duration::from_secs(60 * 5), Listeners); + queue_handle.every(Duration::from_secs(60 * 5), Listeners); + queue_handle.every(Duration::from_secs(60 * 10), RecordLastOnline); - let job_server = JobServer::new(shared.queue_handle().clone()); - - (shared, job_server) + JobServer::new(queue_handle) } #[derive(Clone, Debug)] diff --git a/src/jobs/apub.rs b/src/jobs/apub.rs index d857b46..a5e195c 100644 --- a/src/jobs/apub.rs +++ b/src/jobs/apub.rs @@ -36,13 +36,13 @@ async fn get_inboxes( state.inboxes_without(&actor.inbox, &authority).await } -fn prepare_activity( +fn prepare_activity( mut t: T, id: impl TryInto, to: impl TryInto, ) -> Result where - T: ObjectExt + BaseExt, + T: ObjectExt + BaseExt, Error: From + From, { t.set_id(id.try_into()?) diff --git a/src/jobs/apub/announce.rs b/src/jobs/apub/announce.rs index 93dec67..480f8db 100644 --- a/src/jobs/apub/announce.rs +++ b/src/jobs/apub/announce.rs @@ -42,7 +42,7 @@ impl Announce { .queue(DeliverMany::new(inboxes, announce)?) .await?; - state.state.cache(self.object_id, activity_id).await; + state.state.cache(self.object_id, activity_id); Ok(()) } } diff --git a/src/jobs/contact.rs b/src/jobs/contact.rs index a98ac8f..3c880af 100644 --- a/src/jobs/contact.rs +++ b/src/jobs/contact.rs @@ -42,7 +42,7 @@ impl QueryContact { let contact = match state .requests - .fetch::(self.contact_id.as_str()) + .fetch::(&self.contact_id) .await { Ok(contact) => contact, diff --git a/src/jobs/deliver.rs b/src/jobs/deliver.rs index 223608e..72f4aec 100644 --- a/src/jobs/deliver.rs +++ b/src/jobs/deliver.rs @@ -35,7 +35,7 @@ impl Deliver { #[tracing::instrument(name = "Deliver", skip(state))] async fn permform(self, state: JobState) -> Result<(), Error> { - if let Err(e) = state.requests.deliver(self.to, &self.data).await { + if let Err(e) = state.requests.deliver(&self.to, &self.data).await { if e.is_breaker() { tracing::debug!("Not trying due to failed breaker"); return Ok(()); diff --git a/src/jobs/instance.rs b/src/jobs/instance.rs index 4339845..59826b5 100644 --- a/src/jobs/instance.rs +++ b/src/jobs/instance.rs @@ -20,11 +20,41 @@ impl std::fmt::Debug for QueryInstance { } } +enum InstanceApiType { + Mastodon, + Misskey, +} + impl QueryInstance { pub(crate) fn new(actor_id: IriString) -> Self { QueryInstance { actor_id } } + async fn get_instance( + instance_type: InstanceApiType, + state: &JobState, + scheme: &str, + authority: &str, + ) -> Result { + match instance_type { + InstanceApiType::Mastodon => { + let mastodon_instance_uri = iri!(format!("{scheme}://{authority}/api/v1/instance")); + state + .requests + .fetch_json::(&mastodon_instance_uri) + .await + } + InstanceApiType::Misskey => { + let msky_meta_uri = iri!(format!("{scheme}://{authority}/api/meta")); + state + .requests + .fetch_json_msky::(&msky_meta_uri) + .await + .map(|res| res.into()) + } + } + } + #[tracing::instrument(name = "Query instance", skip(state))] async fn perform(self, state: JobState) -> Result<(), Error> { let contact_outdated = state @@ -45,23 +75,40 @@ impl QueryInstance { .authority_str() .ok_or(ErrorKind::MissingDomain)?; let scheme = self.actor_id.scheme_str(); - let instance_uri = iri!(format!("{}://{}/api/v1/instance", scheme, authority)); - let instance = match state - .requests - .fetch_json::(instance_uri.as_str()) - .await - { - Ok(instance) => instance, - Err(e) if e.is_breaker() => { - tracing::debug!("Not retrying due to failed breaker"); + // Attempt all endpoint. + let instance_futures = [ + Self::get_instance(InstanceApiType::Mastodon, &state, scheme, authority), + Self::get_instance(InstanceApiType::Misskey, &state, scheme, authority), + ]; + + let mut instance_result: Option = None; + for instance_future in instance_futures { + match instance_future.await { + Ok(instance) => { + instance_result = Some(instance); + break; + } + Err(e) if e.is_breaker() => { + tracing::debug!("Not retrying due to failed breaker"); + return Ok(()); + } + Err(e) if e.is_not_found() => { + tracing::debug!("Server doesn't implement instance endpoint"); + } + Err(e) if e.is_malformed_json() => { + tracing::debug!("Server doesn't returned proper json"); + } + Err(e) => return Err(e), + } + } + + let instance = match instance_result { + Some(instance) => instance, + None => { + tracing::debug!("Server doesn't implement all instance endpoint"); return Ok(()); } - Err(e) if e.is_not_found() => { - tracing::debug!("Server doesn't implement instance endpoint"); - return Ok(()); - } - Err(e) => return Err(e), }; let description = instance.short_description.unwrap_or(instance.description); @@ -144,12 +191,59 @@ struct Contact { avatar: IriString, } +#[derive(serde::Deserialize)] +#[serde(rename_all(deserialize = "camelCase"))] +struct MisskeyMeta { + name: Option, + description: Option, + version: String, + maintainer_name: Option, + // Yes, I know, this is instance URL... but we does not have any choice. + uri: IriString, + // Use instance icon as a profile picture... + icon_url: Option, + features: MisskeyFeatures, +} + +#[derive(serde::Deserialize)] +struct MisskeyFeatures { + registration: Boolish, // Corresponding to Mastodon registration +} + +impl From for Instance { + fn from(meta: MisskeyMeta) -> Self { + let contact = match (meta.maintainer_name, meta.icon_url) { + (Some(maintainer), Some(icon)) => Some(Contact { + username: maintainer.clone(), + display_name: maintainer, + url: meta.uri, + avatar: icon, + }), + (_, _) => None, + }; + + // Transform it into Mastodon Instance object + Instance { + title: meta.name.unwrap_or_else(|| "".to_owned()), + short_description: None, + description: meta.description.unwrap_or_else(|| "".to_owned()), + version: meta.version, + registrations: meta.features.registration, + approval_required: false, + contact, + } + } +} + #[cfg(test)] mod tests { use super::Instance; + use super::MisskeyMeta; - const ASONIX_INSTANCE: &'static str = r#"{"uri":"masto.asonix.dog","title":"asonix.dog","short_description":"The asonix of furry mastodon. For me and a few friends. DM me somewhere if u want an account lol","description":"A mastodon server that's only for me and nobody else sorry","email":"asonix@asonix.dog","version":"4.0.0rc2-asonix-changes","urls":{"streaming_api":"wss://masto.asonix.dog"},"stats":{"user_count":7,"status_count":12328,"domain_count":5146},"thumbnail":"https://masto.asonix.dog/system/site_uploads/files/000/000/002/@1x/32f51462a2b2bf2d.png","languages":["dog"],"registrations":false,"approval_required":false,"invites_enabled":false,"configuration":{"accounts":{"max_featured_tags":10},"statuses":{"max_characters":500,"max_media_attachments":4,"characters_reserved_per_url":23},"media_attachments":{"supported_mime_types":["image/jpeg","image/png","image/gif","image/heic","image/heif","image/webp","image/avif","video/webm","video/mp4","video/quicktime","video/ogg","audio/wave","audio/wav","audio/x-wav","audio/x-pn-wave","audio/vnd.wave","audio/ogg","audio/vorbis","audio/mpeg","audio/mp3","audio/webm","audio/flac","audio/aac","audio/m4a","audio/x-m4a","audio/mp4","audio/3gpp","video/x-ms-asf"],"image_size_limit":10485760,"image_matrix_limit":16777216,"video_size_limit":41943040,"video_frame_rate_limit":60,"video_matrix_limit":2304000},"polls":{"max_options":4,"max_characters_per_option":50,"min_expiration":300,"max_expiration":2629746}},"contact_account":{"id":"1","username":"asonix","acct":"asonix","display_name":"Liom on Mane :antiverified:","locked":true,"bot":false,"discoverable":true,"group":false,"created_at":"2021-02-09T00:00:00.000Z","note":"\u003cp\u003e26, local liom, friend, rust (lang) stan, bi \u003c/p\u003e\u003cp\u003eicon by \u003cspan class=\"h-card\"\u003e\u003ca href=\"https://furaffinity.net/user/lalupine\" target=\"blank\" rel=\"noopener noreferrer\" class=\"u-url mention\"\u003e@\u003cspan\u003elalupine@furaffinity.net\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e\u003cbr /\u003eheader by \u003cspan class=\"h-card\"\u003e\u003ca href=\"https://furaffinity.net/user/tronixx\" target=\"blank\" rel=\"noopener noreferrer\" class=\"u-url mention\"\u003e@\u003cspan\u003etronixx@furaffinity.net\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e\u003c/p\u003e\u003cp\u003eTestimonials:\u003c/p\u003e\u003cp\u003eStand: LIONS\u003cbr /\u003eStand User: AODE\u003cbr /\u003e- Keris (not on here)\u003c/p\u003e","url":"https://masto.asonix.dog/@asonix","avatar":"https://masto.asonix.dog/system/accounts/avatars/000/000/001/original/00852df0e6fee7e0.png","avatar_static":"https://masto.asonix.dog/system/accounts/avatars/000/000/001/original/00852df0e6fee7e0.png","header":"https://masto.asonix.dog/system/accounts/headers/000/000/001/original/8122ce3e5a745385.png","header_static":"https://masto.asonix.dog/system/accounts/headers/000/000/001/original/8122ce3e5a745385.png","followers_count":237,"following_count":474,"statuses_count":8798,"last_status_at":"2022-11-08","noindex":true,"emojis":[{"shortcode":"antiverified","url":"https://masto.asonix.dog/system/custom_emojis/images/000/030/053/original/bb0bc2e395b9a127.png","static_url":"https://masto.asonix.dog/system/custom_emojis/images/000/030/053/static/bb0bc2e395b9a127.png","visible_in_picker":true}],"fields":[{"name":"pronouns","value":"he/they","verified_at":null},{"name":"software","value":"bad","verified_at":null},{"name":"gitea","value":"\u003ca href=\"https://git.asonix.dog\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003egit.asonix.dog\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e","verified_at":null},{"name":"join my","value":"relay","verified_at":null}]},"rules":[]}"#; - const HYNET_INSTANCE: &'static str = r#"{"approval_required":false,"avatar_upload_limit":2000000,"background_image":"https://soc.hyena.network/images/city.jpg","background_upload_limit":4000000,"banner_upload_limit":4000000,"description":"Akkoma: The cooler fediverse server","description_limit":5000,"email":"me@hyena.network","languages":["en"],"max_toot_chars":"5000","pleroma":{"metadata":{"account_activation_required":true,"features":["pleroma_api","mastodon_api","mastodon_api_streaming","polls","v2_suggestions","pleroma_explicit_addressing","shareable_emoji_packs","multifetch","pleroma:api/v1/notifications:include_types_filter","chat","shout","relay","safe_dm_mentions","pleroma_emoji_reactions","pleroma_chat_messages","exposable_reactions","profile_directory","custom_emoji_reactions"],"federation":{"enabled":true,"exclusions":false,"mrf_hashtag":{"federated_timeline_removal":[],"reject":[],"sensitive":["nsfw"]},"mrf_policies":["SimplePolicy","EnsureRePrepended","HashtagPolicy"],"mrf_simple":{"accept":[],"avatar_removal":[],"banner_removal":[],"federated_timeline_removal":["botsin.space"],"followers_only":[],"media_nsfw":["mstdn.jp","wxw.moe","knzk.me","vipgirlfriend.xxx","humblr.social","switter.at","kinkyelephant.com","sinblr.com","kinky.business","rubber.social"],"media_removal":[],"reject":["*.10minutepleroma.com","101010.pl","13bells.com","2.distsn.org","2hu.club","2ndamendment.social","434.earth","4chan.icu","4qq.org","7td.org","80percent.social","a.nti.social","aaathats3as.com","accela.online","amala.schwartzwelt.xyz","angrytoday.com","anime.website","antitwitter.moe","antivaxxer.icu","archivefedifor.fun","artalley.social","bae.st","bajax.us","baraag.net","bbs.kawa-kun.com","beefyboys.club","beefyboys.win","bikeshed.party","bitcoinhackers.org","bleepp.com","blovice.bahnhof.cz","brighteon.social","buildthatwallandmakeamericagreatagain.trumpislovetrumpis.life","bungle.online","cawfee.club","censorship.icu","chungus.cc","club.darknight-coffee.org","clubcyberia.co","cock.fish","cock.li","comfyboy.club","contrapointsfan.club","coon.town","counter.social","cum.salon","d-fens.systems","definitely-not-archivefedifor.fun","degenerates.fail","desuposter.club","detroitriotcity.com","developer.gab.com","dogwhipping.day","eientei.org","enigmatic.observer","eveningzoo.club","exited.eu","federation.krowverse.services","fedi.cc","fedi.krowverse.services","fedi.pawlicker.com","fedi.vern.cc","freak.university","freeatlantis.com","freecumextremist.com","freesoftwareextremist.com","freespeech.firedragonstudios.com","freespeech.host","freespeechextremist.com","freevoice.space","freezepeach.xyz","froth.zone","fuckgov.org","gab.ai","gab.polaris-1.work","gab.protohype.net","gabfed.com","gameliberty.club","gearlandia.haus","gitmo.life","glindr.org","glittersluts.xyz","glowers.club","godspeed.moe","gorf.pub","goyim.app","gs.kawa-kun.com","hagra.net","hallsofamenti.io","hayu.sh","hentai.baby","honkwerx.tech","hunk.city","husk.site","iddqd.social","ika.moe","isexychat.space","jaeger.website","justicewarrior.social","kag.social","katiehopkinspolitical.icu","kiwifarms.cc","kiwifarms.is","kiwifarms.net","kohrville.net","koyu.space","kys.moe","lain.com","lain.sh","leafposter.club","lets.saynoto.lgbt","liberdon.com","libertarianism.club","ligma.pro","lolis.world","masochi.st","masthead.social","mastodon.digitalsuccess.dev","mastodon.fidonet.io","mastodon.grin.hu","mastodon.ml","midnightride.rs","milker.cafe","mobile.tmediatech.io","moon.holiday","mstdn.foxfam.club","mstdn.io","mstdn.starnix.network","mulmeyun.church","nazi.social","neckbeard.xyz","neenster.org","neko.ci","netzsphaere.xyz","newjack.city","nicecrew.digital","nnia.space","noagendasocial.com","norrebro.space","oursocialism.today","ovo.sc","pawoo.net","paypig.org","pedo.school","phreedom.tk","pieville.net","pkteerium.xyz","pl.murky.club","pl.spiderden.net","pl.tkammer.de","pl.zombiecats.run","pleroma.nobodyhasthe.biz","pleroma.runfox.tk","pleroma.site","plr.inferencium.net","pmth.us","poa.st","pod.vladtepesblog.com","political.icu","pooper.social","posting.lolicon.rocks","preteengirls.biz","prout.social","qoto.org","rage.lol","rakket.app","raplst.town","rdrama.cc","ryona.agency","s.sneak.berlin","seal.cafe","sealion.club","search.fedi.app","sementerrori.st","shitposter.club","shortstackran.ch","silkhe.art","sleepy.cafe","soc.mahodou.moe","soc.redeyes.site","social.076.ne.jp","social.anoxinon.de","social.chadland.net","social.freetalklive.com","social.getgle.org","social.handholding.io","social.headsca.la","social.imirhil.fr","social.lovingexpressions.net","social.manalejandro.com","social.midwaytrades.com","social.pseudo-whiskey.bar","social.targaryen.house","social.teci.world","societal.co","society.oftrolls.com","socks.pinnoto.org","socnet.supes.com","solagg.com","spinster.xyz","springbo.cc","stereophonic.space","sunshinegardens.org","theautisticinvestors.quest","thechad.zone","theduran.icu","theosis.church","toot.love","toots.alirezahayati.com","traboone.com","truthsocial.co.in","truthsocial.com","tuusin.misono-ya.info","tweety.icu","unbound.social","unsafe.space","varishangout.net","video.nobodyhasthe.biz","voicenews.icu","voluntaryism.club","waifu.social","weeaboo.space","whinge.town","wolfgirl.bar","workers.dev","wurm.host","xiii.ch","xn--p1abe3d.xn--80asehdb","yggdrasil.social","youjo.love"],"reject_deletes":[],"report_removal":[]},"mrf_simple_info":{"federated_timeline_removal":{"botsin.space":{"reason":"A lot of bot content"}},"media_nsfw":{"humblr.social":{"reason":"NSFW Instance, safe to assume most content is NSFW"},"kinky.business":{"reason":"NSFW Instance, safe to assume most content is NSFW"},"kinkyelephant.com":{"reason":"NSFW Instance, safe to assume most content is NSFW"},"knzk.me":{"reason":"Unmarked nsfw media"},"mstdn.jp":{"reason":"Not sure about the media policy"},"rubber.social":{"reason":"NSFW Instance, safe to assume most content is NSFW"},"sinblr.com":{"reason":"NSFW Instance, safe to assume most content is NSFW"},"switter.at":{"reason":"NSFW Instance, safe to assume most content is NSFW"},"vipgirlfriend.xxx":{"reason":"Unmarked nsfw media"},"wxw.moe":{"reason":"Unmarked nsfw media"}}},"quarantined_instances":[],"quarantined_instances_info":{"quarantined_instances":{}}},"fields_limits":{"max_fields":10,"max_remote_fields":20,"name_length":512,"value_length":2048},"post_formats":["text/plain","text/html","text/markdown","text/bbcode","text/x.misskeymarkdown"],"privileged_staff":false},"stats":{"mau":1},"vapid_public_key":"BMg4q-rT3rkMzc29F7OS5uM6t-Rx4HncMIB1NXrKwNlVRfX-W1kwgOuq5pDy-WhWmOZudaegftjBTCX3-pzdDFc"},"poll_limits":{"max_expiration":31536000,"max_option_chars":200,"max_options":20,"min_expiration":0},"registrations":"FALSE","shout_limit":5000,"stats":{"domain_count":1035,"status_count":7,"user_count":1},"thumbnail":"https://soc.hyena.network/instance/thumbnail.jpeg","title":"HyNET Social","upload_limit":16000000,"uri":"https://soc.hyena.network","urls":{"streaming_api":"wss://soc.hyena.network"},"version":"2.7.2 (compatible; Akkoma 3.0.0)"}"#; + const ASONIX_INSTANCE: &str = r#"{"uri":"masto.asonix.dog","title":"asonix.dog","short_description":"The asonix of furry mastodon. For me and a few friends. DM me somewhere if u want an account lol","description":"A mastodon server that's only for me and nobody else sorry","email":"asonix@asonix.dog","version":"4.0.0rc2-asonix-changes","urls":{"streaming_api":"wss://masto.asonix.dog"},"stats":{"user_count":7,"status_count":12328,"domain_count":5146},"thumbnail":"https://masto.asonix.dog/system/site_uploads/files/000/000/002/@1x/32f51462a2b2bf2d.png","languages":["dog"],"registrations":false,"approval_required":false,"invites_enabled":false,"configuration":{"accounts":{"max_featured_tags":10},"statuses":{"max_characters":500,"max_media_attachments":4,"characters_reserved_per_url":23},"media_attachments":{"supported_mime_types":["image/jpeg","image/png","image/gif","image/heic","image/heif","image/webp","image/avif","video/webm","video/mp4","video/quicktime","video/ogg","audio/wave","audio/wav","audio/x-wav","audio/x-pn-wave","audio/vnd.wave","audio/ogg","audio/vorbis","audio/mpeg","audio/mp3","audio/webm","audio/flac","audio/aac","audio/m4a","audio/x-m4a","audio/mp4","audio/3gpp","video/x-ms-asf"],"image_size_limit":10485760,"image_matrix_limit":16777216,"video_size_limit":41943040,"video_frame_rate_limit":60,"video_matrix_limit":2304000},"polls":{"max_options":4,"max_characters_per_option":50,"min_expiration":300,"max_expiration":2629746}},"contact_account":{"id":"1","username":"asonix","acct":"asonix","display_name":"Liom on Mane :antiverified:","locked":true,"bot":false,"discoverable":true,"group":false,"created_at":"2021-02-09T00:00:00.000Z","note":"\u003cp\u003e26, local liom, friend, rust (lang) stan, bi \u003c/p\u003e\u003cp\u003eicon by \u003cspan class=\"h-card\"\u003e\u003ca href=\"https://furaffinity.net/user/lalupine\" target=\"blank\" rel=\"noopener noreferrer\" class=\"u-url mention\"\u003e@\u003cspan\u003elalupine@furaffinity.net\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e\u003cbr /\u003eheader by \u003cspan class=\"h-card\"\u003e\u003ca href=\"https://furaffinity.net/user/tronixx\" target=\"blank\" rel=\"noopener noreferrer\" class=\"u-url mention\"\u003e@\u003cspan\u003etronixx@furaffinity.net\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e\u003c/p\u003e\u003cp\u003eTestimonials:\u003c/p\u003e\u003cp\u003eStand: LIONS\u003cbr /\u003eStand User: AODE\u003cbr /\u003e- Keris (not on here)\u003c/p\u003e","url":"https://masto.asonix.dog/@asonix","avatar":"https://masto.asonix.dog/system/accounts/avatars/000/000/001/original/00852df0e6fee7e0.png","avatar_static":"https://masto.asonix.dog/system/accounts/avatars/000/000/001/original/00852df0e6fee7e0.png","header":"https://masto.asonix.dog/system/accounts/headers/000/000/001/original/8122ce3e5a745385.png","header_static":"https://masto.asonix.dog/system/accounts/headers/000/000/001/original/8122ce3e5a745385.png","followers_count":237,"following_count":474,"statuses_count":8798,"last_status_at":"2022-11-08","noindex":true,"emojis":[{"shortcode":"antiverified","url":"https://masto.asonix.dog/system/custom_emojis/images/000/030/053/original/bb0bc2e395b9a127.png","static_url":"https://masto.asonix.dog/system/custom_emojis/images/000/030/053/static/bb0bc2e395b9a127.png","visible_in_picker":true}],"fields":[{"name":"pronouns","value":"he/they","verified_at":null},{"name":"software","value":"bad","verified_at":null},{"name":"gitea","value":"\u003ca href=\"https://git.asonix.dog\" target=\"_blank\" rel=\"nofollow noopener noreferrer me\"\u003e\u003cspan class=\"invisible\"\u003ehttps://\u003c/span\u003e\u003cspan class=\"\"\u003egit.asonix.dog\u003c/span\u003e\u003cspan class=\"invisible\"\u003e\u003c/span\u003e\u003c/a\u003e","verified_at":null},{"name":"join my","value":"relay","verified_at":null}]},"rules":[]}"#; + const HYNET_INSTANCE: &str = r#"{"approval_required":false,"avatar_upload_limit":2000000,"background_image":"https://soc.hyena.network/images/city.jpg","background_upload_limit":4000000,"banner_upload_limit":4000000,"description":"Akkoma: The cooler fediverse server","description_limit":5000,"email":"me@hyena.network","languages":["en"],"max_toot_chars":"5000","pleroma":{"metadata":{"account_activation_required":true,"features":["pleroma_api","mastodon_api","mastodon_api_streaming","polls","v2_suggestions","pleroma_explicit_addressing","shareable_emoji_packs","multifetch","pleroma:api/v1/notifications:include_types_filter","chat","shout","relay","safe_dm_mentions","pleroma_emoji_reactions","pleroma_chat_messages","exposable_reactions","profile_directory","custom_emoji_reactions"],"federation":{"enabled":true,"exclusions":false,"mrf_hashtag":{"federated_timeline_removal":[],"reject":[],"sensitive":["nsfw"]},"mrf_policies":["SimplePolicy","EnsureRePrepended","HashtagPolicy"],"mrf_simple":{"accept":[],"avatar_removal":[],"banner_removal":[],"federated_timeline_removal":["botsin.space"],"followers_only":[],"media_nsfw":["mstdn.jp","wxw.moe","knzk.me","vipgirlfriend.xxx","humblr.social","switter.at","kinkyelephant.com","sinblr.com","kinky.business","rubber.social"],"media_removal":[],"reject":["*.10minutepleroma.com","101010.pl","13bells.com","2.distsn.org","2hu.club","2ndamendment.social","434.earth","4chan.icu","4qq.org","7td.org","80percent.social","a.nti.social","aaathats3as.com","accela.online","amala.schwartzwelt.xyz","angrytoday.com","anime.website","antitwitter.moe","antivaxxer.icu","archivefedifor.fun","artalley.social","bae.st","bajax.us","baraag.net","bbs.kawa-kun.com","beefyboys.club","beefyboys.win","bikeshed.party","bitcoinhackers.org","bleepp.com","blovice.bahnhof.cz","brighteon.social","buildthatwallandmakeamericagreatagain.trumpislovetrumpis.life","bungle.online","cawfee.club","censorship.icu","chungus.cc","club.darknight-coffee.org","clubcyberia.co","cock.fish","cock.li","comfyboy.club","contrapointsfan.club","coon.town","counter.social","cum.salon","d-fens.systems","definitely-not-archivefedifor.fun","degenerates.fail","desuposter.club","detroitriotcity.com","developer.gab.com","dogwhipping.day","eientei.org","enigmatic.observer","eveningzoo.club","exited.eu","federation.krowverse.services","fedi.cc","fedi.krowverse.services","fedi.pawlicker.com","fedi.vern.cc","freak.university","freeatlantis.com","freecumextremist.com","freesoftwareextremist.com","freespeech.firedragonstudios.com","freespeech.host","freespeechextremist.com","freevoice.space","freezepeach.xyz","froth.zone","fuckgov.org","gab.ai","gab.polaris-1.work","gab.protohype.net","gabfed.com","gameliberty.club","gearlandia.haus","gitmo.life","glindr.org","glittersluts.xyz","glowers.club","godspeed.moe","gorf.pub","goyim.app","gs.kawa-kun.com","hagra.net","hallsofamenti.io","hayu.sh","hentai.baby","honkwerx.tech","hunk.city","husk.site","iddqd.social","ika.moe","isexychat.space","jaeger.website","justicewarrior.social","kag.social","katiehopkinspolitical.icu","kiwifarms.cc","kiwifarms.is","kiwifarms.net","kohrville.net","koyu.space","kys.moe","lain.com","lain.sh","leafposter.club","lets.saynoto.lgbt","liberdon.com","libertarianism.club","ligma.pro","lolis.world","masochi.st","masthead.social","mastodon.digitalsuccess.dev","mastodon.fidonet.io","mastodon.grin.hu","mastodon.ml","midnightride.rs","milker.cafe","mobile.tmediatech.io","moon.holiday","mstdn.foxfam.club","mstdn.io","mstdn.starnix.network","mulmeyun.church","nazi.social","neckbeard.xyz","neenster.org","neko.ci","netzsphaere.xyz","newjack.city","nicecrew.digital","nnia.space","noagendasocial.com","norrebro.space","oursocialism.today","ovo.sc","pawoo.net","paypig.org","pedo.school","phreedom.tk","pieville.net","pkteerium.xyz","pl.murky.club","pl.spiderden.net","pl.tkammer.de","pl.zombiecats.run","pleroma.nobodyhasthe.biz","pleroma.runfox.tk","pleroma.site","plr.inferencium.net","pmth.us","poa.st","pod.vladtepesblog.com","political.icu","pooper.social","posting.lolicon.rocks","preteengirls.biz","prout.social","qoto.org","rage.lol","rakket.app","raplst.town","rdrama.cc","ryona.agency","s.sneak.berlin","seal.cafe","sealion.club","search.fedi.app","sementerrori.st","shitposter.club","shortstackran.ch","silkhe.art","sleepy.cafe","soc.mahodou.moe","soc.redeyes.site","social.076.ne.jp","social.anoxinon.de","social.chadland.net","social.freetalklive.com","social.getgle.org","social.handholding.io","social.headsca.la","social.imirhil.fr","social.lovingexpressions.net","social.manalejandro.com","social.midwaytrades.com","social.pseudo-whiskey.bar","social.targaryen.house","social.teci.world","societal.co","society.oftrolls.com","socks.pinnoto.org","socnet.supes.com","solagg.com","spinster.xyz","springbo.cc","stereophonic.space","sunshinegardens.org","theautisticinvestors.quest","thechad.zone","theduran.icu","theosis.church","toot.love","toots.alirezahayati.com","traboone.com","truthsocial.co.in","truthsocial.com","tuusin.misono-ya.info","tweety.icu","unbound.social","unsafe.space","varishangout.net","video.nobodyhasthe.biz","voicenews.icu","voluntaryism.club","waifu.social","weeaboo.space","whinge.town","wolfgirl.bar","workers.dev","wurm.host","xiii.ch","xn--p1abe3d.xn--80asehdb","yggdrasil.social","youjo.love"],"reject_deletes":[],"report_removal":[]},"mrf_simple_info":{"federated_timeline_removal":{"botsin.space":{"reason":"A lot of bot content"}},"media_nsfw":{"humblr.social":{"reason":"NSFW Instance, safe to assume most content is NSFW"},"kinky.business":{"reason":"NSFW Instance, safe to assume most content is NSFW"},"kinkyelephant.com":{"reason":"NSFW Instance, safe to assume most content is NSFW"},"knzk.me":{"reason":"Unmarked nsfw media"},"mstdn.jp":{"reason":"Not sure about the media policy"},"rubber.social":{"reason":"NSFW Instance, safe to assume most content is NSFW"},"sinblr.com":{"reason":"NSFW Instance, safe to assume most content is NSFW"},"switter.at":{"reason":"NSFW Instance, safe to assume most content is NSFW"},"vipgirlfriend.xxx":{"reason":"Unmarked nsfw media"},"wxw.moe":{"reason":"Unmarked nsfw media"}}},"quarantined_instances":[],"quarantined_instances_info":{"quarantined_instances":{}}},"fields_limits":{"max_fields":10,"max_remote_fields":20,"name_length":512,"value_length":2048},"post_formats":["text/plain","text/html","text/markdown","text/bbcode","text/x.misskeymarkdown"],"privileged_staff":false},"stats":{"mau":1},"vapid_public_key":"BMg4q-rT3rkMzc29F7OS5uM6t-Rx4HncMIB1NXrKwNlVRfX-W1kwgOuq5pDy-WhWmOZudaegftjBTCX3-pzdDFc"},"poll_limits":{"max_expiration":31536000,"max_option_chars":200,"max_options":20,"min_expiration":0},"registrations":"FALSE","shout_limit":5000,"stats":{"domain_count":1035,"status_count":7,"user_count":1},"thumbnail":"https://soc.hyena.network/instance/thumbnail.jpeg","title":"HyNET Social","upload_limit":16000000,"uri":"https://soc.hyena.network","urls":{"streaming_api":"wss://soc.hyena.network"},"version":"2.7.2 (compatible; Akkoma 3.0.0)"}"#; + const MISSKEY_BARE_INSTANCE: &str = r#"{"maintainerName":null,"maintainerEmail":null,"version":"12.119.2","name":null,"uri":"https://msky-lab-01.arewesecureyet.org","description":null,"langs":[],"tosUrl":null,"repositoryUrl":"https://github.com/misskey-dev/misskey","feedbackUrl":"https://github.com/misskey-dev/misskey/issues/new","disableRegistration":false,"disableLocalTimeline":false,"disableGlobalTimeline":false,"driveCapacityPerLocalUserMb":1024,"driveCapacityPerRemoteUserMb":32,"emailRequiredForSignup":false,"enableHcaptcha":false,"hcaptchaSiteKey":null,"enableRecaptcha":false,"recaptchaSiteKey":null,"swPublickey":null,"themeColor":null,"mascotImageUrl":"/assets/ai.png","bannerUrl":null,"errorImageUrl":"https://xn--931a.moe/aiart/yubitun.png","iconUrl":null,"backgroundImageUrl":null,"logoImageUrl":null,"maxNoteTextLength":3000,"emojis":[],"defaultLightTheme":null,"defaultDarkTheme":null,"ads":[],"enableEmail":false,"enableTwitterIntegration":false,"enableGithubIntegration":false,"enableDiscordIntegration":false,"enableServiceWorker":false,"translatorAvailable":false,"pinnedPages":["/featured","/channels","/explore","/pages","/about-misskey"],"pinnedClipId":null,"cacheRemoteFiles":true,"requireSetup":false,"proxyAccountName":null,"features":{"registration":true,"localTimeLine":true,"globalTimeLine":true,"emailRequiredForSignup":false,"elasticsearch":false,"hcaptcha":false,"recaptcha":false,"objectStorage":false,"twitter":false,"github":false,"discord":false,"serviceWorker":false,"miauth":true}}"#; + const MISSKEY_STELLA_INSTANCE: &str = r###"{"maintainerName":"Caipira","maintainerEmail":"caipira@sagestn.one","version":"12.120.0-alpha.8+cs","name":"Stella","uri":"https://stella.place","description":"
무수히 많은 별 중 하나인 인스턴스입니다.
\n
SINCE 2022. 5. 8. ~
\n
|
\n
Enable
\nCastella = Misskey fork (.....)","langs":[],"tosUrl":"https://docs.stella.place/tos","repositoryUrl":"https://github.com/misskey-dev/misskey","feedbackUrl":"https://github.com/misskey-dev/misskey/issues/new","disableRegistration":false,"disableLocalTimeline":false,"disableGlobalTimeline":false,"driveCapacityPerLocalUserMb":3072,"driveCapacityPerRemoteUserMb":32,"emailRequiredForSignup":true,"enableHcaptcha":true,"hcaptchaSiteKey":"94d629f6-a38e-4f24-83dd-63326c7e3bbf","enableRecaptcha":false,"recaptchaSiteKey":"6Lf-9dIfAAAAAF0Jp_QSsIlltyi371ZSU48Csisy","enableTurnstile":false,"turnstileSiteKey":"0x4AAAAAAAArrDq-OcfsyU-R","swPublickey":"BNTI1ms29LPGpdF8spPKa5khs6B2UYnVWa3KcO6e6JJoVXzbCBjdUdpkZHo-MK_AZfJxbTE8Z8C7g5kQChEkfp8","themeColor":"#df99f7","mascotImageUrl":"/assets/ai.png","bannerUrl":"https://cdn.stella.place/assets/bg.jpg","errorImageUrl":"https://xn--931a.moe/aiart/yubitun.png","iconUrl":"https://cdn.stella.place/assets/Stella.png","backgroundImageUrl":"https://cdn.stella.place/assets/bg.jpg","logoImageUrl":null,"maxNoteTextLength":3000,"emojis":[{"id":"97f9mubsmt","aliases":[""],"name":"big_blobhaj_hug","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/15d27c96-093a-4dc0-ae57-b848180b073b.png"},{"id":"97f9rzt5ok","aliases":[""],"name":"blobhaj","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/fb06df30-00d8-4b3b-ac8c-ee779ff06599.png"},{"id":"97f9rzjso5","aliases":[""],"name":"blobhaj_asparagus","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/35ed1236-8ebc-4c91-a793-0cfd04532148.png"},{"id":"97f9p8gtn3","aliases":[""],"name":"blobhaj_blanket_blue","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/d5876a69-1dd3-4e6a-b3cd-d497c06064fa.png"},{"id":"97f9p8gonf","aliases":[""],"name":"blobhaj_blanket_slate","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/43c461e7-f8af-4636-b72a-6d0ef40c2655.png"},{"id":"97f9rzl7nt","aliases":[""],"name":"blobhaj_blobby_hug","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/8a272ac5-b9d7-4554-ab18-7088f6132bc3.png"},{"id":"97f9rzmjo7","aliases":[""],"name":"blobhaj_full_body_hug","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/9f8251d0-c816-441e-9eef-2687502023fc.png"},{"id":"97f9rzl0ns","aliases":[""],"name":"blobhaj_heart","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/48ec936e-ae27-4b7c-94db-b673b628e231.png"},{"id":"97f9gwvvl8","aliases":[""],"name":"blobhaj_mdbook","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/56fdbaa3-06e6-4f5d-81d6-3e8e54ae059c.png"},{"id":"97f9rzk7nq","aliases":[""],"name":"blobhaj_mlem","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/03ea3ae0-2d40-4faf-8d3c-10f788a3de1d.png"},{"id":"97f9fpovkq","aliases":[""],"name":"blobhaj_octobook","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/6e992574-d8ca-4592-80a0-4f7bdff03cf8.png"},{"id":"97f9rzpjoc","aliases":[""],"name":"blobhaj_pride_heart","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/c397da98-dd44-484e-8de4-7db11a677e42.png"},{"id":"97f9rzjko4","aliases":[""],"name":"blobhaj_reach","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/e2c00652-a2f6-4ccf-bf0e-796f85b7854d.png"},{"id":"97f9rzjxo6","aliases":[""],"name":"blobhaj_sad_reach","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/bf36e678-20fd-49cc-8485-3ae5b8db033e.png"},{"id":"97f9rzqxod","aliases":[""],"name":"blobhaj_shock","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/ab9a3062-3bda-48c3-a91a-95beb86d56cc.png"},{"id":"97f9rzo0oa","aliases":[""],"name":"blobhaj_tiny_heart","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/aec32c7c-2b53-4251-b3ba-862587fa6ff6.png"},{"id":"97f9rznto8","aliases":[""],"name":"blobhaj_trans_pride_heart","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/e0dad2d0-9136-4310-8841-7bf3819ba152.png"},{"id":"97f9k7iqm2","aliases":[""],"name":"sir_blobhaj","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/70546774-e704-4a93-ab28-059ef3c54b65.png"},{"id":"97f9ikojll","aliases":[""],"name":"sir_blobhaj_stern","category":"Blobhaj Hub","host":null,"url":"https://cdn.stella.place/D1/2d69a377-a562-4769-8f60-b3ab8794b2a2.png"},{"id":"953ytptaah","aliases":[""],"name":"ysoyaboom","category":"Blue Archive","host":null,"url":"https://cdn.stella.place/D1/51240ea1-345e-4d43-a293-300dc968197a.gif"},{"id":"953ytpt8ag","aliases":[""],"name":"ysoyasnap","category":"Blue Archive","host":null,"url":"https://cdn.stella.place/D1/e95337b8-499b-47b2-811e-e1f4398efc69.gif"},{"id":"97q78i6ss2","aliases":[""],"name":"terminal_blinker","category":"Dev","host":null,"url":"https://cdn.stella.place/D1/a04022ea-d8dc-4861-a7fd-360d178bd01f.png"},{"id":"97v0x375vq","aliases":[],"name":"ff14_msq","category":"FF14","host":null,"url":"https://cdn.stella.place/D1/db14bccd-8f89-428b-b1b9-8da7e821656b.png"},{"id":"97v0x375jq","aliases":[],"name":"ff14_msq_done","category":"FF14","host":null,"url":"https://cdn.stella.place/D1/7be4bb6d-9271-4e40-abaf-24fe97ec9a76.png"},{"id":"97v0x37yjs","aliases":[],"name":"ff14_msq_locked","category":"FF14","host":null,"url":"https://cdn.stella.place/D1/e2c85711-032b-4a83-b933-24e8a96ece82.png"},{"id":"9542b9c4io","aliases":["사이노"],"name":"cyno_oops","category":"Genshin Impact","host":null,"url":"https://cdn.stella.place/D1/2507ad57-b042-407d-a84e-e676ea8710c5.gif"},{"id":"97lo6lbcin","aliases":["합니다"],"name":"kr_doing","category":"KR","host":null,"url":"https://cdn.stella.place/D1/eeee5f16-ac99-42e7-8c4c-c773150d4bd5.png"},{"id":"97lo6u3zqa","aliases":["정상"],"name":"kr_normal","category":"KR","host":null,"url":"https://cdn.stella.place/D1/29e82750-da88-4baf-a8ec-64b4bcafdf28.png"},{"id":"97lo7523j2","aliases":["우리"],"name":"kr_our","category":"KR","host":null,"url":"https://cdn.stella.place/D1/458304e1-72e3-4fd2-87d4-c05a6a152083.png"},{"id":"97lo6zujj0","aliases":["식당"],"name":"kr_restaurant","category":"KR","host":null,"url":"https://cdn.stella.place/D1/e257d140-e8fe-477a-b5be-4e7e29239544.png"},{"id":"97lo6q34ir","aliases":["영업"],"name":"kr_sales","category":"KR","host":null,"url":"https://cdn.stella.place/D1/2331cb3a-5ca5-42ae-b677-691f8fe3b4e4.png"},{"id":"96kc58706a","aliases":[""],"name":"Kirkland_Signature","category":"Logo","host":null,"url":"https://cdn.stella.place/D1/b24c722a-0cf3-485c-8bb6-e8385e2dcd2b.png"},{"id":"95dwescv8x","aliases":[""],"name":"ms_angry","category":"Messtodon","host":null,"url":"https://cdn.stella.place/D1/08407ba0-eb70-4385-ad7e-7987a1b178b8.png"},{"id":"95dwdph489","aliases":[""],"name":"ms_balloon","category":"Messtodon","host":null,"url":"https://cdn.stella.place/D1/d3e49618-d9fb-4142-b369-b8b0a19f6875.png"},{"id":"95dwcb0w7c","aliases":[""],"name":"ms_contempt","category":"Messtodon","host":null,"url":"https://cdn.stella.place/D1/b89d5827-d4ca-40d8-b250-02de2ab44ed9.png"},{"id":"95dwe68v8j","aliases":[""],"name":"ms_lie","category":"Messtodon","host":null,"url":"https://cdn.stella.place/D1/889a793d-07a7-4f1f-a6a8-a151ed4ce1e3.png"},{"id":"95dwa1yc5x","aliases":[""],"name":"ms_mastodon","category":"Messtodon","host":null,"url":"https://cdn.stella.place/D1/75fce83f-50a4-4ae9-86f3-52882279ccfd.png"},{"id":"95dwgcp0a8","aliases":[""],"name":"ms_messgaki","category":"Messtodon","host":null,"url":"https://cdn.stella.place/D1/a432b00e-0ba0-4e13-aa25-1b6b61469807.png"},{"id":"95dwfs4h9q","aliases":[""],"name":"ms_messgaki_normal","category":"Messtodon","host":null,"url":"https://cdn.stella.place/D1/5b9e1a10-f4af-4d35-af4f-a1cca7df5454.png"},{"id":"95dwb9i26m","aliases":[""],"name":"ms_messtodon","category":"Messtodon","host":null,"url":"https://cdn.stella.place/D1/a2c7ff09-3090-445d-be8b-68144ac59e5a.png"},{"id":"95dwdbym81","aliases":[""],"name":"ms_sleepy","category":"Messtodon","host":null,"url":"https://cdn.stella.place/D1/bbf5648e-6deb-4f3d-9fc0-6f9d1bbccd40.png"},{"id":"95dwf76i98","aliases":[""],"name":"ms_small_messgaki","category":"Messtodon","host":null,"url":"https://cdn.stella.place/D1/430b9d2a-591e-4beb-a037-fea66c777319.png"},{"id":"97pjdnpp76","aliases":["42"],"name":"text_42","category":"TEXT","host":null,"url":"https://cdn.stella.place/D1/e253653a-94b0-4cad-9277-f9c8e1188c5f.png"},{"id":"96njxnbkgt","aliases":[""],"name":"yt_social_circle_dark","category":"YouTube Brand resources","host":null,"url":"https://cdn.stella.place/D1/webpublic-0e0615fe-c430-43c2-910b-c9eea6ebf5ab.png"},{"id":"96njxneyh4","aliases":[""],"name":"yt_social_circle_red","category":"YouTube Brand resources","host":null,"url":"https://cdn.stella.place/D1/webpublic-7780f3d7-c0ed-46c8-93f2-afa01c39c65e.png"},{"id":"96njxnazgp","aliases":[""],"name":"yt_social_circle_white","category":"YouTube Brand resources","host":null,"url":"https://cdn.stella.place/D1/webpublic-ce023618-077a-4e80-8c37-827bd1490803.png"},{"id":"96njxnb8gr","aliases":[""],"name":"yt_social_square_dark","category":"YouTube Brand resources","host":null,"url":"https://cdn.stella.place/D1/webpublic-c48f67f6-6b46-4101-a8ba-123f5fa2508d.png"},{"id":"96njxnc7gv","aliases":[""],"name":"yt_social_square_red","category":"YouTube Brand resources","host":null,"url":"https://cdn.stella.place/D1/webpublic-51e24c3e-d8a7-4f52-b342-718823fc9631.png"},{"id":"96njxngrh7","aliases":[""],"name":"yt_social_square_white","category":"YouTube Brand resources","host":null,"url":"https://cdn.stella.place/D1/webpublic-de69c7e1-7044-4eab-b53f-7629342bcb11.png"},{"id":"96njxnbags","aliases":[""],"name":"yt_social_squircle_dark","category":"YouTube Brand resources","host":null,"url":"https://cdn.stella.place/D1/webpublic-de763d0f-3659-463e-b9b4-f6975a007b37.png"},{"id":"96njxnh5ha","aliases":[""],"name":"yt_social_squircle_red","category":"YouTube Brand resources","host":null,"url":"https://cdn.stella.place/D1/webpublic-a7e847b3-23ad-40ad-a06e-f6eafe23e001.png"},{"id":"96njxnb4gq","aliases":[""],"name":"yt_social_squircle_white","category":"YouTube Brand resources","host":null,"url":"https://cdn.stella.place/D1/webpublic-7d1878a0-e2a8-4336-a6f8-094a4b44a759.png"},{"id":"937z342qj0","aliases":[""],"name":"blackverified","category":"verified","host":null,"url":"https://cdn.stella.place/D1/496d2618-4a32-41a8-a1ba-df798a16f209.gif"},{"id":"937zd787m6","aliases":[""],"name":"blueviolet_verified","category":"verified","host":null,"url":"https://cdn.stella.place/D1/357c3a1e-88d0-47f3-9812-5f1f15dec382.gif"},{"id":"937z127ui9","aliases":[""],"name":"freshair_verified","category":"verified","host":null,"url":"https://cdn.stella.place/D1/7d10a1b1-8128-4400-af63-f28d4c3c9888.gif"},{"id":"937zkingmk","aliases":[""],"name":"fuchsia_verified","category":"verified","host":null,"url":"https://cdn.stella.place/D1/5cf05079-8216-40ca-875d-8cacb546e1f9.gif"},{"id":"937zhe1mmg","aliases":[""],"name":"lightred_verified","category":"verified","host":null,"url":"https://cdn.stella.place/D1/abd3c0f9-d046-4549-9d1e-f018d92982bf.gif"},{"id":"937zfpirmc","aliases":[""],"name":"mangotango_verified","category":"verified","host":null,"url":"https://cdn.stella.place/D1/9c4de8ba-2c63-41bb-b581-e3e52e2017be.gif"},{"id":"937ziz3lmi","aliases":[""],"name":"middleyellow_verified","category":"verified","host":null,"url":"https://cdn.stella.place/D1/86a74a5f-51e9-40f8-b2fd-de56927b72b0.gif"},{"id":"937zlhbumm","aliases":[""],"name":"palelavender_verifiedX","category":"verified","host":null,"url":"https://cdn.stella.place/D1/6364fb55-8c48-49b9-9cb9-2a06f50a920a.gif"},{"id":"937xqp173v","aliases":[""],"name":"pink_verified","category":"verified","host":null,"url":"https://cdn.stella.place/D1/41f5eb90-86f5-4955-9de5-5439293b2a90.gif"},{"id":"937z46vbje","aliases":[""],"name":"red_verified","category":"verified","host":null,"url":"https://cdn.stella.place/D1/bac2a25a-b79b-42db-bc75-f398dc18b2d1.gif"},{"id":"937yrlcvfv","aliases":[""],"name":"turquoise_verified","category":"verified","host":null,"url":"https://cdn.stella.place/D1/2ff8d332-5563-4951-a2dc-c627fc5c1ff1.gif"},{"id":"937atf86py","aliases":[""],"name":"verified","category":"verified","host":null,"url":"https://cdn.stella.place/D1/654525f0-a8f3-415f-9051-c79739f72c31.gif"},{"id":"937yzdnihz","aliases":[""],"name":"vividred_verified","category":"verified","host":null,"url":"https://cdn.stella.place/D1/3d06e1ef-372b-4d22-9d80-02e836b911b1.gif"},{"id":"98px6gj0a9","aliases":["엘렐레"],"name":"gardeneel_ellelle","category":null,"host":null,"url":"https://cdn.stella.place/D1/c5810e07-57ad-4fd8-ae86-753e2dd799d1.png"},{"id":"98pw3pndpo","aliases":["메롱","엘렐레"],"name":"gardeneel_tongue","category":null,"host":null,"url":"https://cdn.stella.place/D1/877b2ca3-6540-4d77-a061-f1a5e047e147.png"},{"id":"97rs46kkuz","aliases":["자빠"],"name":"yum_1","category":null,"host":null,"url":"https://cdn.stella.place/D1/74d00105-84fc-4050-8bd0-28d16abba3dd.png"},{"id":"97rs4w2ubs","aliases":["지게"],"name":"yum_2","category":null,"host":null,"url":"https://cdn.stella.place/D1/8cd4b526-d42f-42af-b3a5-6f6502798866.png"},{"id":"97rs593z6t","aliases":["맛있ㅇ"],"name":"yum_3","category":null,"host":null,"url":"https://cdn.stella.place/D1/095eba74-7862-4719-aa09-5ad28aa7d29a.png"},{"id":"97rs5lph70","aliases":["ㅓ요"],"name":"yum_4","category":null,"host":null,"url":"https://cdn.stella.place/D1/1d28ee5a-dd45-4fb0-bb65-a96ee20ed971.png"}],"defaultLightTheme":null,"defaultDarkTheme":null,"ads":[],"enableEmail":true,"enableTwitterIntegration":false,"enableGithubIntegration":false,"enableDiscordIntegration":true,"enableServiceWorker":true,"translatorAvailable":false,"pinnedPages":["/featured","/channels","/explore","/pages","/about-misskey"],"pinnedClipId":null,"cacheRemoteFiles":true,"requireSetup":false,"proxyAccountName":"proxy","features":{"registration":true,"localTimeLine":true,"globalTimeLine":true,"emailRequiredForSignup":true,"elasticsearch":false,"hcaptcha":true,"recaptcha":false,"turnstile":false,"objectStorage":true,"twitter":false,"github":false,"discord":true,"serviceWorker":true,"miauth":true}}"###; #[test] fn deser_masto_instance_with_contact() { @@ -162,4 +256,30 @@ mod tests { let inst: Instance = serde_json::from_str(HYNET_INSTANCE).unwrap(); assert!(inst.contact.is_none()); } + + #[test] + fn deser_misskey_instance_without_contact() { + let meta: MisskeyMeta = serde_json::from_str(MISSKEY_BARE_INSTANCE).unwrap(); + assert!(meta.icon_url.is_none()); + } + + #[test] + fn deser_misskey_instance_with_contact() { + let meta: MisskeyMeta = serde_json::from_str(MISSKEY_STELLA_INSTANCE).unwrap(); + assert_eq!( + meta.icon_url.unwrap(), + "https://cdn.stella.place/assets/Stella.png" + ); + } + + #[test] + fn deser_misskey_instance_into() { + let meta: MisskeyMeta = serde_json::from_str(MISSKEY_STELLA_INSTANCE).unwrap(); + let inst: Instance = meta.into(); + + assert_eq!( + inst.contact.unwrap().avatar, + "https://cdn.stella.place/assets/Stella.png" + ); + } } diff --git a/src/jobs/nodeinfo.rs b/src/jobs/nodeinfo.rs index fe86ad8..fa4812f 100644 --- a/src/jobs/nodeinfo.rs +++ b/src/jobs/nodeinfo.rs @@ -39,11 +39,11 @@ impl QueryNodeinfo { .authority_str() .ok_or(ErrorKind::MissingDomain)?; let scheme = self.actor_id.scheme_str(); - let well_known_uri = iri!(format!("{}://{}/.well-known/nodeinfo", scheme, authority)); + let well_known_uri = iri!(format!("{scheme}://{authority}/.well-known/nodeinfo")); let well_known = match state .requests - .fetch_json::(well_known_uri.as_str()) + .fetch_json::(&well_known_uri) .await { Ok(well_known) => well_known, @@ -55,7 +55,7 @@ impl QueryNodeinfo { }; let href = if let Some(link) = well_known.links.into_iter().find(|l| l.rel.is_supported()) { - link.href + iri!(&link.href) } else { return Ok(()); }; @@ -168,7 +168,7 @@ impl<'de> serde::de::Visitor<'de> for SupportedVersionVisitor { type Value = SupportedVersion; fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "a string starting with '{}'", SUPPORTED_VERSIONS) + write!(f, "a string starting with '{SUPPORTED_VERSIONS}'") } fn visit_str(self, s: &str) -> Result @@ -187,7 +187,7 @@ impl<'de> serde::de::Visitor<'de> for SupportedNodeinfoVisitor { type Value = SupportedNodeinfo; fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - write!(f, "a string starting with '{}'", SUPPORTED_NODEINFO) + write!(f, "a string starting with '{SUPPORTED_NODEINFO}'") } fn visit_str(self, s: &str) -> Result diff --git a/src/jobs/record_last_online.rs b/src/jobs/record_last_online.rs new file mode 100644 index 0000000..3c81b31 --- /dev/null +++ b/src/jobs/record_last_online.rs @@ -0,0 +1,28 @@ +use crate::{error::Error, jobs::JobState}; +use background_jobs::{ActixJob, Backoff}; +use std::{future::Future, pin::Pin}; + +#[derive(Clone, Debug, serde::Deserialize, serde::Serialize)] +pub(crate) struct RecordLastOnline; + +impl RecordLastOnline { + #[tracing::instrument(skip(state))] + async fn perform(self, state: JobState) -> Result<(), Error> { + let nodes = state.state.last_online.take(); + + state.state.db.mark_last_seen(nodes).await + } +} + +impl ActixJob for RecordLastOnline { + type State = JobState; + type Future = Pin>>>; + + const NAME: &'static str = "relay::jobs::RecordLastOnline"; + const QUEUE: &'static str = "maintenance"; + const BACKOFF: Backoff = Backoff::Linear(1); + + fn run(self, state: Self::State) -> Self::Future { + Box::pin(async move { self.perform(state).await.map_err(Into::into) }) + } +} diff --git a/src/main.rs b/src/main.rs index a428991..6ce2f22 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,10 +2,14 @@ #![allow(clippy::needless_borrow)] use activitystreams::iri_string::types::IriString; +use actix_rt::task::JoinHandle; use actix_web::{middleware::Compress, web, App, HttpServer}; use collector::MemoryCollector; #[cfg(feature = "console")] use console_subscriber::ConsoleLayer; +use http_signature_normalization_actix::middleware::VerifySignature; +use metrics_exporter_prometheus::PrometheusBuilder; +use metrics_util::layers::FanoutBuilder; use opentelemetry::{sdk::Resource, KeyValue}; use opentelemetry_otlp::WithExportConfig; use rustls::ServerConfig; @@ -35,8 +39,8 @@ use self::{ data::{ActorCache, MediaCache, State}, db::Db, jobs::create_workers, - middleware::{DebugPayload, RelayResolver, Timings}, - routes::{actor, inbox, index, nodeinfo, nodeinfo_meta, statics}, + middleware::{DebugPayload, MyVerify, RelayResolver, Timings}, + routes::{actor, healthz, inbox, index, nodeinfo, nodeinfo_meta, statics}, }; fn init_subscriber( @@ -94,19 +98,35 @@ fn init_subscriber( Ok(()) } -fn main() -> Result<(), anyhow::Error> { +#[actix_rt::main] +async fn main() -> Result<(), anyhow::Error> { dotenv::dotenv().ok(); let config = Config::build()?; init_subscriber(Config::software_name(), config.opentelemetry_url())?; - let collector = MemoryCollector::new(); - collector.install()?; let args = Args::new(); if args.any() { - return client_main(config, args); + return client_main(config, args).await?; + } + + let collector = MemoryCollector::new(); + + if let Some(bind_addr) = config.prometheus_bind_address() { + let (recorder, exporter) = PrometheusBuilder::new() + .with_http_listener(bind_addr) + .build()?; + + actix_rt::spawn(exporter); + let recorder = FanoutBuilder::default() + .add_recorder(recorder) + .add_recorder(collector.clone()) + .build(); + metrics::set_boxed_recorder(Box::new(recorder))?; + } else { + collector.install()?; } tracing::warn!("Opening DB"); @@ -116,20 +136,19 @@ fn main() -> Result<(), anyhow::Error> { let actors = ActorCache::new(db.clone()); let media = MediaCache::new(db.clone()); - server_main(db, actors, media, collector, config)?; + server_main(db, actors, media, collector, config).await??; tracing::warn!("Application exit"); Ok(()) } -#[actix_rt::main] -async fn client_main(config: Config, args: Args) -> Result<(), anyhow::Error> { - actix_rt::spawn(do_client_main(config, args)).await? +fn client_main(config: Config, args: Args) -> JoinHandle> { + actix_rt::spawn(do_client_main(config, args)) } async fn do_client_main(config: Config, args: Args) -> Result<(), anyhow::Error> { - let client = requests::build_client(&config.user_agent()); + let client = requests::build_client(&config.user_agent(), config.client_pool_size()); if !args.blocks().is_empty() || !args.allowed().is_empty() { if args.undo() { @@ -142,6 +161,39 @@ async fn do_client_main(config: Config, args: Args) -> Result<(), anyhow::Error> println!("Updated lists"); } + if args.contacted() { + let last_seen = admin::client::last_seen(&client, &config).await?; + + let mut report = String::from("Contacted:"); + + if !last_seen.never.is_empty() { + report += "\nNever seen:\n"; + } + + for domain in last_seen.never { + report += "\t"; + report += &domain; + report += "\n"; + } + + if !last_seen.last_seen.is_empty() { + report += "\nSeen:\n"; + } + + for (datetime, domains) in last_seen.last_seen { + for domain in domains { + report += "\t"; + report += &datetime.to_string(); + report += " - "; + report += &domain; + report += "\n"; + } + } + + report += "\n"; + println!("{report}"); + } + if args.list() { let (blocked, allowed, connected) = tokio::try_join!( admin::client::blocked(&client, &config), @@ -174,15 +226,14 @@ async fn do_client_main(config: Config, args: Args) -> Result<(), anyhow::Error> Ok(()) } -#[actix_rt::main] -async fn server_main( +fn server_main( db: Db, actors: ActorCache, media: MediaCache, collector: MemoryCollector, config: Config, -) -> Result<(), anyhow::Error> { - actix_rt::spawn(do_server_main(db, actors, media, collector, config)).await? +) -> JoinHandle> { + actix_rt::spawn(do_server_main(db, actors, media, collector, config)) } async fn do_server_main( @@ -195,10 +246,6 @@ async fn do_server_main( tracing::warn!("Creating state"); let state = State::build(db.clone()).await?; - tracing::warn!("Creating workers"); - let (manager, job_server) = - create_workers(state.clone(), actors.clone(), media.clone(), config.clone()); - if let Some((token, admin_handle)) = config.telegram_info() { tracing::warn!("Creating telegram handler"); telegram::start(admin_handle.to_owned(), db.clone(), token); @@ -208,13 +255,18 @@ async fn do_server_main( let bind_address = config.bind_address(); let server = HttpServer::new(move || { + let requests = state.requests(&config); + + let job_server = + create_workers(state.clone(), actors.clone(), media.clone(), config.clone()); + let app = App::new() .app_data(web::Data::new(db.clone())) .app_data(web::Data::new(state.clone())) - .app_data(web::Data::new(state.requests(&config))) + .app_data(web::Data::new(requests.clone())) .app_data(web::Data::new(actors.clone())) .app_data(web::Data::new(config.clone())) - .app_data(web::Data::new(job_server.clone())) + .app_data(web::Data::new(job_server)) .app_data(web::Data::new(media.clone())) .app_data(web::Data::new(collector.clone())); @@ -227,15 +279,15 @@ async fn do_server_main( app.wrap(Compress::default()) .wrap(TracingLogger::default()) .wrap(Timings) + .route("/healthz", web::get().to(healthz)) .service(web::resource("/").route(web::get().to(index))) .service(web::resource("/media/{path}").route(web::get().to(routes::media))) .service( web::resource("/inbox") .wrap(config.digest_middleware()) - .wrap(config.signature_middleware( - state.requests(&config), - actors.clone(), - state.clone(), + .wrap(VerifySignature::new( + MyVerify(requests, actors.clone(), state.clone()), + Default::default(), )) .wrap(DebugPayload(config.debug())) .route(web::post().to(inbox)), @@ -258,7 +310,8 @@ async fn do_server_main( .route("/allowed", web::get().to(admin::routes::allowed)) .route("/blocked", web::get().to(admin::routes::blocked)) .route("/connected", web::get().to(admin::routes::connected)) - .route("/stats", web::get().to(admin::routes::stats)), + .route("/stats", web::get().to(admin::routes::stats)) + .route("/last_seen", web::get().to(admin::routes::last_seen)), ), ) }); @@ -282,10 +335,6 @@ async fn do_server_main( tracing::warn!("Server closed"); - drop(manager); - - tracing::warn!("Main complete"); - Ok(()) } diff --git a/src/middleware/verifier.rs b/src/middleware/verifier.rs index 21d5b06..6528b83 100644 --- a/src/middleware/verifier.rs +++ b/src/middleware/verifier.rs @@ -6,10 +6,12 @@ use crate::{ }; use activitystreams::{base::BaseExt, iri, iri_string::types::IriString}; use actix_web::web; +use base64::{engine::general_purpose::STANDARD, Engine}; use http_signature_normalization_actix::{prelude::*, verify::DeprecatedAlgorithm}; -use rsa::{pkcs1v15::VerifyingKey, pkcs8::DecodePublicKey, RsaPublicKey}; -use sha2::{Digest, Sha256}; -use signature::{DigestVerifier, Signature}; +use rsa::{ + pkcs1v15::Signature, pkcs1v15::VerifyingKey, pkcs8::DecodePublicKey, sha2::Sha256, + signature::Verifier, RsaPublicKey, +}; use std::{future::Future, pin::Pin}; #[derive(Clone, Debug)] @@ -65,11 +67,17 @@ impl MyVerify { actor_id } else { - self.0 - .fetch::(public_key_id.as_str()) - .await? - .actor_id() - .ok_or(ErrorKind::MissingId)? + match self.0.fetch::(&public_key_id).await { + Ok(res) => res.actor_id().ok_or(ErrorKind::MissingId), + Err(e) => { + if e.is_gone() { + tracing::warn!("Actor gone: {public_key_id}"); + return Ok(false); + } else { + return Err(e); + } + } + }? }; // Previously we verified the sig from an actor's local cache @@ -117,13 +125,13 @@ async fn do_verify( let span = tracing::Span::current(); web::block(move || { span.in_scope(|| { - let decoded = base64::decode(signature)?; - let signature = Signature::from_bytes(&decoded).map_err(ErrorKind::ReadSignature)?; - let hashed = Sha256::new_with_prefix(signing_string.as_bytes()); + let decoded = STANDARD.decode(signature)?; + let signature = + Signature::try_from(decoded.as_slice()).map_err(ErrorKind::ReadSignature)?; - let verifying_key = VerifyingKey::new_with_prefix(public_key); + let verifying_key = VerifyingKey::::new(public_key); verifying_key - .verify_digest(hashed, &signature) + .verify(signing_string.as_bytes(), &signature) .map_err(ErrorKind::VerifySignature)?; Ok(()) as Result<(), Error> @@ -159,20 +167,20 @@ mod tests { use crate::apub::AcceptedActors; use rsa::{pkcs8::DecodePublicKey, RsaPublicKey}; - const ASONIX_DOG_ACTOR: &'static str = r#"{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"manuallyApprovesFollowers":"as:manuallyApprovesFollowers","toot":"http://joinmastodon.org/ns#","featured":{"@id":"toot:featured","@type":"@id"},"featuredTags":{"@id":"toot:featuredTags","@type":"@id"},"alsoKnownAs":{"@id":"as:alsoKnownAs","@type":"@id"},"movedTo":{"@id":"as:movedTo","@type":"@id"},"schema":"http://schema.org#","PropertyValue":"schema:PropertyValue","value":"schema:value","discoverable":"toot:discoverable","Device":"toot:Device","Ed25519Signature":"toot:Ed25519Signature","Ed25519Key":"toot:Ed25519Key","Curve25519Key":"toot:Curve25519Key","EncryptedMessage":"toot:EncryptedMessage","publicKeyBase64":"toot:publicKeyBase64","deviceId":"toot:deviceId","claim":{"@type":"@id","@id":"toot:claim"},"fingerprintKey":{"@type":"@id","@id":"toot:fingerprintKey"},"identityKey":{"@type":"@id","@id":"toot:identityKey"},"devices":{"@type":"@id","@id":"toot:devices"},"messageFranking":"toot:messageFranking","messageType":"toot:messageType","cipherText":"toot:cipherText","suspended":"toot:suspended"}],"id":"https://masto.asonix.dog/actor","type":"Application","inbox":"https://masto.asonix.dog/actor/inbox","outbox":"https://masto.asonix.dog/actor/outbox","preferredUsername":"masto.asonix.dog","url":"https://masto.asonix.dog/about/more?instance_actor=true","manuallyApprovesFollowers":true,"publicKey":{"id":"https://masto.asonix.dog/actor#main-key","owner":"https://masto.asonix.dog/actor","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx8zXS0QNg9YGUBsxAOBH\nJaxIn7i6t+Z4UOpSFDVa2kP0NvQgIJsq3wzRqvaiuncRWpkyFk1fTakiRGD32xnY\nt+juuAaIBlU8eswKyANFqhcLAvFHmT3rA1848M4/YM19djvlL/PR9T53tPNHU+el\nS9MlsG3o6Zsj8YaUJtCI8RgEuJoROLHUb/V9a3oMQ7CfuIoSvF3VEz3/dRT09RW6\n0wQX7yhka9WlKuayWLWmTcB9lAIX6neBk+qKc8VSEsO7mHkzB8mRgVcS2uYZl1eA\nD8/jTT+SlpeFNDZk0Oh35GNFoOxh9qjRw3NGxu7jJCVBehDODzasOv4xDxKAhONa\njQIDAQAB\n-----END PUBLIC KEY-----\n"},"endpoints":{"sharedInbox":"https://masto.asonix.dog/inbox"}}"#; - const KARJALAZET_RELAY: &'static str = r#"{"@context":["https://www.w3.org/ns/activitystreams","https://pleroma.karjalazet.se/schemas/litepub-0.1.jsonld",{"@language":"und"}],"alsoKnownAs":[],"attachment":[],"capabilities":{},"discoverable":false,"endpoints":{"oauthAuthorizationEndpoint":"https://pleroma.karjalazet.se/oauth/authorize","oauthRegistrationEndpoint":"https://pleroma.karjalazet.se/api/v1/apps","oauthTokenEndpoint":"https://pleroma.karjalazet.se/oauth/token","sharedInbox":"https://pleroma.karjalazet.se/inbox","uploadMedia":"https://pleroma.karjalazet.se/api/ap/upload_media"},"featured":"https://pleroma.karjalazet.se/relay/collections/featured","followers":"https://pleroma.karjalazet.se/relay/followers","following":"https://pleroma.karjalazet.se/relay/following","id":"https://pleroma.karjalazet.se/relay","inbox":"https://pleroma.karjalazet.se/relay/inbox","manuallyApprovesFollowers":false,"name":null,"outbox":"https://pleroma.karjalazet.se/relay/outbox","preferredUsername":"relay","publicKey":{"id":"https://pleroma.karjalazet.se/relay#main-key","owner":"https://pleroma.karjalazet.se/relay","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAucoyCht6QpEzUPdQWP/J\nJYxObSH3MCcXBnG4d0OX78QshloeAHhl78EZ5c8I0ePmIjDg2NFK3/pG0EvSrHe2\nIZHnHaN5emgCb2ifNya5W572yfQXo1tUQy+ZXtbTUA7BWbr4LuCvd+HUavMwbx72\neraSZTiQj//ObwpbXFoZO5I/+e5avGmVnfmr/y2cG95hqFDtI3438RgZyBjY5kJM\nY1MLWoY9itGSfYmBtxRj3umlC2bPuBB+hHUJi6TvP7NO6zuUZ66m4ETyuBDi8iP6\ngnUp3Q4+1/I3nDUmhjt7OXckUcX3r5M4UHD3VVUFG0aZw6WWMEAxlyFf/07fCkhR\nBwIDAQAB\n-----END PUBLIC KEY-----\n\n"},"summary":"","tag":[],"type":"Person","url":"https://pleroma.karjalazet.se/relay"}"#; - const ASONIX_DOG_KEY: &'static str = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx8zXS0QNg9YGUBsxAOBH\nJaxIn7i6t+Z4UOpSFDVa2kP0NvQgIJsq3wzRqvaiuncRWpkyFk1fTakiRGD32xnY\nt+juuAaIBlU8eswKyANFqhcLAvFHmT3rA1848M4/YM19djvlL/PR9T53tPNHU+el\nS9MlsG3o6Zsj8YaUJtCI8RgEuJoROLHUb/V9a3oMQ7CfuIoSvF3VEz3/dRT09RW6\n0wQX7yhka9WlKuayWLWmTcB9lAIX6neBk+qKc8VSEsO7mHkzB8mRgVcS2uYZl1eA\nD8/jTT+SlpeFNDZk0Oh35GNFoOxh9qjRw3NGxu7jJCVBehDODzasOv4xDxKAhONa\njQIDAQAB\n-----END PUBLIC KEY-----\n"; - const KARJALAZET_KEY: &'static str = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAucoyCht6QpEzUPdQWP/J\nJYxObSH3MCcXBnG4d0OX78QshloeAHhl78EZ5c8I0ePmIjDg2NFK3/pG0EvSrHe2\nIZHnHaN5emgCb2ifNya5W572yfQXo1tUQy+ZXtbTUA7BWbr4LuCvd+HUavMwbx72\neraSZTiQj//ObwpbXFoZO5I/+e5avGmVnfmr/y2cG95hqFDtI3438RgZyBjY5kJM\nY1MLWoY9itGSfYmBtxRj3umlC2bPuBB+hHUJi6TvP7NO6zuUZ66m4ETyuBDi8iP6\ngnUp3Q4+1/I3nDUmhjt7OXckUcX3r5M4UHD3VVUFG0aZw6WWMEAxlyFf/07fCkhR\nBwIDAQAB\n-----END PUBLIC KEY-----\n\n"; + const ASONIX_DOG_ACTOR: &str = r#"{"@context":["https://www.w3.org/ns/activitystreams","https://w3id.org/security/v1",{"manuallyApprovesFollowers":"as:manuallyApprovesFollowers","toot":"http://joinmastodon.org/ns#","featured":{"@id":"toot:featured","@type":"@id"},"featuredTags":{"@id":"toot:featuredTags","@type":"@id"},"alsoKnownAs":{"@id":"as:alsoKnownAs","@type":"@id"},"movedTo":{"@id":"as:movedTo","@type":"@id"},"schema":"http://schema.org#","PropertyValue":"schema:PropertyValue","value":"schema:value","discoverable":"toot:discoverable","Device":"toot:Device","Ed25519Signature":"toot:Ed25519Signature","Ed25519Key":"toot:Ed25519Key","Curve25519Key":"toot:Curve25519Key","EncryptedMessage":"toot:EncryptedMessage","publicKeyBase64":"toot:publicKeyBase64","deviceId":"toot:deviceId","claim":{"@type":"@id","@id":"toot:claim"},"fingerprintKey":{"@type":"@id","@id":"toot:fingerprintKey"},"identityKey":{"@type":"@id","@id":"toot:identityKey"},"devices":{"@type":"@id","@id":"toot:devices"},"messageFranking":"toot:messageFranking","messageType":"toot:messageType","cipherText":"toot:cipherText","suspended":"toot:suspended"}],"id":"https://masto.asonix.dog/actor","type":"Application","inbox":"https://masto.asonix.dog/actor/inbox","outbox":"https://masto.asonix.dog/actor/outbox","preferredUsername":"masto.asonix.dog","url":"https://masto.asonix.dog/about/more?instance_actor=true","manuallyApprovesFollowers":true,"publicKey":{"id":"https://masto.asonix.dog/actor#main-key","owner":"https://masto.asonix.dog/actor","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx8zXS0QNg9YGUBsxAOBH\nJaxIn7i6t+Z4UOpSFDVa2kP0NvQgIJsq3wzRqvaiuncRWpkyFk1fTakiRGD32xnY\nt+juuAaIBlU8eswKyANFqhcLAvFHmT3rA1848M4/YM19djvlL/PR9T53tPNHU+el\nS9MlsG3o6Zsj8YaUJtCI8RgEuJoROLHUb/V9a3oMQ7CfuIoSvF3VEz3/dRT09RW6\n0wQX7yhka9WlKuayWLWmTcB9lAIX6neBk+qKc8VSEsO7mHkzB8mRgVcS2uYZl1eA\nD8/jTT+SlpeFNDZk0Oh35GNFoOxh9qjRw3NGxu7jJCVBehDODzasOv4xDxKAhONa\njQIDAQAB\n-----END PUBLIC KEY-----\n"},"endpoints":{"sharedInbox":"https://masto.asonix.dog/inbox"}}"#; + const KARJALAZET_RELAY: &str = r#"{"@context":["https://www.w3.org/ns/activitystreams","https://pleroma.karjalazet.se/schemas/litepub-0.1.jsonld",{"@language":"und"}],"alsoKnownAs":[],"attachment":[],"capabilities":{},"discoverable":false,"endpoints":{"oauthAuthorizationEndpoint":"https://pleroma.karjalazet.se/oauth/authorize","oauthRegistrationEndpoint":"https://pleroma.karjalazet.se/api/v1/apps","oauthTokenEndpoint":"https://pleroma.karjalazet.se/oauth/token","sharedInbox":"https://pleroma.karjalazet.se/inbox","uploadMedia":"https://pleroma.karjalazet.se/api/ap/upload_media"},"featured":"https://pleroma.karjalazet.se/relay/collections/featured","followers":"https://pleroma.karjalazet.se/relay/followers","following":"https://pleroma.karjalazet.se/relay/following","id":"https://pleroma.karjalazet.se/relay","inbox":"https://pleroma.karjalazet.se/relay/inbox","manuallyApprovesFollowers":false,"name":null,"outbox":"https://pleroma.karjalazet.se/relay/outbox","preferredUsername":"relay","publicKey":{"id":"https://pleroma.karjalazet.se/relay#main-key","owner":"https://pleroma.karjalazet.se/relay","publicKeyPem":"-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAucoyCht6QpEzUPdQWP/J\nJYxObSH3MCcXBnG4d0OX78QshloeAHhl78EZ5c8I0ePmIjDg2NFK3/pG0EvSrHe2\nIZHnHaN5emgCb2ifNya5W572yfQXo1tUQy+ZXtbTUA7BWbr4LuCvd+HUavMwbx72\neraSZTiQj//ObwpbXFoZO5I/+e5avGmVnfmr/y2cG95hqFDtI3438RgZyBjY5kJM\nY1MLWoY9itGSfYmBtxRj3umlC2bPuBB+hHUJi6TvP7NO6zuUZ66m4ETyuBDi8iP6\ngnUp3Q4+1/I3nDUmhjt7OXckUcX3r5M4UHD3VVUFG0aZw6WWMEAxlyFf/07fCkhR\nBwIDAQAB\n-----END PUBLIC KEY-----\n\n"},"summary":"","tag":[],"type":"Person","url":"https://pleroma.karjalazet.se/relay"}"#; + const ASONIX_DOG_KEY: &str = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx8zXS0QNg9YGUBsxAOBH\nJaxIn7i6t+Z4UOpSFDVa2kP0NvQgIJsq3wzRqvaiuncRWpkyFk1fTakiRGD32xnY\nt+juuAaIBlU8eswKyANFqhcLAvFHmT3rA1848M4/YM19djvlL/PR9T53tPNHU+el\nS9MlsG3o6Zsj8YaUJtCI8RgEuJoROLHUb/V9a3oMQ7CfuIoSvF3VEz3/dRT09RW6\n0wQX7yhka9WlKuayWLWmTcB9lAIX6neBk+qKc8VSEsO7mHkzB8mRgVcS2uYZl1eA\nD8/jTT+SlpeFNDZk0Oh35GNFoOxh9qjRw3NGxu7jJCVBehDODzasOv4xDxKAhONa\njQIDAQAB\n-----END PUBLIC KEY-----\n"; + const KARJALAZET_KEY: &str = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAucoyCht6QpEzUPdQWP/J\nJYxObSH3MCcXBnG4d0OX78QshloeAHhl78EZ5c8I0ePmIjDg2NFK3/pG0EvSrHe2\nIZHnHaN5emgCb2ifNya5W572yfQXo1tUQy+ZXtbTUA7BWbr4LuCvd+HUavMwbx72\neraSZTiQj//ObwpbXFoZO5I/+e5avGmVnfmr/y2cG95hqFDtI3438RgZyBjY5kJM\nY1MLWoY9itGSfYmBtxRj3umlC2bPuBB+hHUJi6TvP7NO6zuUZ66m4ETyuBDi8iP6\ngnUp3Q4+1/I3nDUmhjt7OXckUcX3r5M4UHD3VVUFG0aZw6WWMEAxlyFf/07fCkhR\nBwIDAQAB\n-----END PUBLIC KEY-----\n\n"; #[test] fn handles_masto_keys() { - println!("{}", ASONIX_DOG_KEY); + println!("{ASONIX_DOG_KEY}"); let _ = RsaPublicKey::from_public_key_pem(ASONIX_DOG_KEY.trim()).unwrap(); } #[test] fn handles_pleromo_keys() { - println!("{}", KARJALAZET_KEY); + println!("{KARJALAZET_KEY}"); let _ = RsaPublicKey::from_public_key_pem(KARJALAZET_KEY.trim()).unwrap(); } diff --git a/src/requests.rs b/src/requests.rs index 332024a..a1fc8ef 100644 --- a/src/requests.rs +++ b/src/requests.rs @@ -1,20 +1,22 @@ -use crate::error::{Error, ErrorKind}; +use crate::{ + data::LastOnline, + error::{Error, ErrorKind}, +}; use activitystreams::iri_string::types::IriString; use actix_web::http::header::Date; -use awc::{error::SendRequestError, Client, ClientResponse}; +use awc::{error::SendRequestError, Client, ClientResponse, Connector}; +use base64::{engine::general_purpose::STANDARD, Engine}; use dashmap::DashMap; use http_signature_normalization_actix::prelude::*; use rand::thread_rng; -use rsa::{pkcs1v15::SigningKey, RsaPrivateKey}; -use sha2::{Digest, Sha256}; -use signature::RandomizedSigner; +use rsa::{ + pkcs1v15::SigningKey, + sha2::{Digest, Sha256}, + signature::{RandomizedSigner, SignatureEncoding}, + RsaPrivateKey, +}; use std::{ - cell::RefCell, - rc::Rc, - sync::{ - atomic::{AtomicUsize, Ordering}, - Arc, - }, + sync::Arc, time::{Duration, SystemTime}, }; use tracing_awc::Tracing; @@ -54,7 +56,7 @@ impl Breakers { if let Some(mut breaker) = self.inner.get_mut(authority) { breaker.fail(); if !breaker.should_try() { - tracing::warn!("Failed breaker for {}", authority); + tracing::warn!("Failed breaker for {authority}"); } false } else { @@ -138,20 +140,20 @@ impl Default for Breaker { #[derive(Clone)] pub(crate) struct Requests { - client: Rc>, - consecutive_errors: Rc, - error_limit: usize, + pool_size: usize, + client: Client, key_id: String, user_agent: String, private_key: RsaPrivateKey, config: Config, breakers: Breakers, + last_online: Arc, } impl std::fmt::Debug for Requests { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("Requests") - .field("error_limit", &self.error_limit) + .field("pool_size", &self.pool_size) .field("key_id", &self.key_id) .field("user_agent", &self.user_agent) .field("config", &self.config) @@ -160,12 +162,25 @@ impl std::fmt::Debug for Requests { } } -pub(crate) fn build_client(user_agent: &str) -> Client { - Client::builder() - .wrap(Tracing) - .add_default_header(("User-Agent", user_agent.to_string())) - .timeout(Duration::from_secs(15)) - .finish() +thread_local! { + static CLIENT: std::cell::OnceCell = std::cell::OnceCell::new(); +} + +pub(crate) fn build_client(user_agent: &str, pool_size: usize) -> Client { + CLIENT.with(|client| { + client + .get_or_init(|| { + let connector = Connector::new().limit(pool_size); + + Client::builder() + .connector(connector) + .wrap(Tracing) + .add_default_header(("User-Agent", user_agent.to_string())) + .timeout(Duration::from_secs(15)) + .finish() + }) + .clone() + }) } impl Requests { @@ -174,16 +189,18 @@ impl Requests { private_key: RsaPrivateKey, user_agent: String, breakers: Breakers, + last_online: Arc, + pool_size: usize, ) -> Self { Requests { - client: Rc::new(RefCell::new(build_client(&user_agent))), - consecutive_errors: Rc::new(AtomicUsize::new(0)), - error_limit: 3, + pool_size, + client: build_client(&user_agent, pool_size), key_id, user_agent, private_key, config: Config::default().mastodon_compat(), breakers, + last_online, } } @@ -191,41 +208,25 @@ impl Requests { self.breakers.succeed(iri); } - fn count_err(&self) { - let count = self.consecutive_errors.fetch_add(1, Ordering::Relaxed); - if count + 1 >= self.error_limit { - tracing::warn!("{} consecutive errors, rebuilding http client", count + 1); - *self.client.borrow_mut() = build_client(&self.user_agent); - self.reset_err(); - } - } - - fn reset_err(&self) { - self.consecutive_errors.swap(0, Ordering::Relaxed); - } - async fn check_response( &self, parsed_url: &IriString, res: Result, ) -> Result { if res.is_err() { - self.count_err(); self.breakers.fail(&parsed_url); } let mut res = res.map_err(|e| ErrorKind::SendRequest(parsed_url.to_string(), e.to_string()))?; - self.reset_err(); - - if !res.status().is_success() { + if res.status().is_server_error() { self.breakers.fail(&parsed_url); if let Ok(bytes) = res.body().await { if let Ok(s) = String::from_utf8(bytes.as_ref().to_vec()) { if !s.is_empty() { - tracing::warn!("Response from {}, {}", parsed_url, s); + tracing::warn!("Response from {parsed_url}, {s}"); } } } @@ -233,58 +234,55 @@ impl Requests { return Err(ErrorKind::Status(parsed_url.to_string(), res.status()).into()); } + self.last_online.mark_seen(&parsed_url); self.breakers.succeed(&parsed_url); Ok(res) } #[tracing::instrument(name = "Fetch Json", skip(self), fields(signing_string))] - pub(crate) async fn fetch_json(&self, url: &str) -> Result + pub(crate) async fn fetch_json(&self, url: &IriString) -> Result where T: serde::de::DeserializeOwned, { self.do_fetch(url, "application/json").await } + #[tracing::instrument(name = "Fetch Json", skip(self), fields(signing_string))] + pub(crate) async fn fetch_json_msky(&self, url: &IriString) -> Result + where + T: serde::de::DeserializeOwned, + { + let mut res = self + .do_deliver( + url, + &serde_json::json!({}), + "application/json", + "application/json", + ) + .await?; + + let body = res + .body() + .await + .map_err(|e| ErrorKind::ReceiveResponse(url.to_string(), e.to_string()))?; + + Ok(serde_json::from_slice(body.as_ref())?) + } + #[tracing::instrument(name = "Fetch Activity+Json", skip(self), fields(signing_string))] - pub(crate) async fn fetch(&self, url: &str) -> Result + pub(crate) async fn fetch(&self, url: &IriString) -> Result where T: serde::de::DeserializeOwned, { self.do_fetch(url, "application/activity+json").await } - async fn do_fetch(&self, url: &str, accept: &str) -> Result + async fn do_fetch(&self, url: &IriString, accept: &str) -> Result where T: serde::de::DeserializeOwned, { - let parsed_url = url.parse::()?; - - if !self.breakers.should_try(&parsed_url) { - return Err(ErrorKind::Breaker.into()); - } - - let signer = self.signer(); - let span = tracing::Span::current(); - - let client: Client = self.client.borrow().clone(); - let res = client - .get(url) - .insert_header(("Accept", accept)) - .insert_header(Date(SystemTime::now().into())) - .signature( - self.config.clone(), - self.key_id.clone(), - move |signing_string| { - span.record("signing_string", signing_string); - span.in_scope(|| signer.sign(signing_string)) - }, - ) - .await? - .send() - .await; - - let mut res = self.check_response(&parsed_url, res).await?; + let mut res = self.do_fetch_response(url, accept).await?; let body = res .body() @@ -295,18 +293,26 @@ impl Requests { } #[tracing::instrument(name = "Fetch response", skip(self), fields(signing_string))] - pub(crate) async fn fetch_response(&self, url: IriString) -> Result { - if !self.breakers.should_try(&url) { + pub(crate) async fn fetch_response(&self, url: &IriString) -> Result { + self.do_fetch_response(url, "*/*").await + } + + pub(crate) async fn do_fetch_response( + &self, + url: &IriString, + accept: &str, + ) -> Result { + if !self.breakers.should_try(url) { return Err(ErrorKind::Breaker.into()); } let signer = self.signer(); let span = tracing::Span::current(); - let client: Client = self.client.borrow().clone(); - let res = client + let res = self + .client .get(url.as_str()) - .insert_header(("Accept", "*/*")) + .insert_header(("Accept", accept)) .insert_header(Date(SystemTime::now().into())) .no_decompress() .signature( @@ -321,7 +327,7 @@ impl Requests { .send() .await; - let res = self.check_response(&url, res).await?; + let res = self.check_response(url, res).await?; Ok(res) } @@ -331,7 +337,27 @@ impl Requests { skip_all, fields(inbox = inbox.to_string().as_str(), signing_string) )] - pub(crate) async fn deliver(&self, inbox: IriString, item: &T) -> Result<(), Error> + pub(crate) async fn deliver(&self, inbox: &IriString, item: &T) -> Result<(), Error> + where + T: serde::ser::Serialize + std::fmt::Debug, + { + self.do_deliver( + inbox, + item, + "application/activity+json", + "application/activity+json", + ) + .await?; + Ok(()) + } + + async fn do_deliver( + &self, + inbox: &IriString, + item: &T, + content_type: &str, + accept: &str, + ) -> Result where T: serde::ser::Serialize + std::fmt::Debug, { @@ -343,11 +369,11 @@ impl Requests { let span = tracing::Span::current(); let item_string = serde_json::to_string(item)?; - let client: Client = self.client.borrow().clone(); - let (req, body) = client + let (req, body) = self + .client .post(inbox.as_str()) - .insert_header(("Accept", "application/activity+json")) - .insert_header(("Content-Type", "application/activity+json")) + .insert_header(("Accept", accept)) + .insert_header(("Content-Type", content_type)) .insert_header(Date(SystemTime::now().into())) .signature_with_digest( self.config.clone(), @@ -364,9 +390,9 @@ impl Requests { let res = req.send_body(body).await; - self.check_response(&inbox, res).await?; + let res = self.check_response(inbox, res).await?; - Ok(()) + Ok(res) } fn signer(&self) -> Signer { @@ -382,8 +408,9 @@ struct Signer { impl Signer { fn sign(&self, signing_string: &str) -> Result { - let signing_key = SigningKey::::new_with_prefix(self.private_key.clone()); - let signature = signing_key.try_sign_with_rng(thread_rng(), signing_string.as_bytes())?; - Ok(base64::encode(signature.as_ref())) + let signing_key = SigningKey::::new(self.private_key.clone()); + let signature = + signing_key.try_sign_with_rng(&mut thread_rng(), signing_string.as_bytes())?; + Ok(STANDARD.encode(signature.to_bytes().as_ref())) } } diff --git a/src/routes.rs b/src/routes.rs index d80a0a1..9afd38b 100644 --- a/src/routes.rs +++ b/src/routes.rs @@ -1,4 +1,5 @@ mod actor; +mod healthz; mod inbox; mod index; mod media; @@ -7,6 +8,7 @@ mod statics; pub(crate) use self::{ actor::route as actor, + healthz::route as healthz, inbox::route as inbox, index::route as index, media::route as media, diff --git a/src/routes/healthz.rs b/src/routes/healthz.rs new file mode 100644 index 0000000..f297ba5 --- /dev/null +++ b/src/routes/healthz.rs @@ -0,0 +1,7 @@ +use crate::{data::State, error::Error}; +use actix_web::{web, HttpResponse}; + +pub(crate) async fn route(state: web::Data) -> Result { + state.db.check_health().await?; + Ok(HttpResponse::Ok().finish()) +} diff --git a/src/routes/inbox.rs b/src/routes/inbox.rs index 14286df..133d7dd 100644 --- a/src/routes/inbox.rs +++ b/src/routes/inbox.rs @@ -16,7 +16,8 @@ use activitystreams::{ use actix_web::{web, HttpResponse}; use http_signature_normalization_actix::prelude::{DigestVerified, SignatureVerified}; -#[tracing::instrument(name = "Inbox", skip_all)] +#[tracing::instrument(name = "Inbox", skip_all, fields(id = tracing::field::debug(&input.id_unchecked()), kind = tracing::field::debug(&input.kind())))] +#[allow(clippy::too_many_arguments)] pub(crate) async fn route( state: web::Data, actors: web::Data, @@ -24,22 +25,48 @@ pub(crate) async fn route( client: web::Data, jobs: web::Data, input: web::Json, - verified: Option<(SignatureVerified, DigestVerified)>, + digest_verified: Option, + signature_verified: Option, ) -> Result { let input = input.into_inner(); - let actor = actors - .get( - input.actor()?.as_single_id().ok_or(ErrorKind::MissingId)?, - &client, - ) - .await? - .into_inner(); + let kind = input.kind().ok_or(ErrorKind::MissingKind)?; - let is_allowed = state.db.is_allowed(actor.id.clone()); - let is_connected = state.db.is_connected(actor.id.clone()); + if digest_verified.is_some() && signature_verified.is_none() && *kind == ValidTypes::Delete { + return Ok(accepted(serde_json::json!({}))); + } else if config.validate_signatures() + && (digest_verified.is_none() || signature_verified.is_none()) + { + return Err(ErrorKind::NoSignature(None).into()); + } - let (is_allowed, is_connected) = tokio::try_join!(is_allowed, is_connected)?; + let actor_id = if input.id_unchecked().is_some() { + input.actor()?.as_single_id().ok_or(ErrorKind::MissingId)? + } else { + input + .actor_unchecked() + .as_single_id() + .ok_or(ErrorKind::MissingId)? + }; + + let actor = actors.get(actor_id, &client).await?.into_inner(); + + if let Some(verified) = signature_verified { + if actor.public_key_id.as_str() != verified.key_id() { + tracing::error!("Actor signed with wrong key"); + return Err(ErrorKind::BadActor( + actor.public_key_id.to_string(), + verified.key_id().to_owned(), + ) + .into()); + } + } else if config.validate_signatures() { + tracing::error!("This case should never be reachable, since I handle signature checks earlier in the flow. If you see this in a log it means I did it wrong"); + return Err(ErrorKind::NoSignature(Some(actor.public_key_id.to_string())).into()); + } + + let is_allowed = state.db.is_allowed(actor.id.clone()).await?; + let is_connected = state.db.is_connected(actor.id.clone()).await?; if !is_allowed { return Err(ErrorKind::NotAllowed(actor.id.to_string()).into()); @@ -49,29 +76,16 @@ pub(crate) async fn route( return Err(ErrorKind::NotSubscribed(actor.id.to_string()).into()); } - if config.validate_signatures() && verified.is_none() { - return Err(ErrorKind::NoSignature(actor.public_key_id.to_string()).into()); - } else if config.validate_signatures() { - if let Some((verified, _)) = verified { - if actor.public_key_id.as_str() != verified.key_id() { - tracing::error!("Bad actor, more info: {:?}", input); - return Err(ErrorKind::BadActor( - actor.public_key_id.to_string(), - verified.key_id().to_owned(), - ) - .into()); - } - } - } - - match input.kind().ok_or(ErrorKind::MissingKind)? { + match kind { ValidTypes::Accept => handle_accept(&config, input).await?, ValidTypes::Reject => handle_reject(&config, &jobs, input, actor).await?, ValidTypes::Announce | ValidTypes::Create => { handle_announce(&state, &jobs, input, actor).await? } ValidTypes::Follow => handle_follow(&config, &jobs, input, actor).await?, - ValidTypes::Delete | ValidTypes::Update => handle_forward(&jobs, input, actor).await?, + ValidTypes::Add | ValidTypes::Delete | ValidTypes::Remove | ValidTypes::Update => { + handle_forward(&jobs, input, actor).await? + } ValidTypes::Undo => handle_undo(&config, &jobs, input, actor, is_connected).await?, }; @@ -203,7 +217,7 @@ async fn handle_announce( .as_single_id() .ok_or(ErrorKind::MissingId)?; - if state.is_cached(object_id).await { + if state.is_cached(object_id) { return Err(ErrorKind::Duplicate.into()); } diff --git a/src/routes/index.rs b/src/routes/index.rs index 835e2b8..cdd2a91 100644 --- a/src/routes/index.rs +++ b/src/routes/index.rs @@ -14,8 +14,11 @@ const MINIFY_CONFIG: minify_html::Cfg = minify_html::Cfg { keep_html_and_head_opening_tags: false, keep_spaces_between_attributes: true, keep_comments: false, - minify_js: true, minify_css: true, + minify_css_level_1: true, + minify_css_level_2: false, + minify_css_level_3: false, + minify_js: true, remove_bangs: true, remove_processing_instructions: true, }; @@ -71,7 +74,7 @@ pub(crate) async fn route( let mut buf = BufWriter::new(Vec::new()); - crate::templates::index(&mut buf, &local, &nodes, &config)?; + crate::templates::index_html(&mut buf, &local, &nodes, &config)?; let html = buf.into_inner().map_err(|e| { tracing::error!("Error rendering template, {}", e.error()); ErrorKind::FlushBuffer diff --git a/src/routes/media.rs b/src/routes/media.rs index 8a9de62..7cc3ed9 100644 --- a/src/routes/media.rs +++ b/src/routes/media.rs @@ -11,7 +11,7 @@ pub(crate) async fn route( let uuid = uuid.into_inner(); if let Some(url) = media.get_url(uuid).await? { - let res = requests.fetch_response(url).await?; + let res = requests.fetch_response(&url).await?; let mut response = HttpResponse::build(res.status()); diff --git a/src/routes/nodeinfo.rs b/src/routes/nodeinfo.rs index 18b1c3a..66785e0 100644 --- a/src/routes/nodeinfo.rs +++ b/src/routes/nodeinfo.rs @@ -24,18 +24,18 @@ struct Links { links: Vec, } -#[tracing::instrument(name = "NodeInfo")] +#[tracing::instrument(name = "NodeInfo", skip_all)] pub(crate) async fn route( config: web::Data, state: web::Data, ) -> web::Json { - let (inboxes, blocks) = tokio::join!(state.db.inboxes(), async { - if config.publish_blocks() { - Some(state.db.blocks().await.unwrap_or_default()) - } else { - None - } - }); + let inboxes = state.db.inboxes().await; + + let blocks = if config.publish_blocks() { + Some(state.db.blocks().await.unwrap_or_default()) + } else { + None + }; let peers = inboxes .unwrap_or_default() @@ -44,6 +44,8 @@ pub(crate) async fn route( .map(|s| s.to_owned()) .collect(); + let open_registrations = !config.restricted_mode(); + web::Json(NodeInfo { version: NodeInfoVersion, software: Software { @@ -55,7 +57,7 @@ pub(crate) async fn route( inbound: vec![], outbound: vec![], }, - open_registrations: false, + open_registrations, usage: Usage { users: Users { total: 1, diff --git a/src/routes/statics.rs b/src/routes/statics.rs index 31e37c1..6c7788a 100644 --- a/src/routes/statics.rs +++ b/src/routes/statics.rs @@ -5,7 +5,7 @@ use actix_web::{ }; #[allow(clippy::async_yields_async)] -#[tracing::instrument(name = "Statistics")] +#[tracing::instrument(name = "Statics")] pub(crate) async fn route(filename: web::Path) -> HttpResponse { if let Some(data) = StaticFile::get(&filename.into_inner()) { HttpResponse::Ok() diff --git a/src/telegram.rs b/src/telegram.rs index 270e1af..f3cce43 100644 --- a/src/telegram.rs +++ b/src/telegram.rs @@ -89,19 +89,19 @@ async fn answer(bot: Bot, msg: Message, cmd: Command, db: Db) -> ResponseResult< .await?; } Command::Block { domain } if db.add_blocks(vec![domain.clone()]).await.is_ok() => { - bot.send_message(msg.chat.id, format!("{} has been blocked", domain)) + bot.send_message(msg.chat.id, format!("{domain} has been blocked")) .await?; } Command::Unblock { domain } if db.remove_blocks(vec![domain.clone()]).await.is_ok() => { - bot.send_message(msg.chat.id, format!("{} has been unblocked", domain)) + bot.send_message(msg.chat.id, format!("{domain} has been unblocked")) .await?; } Command::Allow { domain } if db.add_allows(vec![domain.clone()]).await.is_ok() => { - bot.send_message(msg.chat.id, format!("{} has been allowed", domain)) + bot.send_message(msg.chat.id, format!("{domain} has been allowed")) .await?; } Command::Disallow { domain } if db.remove_allows(vec![domain.clone()]).await.is_ok() => { - bot.send_message(msg.chat.id, format!("{} has been disallowed", domain)) + bot.send_message(msg.chat.id, format!("{domain} has been disallowed")) .await?; } Command::ListAllowed => { diff --git a/systemd/example-relay.service b/systemd/example-relay.service new file mode 100644 index 0000000..3e6f7ed --- /dev/null +++ b/systemd/example-relay.service @@ -0,0 +1,15 @@ +[Unit] +Description=Activitypub Relay +Documentation=https://git.asonix.dog/asonix/relay +Wants=network.target +After=network.target + +[Install] +WantedBy=multi-user.target + +[Service] +Type=simple +EnvironmentFile=/etc/systemd/system/example-relay.service.env +ExecStart=/path/to/relay +Restart=always + diff --git a/systemd/example-relay.service.env b/systemd/example-relay.service.env new file mode 100644 index 0000000..e74a6a0 --- /dev/null +++ b/systemd/example-relay.service.env @@ -0,0 +1,19 @@ +HOSTNAME='relay.example.com' +ADDR='0.0.0.0' +PORT='8080' +RESTRICTED_MODE='true' +VALIDATE_SIGNATURES='true' +HTTPS='true' +PRETTY_LOG='false' +PUBLISH_BLOCKS='true' +DEBUG='false' +SLED_PATH='/opt/sled' +TELEGRAM_ADMIN_HANDLE='myhandle' +RUST_BACKTRACE='full' +FOOTER_BLURB='Contact @example for inquiries.' +LOCAL_DOMAINS='masto.example.com' +LOCAL_BLURB='

An ActivityPub relay for servers. Currently running somewhere. Let me know if you want to join!

' +OPENTELEMETRY_URL='http://otel.example.com:4317' +API_TOKEN='blahblahblahblahblahblahblah' +TELEGRAM_TOKEN='blahblahblahblahblahblahblah' + diff --git a/systemd/example-relay.socket b/systemd/example-relay.socket new file mode 100644 index 0000000..9c6ea0b --- /dev/null +++ b/systemd/example-relay.socket @@ -0,0 +1,11 @@ +[Unit] +Description=Activitypub Relay Socket +Before=multi-user.target +After=network.target + +[Socket] +Service=example-relay.service +ListenStream=8080 + +[Install] +WantedBy=sockets.target diff --git a/templates/admin.rs.html b/templates/admin.rs.html index 1af6bc2..e457ce7 100644 --- a/templates/admin.rs.html +++ b/templates/admin.rs.html @@ -6,7 +6,7 @@
- @contact.display_name's avatar + @contact.display_name's avatar
diff --git a/templates/index.rs.html b/templates/index.rs.html index ab9bb9e..9fa04c5 100644 --- a/templates/index.rs.html +++ b/templates/index.rs.html @@ -1,7 +1,7 @@ @use crate::{ config::{Config, UrlKind}, data::Node, -templates::{info, instance, statics::index_css}, +templates::{info_html, instance_html, statics::index_css}, }; @(local: &[Node], nodes: &[Node], config: &Config) @@ -39,13 +39,13 @@ templates::{info, instance, statics::index_css}, @for node in local { @if let Some(inst) = node.instance.as_ref() {
  • - @:instance(inst, node.info.as_ref().map(|info| { info.software.as_ref() }), node.contact.as_ref(), + @:instance_html(inst, node.info.as_ref().map(|info| { info.software.as_ref() }), node.contact.as_ref(), &node.base)
  • } else { @if let Some(inf) = node.info.as_ref() {
  • - @:info(inf, &node.base) + @:info_html(inf, &node.base)
  • } } @@ -94,13 +94,13 @@ templates::{info, instance, statics::index_css}, @for node in nodes { @if let Some(inst) = node.instance.as_ref() {
  • - @:instance(inst, node.info.as_ref().map(|info| { info.software.as_ref() }), node.contact.as_ref(), + @:instance_html(inst, node.info.as_ref().map(|info| { info.software.as_ref() }), node.contact.as_ref(), &node.base)
  • } else { @if let Some(inf) = node.info.as_ref() {
  • - @:info(inf, &node.base) + @:info_html(inf, &node.base)
  • } } diff --git a/templates/instance.rs.html b/templates/instance.rs.html index e8e6ad8..47a9019 100644 --- a/templates/instance.rs.html +++ b/templates/instance.rs.html @@ -1,4 +1,4 @@ -@use crate::{db::{Contact, Instance}, templates::admin}; +@use crate::{db::{Contact, Instance}, templates::admin_html}; @use activitystreams::iri_string::types::IriString; @(instance: &Instance, software: Option<&str>, contact: Option<&Contact>, base: &IriString) @@ -33,7 +33,7 @@
    @if let Some(contact) = contact {
    Administré par:
    - @:admin(contact, base) + @:admin_html(contact, base) } }