diff --git a/Cargo.lock b/Cargo.lock index 6c51629..5ccc4ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -59,6 +59,18 @@ dependencies = [ "libc", ] +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] + [[package]] name = "arrayref" version = "0.3.9" @@ -588,6 +600,17 @@ dependencies = [ "tracing", ] +[[package]] +name = "axum-client-ip" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eefda7e2b27e1bda4d6fa8a06b50803b8793769045918bc37ad062d48a6efac" +dependencies = [ + "axum", + "forwarded-header-value", + "serde", +] + [[package]] name = "axum-core" version = "0.4.5" @@ -630,6 +653,12 @@ dependencies = [ "tower-http 0.5.2", ] +[[package]] +name = "b64-ct" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32261e5a95e234446dd31774ef4305dc164039370fe2622fd3e935a0f2730689" + [[package]] name = "backtrace" version = "0.3.71" @@ -730,6 +759,15 @@ dependencies = [ "serde", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + [[package]] name = "blake3" version = "1.5.5" @@ -820,6 +858,17 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chacha20" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "chir-rs" version = "0.1.0" @@ -873,6 +922,7 @@ version = "0.1.0" dependencies = [ "bincode", "blake3", + "chir-rs-http-api", "eyre", "mime", "serde", @@ -901,20 +951,27 @@ dependencies = [ name = "chir-rs-http" version = "0.1.0" dependencies = [ + "argon2", "axum", + "axum-client-ip", "axum-prometheus", + "b64-ct", + "base64 0.22.1", "bincode", "chir-rs-castore", "chir-rs-config", "chir-rs-db", "chir-rs-http-api", "chir-rs-misc", + "chrono", "eyre", "mime", + "rusty_paseto", "sentry-tower", "tokio", "tower-http 0.6.2", "tracing", + "unicode-normalization", ] [[package]] @@ -925,8 +982,10 @@ dependencies = [ "axum-core", "bincode", "bytes", + "educe", "http 1.1.0", "mime", + "serde", "thiserror 2.0.3", "tracing", ] @@ -954,6 +1013,16 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clang-sys" version = "1.8.1" @@ -1311,6 +1380,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "erased-serde" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" +dependencies = [ + "serde", + "typeid", +] + [[package]] name = "errno" version = "0.3.10" @@ -1425,6 +1504,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "forwarded-header-value" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835f84f38484cc86f110a805655697908257fb9a7af005234060891557198e9" +dependencies = [ + "nonempty", + "thiserror 1.0.69", +] + [[package]] name = "fs_extra" version = "1.3.0" @@ -2061,12 +2150,30 @@ dependencies = [ "hashbrown 0.15.2", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "ipnet" version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +[[package]] +name = "iso8601" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924e5d73ea28f59011fec52a0d12185d496a9b075d360657aed2a5707f701153" +dependencies = [ + "nom", +] + [[package]] name = "itertools" version = "0.12.1" @@ -2304,6 +2411,12 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nonempty" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7" + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -2467,6 +2580,17 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + [[package]] name = "paste" version = "1.0.15" @@ -3043,6 +3167,28 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" +[[package]] +name = "rusty_paseto" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c28b9f48df2de43da68fb7dcbd60c4f85bca5f6ae4c92cdd9540bcd4a606cb3" +dependencies = [ + "base64 0.22.1", + "blake2", + "chacha20", + "digest", + "erased-serde", + "hex", + "iso8601", + "rand_core", + "ring", + "serde", + "serde_json", + "thiserror 1.0.69", + "time", + "zeroize", +] + [[package]] name = "ryu" version = "1.0.18" @@ -3801,9 +3947,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -3822,9 +3968,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", @@ -4134,6 +4280,12 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "typeid" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" + [[package]] name = "typenum" version = "1.17.0" @@ -4748,6 +4900,20 @@ name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] [[package]] name = "zerovec" diff --git a/Cargo.nix b/Cargo.nix index 0b7bfc4..6d9af1f 100644 --- a/Cargo.nix +++ b/Cargo.nix @@ -8,9 +8,9 @@ args@{ "chir-rs-config/default" "chir-rs-misc/default" "chir-rs-db/default" + "chir-rs-http-api/default" "chir-rs-gemini/default" "chir-rs-http/default" - "chir-rs-http-api/default" "chir-rs/default" ], rustPackages, @@ -31,7 +31,7 @@ args@{ ignoreLockHash, }: let - nixifiedLockHash = "15bd19e95e9d0f4da8a30b83aa463de93e06b1af9b257aa15d3779c3c64feae9"; + nixifiedLockHash = "73ff0a6e5f052a9577d0aac2888498a5a588a21319b04b60f8739765f62dae09"; workspaceSrc = if args.workspaceSrc == null then ./. else args.workspaceSrc; currentLockHash = builtins.hashFile "sha256" (workspaceSrc + /Cargo.lock); lockHashIgnored = @@ -95,9 +95,9 @@ else chir-rs-config = rustPackages.unknown.chir-rs-config."0.1.0"; chir-rs-misc = rustPackages.unknown.chir-rs-misc."0.1.0"; chir-rs-db = rustPackages.unknown.chir-rs-db."0.1.0"; + chir-rs-http-api = rustPackages.unknown.chir-rs-http-api."0.1.0"; chir-rs-gemini = rustPackages.unknown.chir-rs-gemini."0.1.0"; chir-rs-http = rustPackages.unknown.chir-rs-http."0.1.0"; - chir-rs-http-api = rustPackages.unknown.chir-rs-http-api."0.1.0"; chir-rs = rustPackages.unknown.chir-rs."0.1.0"; }; "registry+https://github.com/rust-lang/crates.io-index".addr2line."0.21.0" = @@ -239,6 +239,47 @@ else }; }); + "registry+https://github.com/rust-lang/crates.io-index".argon2."0.5.3" = + overridableMkRustCrate + (profileName: rec { + name = "argon2"; + version = "0.5.3"; + registry = "registry+https://github.com/rust-lang/crates.io-index"; + src = fetchCratesIo { + inherit name version; + sha256 = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072"; + }; + features = builtins.concatLists [ + [ "alloc" ] + [ "default" ] + [ "password-hash" ] + [ "rand" ] + ]; + dependencies = { + base64ct = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".base64ct."1.6.0" { + inherit profileName; + }).out; + blake2 = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".blake2."0.10.6" { + inherit profileName; + }).out; + ${ + if hostPlatform.parsed.cpu.name == "i686" || hostPlatform.parsed.cpu.name == "x86_64" then + "cpufeatures" + else + null + } = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".cpufeatures."0.2.16" { + inherit profileName; + }).out; + password_hash = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".password-hash."0.5.0" { + inherit profileName; + }).out; + }; + }); + "registry+https://github.com/rust-lang/crates.io-index".arrayref."0.3.9" = overridableMkRustCrate (profileName: rec { @@ -570,7 +611,7 @@ else inherit profileName; }).out; time = - (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time."0.3.36" { + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time."0.3.37" { inherit profileName; }).out; tokio = @@ -1254,7 +1295,7 @@ else inherit profileName; }).out; time = - (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time."0.3.36" { + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time."0.3.37" { inherit profileName; }).out; tracing = @@ -1733,7 +1774,7 @@ else inherit profileName; }).out; time = - (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time."0.3.36" { + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time."0.3.37" { inherit profileName; }).out; tokio = @@ -1935,6 +1976,32 @@ else }; }); + "registry+https://github.com/rust-lang/crates.io-index".axum-client-ip."0.6.1" = + overridableMkRustCrate + (profileName: rec { + name = "axum-client-ip"; + version = "0.6.1"; + registry = "registry+https://github.com/rust-lang/crates.io-index"; + src = fetchCratesIo { + inherit name version; + sha256 = "9eefda7e2b27e1bda4d6fa8a06b50803b8793769045918bc37ad062d48a6efac"; + }; + dependencies = { + axum = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".axum."0.7.9" { + inherit profileName; + }).out; + forwarded_header_value = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".forwarded-header-value."0.1.1" + { inherit profileName; } + ).out; + serde = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".serde."1.0.215" { + inherit profileName; + }).out; + }; + }); + "registry+https://github.com/rust-lang/crates.io-index".axum-core."0.4.5" = overridableMkRustCrate (profileName: rec { @@ -2076,6 +2143,22 @@ else }; }); + "registry+https://github.com/rust-lang/crates.io-index".b64-ct."0.1.2" = + overridableMkRustCrate + (profileName: rec { + name = "b64-ct"; + version = "0.1.2"; + registry = "registry+https://github.com/rust-lang/crates.io-index"; + src = fetchCratesIo { + inherit name version; + sha256 = "32261e5a95e234446dd31774ef4305dc164039370fe2622fd3e935a0f2730689"; + }; + features = builtins.concatLists [ + [ "default" ] + [ "std" ] + ]; + }); + "registry+https://github.com/rust-lang/crates.io-index".backtrace."0.3.71" = overridableMkRustCrate (profileName: rec { @@ -2412,6 +2495,28 @@ else }; }); + "registry+https://github.com/rust-lang/crates.io-index".blake2."0.10.6" = + overridableMkRustCrate + (profileName: rec { + name = "blake2"; + version = "0.10.6"; + registry = "registry+https://github.com/rust-lang/crates.io-index"; + src = fetchCratesIo { + inherit name version; + sha256 = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"; + }; + features = builtins.concatLists [ + [ "default" ] + [ "std" ] + ]; + dependencies = { + digest = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".digest."0.10.7" { + inherit profileName; + }).out; + }; + }); + "registry+https://github.com/rust-lang/crates.io-index".blake3."1.5.5" = overridableMkRustCrate (profileName: rec { @@ -2635,6 +2740,37 @@ else }; }); + "registry+https://github.com/rust-lang/crates.io-index".chacha20."0.9.1" = + overridableMkRustCrate + (profileName: rec { + name = "chacha20"; + version = "0.9.1"; + registry = "registry+https://github.com/rust-lang/crates.io-index"; + src = fetchCratesIo { + inherit name version; + sha256 = "c3613f74bd2eac03dad61bd53dbe620703d4371614fe0bc3b9f04dd36fe4e818"; + }; + dependencies = { + cfg_if = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".cfg-if."1.0.0" { + inherit profileName; + }).out; + cipher = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".cipher."0.4.4" { + inherit profileName; + }).out; + ${ + if hostPlatform.parsed.cpu.name == "x86_64" || hostPlatform.parsed.cpu.name == "i686" then + "cpufeatures" + else + null + } = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".cpufeatures."0.2.16" { + inherit profileName; + }).out; + }; + }); + "unknown".chir-rs."0.1.0" = overridableMkRustCrate (profileName: rec { name = "chir-rs"; version = "0.1.0"; @@ -2771,6 +2907,7 @@ else (rustPackages."registry+https://github.com/rust-lang/crates.io-index".blake3."1.5.5" { inherit profileName; }).out; + chir_rs_http_api = (rustPackages."unknown".chir-rs-http-api."0.1.0" { inherit profileName; }).out; eyre = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".eyre."0.6.12" { inherit profileName; @@ -2844,14 +2981,30 @@ else registry = "unknown"; src = fetchCrateLocal (workspaceSrc + "/chir-rs-http"); dependencies = { + argon2 = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".argon2."0.5.3" { + inherit profileName; + }).out; axum = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".axum."0.7.9" { inherit profileName; }).out; + axum_client_ip = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".axum-client-ip."0.6.1" { + inherit profileName; + }).out; axum_prometheus = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".axum-prometheus."0.7.0" { inherit profileName; }).out; + b64_ct = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".b64-ct."0.1.2" { + inherit profileName; + }).out; + base64 = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".base64."0.22.1" { + inherit profileName; + }).out; bincode = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".bincode."2.0.0-rc.3" { inherit profileName; @@ -2861,6 +3014,10 @@ else chir_rs_db = (rustPackages."unknown".chir-rs-db."0.1.0" { inherit profileName; }).out; chir_rs_http_api = (rustPackages."unknown".chir-rs-http-api."0.1.0" { inherit profileName; }).out; chir_rs_misc = (rustPackages."unknown".chir-rs-misc."0.1.0" { inherit profileName; }).out; + chrono = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".chrono."0.4.38" { + inherit profileName; + }).out; eyre = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".eyre."0.6.12" { inherit profileName; @@ -2869,6 +3026,10 @@ else (rustPackages."registry+https://github.com/rust-lang/crates.io-index".mime."0.3.17" { inherit profileName; }).out; + rusty_paseto = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".rusty_paseto."0.7.1" { + inherit profileName; + }).out; sentry_tower = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".sentry-tower."0.34.0" { inherit profileName; @@ -2885,6 +3046,10 @@ else (rustPackages."registry+https://github.com/rust-lang/crates.io-index".tracing."0.1.41" { inherit profileName; }).out; + unicode_normalization = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".unicode-normalization."0.1.24" + { inherit profileName; } + ).out; }; }); @@ -2918,6 +3083,10 @@ else (rustPackages."registry+https://github.com/rust-lang/crates.io-index".bytes."1.9.0" { inherit profileName; }).out; + educe = + (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".educe."0.6.0" { + profileName = "__noProfile"; + }).out; http = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".http."1.1.0" { inherit profileName; @@ -2926,6 +3095,10 @@ else (rustPackages."registry+https://github.com/rust-lang/crates.io-index".mime."0.3.17" { inherit profileName; }).out; + serde = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".serde."1.0.215" { + inherit profileName; + }).out; thiserror = (rustPackages."registry+https://github.com/rust-lang/crates.io-index".thiserror."2.0.3" { inherit profileName; @@ -3033,6 +3206,28 @@ else }; }); + "registry+https://github.com/rust-lang/crates.io-index".cipher."0.4.4" = + overridableMkRustCrate + (profileName: rec { + name = "cipher"; + version = "0.4.4"; + registry = "registry+https://github.com/rust-lang/crates.io-index"; + src = fetchCratesIo { + inherit name version; + sha256 = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad"; + }; + dependencies = { + crypto_common = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".crypto-common."0.1.6" { + inherit profileName; + }).out; + inout = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".inout."0.1.3" { + inherit profileName; + }).out; + }; + }); + "registry+https://github.com/rust-lang/crates.io-index".clang-sys."1.8.1" = overridableMkRustCrate (profileName: rec { @@ -3998,6 +4193,33 @@ else }; }); + "registry+https://github.com/rust-lang/crates.io-index".erased-serde."0.4.5" = + overridableMkRustCrate + (profileName: rec { + name = "erased-serde"; + version = "0.4.5"; + registry = "registry+https://github.com/rust-lang/crates.io-index"; + src = fetchCratesIo { + inherit name version; + sha256 = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d"; + }; + features = builtins.concatLists [ + [ "alloc" ] + [ "default" ] + [ "std" ] + ]; + dependencies = { + serde = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".serde."1.0.215" { + inherit profileName; + }).out; + typeid = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".typeid."1.0.2" { + inherit profileName; + }).out; + }; + }); + "registry+https://github.com/rust-lang/crates.io-index".errno."0.3.10" = overridableMkRustCrate (profileName: rec { @@ -4310,6 +4532,28 @@ else }; }); + "registry+https://github.com/rust-lang/crates.io-index".forwarded-header-value."0.1.1" = + overridableMkRustCrate + (profileName: rec { + name = "forwarded-header-value"; + version = "0.1.1"; + registry = "registry+https://github.com/rust-lang/crates.io-index"; + src = fetchCratesIo { + inherit name version; + sha256 = "8835f84f38484cc86f110a805655697908257fb9a7af005234060891557198e9"; + }; + dependencies = { + nonempty = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".nonempty."0.7.0" { + inherit profileName; + }).out; + thiserror = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".thiserror."1.0.69" { + inherit profileName; + }).out; + }; + }); + "registry+https://github.com/rust-lang/crates.io-index".fs_extra."1.3.0" = overridableMkRustCrate (profileName: rec { @@ -6142,6 +6386,24 @@ else }; }); + "registry+https://github.com/rust-lang/crates.io-index".inout."0.1.3" = + overridableMkRustCrate + (profileName: rec { + name = "inout"; + version = "0.1.3"; + registry = "registry+https://github.com/rust-lang/crates.io-index"; + src = fetchCratesIo { + inherit name version; + sha256 = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5"; + }; + dependencies = { + generic_array = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".generic-array."0.14.7" { + inherit profileName; + }).out; + }; + }); + "registry+https://github.com/rust-lang/crates.io-index".ipnet."2.10.1" = overridableMkRustCrate (profileName: rec { @@ -6158,6 +6420,28 @@ else ]; }); + "registry+https://github.com/rust-lang/crates.io-index".iso8601."0.6.1" = + overridableMkRustCrate + (profileName: rec { + name = "iso8601"; + version = "0.6.1"; + registry = "registry+https://github.com/rust-lang/crates.io-index"; + src = fetchCratesIo { + inherit name version; + sha256 = "924e5d73ea28f59011fec52a0d12185d496a9b075d360657aed2a5707f701153"; + }; + features = builtins.concatLists [ + [ "default" ] + [ "std" ] + ]; + dependencies = { + nom = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".nom."7.1.3" { + inherit profileName; + }).out; + }; + }); + "registry+https://github.com/rust-lang/crates.io-index".itertools."0.12.1" = overridableMkRustCrate (profileName: rec { @@ -6796,6 +7080,18 @@ else }; }); + "registry+https://github.com/rust-lang/crates.io-index".nonempty."0.7.0" = + overridableMkRustCrate + (profileName: rec { + name = "nonempty"; + version = "0.7.0"; + registry = "registry+https://github.com/rust-lang/crates.io-index"; + src = fetchCratesIo { + inherit name version; + sha256 = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7"; + }; + }); + "registry+https://github.com/rust-lang/crates.io-index".nu-ansi-term."0.46.0" = overridableMkRustCrate (profileName: rec { @@ -7221,6 +7517,37 @@ else }; }); + "registry+https://github.com/rust-lang/crates.io-index".password-hash."0.5.0" = + overridableMkRustCrate + (profileName: rec { + name = "password-hash"; + version = "0.5.0"; + registry = "registry+https://github.com/rust-lang/crates.io-index"; + src = fetchCratesIo { + inherit name version; + sha256 = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166"; + }; + features = builtins.concatLists [ + [ "alloc" ] + [ "default" ] + [ "rand_core" ] + ]; + dependencies = { + base64ct = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".base64ct."1.6.0" { + inherit profileName; + }).out; + rand_core = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".rand_core."0.6.4" { + inherit profileName; + }).out; + subtle = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".subtle."2.6.1" { + inherit profileName; + }).out; + }; + }); + "registry+https://github.com/rust-lang/crates.io-index".paste."1.0.15" = overridableMkRustCrate (profileName: rec { @@ -8395,6 +8722,7 @@ else [ "alloc" ] [ "default" ] [ "dev_urandom_fallback" ] + [ "std" ] [ "wasm32_unknown_unknown_js" ] ]; dependencies = { @@ -9050,6 +9378,89 @@ else }; }); + "registry+https://github.com/rust-lang/crates.io-index".rusty_paseto."0.7.1" = + overridableMkRustCrate + (profileName: rec { + name = "rusty_paseto"; + version = "0.7.1"; + registry = "registry+https://github.com/rust-lang/crates.io-index"; + src = fetchCratesIo { + inherit name version; + sha256 = "0c28b9f48df2de43da68fb7dcbd60c4f85bca5f6ae4c92cdd9540bcd4a606cb3"; + }; + features = builtins.concatLists [ + [ "batteries_included" ] + [ "blake2" ] + [ "chacha20" ] + [ "core" ] + [ "erased-serde" ] + [ "generic" ] + [ "local" ] + [ "serde" ] + [ "serde_json" ] + [ "v4" ] + [ "v4_local" ] + ]; + dependencies = { + base64 = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".base64."0.22.1" { + inherit profileName; + }).out; + blake2 = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".blake2."0.10.6" { + inherit profileName; + }).out; + chacha20 = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".chacha20."0.9.1" { + inherit profileName; + }).out; + digest = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".digest."0.10.7" { + inherit profileName; + }).out; + erased_serde = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".erased-serde."0.4.5" { + inherit profileName; + }).out; + hex = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".hex."0.4.3" { + inherit profileName; + }).out; + iso8601 = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".iso8601."0.6.1" { + inherit profileName; + }).out; + rand_core = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".rand_core."0.6.4" { + inherit profileName; + }).out; + ring = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".ring."0.17.8" { + inherit profileName; + }).out; + serde = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".serde."1.0.215" { + inherit profileName; + }).out; + serde_json = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".serde_json."1.0.133" { + inherit profileName; + }).out; + thiserror = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".thiserror."1.0.69" { + inherit profileName; + }).out; + time = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time."0.3.37" { + inherit profileName; + }).out; + zeroize = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".zeroize."1.8.1" { + inherit profileName; + }).out; + }; + }); + "registry+https://github.com/rust-lang/crates.io-index".ryu."1.0.18" = overridableMkRustCrate (profileName: rec { @@ -9656,7 +10067,7 @@ else inherit profileName; }).out; time = - (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time."0.3.36" { + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".time."0.3.37" { inherit profileName; }).out; url = @@ -11308,15 +11719,15 @@ else }; }); - "registry+https://github.com/rust-lang/crates.io-index".time."0.3.36" = + "registry+https://github.com/rust-lang/crates.io-index".time."0.3.37" = overridableMkRustCrate (profileName: rec { name = "time"; - version = "0.3.36"; + version = "0.3.37"; registry = "registry+https://github.com/rust-lang/crates.io-index"; src = fetchCratesIo { inherit name version; - sha256 = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"; + sha256 = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21"; }; features = builtins.concatLists [ [ "alloc" ] @@ -11351,7 +11762,7 @@ else inherit profileName; }).out; time_macros = - (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".time-macros."0.2.18" { + (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".time-macros."0.2.19" { profileName = "__noProfile"; }).out; }; @@ -11369,15 +11780,15 @@ else }; }); - "registry+https://github.com/rust-lang/crates.io-index".time-macros."0.2.18" = + "registry+https://github.com/rust-lang/crates.io-index".time-macros."0.2.19" = overridableMkRustCrate (profileName: rec { name = "time-macros"; - version = "0.2.18"; + version = "0.2.19"; registry = "registry+https://github.com/rust-lang/crates.io-index"; src = fetchCratesIo { inherit name version; - sha256 = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf"; + sha256 = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de"; }; features = builtins.concatLists [ [ "formatting" ] @@ -12286,6 +12697,18 @@ else }; }); + "registry+https://github.com/rust-lang/crates.io-index".typeid."1.0.2" = + overridableMkRustCrate + (profileName: rec { + name = "typeid"; + version = "1.0.2"; + registry = "registry+https://github.com/rust-lang/crates.io-index"; + src = fetchCratesIo { + inherit name version; + sha256 = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e"; + }; + }); + "registry+https://github.com/rust-lang/crates.io-index".typenum."1.17.0" = overridableMkRustCrate (profileName: rec { @@ -13953,7 +14376,40 @@ else features = builtins.concatLists [ [ "alloc" ] [ "default" ] + [ "zeroize_derive" ] ]; + dependencies = { + zeroize_derive = + (buildRustPackages."registry+https://github.com/rust-lang/crates.io-index".zeroize_derive."1.4.2" { + profileName = "__noProfile"; + }).out; + }; + }); + + "registry+https://github.com/rust-lang/crates.io-index".zeroize_derive."1.4.2" = + overridableMkRustCrate + (profileName: rec { + name = "zeroize_derive"; + version = "1.4.2"; + registry = "registry+https://github.com/rust-lang/crates.io-index"; + src = fetchCratesIo { + inherit name version; + sha256 = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"; + }; + dependencies = { + proc_macro2 = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".proc-macro2."1.0.92" { + inherit profileName; + }).out; + quote = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".quote."1.0.37" { + inherit profileName; + }).out; + syn = + (rustPackages."registry+https://github.com/rust-lang/crates.io-index".syn."2.0.90" { + inherit profileName; + }).out; + }; }); "registry+https://github.com/rust-lang/crates.io-index".zerovec."0.10.4" = diff --git a/chir-rs-config/src/lib.rs b/chir-rs-config/src/lib.rs index a851066..e1f359c 100644 --- a/chir-rs-config/src/lib.rs +++ b/chir-rs-config/src/lib.rs @@ -218,6 +218,8 @@ pub struct ChirRs { pub s3: S3Config, /// Ca Cache max size in bytes pub cache_max_size: u64, + /// Paseto secret key file + pub paseto_secret_key_file: String, } impl ChirRs { diff --git a/chir-rs-db/Cargo.toml b/chir-rs-db/Cargo.toml index ed99685..15da796 100644 --- a/chir-rs-db/Cargo.toml +++ b/chir-rs-db/Cargo.toml @@ -12,6 +12,7 @@ tracing = "0.1.40" blake3 = { version = "1.5.4", features = ["serde"] } tokio = { version = "1.41.1", features = ["fs", "macros", "rt", "sync"] } mime = "0.3.17" +chir-rs-http-api = { version = "0.1.0", path = "../chir-rs-http-api" } [lints.rust] deprecated-safe = "forbid" diff --git a/chir-rs-db/migrations/20241130090439_service-user-account.sql b/chir-rs-db/migrations/20241130090439_service-user-account.sql deleted file mode 100644 index 16e5063..0000000 --- a/chir-rs-db/migrations/20241130090439_service-user-account.sql +++ /dev/null @@ -1,2 +0,0 @@ --- Add migration script here -INSERT INTO "user" (username, password_hash) VALUES ('service-raccount', ''); \ No newline at end of file diff --git a/chir-rs-db/src/user.rs b/chir-rs-db/src/user.rs index 4ee5f6b..7bede3c 100644 --- a/chir-rs-db/src/user.rs +++ b/chir-rs-db/src/user.rs @@ -1,9 +1,13 @@ //! User-related APIs +use std::{collections::HashSet, fmt::Debug}; + use bincode::{Decode, Encode}; +use chir_rs_http_api::auth::Scope; use eyre::{Context, Result}; use serde::{Deserialize, Serialize}; use sqlx::{prelude::FromRow, query}; +use tracing::instrument; use crate::Database; @@ -23,7 +27,7 @@ impl User { /// /// # Errors /// An error occurs if accessing the database fails - #[allow(clippy::missing_panics_doc, reason = "sqlx moment")] + #[instrument(skip(db))] pub async fn get(db: &Database, username: &str) -> Result> { #[allow(clippy::panic, reason = "sqlx moment")] let res = query!(r#"SELECT * FROM "user" WHERE username = $1"#, username) @@ -41,4 +45,38 @@ impl User { Ok(None) } } + + /// Creates a new session for user + /// + /// The caller has to ensure that the user has authorized this. + /// + /// # Errors + /// An error occurs if accessing the database fails + #[instrument(skip(db))] + #[allow(clippy::panic, reason = "sqlx moment")] + pub async fn new_session(&self, db: &Database, scopes: HashSet) -> Result { + let mut txn = db.0.begin().await?; + let user_id: i64 = self.id.try_into()?; + + let session = query!( + "INSERT INTO sessions (user_id) VALUES ($1) RETURNING (id)", + user_id + ) + .fetch_one(&mut *txn) + .await?; + + for scope in scopes { + query!( + "INSERT INTO session_scopes (session_id, scope) VALUES ($1, $2)", + session.id, + scope.to_i64() + ) + .execute(&mut *txn) + .await?; + } + + txn.commit().await?; + + Ok(session.id) + } } diff --git a/chir-rs-http-api/Cargo.toml b/chir-rs-http-api/Cargo.toml index a565a03..385f827 100644 --- a/chir-rs-http-api/Cargo.toml +++ b/chir-rs-http-api/Cargo.toml @@ -11,8 +11,10 @@ async-trait = { version = "0.1.83", optional = true } axum-core = { version = "0.4.5", optional = true } bincode = "2.0.0-rc.3" bytes = { version = "1.8.0", optional = true } +educe = { version = "0.6.0", default-features = false, features = ["Debug"] } http = "1.1.0" mime = { version = "0.3.17", optional = true } +serde = { version = "1.0.215", features = ["derive"] } thiserror = "2.0.3" tracing = { version = "0.1.40", optional = true } diff --git a/chir-rs-http-api/src/auth/mod.rs b/chir-rs-http-api/src/auth/mod.rs new file mode 100644 index 0000000..8acc131 --- /dev/null +++ b/chir-rs-http-api/src/auth/mod.rs @@ -0,0 +1,36 @@ +use std::collections::HashSet; + +/// Authentication APIs +use bincode::{Decode, Encode}; +use educe::Educe; +use serde::{Deserialize, Serialize}; + +/// List of supported scopes for authentication +#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Encode, Decode, Hash)] +pub enum Scope { + /// Full scope granted by logging in. + Full, +} + +impl Scope { + /// Converts the scope into an integer suitable for database storage + #[must_use] + pub const fn to_i64(self) -> i64 { + match self { + Self::Full => 0, + } + } +} + +/// Login request for the user +#[derive(Clone, Educe, Serialize, Deserialize, Encode, Decode)] +#[educe(Debug)] +pub struct LoginRequest { + /// Username + pub username: String, + /// Password + #[educe(Debug(ignore))] + pub password: String, + /// Scopes + pub scopes: HashSet, +} diff --git a/chir-rs-http-api/src/errors/mod.rs b/chir-rs-http-api/src/errors/mod.rs index a10520b..8c72d85 100644 --- a/chir-rs-http-api/src/errors/mod.rs +++ b/chir-rs-http-api/src/errors/mod.rs @@ -33,6 +33,15 @@ pub enum APIError { /// Returned when the error is unknown #[error("Unknown Error")] Unknown(String), + /// Returned when there is a database error + #[error("Database error: {0}")] + DatabaseError(String), + /// Returned when the specified user was not found + #[error("Resource not found: {0}")] + UserNotFound(String), + /// Invalid password + #[error("Invalid password for user {0}")] + InvalidPassword(String), } impl APIError { @@ -45,7 +54,8 @@ impl APIError { } Self::PayloadTooBig => StatusCode::PAYLOAD_TOO_LARGE, Self::PayloadLoadError | Self::PayloadInvalid => StatusCode::BAD_REQUEST, - Self::Unknown(_) => StatusCode::INTERNAL_SERVER_ERROR, + Self::UserNotFound(_) | Self::InvalidPassword(_) => StatusCode::UNAUTHORIZED, + Self::Unknown(_) | Self::DatabaseError(_) => StatusCode::INTERNAL_SERVER_ERROR, } } } diff --git a/chir-rs-http-api/src/lib.rs b/chir-rs-http-api/src/lib.rs index d33baa4..8666725 100644 --- a/chir-rs-http-api/src/lib.rs +++ b/chir-rs-http-api/src/lib.rs @@ -1,5 +1,6 @@ //! API Type Definitions for chir.rs +pub mod auth; #[cfg(feature = "axum")] pub mod axum; pub mod errors; diff --git a/chir-rs-http/Cargo.toml b/chir-rs-http/Cargo.toml index aef1db6..caf2d04 100644 --- a/chir-rs-http/Cargo.toml +++ b/chir-rs-http/Cargo.toml @@ -4,8 +4,12 @@ version = "0.1.0" edition = "2021" [dependencies] +argon2 = "0.5.3" axum = { version = "0.7.9", features = ["tracing"] } +axum-client-ip = "0.6.1" axum-prometheus = "0.7.0" +b64-ct = "0.1.2" +base64 = "0.22.1" bincode = "2.0.0-rc.3" chir-rs-castore = { version = "0.1.0", path = "../chir-rs-castore" } chir-rs-config = { version = "0.1.0", path = "../chir-rs-config" } @@ -16,12 +20,15 @@ chir-rs-http-api = { version = "0.1.0", path = "../chir-rs-http-api", features = chir-rs-misc = { version = "0.1.0", path = "../chir-rs-misc", features = [ "base64", ] } +chrono = "0.4.38" eyre = "0.6.12" mime = "0.3.17" +rusty_paseto = { version = "0.7.1", default-features = false, features = ["batteries_included", "v4_local"] } sentry-tower = { version = "0.34.0", features = ["axum", "axum-matched-path"] } -tokio = { version = "1.41.1", features = ["net"] } +tokio = { version = "1.41.1", features = ["fs", "net"] } tower-http = { version = "0.6.2", features = ["trace"] } tracing = "0.1.40" +unicode-normalization = "0.1.24" [lints.rust] deprecated-safe = "forbid" diff --git a/chir-rs-http/src/auth/mod.rs b/chir-rs-http/src/auth/mod.rs new file mode 100644 index 0000000..07a6281 --- /dev/null +++ b/chir-rs-http/src/auth/mod.rs @@ -0,0 +1,3 @@ +//! Authentication related functionality + +pub mod password_login; diff --git a/chir-rs-http/src/auth/password_login/mod.rs b/chir-rs-http/src/auth/password_login/mod.rs new file mode 100644 index 0000000..94935be --- /dev/null +++ b/chir-rs-http/src/auth/password_login/mod.rs @@ -0,0 +1,82 @@ +//! Password based login flow + +use argon2::{Argon2, PasswordHash, PasswordVerifier}; +use axum::extract::State; +use chir_rs_db::user::User; +use chir_rs_http_api::{auth::LoginRequest, axum::bincode::Bincode, errors::APIError}; +use chrono::{Days, Utc}; +use eyre::{Context as _, OptionExt}; +use rusty_paseto::{ + core::{Local, V4}, + prelude::{ + AudienceClaim, ExpirationClaim, IssuerClaim, PasetoBuilder, SubjectClaim, + TokenIdentifierClaim, + }, +}; +use tokio::task::spawn_blocking; +use tracing::instrument; +use unicode_normalization::UnicodeNormalization; + +use crate::AppState; + +/// Logs in using username and password +#[instrument] +pub async fn login( + State(state): State, + Bincode(login_request): Bincode, +) -> Result, APIError> { + let Some(user_info) = User::get(&state.db, &login_request.username) + .await + .with_context(|| format!("Fetching user info for {}", login_request.username)) + .map_err(|e| APIError::DatabaseError(format!("{e:?}")))? + else { + return Err(APIError::UserNotFound(login_request.username)); + }; + + let password = login_request.password.trim().nfkc().collect::(); + + let pwhash = user_info.password_hash.clone(); + + spawn_blocking(move || { + let pwhash = PasswordHash::new(&pwhash)?; + Argon2::default().verify_password(password.as_bytes(), &pwhash) + }) + .await + .with_context(|| { + format!( + "Hashing password for login request for {}", + login_request.username + ) + }) + .map_err(|e| APIError::Unknown(format!("{e:?}")))? + .map_err(|_| APIError::InvalidPassword(login_request.username.clone()))?; + + let session_id = user_info + .new_session(&state.db, login_request.scopes) + .await + .with_context(|| format!("Creating context for {}", login_request.username)) + .map_err(|e| APIError::DatabaseError(format!("{e:?}")))? + .to_string(); + + let now = Utc::now(); + let tomorrow = now + .checked_add_days(Days::new(1)) + .ok_or_eyre("We should not be running several thousand years in the future!") + .map_err(|e| APIError::Unknown(format!("{e:?}")))?; + + let token = PasetoBuilder::::default() + .set_claim(AudienceClaim::from("https://lotte.chir.rs")) + .set_claim(SubjectClaim::from(login_request.username.as_str())) + .set_claim(IssuerClaim::from("https://lotte.chir.rs")) + .set_claim(TokenIdentifierClaim::from(session_id.as_str())) + .set_claim( + ExpirationClaim::try_from(tomorrow.to_rfc3339().as_str()) + .context("valid date") + .map_err(|e| APIError::Unknown(format!("{e:?}")))?, + ) + .build(&state.paseto_key) + .context("Signing paseto key") + .map_err(|e| APIError::Unknown(format!("{e:?}")))?; + + Ok(Bincode(token)) +} diff --git a/chir-rs-http/src/lib.rs b/chir-rs-http/src/lib.rs index 8ac0cb7..b7a4396 100644 --- a/chir-rs-http/src/lib.rs +++ b/chir-rs-http/src/lib.rs @@ -1,32 +1,43 @@ //! HTTP server implementation for chir-rs -use std::sync::Arc; +use std::{fmt::Debug, sync::Arc}; use axum::{ extract::{MatchedPath, Request, State}, http::StatusCode, - routing::get, + routing::{get, post}, Router, }; use axum_prometheus::PrometheusMetricLayer; +use b64_ct::FromBase64; use chir_rs_castore::CaStore; use chir_rs_config::ChirRs; use chir_rs_db::Database; use chir_rs_http_api::{axum::bincode::Bincode, readiness::ReadyState}; -use eyre::{Context, Result}; +use eyre::{bail, eyre, Context, Result}; +use rusty_paseto::core::{Key, Local, PasetoSymmetricKey, V4}; use tokio::net::TcpListener; use tower_http::trace::TraceLayer; use tracing::{error, info, info_span}; +pub mod auth; pub mod ca_server; /// Application state -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct AppState { /// Database handle pub db: Database, /// CA store handle pub ca: CaStore, + /// PASETO private key + pub paseto_key: Arc>, +} + +impl Debug for AppState { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("AppState").finish_non_exhaustive() + } } /// Entrypoint for the HTTP server component @@ -36,6 +47,16 @@ pub struct AppState { /// /// Errors it encounters during runtime should be automatically handled. pub async fn main(cfg: Arc, db: Database, castore: CaStore) -> Result<()> { + let paseto_symmetric_key = + tokio::fs::read_to_string(cfg.paseto_secret_key_file.clone()).await?; + let paseto_symmetric_key = paseto_symmetric_key + .from_base64() + .map_err(|e| eyre!("{e:?}"))?; + if paseto_symmetric_key.len() != 32 { + bail!("Invalid symmetric key size"); + } + let paseto_symmetric_key = PasetoSymmetricKey::from(Key::from(paseto_symmetric_key.as_slice())); + let (prometheus_layer, metric_handle) = PrometheusMetricLayer::pair(); let app = Router::new() // Routes here @@ -58,8 +79,13 @@ pub async fn main(cfg: Arc, db: Database, castore: CaStore) -> Result<() "/.api/metrics", get(|| async move { metric_handle.render() }), ) + .route("/.api/auth/login", post(auth::password_login::login)) .fallback(get(ca_server::serve_files)) - .with_state(AppState { db, ca: castore }) + .with_state(AppState { + db, + ca: castore, + paseto_key: Arc::new(paseto_symmetric_key), + }) .layer( TraceLayer::new_for_http().make_span_with(|request: &Request<_>| { let matched_path = request diff --git a/config-example.toml b/config-example.toml index b454d5b..9be1704 100644 --- a/config-example.toml +++ b/config-example.toml @@ -1,5 +1,6 @@ # Maximum size of the in-memory object cache. cache_max_size = 32_000_000 +paseto_secret_key_file = "secrets/paseto-secret" [logging] #sentry_dsn = "…" diff --git a/flake.nix b/flake.nix index 5a72477..3caefdc 100644 --- a/flake.nix +++ b/flake.nix @@ -77,6 +77,8 @@ sqlx-cli cargo-expand sqlite + treefmt + nixfmt-rfc-style ]; }; packages = pkgs.lib.mapAttrs (_: v: (v { }).overrideAttrs { dontStrip = true; }) rustPkgs.workspace; diff --git a/treefmt.toml b/treefmt.toml new file mode 100644 index 0000000..95f5bb6 --- /dev/null +++ b/treefmt.toml @@ -0,0 +1,56 @@ +# One CLI to format the code tree - https://github.com/numtide/treefmt + +# Do not exit with error if a configured formatter is missing +# Env $TREEFMT_ALLOW_MISSING_FORMATTER +# allow-missing-formatter = true + +# The file into which a cpu profile will be written +# Env $TREEFMT_CPU_PROFILE +# cpu-profile = ./cpu.pprof + +# Exclude files or directories matching the specified globs +# Env $TREEFMT_EXCLUDES +# excludes = ["*.md", "*.gif"] + +# Exit with error if any changes were made during execution +# Useful for CI +# Env $TREEFMT_FAIL_ON_CHANGE +# fail-on-change = true + +# A list of formatters to apply +# Defaults to all configured formatters +# Env $TREEFMT_FORMATTERS +# formatters = ["gofmt", "prettier"] + +# Log paths that did not match any formatters at the specified log level +# Possible values are +# Env $TREEFMT_ON_UNMATCHED +# on-unmatched = "info" + +# The root directory from which treefmt will start walking the filesystem +# Defaults to the directory containing the config file +# Env $TREEFMT_TREE_ROOT +# tree-root = "/tmp/foo" + +# File to search for to find the tree root (if tree-root is not set) +# Env $TREEFMT_TREE_ROOT_FILE +# tree-root-file = ".git/config" + +# Set the verbosity of logs +# 0 = warn, 1 = info, 2 = debug +# Env $TREEFMT_VERBOSE +# verbose = 2 + +# The method used to traverse the files within the tree root +# Currently, we support 'auto', 'git' or 'filesystem' +# Env $TREEFMT_WALK +# walk = "filesystem" + +[formatter.nix] +command = "nixfmt" +includes = ["*.nix"] + +[formatter.rust] +command = "rustfmt" +options = ["--edition", "2021"] +includes = ["*.rs"]