feat: lay the ground for login

This commit is contained in:
2026-03-26 21:56:23 +01:00
parent afc5e94adf
commit 4785ab529c
10 changed files with 801 additions and 39 deletions

584
Cargo.lock generated
View File

@@ -49,7 +49,7 @@ dependencies = [
"mime",
"percent-encoding",
"pin-project-lite",
"rand",
"rand 0.9.2",
"sha1",
"smallvec",
"tokio",
@@ -282,12 +282,30 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "base16ct"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "base64ct"
version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
[[package]]
name = "bindgen"
version = "0.69.5"
@@ -323,6 +341,15 @@ dependencies = [
"generic-array",
]
[[package]]
name = "block-buffer"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be"
dependencies = [
"hybrid-array",
]
[[package]]
name = "brotli"
version = "8.0.2"
@@ -392,6 +419,16 @@ version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "cipher"
version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"
dependencies = [
"crypto-common 0.1.7",
"inout",
]
[[package]]
name = "clang-sys"
version = "1.8.1"
@@ -471,9 +508,21 @@ version = "0.1.0"
source = "git+https://git.javalsai.tuxcord.net/rust/const-macros.git#6f91e1e1a6ce2e5cdb5866a1e1d7841ed5e3cd6f"
dependencies = [
"magic",
"sha2",
"sha2 0.10.9",
]
[[package]]
name = "const-oid"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
[[package]]
name = "const-oid"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c"
[[package]]
name = "const-str"
version = "1.1.0"
@@ -523,6 +572,15 @@ dependencies = [
"libc",
]
[[package]]
name = "cpufeatures"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201"
dependencies = [
"libc",
]
[[package]]
name = "crc32fast"
version = "1.5.0"
@@ -556,6 +614,18 @@ version = "0.8.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
[[package]]
name = "crypto-bigint"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
dependencies = [
"generic-array",
"rand_core 0.6.4",
"subtle",
"zeroize",
]
[[package]]
name = "crypto-common"
version = "0.1.7"
@@ -566,6 +636,25 @@ dependencies = [
"typenum",
]
[[package]]
name = "crypto-common"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710"
dependencies = [
"hybrid-array",
]
[[package]]
name = "der"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb"
dependencies = [
"const-oid 0.9.6",
"zeroize",
]
[[package]]
name = "deranged"
version = "0.5.8"
@@ -604,8 +693,21 @@ version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
"block-buffer 0.10.4",
"const-oid 0.9.6",
"crypto-common 0.1.7",
"subtle",
]
[[package]]
name = "digest"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c"
dependencies = [
"block-buffer 0.12.0",
"const-oid 0.10.2",
"crypto-common 0.2.1",
]
[[package]]
@@ -619,12 +721,45 @@ dependencies = [
"syn 2.0.117",
]
[[package]]
name = "ecdsa"
version = "0.16.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"
dependencies = [
"der",
"digest 0.10.7",
"elliptic-curve",
"rfc6979",
"signature",
"spki",
]
[[package]]
name = "either"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "elliptic-curve"
version = "0.13.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
dependencies = [
"base16ct",
"crypto-bigint",
"digest 0.10.7",
"ff",
"generic-array",
"group",
"pkcs8",
"rand_core 0.6.4",
"sec1",
"subtle",
"zeroize",
]
[[package]]
name = "encoding_rs"
version = "0.8.35"
@@ -634,6 +769,29 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "env_filter"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef"
dependencies = [
"log",
"regex",
]
[[package]]
name = "env_logger"
version = "0.11.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a"
dependencies = [
"anstream",
"anstyle",
"env_filter",
"jiff",
"log",
]
[[package]]
name = "equivalent"
version = "1.0.2"
@@ -671,6 +829,16 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "ff"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393"
dependencies = [
"rand_core 0.6.4",
"subtle",
]
[[package]]
name = "find-msvc-tools"
version = "0.1.9"
@@ -758,6 +926,18 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
"zeroize",
]
[[package]]
name = "getrandom"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0"
dependencies = [
"cfg-if",
"libc",
"wasi",
]
[[package]]
@@ -791,6 +971,17 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
[[package]]
name = "group"
version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
dependencies = [
"ff",
"rand_core 0.6.4",
"subtle",
]
[[package]]
name = "h2"
version = "0.3.27"
@@ -831,6 +1022,15 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hmac"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
dependencies = [
"digest 0.10.7",
]
[[package]]
name = "http"
version = "0.2.12"
@@ -854,6 +1054,15 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]]
name = "hybrid-array"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8655f91cd07f2b9d0c24137bd650fe69617773435ee5ec83022377777ce65ef1"
dependencies = [
"typenum",
]
[[package]]
name = "icu_collections"
version = "2.1.1"
@@ -980,6 +1189,15 @@ dependencies = [
"serde_core",
]
[[package]]
name = "inout"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01"
dependencies = [
"generic-array",
]
[[package]]
name = "is_terminal_polyfill"
version = "1.70.2"
@@ -1001,6 +1219,30 @@ version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "jiff"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359"
dependencies = [
"jiff-static",
"log",
"portable-atomic",
"portable-atomic-util",
"serde_core",
]
[[package]]
name = "jiff-static"
version = "0.2.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.117",
]
[[package]]
name = "jobserver"
version = "0.1.34"
@@ -1032,6 +1274,9 @@ name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
dependencies = [
"spin",
]
[[package]]
name = "lazycell"
@@ -1051,6 +1296,12 @@ version = "0.2.183"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d"
[[package]]
name = "libm"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]]
name = "litemap"
version = "0.8.1"
@@ -1179,10 +1430,56 @@ dependencies = [
]
[[package]]
name = "num-conv"
version = "0.2.0"
name = "num-bigint-dig"
version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050"
checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7"
dependencies = [
"lazy_static",
"libm",
"num-integer",
"num-iter",
"num-traits",
"rand 0.8.5",
"smallvec",
"zeroize",
]
[[package]]
name = "num-conv"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967"
[[package]]
name = "num-integer"
version = "0.1.46"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
dependencies = [
"num-traits",
]
[[package]]
name = "num-iter"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
dependencies = [
"autocfg",
"num-integer",
"num-traits",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
"libm",
]
[[package]]
name = "oidc"
@@ -1194,13 +1491,16 @@ dependencies = [
"clap",
"const-macros",
"const-str",
"env_logger",
"futures-util",
"libc",
"log",
"magic",
"moka",
"pamsock",
"serde",
"sha2",
"sha2 0.11.0",
"ssh-key",
"thiserror",
"tokio",
"toml",
@@ -1219,6 +1519,44 @@ version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "p256"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b"
dependencies = [
"ecdsa",
"elliptic-curve",
"primeorder",
"sha2 0.10.9",
]
[[package]]
name = "p384"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6"
dependencies = [
"ecdsa",
"elliptic-curve",
"primeorder",
"sha2 0.10.9",
]
[[package]]
name = "p521"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2"
dependencies = [
"base16ct",
"ecdsa",
"elliptic-curve",
"primeorder",
"rand_core 0.6.4",
"sha2 0.10.9",
]
[[package]]
name = "pam"
version = "0.8.0"
@@ -1293,6 +1631,15 @@ dependencies = [
"windows-link",
]
[[package]]
name = "pem-rfc7468"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
dependencies = [
"base64ct",
]
[[package]]
name = "percent-encoding"
version = "2.3.2"
@@ -1305,6 +1652,27 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"
[[package]]
name = "pkcs1"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f"
dependencies = [
"der",
"pkcs8",
"spki",
]
[[package]]
name = "pkcs8"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
dependencies = [
"der",
"spki",
]
[[package]]
name = "pkg-config"
version = "0.3.32"
@@ -1317,6 +1685,15 @@ version = "1.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
[[package]]
name = "portable-atomic-util"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3"
dependencies = [
"portable-atomic",
]
[[package]]
name = "potential_utf"
version = "0.1.4"
@@ -1351,6 +1728,15 @@ dependencies = [
"syn 2.0.117",
]
[[package]]
name = "primeorder"
version = "0.13.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6"
dependencies = [
"elliptic-curve",
]
[[package]]
name = "proc-macro2"
version = "1.0.106"
@@ -1381,14 +1767,34 @@ version = "6.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
[[package]]
name = "rand"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
dependencies = [
"rand_chacha 0.3.1",
"rand_core 0.6.4",
]
[[package]]
name = "rand"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
dependencies = [
"rand_chacha",
"rand_core",
"rand_chacha 0.9.0",
"rand_core 0.9.5",
]
[[package]]
name = "rand_chacha"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
dependencies = [
"ppv-lite86",
"rand_core 0.6.4",
]
[[package]]
@@ -1398,7 +1804,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
dependencies = [
"ppv-lite86",
"rand_core",
"rand_core 0.9.5",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
dependencies = [
"getrandom 0.2.17",
]
[[package]]
@@ -1454,6 +1869,37 @@ version = "0.8.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
[[package]]
name = "rfc6979"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
dependencies = [
"hmac",
"subtle",
]
[[package]]
name = "rsa"
version = "0.9.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d"
dependencies = [
"const-oid 0.9.6",
"digest 0.10.7",
"num-bigint-dig",
"num-integer",
"num-traits",
"pkcs1",
"pkcs8",
"rand_core 0.6.4",
"sha2 0.10.9",
"signature",
"spki",
"subtle",
"zeroize",
]
[[package]]
name = "rustc-hash"
version = "1.1.0"
@@ -1487,6 +1933,20 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "sec1"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc"
dependencies = [
"base16ct",
"der",
"generic-array",
"pkcs8",
"subtle",
"zeroize",
]
[[package]]
name = "semver"
version = "1.0.27"
@@ -1564,8 +2024,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
"cpufeatures 0.2.17",
"digest 0.10.7",
]
[[package]]
@@ -1575,8 +2035,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
"cpufeatures 0.2.17",
"digest 0.10.7",
]
[[package]]
name = "sha2"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4"
dependencies = [
"cfg-if",
"cpufeatures 0.3.0",
"digest 0.11.2",
]
[[package]]
@@ -1595,6 +2066,16 @@ dependencies = [
"libc",
]
[[package]]
name = "signature"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
dependencies = [
"digest 0.10.7",
"rand_core 0.6.4",
]
[[package]]
name = "simd-adler32"
version = "0.3.8"
@@ -1633,6 +2114,63 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
[[package]]
name = "spki"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
dependencies = [
"base64ct",
"der",
]
[[package]]
name = "ssh-cipher"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "caac132742f0d33c3af65bfcde7f6aa8f62f0e991d80db99149eb9d44708784f"
dependencies = [
"cipher",
"ssh-encoding",
]
[[package]]
name = "ssh-encoding"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15"
dependencies = [
"base64ct",
"pem-rfc7468",
"sha2 0.10.9",
]
[[package]]
name = "ssh-key"
version = "0.6.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b86f5297f0f04d08cabaa0f6bff7cb6aec4d9c3b49d87990d63da9d9156a8c3"
dependencies = [
"p256",
"p384",
"p521",
"rand_core 0.6.4",
"rsa",
"sec1",
"sha2 0.10.9",
"signature",
"ssh-cipher",
"ssh-encoding",
"subtle",
"zeroize",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.1"
@@ -1645,6 +2183,12 @@ version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
[[package]]
name = "subtle"
version = "2.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "1.0.109"
@@ -1871,9 +2415,9 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
[[package]]
name = "unicode-segmentation"
version = "1.13.1"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da36089a805484bcccfffe0739803392c8298778a2d2f09febf76fac5ad9025b"
checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
[[package]]
name = "unicode-xid"
@@ -2303,6 +2847,12 @@ dependencies = [
"synstructure",
]
[[package]]
name = "zeroize"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0"
[[package]]
name = "zerotrie"
version = "0.2.3"

View File

@@ -46,7 +46,8 @@ log = { version = "0.4.29", optional = true }
magic = "0.16"
moka = { version = "0.12", features = ["async-lock", "future"] }
serde = { version = "1.0", features = ["derive"] }
sha2 = "0.10"
sha2 = "0.11"
ssh-key = "0.6.7"
thiserror = "2.0"
tokio = { version = "1.49", features = ["full"] }
toml = "1.0"

View File

@@ -37,6 +37,11 @@ pub const USER_PFP_PATHS: &[&str] = &[
".face",
];
/// Path relative to a user's home to ssh's `.authorized_keys`, used to verify user's identity when
/// distrusted
pub const AUTHORIZED_KEYS_PATH: &str = ".ssh/authorized_keys";
pub const MAX_AUTHORIZED_KEYS_SIZE: u64 = 64 * 1024; // 64 KiB
pub const ERROR_ASCII_ARTS: &[&str] = &[
include_str!("../assets/lain/lain-dancing.txt"),
include_str!("../assets/lain/lain-head.txt"),
@@ -51,4 +56,5 @@ pub mod mime {
pub mod web_scopes {
pub const IMAGES: &str = "/image";
pub const LOGIN: &str = "/login";
}

32
src/db/mod.rs Normal file
View File

@@ -0,0 +1,32 @@
//! Everything that interacts with DB (or generally persistent state)
//!
//! Currently it's all in memory or with default values until I model all the data properly and
//! choose a DB provider.
use std::collections::HashSet;
use tokio::sync::RwLock;
pub struct DB {
// TODO: should I use some sort of UIDs instead of the username everywhere?
enabled_users: RwLock<HashSet<String>>,
}
impl DB {
#[must_use]
#[expect(clippy::new_without_default)]
pub fn new() -> Self {
Self {
enabled_users: RwLock::new(HashSet::new()),
}
}
pub async fn enable_user(&mut self, user: String) {
self.enabled_users.write().await.insert(user);
}
#[must_use]
pub async fn user_is_enabled(&self, user: &str) -> bool {
self.enabled_users.read().await.contains(user)
}
}

View File

@@ -2,6 +2,7 @@
#![feature(
decl_macro,
duration_constructors,
iterator_try_collect,
never_type,
once_cell_try,
seek_stream_len
@@ -26,6 +27,34 @@
//!
//! I will try to keep those 3 modules as documented as possible, please feel free to open any
//! issues/PRs regarding information in there.
//!
//! # Public Information
//!
//! To make sure this application doesn't expose any public imformation it's important to define
//! what public information we are willing to expose. The application deals with user information
//! so it must leak at least some information, to make sure we don't overreach, we must have clear
//! where we draw the line.
//!
//! By default all information is private, but this application might leak by default:
//!
//! - **User system information:** Unix's UID of a given username.
//! - **User profile pictures:** See [`consts::USER_PFP_PATHS`].
//! - **User's `autorized_ssh_keys`:** See [`consts::AUTHORIZED_KEYS_PATH`].
//!
//! Note that no file information within user's home can be accessed until the user adds `o+x`
//! permissions on their home directory. Once this is done, only state of files regarding the
//! previous can be publicly accessible, there's no arbirtary path reading.
//!
//! Any user information is checked ASAP against the allowed groups (see [`conf::Unix::groups`]) to
//! fail fast without exposing any personal information for users alien to these groups. That means
//! that any reference to the "user", will assume its already from an allowed group, if its not a
//! group member, it will be treated as nonexistent.
//!
//! Information about existance of a user alien to the configured groups might vulnerable to timing
//! attacks though.
//!
//! TODO: This was clearly defined after some API was already written so these assumptions will
//! need to be reviewed for the old code (notably pfp logic).
use std::fs::File;
@@ -37,6 +66,7 @@ pub mod args;
pub mod auth;
pub mod conf;
pub mod consts;
pub mod db;
pub mod ext;
pub mod serdes;
pub mod server;
@@ -61,7 +91,7 @@ async fn main() -> anyhow::Result<()> {
// (idek japanese but im vibing)
println!("\n\x1b[1;3;4;33mConfiguration\x1b[0m: {conf:#?}\n");
server::start_app(args, conf).await?;
server::start_app(args, conf, db::DB::new()).await?;
Ok(())
}

View File

@@ -1,13 +1,14 @@
use std::{ffi::OsStr, io, os::unix::fs::MetadataExt, path::Path, sync::Arc};
use std::{ffi::OsStr, io, path::Path, sync::Arc};
use ::users::os::unix::UserExt as _;
use moka::future::{Cache, CacheBuilder};
use sha2::Digest as _;
use tokio::{fs::File, io::AsyncReadExt};
use ssh_key::PublicKey;
use crate::{
consts,
server::caches::{mime::Mime, users::UsersCache},
utils::fs::{read_limited_path, read_limited_path_str},
};
pub mod mime;
@@ -39,6 +40,8 @@ pub struct AppCache<'a> {
pfp_cache: Cache<String, Option<Image>>,
}
/// Most of the methods in here fail silently with file i/o and some might cache results, I chose
/// either arbitrarily on the spot but I should make this more explicit.
impl<'a> AppCache<'a> {
/// # Errors
///
@@ -97,23 +100,6 @@ impl<'a> AppCache<'a> {
}
async fn read_logo_from_home(&self, home: &Path) -> Option<Image> {
async fn read_limited_path<const MAXSIZE: u64>(path: &Path) -> io::Result<Vec<u8>> {
let f = File::open(path).await?;
let size = f.metadata().await?.size();
if size > MAXSIZE {
return Err(io::Error::new(
io::ErrorKind::FileTooLarge,
"filesize is bigger than MAXSIZE",
));
}
let mut buf = Vec::with_capacity(size.try_into().expect("u64 to fit in usize"));
// `.take()` just in case an open fd happens to grow, `.metadata()` SHOULD take
// properties from the fd and lock the read fd until its closed but still
f.take(MAXSIZE).read_to_end(&mut buf).await?;
Ok(buf)
}
for subpath in consts::USER_PFP_PATHS {
let path = home.join(subpath);
@@ -183,4 +169,45 @@ impl<'a> AppCache<'a> {
Some(img)
}
/// Gets [`consts::AUTHORIZED_KEYS_PATH`] from user's home.
///
/// # Errors
///
/// In any of [`GetAuthorizedKeysError`]
pub async fn get_authorized_keys(
&self,
username: &str,
) -> Result<Box<[PublicKey]>, GetAuthorizedKeysError> {
async fn read_users_authorized_keys(
home_dir: &Path,
) -> Result<Vec<PublicKey>, GetAuthorizedKeysError> {
let buf = read_limited_path_str::<{ consts::MAX_AUTHORIZED_KEYS_SIZE }>(
&home_dir.join(consts::AUTHORIZED_KEYS_PATH),
)
.await
.map_err(GetAuthorizedKeysError::ReadSshFile)?;
Ok(buf.lines().map(PublicKey::from_openssh).try_collect()?)
}
let user = self
.get_member_user_by_name(username)
.await
.ok_or(GetAuthorizedKeysError::UserNotFound)?;
Ok(read_users_authorized_keys(user.home_dir())
.await?
.into_boxed_slice())
}
}
#[derive(Debug, thiserror::Error)]
pub enum GetAuthorizedKeysError {
#[error("said user was not found")]
UserNotFound,
#[error("failure reading ssh file: {0}")]
ReadSshFile(io::Error),
#[error("error parsing ssh key: {0}")]
ParseError(#[from] ssh_key::Error),
}

View File

@@ -10,6 +10,7 @@ pub struct AppState {
pub args: crate::args::Args,
pub config: &'static crate::conf::Config,
pub cache: caches::AppCache<'static>,
pub db: crate::db::DB,
}
/// Type alias to be used just as `data: AppData,` extractor in [`actix_web`] request handlers.
@@ -17,7 +18,11 @@ pub type AppData = static_app_data::StaticAppDataExtractor<&'static AppState>;
/// Leaks memory for the sake of not atomic'ing all over.
#[expect(clippy::missing_errors_doc)]
pub async fn start_app(args: crate::args::Args, config: crate::conf::Config) -> io::Result<()> {
pub async fn start_app(
args: crate::args::Args,
config: crate::conf::Config,
db: crate::db::DB,
) -> io::Result<()> {
use crate::consts::web_scopes as ws;
let config = Box::leak(Box::new(config));
@@ -28,6 +33,7 @@ pub async fn start_app(args: crate::args::Args, config: crate::conf::Config) ->
args,
config,
cache,
db,
}));
println!(
@@ -41,6 +47,7 @@ pub async fn start_app(args: crate::args::Args, config: crate::conf::Config) ->
.wrap(middleware::Logger::new("%a (%{r}a) %r -> %s, %b B in %T s"))
.wrap(middleware::NormalizePath::trim())
.service(services::images::make_scope(ws::IMAGES))
.service(services::login::make_scope(ws::LOGIN))
.default_service(web::to(services::not_found::not_found))
})
.bind(&app.config.server.listen)?

View File

@@ -0,0 +1,54 @@
use actix_web::{
HttpResponse, get, post,
web::{self, Path},
};
use crate::{consts, server::AppData};
#[must_use]
pub fn make_scope(path: &str) -> actix_web::Scope {
web::scope(path)
.service(login)
.service(login_post)
.service(activate)
}
#[get("")]
pub async fn login(_data: AppData) -> HttpResponse {
HttpResponse::Ok().content_type(consts::mime::HTML).body(
"<html><body>\
<form method=\"post\">\
<h2>Username</h2>\
<input type=\"text\" placeholder=\"username\"/>\
<h2>Password</h2>\
<input type=\"password\" placeholder=\"password\"/>\
<button type=\"submit\">Login</button>\
</form>\
</body></html>",
)
}
#[post("")]
pub async fn login_post(_data: AppData) -> HttpResponse {
HttpResponse::NotImplemented()
.content_type(consts::mime::HTML)
.body(
"<html><body>\
<h1>TODO</h1>\
</body></html>",
)
}
#[get("/activate/{username}")]
pub async fn activate(data: AppData, username: Path<String>) -> HttpResponse {
let keys = data.cache.get_authorized_keys(&username).await;
match keys {
Ok(keys) => HttpResponse::Ok()
.content_type(consts::mime::TEXT)
.body(format!("{keys:#?}")),
Err(err) => HttpResponse::BadRequest()
.content_type(consts::mime::TEXT)
.body(err.to_string()),
}
}

View File

@@ -1,2 +1,3 @@
pub mod images;
pub mod not_found;
pub mod login;

View File

@@ -83,3 +83,57 @@ pub mod shasum {
}
}
}
pub mod fs {
use std::{io, os::unix::fs::MetadataExt as _, path::Path};
use tokio::{fs::File, io::AsyncReadExt};
/// # Errors
///
/// On any underlaying file i/o error.
///
/// # Panics
///
/// If a file's [`u64`] doesn't fit in memory.
pub async fn read_limited_path<const MAXSIZE: u64>(path: &Path) -> io::Result<Vec<u8>> {
let f = File::open(path).await?;
let size = f.metadata().await?.size();
if size > MAXSIZE {
return Err(io::Error::new(
io::ErrorKind::FileTooLarge,
"filesize is bigger than MAXSIZE",
));
}
let mut buf = Vec::with_capacity(size.try_into().expect("u64 to fit in usize"));
// `.take()` just in case an open fd happens to grow, `.metadata()` SHOULD take
// properties from the fd and lock the read fd until its closed but still
f.take(MAXSIZE).read_to_end(&mut buf).await?;
Ok(buf)
}
/// # Errors
///
/// On any underlaying file i/o error.
///
/// # Panics
///
/// If a file's [`u64`] doesn't fit in memory.
pub async fn read_limited_path_str<const MAXSIZE: u64>(path: &Path) -> io::Result<String> {
let f = File::open(path).await?;
let size = f.metadata().await?.size();
if size > MAXSIZE {
return Err(io::Error::new(
io::ErrorKind::FileTooLarge,
"filesize is bigger than MAXSIZE",
));
}
let mut buf = String::with_capacity(size.try_into().expect("u64 to fit in usize"));
// `.take()` just in case an open fd happens to grow, `.metadata()` SHOULD take
// properties from the fd and lock the read fd until its closed but still
f.take(MAXSIZE).read_to_string(&mut buf).await?;
Ok(buf)
}
}