forked from lavina/lavina
Compare commits
9 Commits
0b98102580
...
ea1735bd92
Author | SHA1 | Date |
---|---|---|
Nikita Vilunov | ea1735bd92 | |
Nikita Vilunov | 20db4f915b | |
Nikita Vilunov | 013a20cbea | |
Nikita Vilunov | f0b38545bf | |
Nikita Vilunov | ac0b0dc962 | |
Nikita Vilunov | 1b2e322924 | |
JustTestingV | 9582160d2c | |
Nikita Vilunov | 3ff8c98f14 | |
Nikita Vilunov | 1a1136187e |
|
@ -1,6 +1,6 @@
|
|||
*
|
||||
!/src/
|
||||
!/migrations/
|
||||
!/crates/
|
||||
!Cargo.lock
|
||||
!Cargo.toml
|
||||
!rust-toolchain
|
||||
|
|
|
@ -8,6 +8,11 @@ jobs:
|
|||
uses: actions/checkout@v4
|
||||
- name: setup rust
|
||||
uses: https://github.com/actions-rs/toolchain@v1
|
||||
- name: check formatting
|
||||
uses: https://github.com/actions-rs/cargo@v1
|
||||
with:
|
||||
command: fmt
|
||||
args: "--check -p mgmt-api -p lavina-core -p projection-irc"
|
||||
- name: cargo check
|
||||
uses: https://github.com/actions-rs/cargo@v1
|
||||
with:
|
||||
|
@ -16,3 +21,4 @@ jobs:
|
|||
uses: https://github.com/actions-rs/cargo@v1
|
||||
with:
|
||||
command: test
|
||||
args: "--all"
|
||||
|
|
|
@ -31,9 +31,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.0.4"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a"
|
||||
checksum = "ea5d730647d4fadd988536d06fecce94b7b4f2a7efdae548f1cf4b63205518ab"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
@ -46,9 +46,9 @@ checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
|
|||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "0.5.0"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c"
|
||||
checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
|
@ -60,15 +60,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.3"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46"
|
||||
checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
|
||||
checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
@ -84,9 +84,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "2.1.0"
|
||||
version = "3.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
|
||||
checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"windows-sys",
|
||||
|
@ -115,9 +115,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "atomic"
|
||||
version = "0.5.3"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba"
|
||||
checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994"
|
||||
dependencies = [
|
||||
"bytemuck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
|
@ -142,9 +145,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.3"
|
||||
version = "0.21.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53"
|
||||
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
|
@ -178,21 +181,27 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.13.0"
|
||||
version = "3.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
|
||||
checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.4.0"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
|
||||
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
|
@ -211,9 +220,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.4.4"
|
||||
version = "4.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1d7b8d5ec32af0fadc644bf1fd509a688c2103b185644bb1e29d164e0703136"
|
||||
checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
|
@ -221,9 +230,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.4.4"
|
||||
version = "4.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5179bb514e4d7c2051749d8fcefa2ed6d06a9f4e6d69faf3805f5d80b8cf8d56"
|
||||
checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
|
@ -240,7 +249,7 @@ dependencies = [
|
|||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.29",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -267,6 +276,22 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.9"
|
||||
|
@ -388,9 +413,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
|||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.2"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
|
||||
checksum = "add4f07d43996f76ef320709726a556a9d4f965d9410d8d0271132d2f8293480"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
|
@ -426,15 +451,15 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
|||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.0.0"
|
||||
version = "2.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
|
||||
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
||||
|
||||
[[package]]
|
||||
name = "figment"
|
||||
version = "0.10.10"
|
||||
version = "0.10.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4547e226f4c9ab860571e070a9034192b3175580ecea38da34fcdb53a018c9a5"
|
||||
checksum = "a014ac935975a70ad13a3bff2463b1c1b083b35ae4cb6309cfc59476aa7a181f"
|
||||
dependencies = [
|
||||
"atomic",
|
||||
"pear",
|
||||
|
@ -445,14 +470,19 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "flume"
|
||||
version = "0.10.14"
|
||||
name = "finl_unicode"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
|
||||
checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6"
|
||||
|
||||
[[package]]
|
||||
name = "flume"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"pin-project",
|
||||
"spin 0.9.8",
|
||||
]
|
||||
|
||||
|
@ -523,7 +553,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.29",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -609,9 +639,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
|||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.0"
|
||||
version = "0.14.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
||||
checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"allocator-api2",
|
||||
|
@ -619,11 +649,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.8.3"
|
||||
version = "0.8.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "312f66718a2d7789ffef4f4b7b213138ed9f1eb3aa1d0d82fc99f88fb3ffd26f"
|
||||
checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7"
|
||||
dependencies = [
|
||||
"hashbrown 0.14.0",
|
||||
"hashbrown 0.14.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -637,9 +667,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.2"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
|
||||
checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
|
@ -798,12 +828,12 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.0.0"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
|
||||
checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.14.0",
|
||||
"hashbrown 0.14.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -820,9 +850,9 @@ checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
|
|||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
@ -844,7 +874,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "lavina"
|
||||
version = "0.0.1-dev"
|
||||
version = "0.0.2-dev"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert_matches",
|
||||
|
@ -871,7 +901,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "lavina-core"
|
||||
version = "0.0.1-dev"
|
||||
version = "0.0.2-dev"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"prometheus",
|
||||
|
@ -892,15 +922,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.147"
|
||||
version = "0.2.149"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3"
|
||||
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.7"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
|
||||
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
|
@ -915,9 +945,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.5"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
|
||||
checksum = "3852614a3bd9ca9804678ba6be5e3b8ce76dfc902cae004e3e0c44051b6e88db"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
|
@ -937,22 +967,23 @@ checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
|
|||
|
||||
[[package]]
|
||||
name = "md-5"
|
||||
version = "0.10.5"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca"
|
||||
checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"digest",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.5.0"
|
||||
version = "2.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
|
||||
|
||||
[[package]]
|
||||
name = "mgmt-api"
|
||||
version = "0.0.1-dev"
|
||||
version = "0.0.2-dev"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
@ -1075,9 +1106,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.32.0"
|
||||
version = "0.32.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "77ac5bbd07aea88c60a577a1ce218075ffd59208b2d7ca97adf9bfc5aeb21ebe"
|
||||
checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
@ -1143,7 +1174,7 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
"proc-macro2-diagnostics",
|
||||
"quote",
|
||||
"syn 2.0.29",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1161,26 +1192,6 @@ version = "2.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
|
||||
|
||||
[[package]]
|
||||
name = "pin-project"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
|
||||
dependencies = [
|
||||
"pin-project-internal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-internal"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.29",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.13"
|
||||
|
@ -1228,9 +1239,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
|||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.66"
|
||||
version = "1.0.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
|
||||
checksum = "5b1106fec09662ec6dd98ccac0f81cef56984d0b49f75c92d8cbad76e20c005c"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
@ -1243,14 +1254,14 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.29",
|
||||
"syn 2.0.38",
|
||||
"version_check",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "projection-irc"
|
||||
version = "0.0.1-dev"
|
||||
version = "0.0.2-dev"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"futures-util",
|
||||
|
@ -1265,9 +1276,10 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "projection-xmpp"
|
||||
version = "0.0.1-dev"
|
||||
version = "0.0.2-dev"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert_matches",
|
||||
"derive_more",
|
||||
"futures-util",
|
||||
"lavina-core",
|
||||
|
@ -1279,6 +1291,7 @@ dependencies = [
|
|||
"tokio",
|
||||
"tokio-rustls",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
|
@ -1298,7 +1311,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proto-irc"
|
||||
version = "0.0.1-dev"
|
||||
version = "0.0.2-dev"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert_matches",
|
||||
|
@ -1310,9 +1323,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "proto-xmpp"
|
||||
version = "0.0.1-dev"
|
||||
version = "0.0.2-dev"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assert_matches",
|
||||
"base64",
|
||||
"derive_more",
|
||||
"lazy_static",
|
||||
"quick-xml",
|
||||
|
@ -1380,9 +1395,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.9.4"
|
||||
version = "1.9.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12de2eff854e5fa4b1295edd650e227e9d8fb0c9e90b12e7f36d6a6811791a29"
|
||||
checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -1392,9 +1407,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.3.7"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49530408a136e16e5b486e883fbb6ba058e8e4e8ae6621a77b048b314336e629"
|
||||
checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
|
@ -1409,9 +1424,9 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
|
|||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.20"
|
||||
version = "0.11.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1"
|
||||
checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"bytes",
|
||||
|
@ -1432,6 +1447,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"system-configuration",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"url",
|
||||
|
@ -1495,9 +1511,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.9"
|
||||
version = "0.38.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49"
|
||||
checksum = "f25469e9ae0f3d0047ca8b93fc56843f38e6774f0914a107ff8b41be8be8e0b7"
|
||||
dependencies = [
|
||||
"bitflags 2.4.0",
|
||||
"errno",
|
||||
|
@ -1508,9 +1524,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.21.6"
|
||||
version = "0.21.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb"
|
||||
checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8"
|
||||
dependencies = [
|
||||
"log",
|
||||
"ring",
|
||||
|
@ -1529,9 +1545,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rustls-webpki"
|
||||
version = "0.101.4"
|
||||
version = "0.101.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d"
|
||||
checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
|
@ -1561,9 +1577,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.18"
|
||||
version = "1.0.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
|
||||
checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
|
@ -1582,14 +1598,14 @@ checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.29",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.105"
|
||||
version = "1.0.107"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
|
||||
checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
@ -1619,9 +1635,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.5"
|
||||
version = "0.10.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
|
||||
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
|
@ -1630,9 +1646,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.7"
|
||||
version = "0.10.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
|
||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
|
@ -1641,9 +1657,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.4"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
|
||||
checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
]
|
||||
|
@ -1678,9 +1694,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.11.0"
|
||||
version = "1.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
|
||||
checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
|
@ -1694,9 +1710,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.5.3"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877"
|
||||
checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys",
|
||||
|
@ -1729,9 +1745,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sqlformat"
|
||||
version = "0.2.1"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c12bc9199d1db8234678b7051747c07f517cdcf019262d1847b94ec8b1aee3e"
|
||||
checksum = "6b7b278788e7be4d0d29c0f39497a0eef3fba6bbc8e70d8bf7fde46edeaa9e85"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"nom",
|
||||
|
@ -1740,9 +1756,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sqlx"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e58421b6bc416714d5115a2ca953718f6c621a51b68e4f4922aea5a4391a721"
|
||||
checksum = "0e50c216e3624ec8e7ecd14c6a6a6370aad6ee5d8cfc3ab30b5162eeeef2ed33"
|
||||
dependencies = [
|
||||
"sqlx-core",
|
||||
"sqlx-macros",
|
||||
|
@ -1753,9 +1769,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sqlx-core"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd4cef4251aabbae751a3710927945901ee1d97ee96d757f6880ebb9a79bfd53"
|
||||
checksum = "8d6753e460c998bbd4cd8c6f0ed9a64346fcca0723d6e75e52fdc351c5d2169d"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"atoi",
|
||||
|
@ -1773,7 +1789,7 @@ dependencies = [
|
|||
"futures-util",
|
||||
"hashlink",
|
||||
"hex",
|
||||
"indexmap 2.0.0",
|
||||
"indexmap 2.0.2",
|
||||
"log",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
|
@ -1791,9 +1807,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sqlx-macros"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "208e3165167afd7f3881b16c1ef3f2af69fa75980897aac8874a0696516d12c2"
|
||||
checksum = "9a793bb3ba331ec8359c1853bd39eed32cdd7baaf22c35ccf5c92a7e8d1189ec"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -1804,9 +1820,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sqlx-macros-core"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a4a8336d278c62231d87f24e8a7a74898156e34c1c18942857be2acb29c7dfc"
|
||||
checksum = "0a4ee1e104e00dedb6aa5ffdd1343107b0a4702e862a84320ee7cc74782d96fc"
|
||||
dependencies = [
|
||||
"dotenvy",
|
||||
"either",
|
||||
|
@ -1828,9 +1844,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sqlx-mysql"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ca69bf415b93b60b80dc8fda3cb4ef52b2336614d8da2de5456cc942a110482"
|
||||
checksum = "864b869fdf56263f4c95c45483191ea0af340f9f3e3e7b4d57a61c7c87a970db"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64",
|
||||
|
@ -1870,9 +1886,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sqlx-postgres"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0db2df1b8731c3651e204629dd55e52adbae0462fa1bdcbed56a2302c18181e"
|
||||
checksum = "eb7ae0e6a97fb3ba33b23ac2671a5ce6e3cabe003f451abd5a56e7951d975624"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"base64",
|
||||
|
@ -1909,9 +1925,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "sqlx-sqlite"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be4c21bf34c7cae5b283efb3ac1bcc7670df7561124dc2f8bdc0b59be40f79a2"
|
||||
checksum = "d59dc83cf45d89c555a577694534fcd1b55c545a816c816ce51f20bbe56a4f3f"
|
||||
dependencies = [
|
||||
"atoi",
|
||||
"flume",
|
||||
|
@ -1931,10 +1947,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "stringprep"
|
||||
version = "0.1.3"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db3737bde7edce97102e0e2b15365bf7a20bfdb5f60f4f9e8d7004258a51a8da"
|
||||
checksum = "bb41d74e231a107a1b4ee36bd1214b11285b77768d2e3824aedafa988fd36ee6"
|
||||
dependencies = [
|
||||
"finl_unicode",
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
@ -1964,15 +1981,36 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.29"
|
||||
version = "2.0.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
|
||||
checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"core-foundation",
|
||||
"system-configuration-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "system-configuration-sys"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.8.0"
|
||||
|
@ -1988,22 +2026,22 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.47"
|
||||
version = "1.0.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
|
||||
checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4"
|
||||
dependencies = [
|
||||
"thiserror-impl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror-impl"
|
||||
version = "1.0.47"
|
||||
version = "1.0.49"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
|
||||
checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.29",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2045,7 +2083,7 @@ dependencies = [
|
|||
"parking_lot",
|
||||
"pin-project-lite",
|
||||
"signal-hook-registry",
|
||||
"socket2 0.5.3",
|
||||
"socket2 0.5.4",
|
||||
"tokio-macros",
|
||||
"windows-sys",
|
||||
]
|
||||
|
@ -2058,7 +2096,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.29",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2073,9 +2111,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.8"
|
||||
version = "0.7.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
|
||||
checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-core",
|
||||
|
@ -2087,9 +2125,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.7.6"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542"
|
||||
checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
|
@ -2108,11 +2146,11 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.14"
|
||||
version = "0.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a"
|
||||
checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338"
|
||||
dependencies = [
|
||||
"indexmap 2.0.0",
|
||||
"indexmap 2.0.2",
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
|
@ -2146,7 +2184,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.29",
|
||||
"syn 2.0.38",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2192,9 +2230,9 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
|
|||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.16.0"
|
||||
version = "1.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
||||
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||
|
||||
[[package]]
|
||||
name = "uncased"
|
||||
|
@ -2213,9 +2251,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
|
|||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.11"
|
||||
version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
|
||||
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
|
@ -2324,7 +2362,7 @@ dependencies = [
|
|||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.29",
|
||||
"syn 2.0.38",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
|
@ -2358,7 +2396,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
|
|||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.29",
|
||||
"syn 2.0.38",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
@ -2475,9 +2513,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
|
|||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.5.15"
|
||||
version = "0.5.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c2e3184b9c4e92ad5167ca73039d0c42476302ab603e2fec4487511f38ccefc"
|
||||
checksum = "037711d82167854aff2018dfd193aa0fef5370f456732f0d5a0c59b0f1b4b907"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
|
|
@ -9,7 +9,7 @@ members = [
|
|||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.0.1-dev"
|
||||
version = "0.0.2-dev"
|
||||
|
||||
[workspace.dependencies]
|
||||
nom = "7.1.3"
|
||||
|
@ -26,7 +26,9 @@ clap = { version = "4.4.4", features = ["derive"] }
|
|||
serde = { version = "1.0.152", features = ["rc", "serde_derive"] }
|
||||
tracing = "0.1.37" # logging & tracing api
|
||||
prometheus = { version = "0.13.3", default-features = false }
|
||||
base64 = "0.21.3"
|
||||
lavina-core = { path = "crates/lavina-core" }
|
||||
tracing-subscriber = "0.3.16"
|
||||
|
||||
[package]
|
||||
name = "lavina"
|
||||
|
@ -43,7 +45,7 @@ serde.workspace = true
|
|||
serde_json = "1.0.93"
|
||||
tokio.workspace = true
|
||||
tracing.workspace = true
|
||||
tracing-subscriber = "0.3.16"
|
||||
tracing-subscriber.workspace = true
|
||||
futures-util.workspace = true
|
||||
prometheus.workspace = true
|
||||
nonempty.workspace = true
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
## Dependency diagram of the project
|
||||
|
||||
```mermaid
|
||||
graph TD;
|
||||
lavina-->mgmt-api;
|
||||
lavina-->projection-irc;
|
||||
lavina-->projection-xmpp;
|
||||
lavina-->lavina-core;
|
||||
|
||||
projection-irc-->proto-irc;
|
||||
projection-irc-->lavina-core;
|
||||
|
||||
projection-xmpp-->proto-xmpp;
|
||||
projection-xmpp-->lavina-core;
|
||||
|
||||
sim-irc-->proto-irc;
|
||||
sim-irc-->mgmt-api;
|
||||
|
||||
sim-xmpp-->proto-xmpp;
|
||||
sim-xmpp-->mgmt-api;
|
||||
|
||||
workspace-->lavina;
|
||||
workspace-->sim-irc;
|
||||
workspace-->sim-xmpp;
|
||||
```
|
||||
|
||||
A few rules:
|
||||
- Only projections should be direct deps of `lavina`, there is no need to depend on `proto-*` crates.
|
||||
- On the other hand, projections should not be dependencies of `sim-*` crates.
|
||||
- `lavina-core` does not depend on protocol-specific crates.
|
|
@ -0,0 +1,2 @@
|
|||
max_width = 120
|
||||
chain_width = 120
|
|
@ -7,6 +7,7 @@ use nonempty::nonempty;
|
|||
use nonempty::NonEmpty;
|
||||
use prometheus::{IntCounter, IntGauge, Registry as MetricsRegistry};
|
||||
use serde::Deserialize;
|
||||
use tokio::io::AsyncReadExt;
|
||||
use tokio::io::{AsyncBufReadExt, AsyncWrite, AsyncWriteExt, BufReader, BufWriter};
|
||||
use tokio::net::tcp::{ReadHalf, WriteHalf};
|
||||
use tokio::net::{TcpListener, TcpStream};
|
||||
|
@ -96,14 +97,14 @@ async fn handle_registration<'a>(
|
|||
let mut pass: Option<Str> = None;
|
||||
|
||||
let user = loop {
|
||||
let res = reader.read_until(b'\n', &mut buffer).await;
|
||||
let res = read_irc_message(reader, &mut buffer).await;
|
||||
let res = match res {
|
||||
Ok(len) => {
|
||||
if len == 0 {
|
||||
log::info!("Terminating socket");
|
||||
break Err(anyhow::Error::msg("EOF"));
|
||||
}
|
||||
match std::str::from_utf8(&buffer[..len]) {
|
||||
match std::str::from_utf8(&buffer[..len - 2]) {
|
||||
Ok(res) => res,
|
||||
Err(e) => break Err(e.into()),
|
||||
}
|
||||
|
@ -116,7 +117,7 @@ async fn handle_registration<'a>(
|
|||
log::debug!("Incoming raw IRC message: '{res}'");
|
||||
let parsed = client_message(res);
|
||||
match parsed {
|
||||
Ok((_, msg)) => {
|
||||
Ok(msg) => {
|
||||
log::debug!("Incoming IRC message: {msg:?}");
|
||||
match msg {
|
||||
ClientMessage::Pass { password } => {
|
||||
|
@ -252,7 +253,7 @@ async fn handle_registered_socket<'a>(
|
|||
loop {
|
||||
select! {
|
||||
biased;
|
||||
len = reader.read_until(b'\n', &mut buffer) => {
|
||||
len = read_irc_message(reader, &mut buffer) => {
|
||||
let len = len?;
|
||||
let len = if len == 0 {
|
||||
log::info!("EOF, Terminating socket");
|
||||
|
@ -260,7 +261,7 @@ async fn handle_registered_socket<'a>(
|
|||
} else {
|
||||
len
|
||||
};
|
||||
let incoming = std::str::from_utf8(&buffer[0..len])?;
|
||||
let incoming = std::str::from_utf8(&buffer[0..len-2])?;
|
||||
if let HandleResult::Leave = handle_incoming_message(incoming, &config, &user, &rooms, &mut connection, writer).await? {
|
||||
break;
|
||||
}
|
||||
|
@ -291,6 +292,23 @@ async fn handle_registered_socket<'a>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
// TODO this is public only for tests, perhaps move this into proto-irc
|
||||
// TODO limit buffer size in size to protect against dos attacks with large payloads
|
||||
pub async fn read_irc_message(reader: &mut BufReader<ReadHalf<'_>>, buf: &mut Vec<u8>) -> Result<usize> {
|
||||
let mut size = 0;
|
||||
'outer: loop {
|
||||
let res = reader.read_until(b'\r', buf).await?;
|
||||
size += res;
|
||||
let next = reader.read_u8().await?;
|
||||
buf.push(next);
|
||||
size += 1;
|
||||
if next != b'\n' {
|
||||
continue 'outer;
|
||||
}
|
||||
return Ok(size);
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_update(
|
||||
config: &ServerConfig,
|
||||
user: &RegisteredUser,
|
||||
|
@ -398,7 +416,7 @@ async fn handle_incoming_message(
|
|||
let parsed = client_message(buffer);
|
||||
log::debug!("Incoming IRC message: {parsed:?}");
|
||||
match parsed {
|
||||
Ok((_, msg)) => match msg {
|
||||
Ok(msg) => match msg {
|
||||
ClientMessage::Ping { token } => {
|
||||
ServerMessage {
|
||||
tags: vec![],
|
||||
|
@ -652,11 +670,8 @@ async fn produce_on_join_cmd_messages(
|
|||
}
|
||||
.write_async(writer)
|
||||
.await?;
|
||||
let prefixed_members: Vec<PrefixedNick> = room_info
|
||||
.members
|
||||
.iter()
|
||||
.map(|member| PrefixedNick::from_str(member.clone().into_inner()))
|
||||
.collect();
|
||||
let prefixed_members: Vec<PrefixedNick> =
|
||||
room_info.members.iter().map(|member| PrefixedNick::from_str(member.clone().into_inner())).collect();
|
||||
let non_empty_members: NonEmpty<PrefixedNick> =
|
||||
NonEmpty::from_vec(prefixed_members).unwrap_or(nonempty![PrefixedNick::from_str(user.nickname.clone())]);
|
||||
|
||||
|
@ -684,13 +699,24 @@ async fn produce_on_join_cmd_messages(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub struct RunningServer {
|
||||
pub addr: SocketAddr,
|
||||
terminator: Terminator,
|
||||
}
|
||||
|
||||
impl RunningServer {
|
||||
pub async fn terminate(self) -> Result<()> {
|
||||
self.terminator.terminate().await
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn launch(
|
||||
config: ServerConfig,
|
||||
players: PlayerRegistry,
|
||||
rooms: RoomRegistry,
|
||||
metrics: MetricsRegistry,
|
||||
storage: Storage,
|
||||
) -> Result<Terminator> {
|
||||
) -> Result<RunningServer> {
|
||||
log::info!("Starting IRC projection");
|
||||
let (stopped_tx, mut stopped_rx) = channel(32);
|
||||
let current_connections = IntGauge::new("irc_current_connections", "Open and alive TCP connections")?;
|
||||
|
@ -699,6 +725,7 @@ pub async fn launch(
|
|||
metrics.register(Box::new(total_connections.clone()))?;
|
||||
|
||||
let listener = TcpListener::bind(config.listen_on).await?;
|
||||
let addr = listener.local_addr()?;
|
||||
|
||||
let terminator = Terminator::spawn(|mut rx| async move {
|
||||
// TODO probably should separate logic for accepting new connection and storing them
|
||||
|
@ -766,5 +793,5 @@ pub async fn launch(
|
|||
});
|
||||
|
||||
log::info!("Started IRC projection");
|
||||
Ok(terminator)
|
||||
Ok(RunningServer { addr, terminator })
|
||||
}
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
use std::time::Duration;
|
||||
|
||||
use anyhow::Result;
|
||||
use prometheus::Registry as MetricsRegistry;
|
||||
use tokio::io::{AsyncWriteExt, BufReader};
|
||||
use tokio::net::tcp::{ReadHalf, WriteHalf};
|
||||
use tokio::net::TcpStream;
|
||||
|
||||
use lavina_core::repo::{Storage, StorageConfig};
|
||||
use lavina_core::{player::PlayerRegistry, room::RoomRegistry};
|
||||
use projection_irc::{launch, read_irc_message, ServerConfig};
|
||||
|
||||
struct TestScope<'a> {
|
||||
reader: BufReader<ReadHalf<'a>>,
|
||||
writer: WriteHalf<'a>,
|
||||
buffer: Vec<u8>,
|
||||
pub timeout: Duration,
|
||||
}
|
||||
|
||||
impl<'a> TestScope<'a> {
|
||||
fn new(stream: &mut TcpStream) -> TestScope<'_> {
|
||||
let (reader, writer) = stream.split();
|
||||
let reader = BufReader::new(reader);
|
||||
let buffer = vec![];
|
||||
let timeout = Duration::from_millis(100);
|
||||
TestScope {
|
||||
reader,
|
||||
writer,
|
||||
buffer,
|
||||
timeout,
|
||||
}
|
||||
}
|
||||
|
||||
async fn send(&mut self, str: &(impl AsRef<str> + ?Sized)) -> Result<()> {
|
||||
self.writer.write_all(str.as_ref().as_bytes()).await?;
|
||||
self.writer.write_all(b"\r\n").await?;
|
||||
self.writer.flush().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn expect(&mut self, str: &str) -> Result<()> {
|
||||
let len = tokio::time::timeout(self.timeout, read_irc_message(&mut self.reader, &mut self.buffer)).await??;
|
||||
assert_eq!(std::str::from_utf8(&self.buffer[..len - 2])?, str);
|
||||
self.buffer.clear();
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn scenario_basic() -> Result<()> {
|
||||
let config = ServerConfig {
|
||||
listen_on: "127.0.0.1:0".parse().unwrap(),
|
||||
server_name: "testserver".into(),
|
||||
};
|
||||
let mut metrics = MetricsRegistry::new();
|
||||
let mut storage = Storage::open(StorageConfig {
|
||||
db_path: ":memory:".into(),
|
||||
})
|
||||
.await?;
|
||||
let rooms = RoomRegistry::new(&mut metrics, storage.clone()).unwrap();
|
||||
let players = PlayerRegistry::empty(rooms.clone(), &mut metrics).unwrap();
|
||||
let server = launch(config, players, rooms, metrics, storage.clone()).await.unwrap();
|
||||
|
||||
// test scenario
|
||||
|
||||
storage.create_user("tester").await?;
|
||||
storage.set_password("tester", "password").await?;
|
||||
|
||||
let mut stream = TcpStream::connect(server.addr).await?;
|
||||
let mut s = TestScope::new(&mut stream);
|
||||
|
||||
s.send("PASS password").await?;
|
||||
s.send("NICK tester").await?;
|
||||
s.send("USER UserName 0 * :Real Name").await?;
|
||||
s.expect(":testserver NOTICE * :Welcome to my server!").await?;
|
||||
s.expect(":testserver 001 tester :Welcome to Kek Server").await?;
|
||||
s.expect(":testserver 002 tester :Welcome to Kek Server").await?;
|
||||
s.expect(":testserver 003 tester :Welcome to Kek Server").await?;
|
||||
s.expect(":testserver 004 tester testserver kek-0.1.alpha.3 r CFILPQbcefgijklmnopqrstvz").await?;
|
||||
s.expect(":testserver 005 tester CHANTYPES=# :are supported by this server").await?;
|
||||
|
||||
stream.shutdown().await?;
|
||||
|
||||
// wrap up
|
||||
|
||||
server.terminate().await.unwrap();
|
||||
Ok(())
|
||||
}
|
|
@ -15,6 +15,10 @@ futures-util.workspace = true
|
|||
quick-xml.workspace = true
|
||||
proto-xmpp = { path = "../proto-xmpp" }
|
||||
uuid = { version = "1.3.0", features = ["v4"] }
|
||||
tokio-rustls = "0.24.1"
|
||||
tokio-rustls = { version = "0.24.1", features = ["dangerous_configuration"] }
|
||||
rustls-pemfile = "1.0.2"
|
||||
derive_more.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
tracing-subscriber.workspace = true
|
||||
assert_matches = "1.5.0"
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
max_width = 120
|
||||
chain_width = 120
|
|
@ -26,10 +26,12 @@ use lavina_core::player::{PlayerConnection, PlayerId, PlayerRegistry};
|
|||
use lavina_core::prelude::*;
|
||||
use lavina_core::room::{RoomId, RoomRegistry};
|
||||
use lavina_core::terminator::Terminator;
|
||||
use lavina_core::repo::Storage;
|
||||
use proto_xmpp::bind::{BindResponse, Jid, Name, Resource, Server};
|
||||
use proto_xmpp::client::{Iq, Message, MessageType, Presence};
|
||||
use proto_xmpp::disco::*;
|
||||
use proto_xmpp::roster::RosterQuery;
|
||||
use proto_xmpp::sasl::AuthBody;
|
||||
use proto_xmpp::session::Session;
|
||||
use proto_xmpp::stream::*;
|
||||
use proto_xmpp::xml::{Continuation, FromXml, Parser, ToXml};
|
||||
|
@ -55,12 +57,24 @@ struct Authenticated {
|
|||
xmpp_muc_name: Resource,
|
||||
}
|
||||
|
||||
pub struct RunningServer {
|
||||
pub addr: SocketAddr,
|
||||
terminator: Terminator,
|
||||
}
|
||||
|
||||
impl RunningServer {
|
||||
pub async fn terminate(self) -> Result<()> {
|
||||
self.terminator.terminate().await
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn launch(
|
||||
config: ServerConfig,
|
||||
players: PlayerRegistry,
|
||||
rooms: RoomRegistry,
|
||||
metrics: MetricsRegistry,
|
||||
) -> Result<Terminator> {
|
||||
storage: Storage,
|
||||
) -> Result<RunningServer> {
|
||||
log::info!("Starting XMPP projection");
|
||||
|
||||
let certs = certs(&mut SyncBufReader::new(File::open(config.cert)?))?;
|
||||
|
@ -77,6 +91,8 @@ pub async fn launch(
|
|||
});
|
||||
|
||||
let listener = TcpListener::bind(config.listen_on).await?;
|
||||
let addr = listener.local_addr()?;
|
||||
|
||||
let terminator = Terminator::spawn(|mut termination| async move {
|
||||
let (stopped_tx, mut stopped_rx) = channel(32);
|
||||
let mut actors = HashMap::new();
|
||||
|
@ -99,11 +115,12 @@ pub async fn launch(
|
|||
}
|
||||
let players = players.clone();
|
||||
let rooms = rooms.clone();
|
||||
let storage = storage.clone();
|
||||
let terminator = Terminator::spawn(|termination| {
|
||||
let stopped_tx = stopped_tx.clone();
|
||||
let loaded_config = loaded_config.clone();
|
||||
async move {
|
||||
match handle_socket(loaded_config, stream, &socket_addr, players, rooms, termination).await {
|
||||
match handle_socket(loaded_config, stream, &socket_addr, players, rooms, storage, termination).await {
|
||||
Ok(_) => log::info!("Connection terminated"),
|
||||
Err(err) => log::warn!("Connection failed: {err}"),
|
||||
}
|
||||
|
@ -134,7 +151,7 @@ pub async fn launch(
|
|||
Ok(())
|
||||
});
|
||||
log::info!("Started XMPP projection");
|
||||
Ok(terminator)
|
||||
Ok(RunningServer { addr, terminator })
|
||||
}
|
||||
|
||||
async fn handle_socket(
|
||||
|
@ -143,6 +160,7 @@ async fn handle_socket(
|
|||
socket_addr: &SocketAddr,
|
||||
mut players: PlayerRegistry,
|
||||
rooms: RoomRegistry,
|
||||
mut storage: Storage,
|
||||
termination: Deferred<()>, // TODO use it to stop the connection gracefully
|
||||
) -> Result<()> {
|
||||
log::info!("Received an XMPP connection from {socket_addr}");
|
||||
|
@ -159,6 +177,7 @@ async fn handle_socket(
|
|||
.with_single_cert(vec![config.cert.clone()], config.key.clone())?;
|
||||
config.key_log = Arc::new(tokio_rustls::rustls::KeyLogFile::new());
|
||||
|
||||
log::debug!("Accepting TLS connection...");
|
||||
let acceptor = TlsAcceptor::from(Arc::new(config));
|
||||
let new_stream = acceptor.accept(stream).await?;
|
||||
log::debug!("TLS connection established");
|
||||
|
@ -167,7 +186,7 @@ async fn handle_socket(
|
|||
let mut xml_reader = NsReader::from_reader(BufReader::new(a));
|
||||
let mut xml_writer = Writer::new(b);
|
||||
|
||||
let authenticated = socket_auth(&mut xml_reader, &mut xml_writer, &mut reader_buf).await?;
|
||||
let authenticated = socket_auth(&mut xml_reader, &mut xml_writer, &mut reader_buf, &mut storage).await?;
|
||||
log::debug!("User authenticated");
|
||||
let mut connection = players.connect_to_player(authenticated.player_id.clone()).await;
|
||||
socket_final(
|
||||
|
@ -224,6 +243,7 @@ async fn socket_auth(
|
|||
xml_reader: &mut NsReader<(impl AsyncBufRead + Unpin)>,
|
||||
xml_writer: &mut Writer<(impl AsyncWrite + Unpin)>,
|
||||
reader_buf: &mut Vec<u8>,
|
||||
storage: &mut Storage,
|
||||
) -> Result<Authenticated> {
|
||||
read_xml_header(xml_reader, reader_buf).await?;
|
||||
let _ = ClientStreamStart::parse(xml_reader, reader_buf).await?;
|
||||
|
@ -248,16 +268,41 @@ async fn socket_auth(
|
|||
.await?;
|
||||
xml_writer.get_mut().flush().await?;
|
||||
|
||||
let _ = proto_xmpp::sasl::Auth::parse(xml_reader, reader_buf).await?;
|
||||
let auth: proto_xmpp::sasl::Auth = proto_xmpp::sasl::Auth::parse(xml_reader, reader_buf).await?;
|
||||
proto_xmpp::sasl::Success.write_xml(xml_writer).await?;
|
||||
|
||||
let name: Str = "darova".into();
|
||||
Ok(Authenticated {
|
||||
player_id: PlayerId::from("darova")?,
|
||||
xmpp_name: Name(name.clone()),
|
||||
xmpp_resource: Resource(name.clone()),
|
||||
xmpp_muc_name: Resource(name),
|
||||
})
|
||||
match AuthBody::from_str(&auth.body) {
|
||||
Ok(logopass) => {
|
||||
let name = &logopass.login;
|
||||
let stored_user = storage.retrieve_user_by_name(name).await?;
|
||||
|
||||
let stored_user = match stored_user {
|
||||
Some(u) => u,
|
||||
None => {
|
||||
log::info!("User '{}' not found", name);
|
||||
return Err(fail("no user found"));
|
||||
}
|
||||
};
|
||||
// TODO return proper XML errors to the client
|
||||
|
||||
if stored_user.password.is_none() {
|
||||
log::info!("Password not defined for user '{}'", name);
|
||||
return Err(fail("password is not defined"));
|
||||
}
|
||||
if stored_user.password.as_deref() != Some(&logopass.password) {
|
||||
log::info!("Incorrect password supplied for user '{}'", name);
|
||||
return Err(fail("passwords do not match"));
|
||||
}
|
||||
|
||||
Ok(Authenticated {
|
||||
player_id: PlayerId::from(name.as_str())?,
|
||||
xmpp_name: Name(name.to_string().into()),
|
||||
xmpp_resource: Resource(name.to_string().into()),
|
||||
xmpp_muc_name: Resource(name.to_string().into()),
|
||||
})
|
||||
},
|
||||
Err(e) => return Err(e)
|
||||
}
|
||||
}
|
||||
|
||||
async fn socket_final(
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
-----BEGIN PRIVATE KEY-----
|
||||
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
|
||||
kO/SCOEdhp17yWQspky/Uo1RC4lKVA==
|
||||
-----END PRIVATE KEY-----
|
|
@ -0,0 +1,30 @@
|
|||
-----BEGIN CERTIFICATE-----
|
||||
MIIFDTCCAvWgAwIBAgIUGd9jmau898T/kGdIeiRCcdXueaowDQYJKoZIhvcNAQEL
|
||||
BQAwFjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wHhcNMjMxMDA5MTIyMTU2WhcNMjMx
|
||||
MTA4MTIyMTU2WjAWMRQwEgYDVQQDDAtleGFtcGxlLmNvbTCCAiIwDQYJKoZIhvcN
|
||||
AQEBBQADggIPADCCAgoCggIBAK5WIFMY3y0xpDwbzOLEvt24SVMUK4/rBCGYOxfy
|
||||
63hXd4SyFSkMggWQJJfXuHN8jt24GnWl7sp634XPleNtX6u6/GlrC+wKCx8avBcT
|
||||
W9oNUl27LQnJHMu9FJcQtaABtx2WVu8Eq8Yu1jWiCblglYtu2BAmO60yguKzGftd
|
||||
3Th/MxDLhqqHLZmuzHJBIwg25HVDP9UHMNmLgQdDTytvsYxqdB9tpttOzUj8Ye4A
|
||||
zs8N5v+i70Bkc8BKDZ/NqblImG8Ni60eZfzA5Ldv4j5qYjqDc3x8myyPHSvIAQv5
|
||||
z4xu/qZdCEaqHtP76Re0HyHkagsI6DfIa1pbujQ9pwA/VSxp0OwY3XdxYACzK2DU
|
||||
HGqBaToioDdh9/m5zYD5NiZfkrkNXjqyiei/JugUj190qYvigJswjP5Or4vm8ex1
|
||||
SHn/lLoXZEgpAMkgNgl8TtdUI/JOhptCKtCxD8GfbsvRsI7WEP1wZH7Pm131M8bG
|
||||
ubsZRUZn98LnxDhYP9OtWELelSryfuEzMZqSD7BGLsVIlM8hlBeJMv8e0+V5b7XL
|
||||
p3xDzhQjpCbf29W55LlhIKMUKJBbZ96h34vixNSwTRG6Zu9v6xpLpyZftkHN2AmE
|
||||
/0nkWIA4+qzCAJLnDngXmG99uD7JLhKB4qu9kXd0B/7fBbyvTf2wU35H+BCjDFlx
|
||||
hnA7AgMBAAGjUzBRMB0GA1UdDgQWBBSFuG4k9lOlZweMeqvBejQic3Me1zAfBgNV
|
||||
HSMEGDAWgBSFuG4k9lOlZweMeqvBejQic3Me1zAPBgNVHRMBAf8EBTADAQH/MA0G
|
||||
CSqGSIb3DQEBCwUAA4ICAQAjLko9eLBofC9QzF/rm59kOtS6P8fRD0OJKawRdxvP
|
||||
5ClQFz9Q/2I7E1jbXL9y8r8iB31hpfnMT/XYxHAmJXyV+X2jHlnKmhzWpfrHx84V
|
||||
ZYeFIEFlwJHacPU6mVUUnXLwZIt0VWB3RUT9bgbkXFfkg7Qrccl7Blc0458l8wd2
|
||||
mvNgdEGG9Z8VhyaExAHerpOD299llaDTcV+jKLLAboXzDGJsPmMfRu2DWwosfYQJ
|
||||
MIKajyylmGOrAk+8fVTVWOPJBE6AmxDpKtZQO04nQq78PohP/CsibalimOf00Wqb
|
||||
2x05ssWFP71lmdGilaXCp/mkhaVz/G7ZuDSY9AxCPH4+3pTUbMgsfEmLXRTrUo9c
|
||||
B4zz0eDoUiqU9I4TWAHGhnn7b2e6o8ko0baq+PaCSCDK8haL/17CUyMYQBBdhlG6
|
||||
sSR2IBSXkxGQZnhfmQdYwc7Y3IgsJJoN0ZfqnyBY+u/ZOBegcZFuhMiDGILJBgFi
|
||||
QmgQFTozXKkeEzFdWoRn57lgcBABcMHSucnjekk80uLIWIlL36IyYkPbeI6/I0/l
|
||||
ajKftsVEY96hYUXtDBykBpg6gsJXj2gP2FXHW7ngtuI4/mOqI3ltcWh1C83MvM5N
|
||||
zMYfTNtxVM1vyvN1M7b7iMeosvmAIvQE3bFk/pJCHAZPfsu0zmeizPHBgCySygLn
|
||||
JQ==
|
||||
-----END CERTIFICATE-----
|
|
@ -0,0 +1,185 @@
|
|||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::Result;
|
||||
use assert_matches::*;
|
||||
use prometheus::Registry as MetricsRegistry;
|
||||
use quick_xml::events::Event;
|
||||
use quick_xml::NsReader;
|
||||
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
|
||||
use tokio::io::{ReadHalf as GenericReadHalf, WriteHalf as GenericWriteHalf};
|
||||
use tokio::net::tcp::{ReadHalf, WriteHalf};
|
||||
use tokio::net::TcpStream;
|
||||
use tokio_rustls::client::TlsStream;
|
||||
use tokio_rustls::rustls::client::ServerCertVerifier;
|
||||
use tokio_rustls::rustls::{ClientConfig, ServerName};
|
||||
use tokio_rustls::TlsConnector;
|
||||
|
||||
use lavina_core::player::PlayerRegistry;
|
||||
use lavina_core::repo::{Storage, StorageConfig};
|
||||
use lavina_core::room::RoomRegistry;
|
||||
use projection_xmpp::{launch, ServerConfig};
|
||||
use proto_xmpp::xml::{Continuation, FromXml, Parser};
|
||||
|
||||
pub async fn read_irc_message(reader: &mut BufReader<ReadHalf<'_>>, buf: &mut Vec<u8>) -> Result<usize> {
|
||||
let mut size = 0;
|
||||
let res = reader.read_until(b'\n', buf).await?;
|
||||
size += res;
|
||||
return Ok(size);
|
||||
}
|
||||
|
||||
struct TestScope<'a> {
|
||||
reader: NsReader<BufReader<ReadHalf<'a>>>,
|
||||
writer: WriteHalf<'a>,
|
||||
buffer: Vec<u8>,
|
||||
}
|
||||
|
||||
impl<'a> TestScope<'a> {
|
||||
fn new(stream: &mut TcpStream) -> TestScope<'_> {
|
||||
let (reader, writer) = stream.split();
|
||||
let reader = NsReader::from_reader(BufReader::new(reader));
|
||||
let buffer = vec![];
|
||||
TestScope { reader, writer, buffer }
|
||||
}
|
||||
|
||||
async fn send(&mut self, str: &str) -> Result<()> {
|
||||
self.writer.write_all(str.as_bytes()).await?;
|
||||
self.writer.write_all(b"\n").await?;
|
||||
self.writer.flush().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn next_xml_event(&mut self) -> Result<Event<'_>> {
|
||||
self.buffer.clear();
|
||||
let event = self.reader.read_event_into_async(&mut self.buffer).await?;
|
||||
Ok(event)
|
||||
}
|
||||
|
||||
async fn read<T: FromXml>(&mut self) -> Result<T> {
|
||||
self.buffer.clear();
|
||||
let (ns, event) = self.reader.read_resolved_event_into_async(&mut self.buffer).await?;
|
||||
let mut parser: Continuation<_, std::result::Result<T, anyhow::Error>> = T::parse().consume(ns, &event);
|
||||
loop {
|
||||
match parser {
|
||||
Continuation::Final(res) => return Ok(res?),
|
||||
Continuation::Continue(next) => {
|
||||
let (ns, event) = self.reader.read_resolved_event_into_async(&mut self.buffer).await?;
|
||||
parser = next.consume(ns, &event);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct TestScopeTls<'a> {
|
||||
reader: NsReader<BufReader<GenericReadHalf<&'a mut TlsStream<TcpStream>>>>,
|
||||
writer: GenericWriteHalf<&'a mut TlsStream<TcpStream>>,
|
||||
buffer: Vec<u8>,
|
||||
pub timeout: Duration,
|
||||
}
|
||||
|
||||
impl<'a> TestScopeTls<'a> {
|
||||
fn new(stream: &'a mut TlsStream<TcpStream>, buffer: Vec<u8>) -> TestScopeTls<'a> {
|
||||
let (reader, writer) = tokio::io::split(stream);
|
||||
let reader = NsReader::from_reader(BufReader::new(reader));
|
||||
let timeout = Duration::from_millis(100);
|
||||
|
||||
TestScopeTls {
|
||||
reader,
|
||||
writer,
|
||||
buffer,
|
||||
timeout,
|
||||
}
|
||||
}
|
||||
|
||||
async fn send(&mut self, str: &str) -> Result<()> {
|
||||
self.writer.write_all(str.as_bytes()).await?;
|
||||
self.writer.write_all(b"\n").await?;
|
||||
self.writer.flush().await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn next_xml_event(&mut self) -> Result<Event<'_>> {
|
||||
self.buffer.clear();
|
||||
let event = self.reader.read_event_into_async(&mut self.buffer);
|
||||
let event = tokio::time::timeout(self.timeout, event).await??;
|
||||
Ok(event)
|
||||
}
|
||||
}
|
||||
|
||||
struct IgnoreCertVerification;
|
||||
impl ServerCertVerifier for IgnoreCertVerification {
|
||||
fn verify_server_cert(
|
||||
&self,
|
||||
_end_entity: &tokio_rustls::rustls::Certificate,
|
||||
_intermediates: &[tokio_rustls::rustls::Certificate],
|
||||
_server_name: &ServerName,
|
||||
_scts: &mut dyn Iterator<Item = &[u8]>,
|
||||
_ocsp_response: &[u8],
|
||||
_now: std::time::SystemTime,
|
||||
) -> std::result::Result<tokio_rustls::rustls::client::ServerCertVerified, tokio_rustls::rustls::Error> {
|
||||
Ok(tokio_rustls::rustls::client::ServerCertVerified::assertion())
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn scenario_basic() -> Result<()> {
|
||||
tracing_subscriber::fmt::init();
|
||||
let config = ServerConfig {
|
||||
listen_on: "127.0.0.1:0".parse().unwrap(),
|
||||
cert: "tests/certs/xmpp.pem".parse().unwrap(),
|
||||
key: "tests/certs/xmpp.key".parse().unwrap(),
|
||||
};
|
||||
let mut metrics = MetricsRegistry::new();
|
||||
let mut storage = Storage::open(StorageConfig {
|
||||
db_path: ":memory:".into(),
|
||||
})
|
||||
.await?;
|
||||
let rooms = RoomRegistry::new(&mut metrics, storage.clone()).unwrap();
|
||||
let players = PlayerRegistry::empty(rooms.clone(), &mut metrics).unwrap();
|
||||
let server = launch(config, players, rooms, metrics, storage.clone()).await.unwrap();
|
||||
|
||||
// test scenario
|
||||
|
||||
storage.create_user("tester").await?;
|
||||
storage.set_password("tester", "password").await?;
|
||||
|
||||
let mut stream = TcpStream::connect(server.addr).await?;
|
||||
let mut s = TestScope::new(&mut stream);
|
||||
|
||||
s.send(r#"<?xml version="1.0"?>"#).await?;
|
||||
s.send(r#"<stream:stream xmlns:stream="http://etherx.jabber.org/streams" to="127.0.0.1" xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns="jabber:client" version="1.0">"#).await?;
|
||||
assert_matches!(s.next_xml_event().await?, Event::Decl(_) => {});
|
||||
assert_matches!(s.next_xml_event().await?, Event::Start(b) => assert_eq!(b.local_name().into_inner(), b"stream"));
|
||||
assert_matches!(s.next_xml_event().await?, Event::Start(b) => assert_eq!(b.local_name().into_inner(), b"features"));
|
||||
assert_matches!(s.next_xml_event().await?, Event::Start(b) => assert_eq!(b.local_name().into_inner(), b"starttls"));
|
||||
assert_matches!(s.next_xml_event().await?, Event::Empty(b) => assert_eq!(b.local_name().into_inner(), b"required"));
|
||||
assert_matches!(s.next_xml_event().await?, Event::End(b) => assert_eq!(b.local_name().into_inner(), b"starttls"));
|
||||
assert_matches!(s.next_xml_event().await?, Event::End(b) => assert_eq!(b.local_name().into_inner(), b"features"));
|
||||
s.send(r#"<starttls/>"#).await?;
|
||||
assert_matches!(s.next_xml_event().await?, Event::Empty(b) => assert_eq!(b.local_name().into_inner(), b"proceed"));
|
||||
let buffer = s.buffer;
|
||||
|
||||
let connector = TlsConnector::from(Arc::new(
|
||||
ClientConfig::builder()
|
||||
.with_safe_defaults()
|
||||
.with_custom_certificate_verifier(Arc::new(IgnoreCertVerification))
|
||||
.with_no_client_auth(),
|
||||
));
|
||||
tracing::debug!("Initiating TLS connection...");
|
||||
let mut stream = connector.connect(ServerName::IpAddress(server.addr.ip()), stream).await?;
|
||||
|
||||
let mut s = TestScopeTls::new(&mut stream, buffer);
|
||||
|
||||
s.send(r#"<?xml version="1.0"?>"#).await?;
|
||||
s.send(r#"<stream:stream xmlns:stream="http://etherx.jabber.org/streams" to="127.0.0.1" xml:lang="en" xmlns:xml="http://www.w3.org/XML/1998/namespace" xmlns="jabber:client" version="1.0">"#).await?;
|
||||
assert_matches!(s.next_xml_event().await?, Event::Decl(_) => {});
|
||||
assert_matches!(s.next_xml_event().await?, Event::Start(b) => assert_eq!(b.local_name().into_inner(), b"stream"));
|
||||
|
||||
stream.shutdown().await?;
|
||||
|
||||
// wrap up
|
||||
|
||||
server.terminate().await?;
|
||||
Ok(())
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
use super::*;
|
||||
|
||||
use nom::combinator::opt;
|
||||
use anyhow::{anyhow, Result};
|
||||
use nom::combinator::{all_consuming, opt};
|
||||
|
||||
/// Client-to-server command.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -60,8 +61,8 @@ pub enum ClientMessage {
|
|||
},
|
||||
}
|
||||
|
||||
pub fn client_message(input: &str) -> IResult<&str, ClientMessage> {
|
||||
alt((
|
||||
pub fn client_message(input: &str) -> Result<ClientMessage> {
|
||||
let res = all_consuming(alt((
|
||||
client_message_capability,
|
||||
client_message_ping,
|
||||
client_message_pong,
|
||||
|
@ -75,7 +76,11 @@ pub fn client_message(input: &str) -> IResult<&str, ClientMessage> {
|
|||
client_message_part,
|
||||
client_message_privmsg,
|
||||
client_message_quit,
|
||||
))(input)
|
||||
)))(input);
|
||||
match res {
|
||||
Ok((_, e)) => Ok(e),
|
||||
Err(e) => Err(anyhow!("Parsing failed: {e}")),
|
||||
}
|
||||
}
|
||||
|
||||
fn client_message_capability(input: &str) -> IResult<&str, ClientMessage> {
|
||||
|
@ -89,24 +94,14 @@ fn client_message_ping(input: &str) -> IResult<&str, ClientMessage> {
|
|||
let (input, _) = tag("PING ")(input)?;
|
||||
let (input, token) = token(input)?;
|
||||
|
||||
Ok((
|
||||
input,
|
||||
ClientMessage::Ping {
|
||||
token: token.into(),
|
||||
},
|
||||
))
|
||||
Ok((input, ClientMessage::Ping { token: token.into() }))
|
||||
}
|
||||
|
||||
fn client_message_pong(input: &str) -> IResult<&str, ClientMessage> {
|
||||
let (input, _) = tag("PONG ")(input)?;
|
||||
let (input, token) = token(input)?;
|
||||
|
||||
Ok((
|
||||
input,
|
||||
ClientMessage::Pong {
|
||||
token: token.into(),
|
||||
},
|
||||
))
|
||||
Ok((input, ClientMessage::Pong { token: token.into() }))
|
||||
}
|
||||
|
||||
fn client_message_nick(input: &str) -> IResult<&str, ClientMessage> {
|
||||
|
@ -225,12 +220,7 @@ fn client_message_quit(input: &str) -> IResult<&str, ClientMessage> {
|
|||
let (input, _) = tag("QUIT :")(input)?;
|
||||
let (input, reason) = token(input)?;
|
||||
|
||||
Ok((
|
||||
input,
|
||||
ClientMessage::Quit {
|
||||
reason: reason.into(),
|
||||
},
|
||||
))
|
||||
Ok((input, ClientMessage::Quit { reason: reason.into() }))
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -275,7 +265,7 @@ mod test {
|
|||
};
|
||||
|
||||
let result = client_message(input);
|
||||
assert_matches!(result, Ok((_, result)) => assert_eq!(expected, result));
|
||||
assert_matches!(result, Ok(result) => assert_eq!(expected, result));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -286,28 +276,24 @@ mod test {
|
|||
};
|
||||
|
||||
let result = client_message(input);
|
||||
assert_matches!(result, Ok((_, result)) => assert_eq!(expected, result));
|
||||
assert_matches!(result, Ok(result) => assert_eq!(expected, result));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_client_message_ping() {
|
||||
let input = "PING 1337";
|
||||
let expected = ClientMessage::Ping {
|
||||
token: "1337".into(),
|
||||
};
|
||||
let expected = ClientMessage::Ping { token: "1337".into() };
|
||||
|
||||
let result = client_message(input);
|
||||
assert_matches!(result, Ok((_, result)) => assert_eq!(expected, result));
|
||||
assert_matches!(result, Ok(result) => assert_eq!(expected, result));
|
||||
}
|
||||
#[test]
|
||||
fn test_client_message_pong() {
|
||||
let input = "PONG 1337";
|
||||
let expected = ClientMessage::Pong {
|
||||
token: "1337".into(),
|
||||
};
|
||||
let expected = ClientMessage::Pong { token: "1337".into() };
|
||||
|
||||
let result = client_message(input);
|
||||
assert_matches!(result, Ok((_, result)) => assert_eq!(expected, result));
|
||||
assert_matches!(result, Ok(result) => assert_eq!(expected, result));
|
||||
}
|
||||
#[test]
|
||||
fn test_client_message_nick() {
|
||||
|
@ -317,7 +303,7 @@ mod test {
|
|||
};
|
||||
|
||||
let result = client_message(input);
|
||||
assert_matches!(result, Ok((_, result)) => assert_eq!(expected, result));
|
||||
assert_matches!(result, Ok(result) => assert_eq!(expected, result));
|
||||
}
|
||||
#[test]
|
||||
fn test_client_message_user() {
|
||||
|
@ -328,7 +314,7 @@ mod test {
|
|||
};
|
||||
|
||||
let result = client_message(input);
|
||||
assert_matches!(result, Ok((_, result)) => assert_eq!(expected, result));
|
||||
assert_matches!(result, Ok(result) => assert_eq!(expected, result));
|
||||
}
|
||||
#[test]
|
||||
fn test_client_message_part() {
|
||||
|
@ -339,6 +325,6 @@ mod test {
|
|||
};
|
||||
|
||||
let result = client_message(input);
|
||||
assert_matches!(result, Ok((_, result)) => assert_eq!(expected, result));
|
||||
assert_matches!(result, Ok(result) => assert_eq!(expected, result));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ mod testkit;
|
|||
pub mod user;
|
||||
|
||||
use crate::prelude::Str;
|
||||
use std::io::Result;
|
||||
|
||||
use nom::{
|
||||
branch::alt,
|
||||
|
@ -39,7 +38,7 @@ pub enum Chan {
|
|||
Local(Str),
|
||||
}
|
||||
impl Chan {
|
||||
pub async fn write_async(&self, writer: &mut (impl AsyncWrite + Unpin)) -> Result<()> {
|
||||
pub async fn write_async(&self, writer: &mut (impl AsyncWrite + Unpin)) -> std::io::Result<()> {
|
||||
match self {
|
||||
Chan::Global(name) => {
|
||||
writer.write_all(b"#").await?;
|
||||
|
@ -76,7 +75,7 @@ pub enum Recipient {
|
|||
Chan(Chan),
|
||||
}
|
||||
impl Recipient {
|
||||
pub async fn write_async(&self, writer: &mut (impl AsyncWrite + Unpin)) -> Result<()> {
|
||||
pub async fn write_async(&self, writer: &mut (impl AsyncWrite + Unpin)) -> std::io::Result<()> {
|
||||
match self {
|
||||
Recipient::Nick(nick) => writer.write_all(nick.as_bytes()).await?,
|
||||
Recipient::Chan(chan) => chan.write_async(writer).await?,
|
||||
|
|
|
@ -10,3 +10,7 @@ regex.workspace = true
|
|||
anyhow.workspace = true
|
||||
tokio.workspace = true
|
||||
derive_more.workspace = true
|
||||
base64.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
assert_matches.workspace = true
|
||||
|
|
|
@ -5,6 +5,7 @@ use quick_xml::{
|
|||
NsReader, Writer,
|
||||
};
|
||||
use tokio::io::{AsyncBufRead, AsyncWrite};
|
||||
use base64::{Engine as _, engine::general_purpose};
|
||||
|
||||
use super::skip_text;
|
||||
use anyhow::{anyhow, Result};
|
||||
|
@ -12,6 +13,7 @@ use anyhow::{anyhow, Result};
|
|||
pub enum Mechanism {
|
||||
Plain,
|
||||
}
|
||||
|
||||
impl Mechanism {
|
||||
pub fn to_str(&self) -> &'static str {
|
||||
match self {
|
||||
|
@ -27,10 +29,93 @@ impl Mechanism {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct AuthBody {
|
||||
pub login: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
impl AuthBody {
|
||||
pub fn from_str(input: &[u8]) -> Result<AuthBody> {
|
||||
match general_purpose::STANDARD.decode(input){
|
||||
Ok(decoded_body) => {
|
||||
match String::from_utf8(decoded_body) {
|
||||
Ok(parsed_to_string) => {
|
||||
let separated_words: Vec<&str> = parsed_to_string.split("\x00").collect::<Vec<_>>().clone();
|
||||
if separated_words.len() == 3 {
|
||||
// first segment ignored (might be needed in the future)
|
||||
Ok(AuthBody { login: separated_words[1].to_string(), password: separated_words[2].to_string() })
|
||||
} else { return Err(anyhow!("Incorrect auth format")) }
|
||||
},
|
||||
Err(e) => return Err(anyhow!(e))
|
||||
}
|
||||
},
|
||||
Err(e) => return Err(anyhow!(e))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_returning_auth_body() {
|
||||
let orig = b"\x00login\x00pass";
|
||||
let encoded = general_purpose::STANDARD.encode(orig);
|
||||
let expected = AuthBody {login: "login".to_string(), password: "pass".to_string()};
|
||||
let result = AuthBody::from_str(encoded.as_bytes()).unwrap();
|
||||
|
||||
assert_eq!(expected, result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ignoring_first_segment() {
|
||||
let orig = b"ignored\x00login\x00pass";
|
||||
let encoded = general_purpose::STANDARD.encode(orig);
|
||||
let expected = AuthBody {login: "login".to_string(), password: "pass".to_string()};
|
||||
let result = AuthBody::from_str(encoded.as_bytes()).unwrap();
|
||||
|
||||
assert_eq!(expected, result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_returning_auth_body_with_empty_strings() {
|
||||
let orig = b"\x00\x00";
|
||||
let encoded = general_purpose::STANDARD.encode(orig);
|
||||
let expected = AuthBody {login: "".to_string(), password: "".to_string()};
|
||||
let result = AuthBody::from_str(encoded.as_bytes()).unwrap();
|
||||
|
||||
assert_eq!(expected, result);
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_fail_if_size_less_then_3() {
|
||||
let orig = b"login\x00pass";
|
||||
let encoded = general_purpose::STANDARD.encode(orig);
|
||||
let expected = AuthBody {login: "login".to_string(), password: "pass".to_string()};
|
||||
let result = AuthBody::from_str(encoded.as_bytes());
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fail_if_size_greater_then_3() {
|
||||
let orig = b"first\x00login\x00pass\x00other";
|
||||
let encoded = general_purpose::STANDARD.encode(orig);
|
||||
let expected = AuthBody {login: "login".to_string(), password: "pass".to_string()};
|
||||
let result = AuthBody::from_str(encoded.as_bytes());
|
||||
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub struct Auth {
|
||||
pub mechanism: Mechanism,
|
||||
pub body: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Auth {
|
||||
pub async fn parse(
|
||||
reader: &mut NsReader<impl AsyncBufRead + Unpin>,
|
||||
|
@ -69,6 +154,7 @@ impl Auth {
|
|||
}
|
||||
|
||||
pub struct Success;
|
||||
|
||||
impl Success {
|
||||
pub async fn write_xml(&self, writer: &mut Writer<impl AsyncWrite + Unpin>) -> Result<()> {
|
||||
let event = BytesStart::new(r#"success xmlns="urn:ietf:params:xml:ns:xmpp-sasl""#);
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
## Dependency diagram of the project
|
||||
|
||||
```mermaid
|
||||
graph TD;
|
||||
lavina-->mgmt-api;
|
||||
lavina-->projection-irc;
|
||||
lavina-->projection-xmpp;
|
||||
lavina-->lavina-core;
|
||||
|
||||
projection-irc-->proto-irc;
|
||||
projection-irc-->lavina-core;
|
||||
|
||||
projection-xmpp-->proto-xmpp;
|
||||
projection-xmpp-->lavina-core;
|
||||
|
||||
sim-irc-->proto-irc;
|
||||
sim-irc-->mgmt-api;
|
||||
|
||||
sim-xmpp-->proto-xmpp;
|
||||
sim-xmpp-->mgmt-api;
|
||||
|
||||
workspace-->lavina;
|
||||
workspace-->sim-irc;
|
||||
workspace-->sim-xmpp;
|
||||
```
|
||||
|
||||
A few rules:
|
||||
- Only projections should be direct deps of `lavina`, there is no need to depend on `proto-*` crates.
|
||||
- On the other hand, projections should not be dependencies of `sim-*` crates.
|
||||
- `lavina-core` does not depend on protocol-specific crates.
|
||||
|
||||
## Lavina
|
||||
|
||||
**lavina-core**. This crate implements the core functionality of the server not specific to public interfaces. It includes handling general persistence, message casts, in future room authorization and cross-node communication.
|
||||
|
||||
**lavina**. The application crate. It's used to link other crates together and build the final binary with support for all protocols.
|
||||
|
||||
**mgmt-api**. Model definitions for management API to be used both in the server and client implementations.
|
||||
|
||||
## IRC
|
||||
|
||||
**proto-irc**. Protocol definition for IRC, includes both server-side and client-side messages and both serialization and deserialization where needed.
|
||||
|
||||
**projection-irc**. Projection of lavina-core onto the IRC client-to-server protocol implementation.
|
||||
|
||||
**sim-irc**. Future implementation of IRC client simulator to be used in integration and load testing.
|
|
@ -18,25 +18,12 @@ Print content of a TLS certificate:
|
|||
|
||||
openssl x509 -in certs/xmpp.pem -text
|
||||
|
||||
Make sure `xmpp.key` starts and ends with:
|
||||
```
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
-----END RSA PRIVATE KEY-----
|
||||
```
|
||||
|
||||
|
||||
## Protocol Specs
|
||||
|
||||
XMPP XSDs - [https://xmpp.org/schemas/index.shtml]
|
||||
|
||||
IRC modern spec - [https://modern.ircdocs.horse/]
|
||||
|
||||
## Initializing DB with some users
|
||||
|
||||
sqlite3 db.sqlite < test/init_state.sql
|
||||
|
||||
Same test migration could be used for integration tests in the future.
|
||||
|
||||
## Using irssi
|
||||
|
||||
irssi in a TUI-based IRC client.
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
# Building & Running Lavina
|
||||
|
||||
## Configuration
|
||||
|
||||
A server instance must be supplied with a configuration file to start up. The path to configuration is specified with a required CLI argument `--config <path>`.
|
||||
|
||||
Example configuration:
|
||||
```toml
|
||||
[telemetry]
|
||||
# address for management and telemetry API
|
||||
# should be kept private
|
||||
listen_on = "127.0.0.1:8080"
|
||||
|
||||
[irc]
|
||||
listen_on = "127.0.0.1:6667"
|
||||
server_name = "irc.localhost"
|
||||
|
||||
[xmpp]
|
||||
listen_on = "127.0.0.1:5222"
|
||||
cert = "./certs/xmpp.pem"
|
||||
key = "./certs/xmpp.key"
|
||||
|
||||
[storage]
|
||||
db_path = "db.sqlite"
|
||||
```
|
||||
|
||||
## With Docker Compose
|
||||
|
||||
Example `docker-compose.yml` file:
|
||||
```yaml
|
||||
version: '3.0'
|
||||
|
||||
services:
|
||||
lavina:
|
||||
image: git.vilunov.me/lavina/lavina:0.0.1
|
||||
volumes:
|
||||
- './config/:/etc/lavina/'
|
||||
- './data/:/var/lib/lavina/'
|
||||
ports:
|
||||
- '5222:5222' # xmpp
|
||||
- '6667:6667' # irc non-tls
|
||||
- '127.0.0.1:1380:8080' # management http (private)
|
||||
```
|
||||
|
||||
## With Cargo
|
||||
|
||||
You can run it via cargo:
|
||||
|
||||
cargo run -- --config config.toml
|
||||
|
||||
Or you can build it and run manually:
|
||||
|
||||
cargo build --release
|
||||
./target/release/lavina --config config.toml
|
|
@ -2,6 +2,10 @@
|
|||
|
||||
Multiprotocol chat server based on open protocols.
|
||||
|
||||
- [How to run Lavina locally](docs/running.md)
|
||||
- [Architectural diagrams](docs/flow.md)
|
||||
- [Project structure](crates/readme.md)
|
||||
|
||||
## Goals
|
||||
|
||||
#### Support for multiple open protocols
|
||||
|
|
|
@ -1 +1 @@
|
|||
nightly-2023-08-15
|
||||
nightly-2023-10-06
|
||||
|
|
|
@ -62,7 +62,7 @@ async fn main() -> Result<()> {
|
|||
storage.clone(),
|
||||
)
|
||||
.await?;
|
||||
let xmpp = projection_xmpp::launch(xmpp_config, players.clone(), rooms.clone(), metrics.clone()).await?;
|
||||
let xmpp = projection_xmpp::launch(xmpp_config, players.clone(), rooms.clone(), metrics.clone(), storage.clone()).await?;
|
||||
tracing::info!("Started");
|
||||
|
||||
sleep.await;
|
||||
|
|
Loading…
Reference in New Issue