mirror of
https://github.com/zaphar/kitchen.git
synced 2025-07-21 19:29:49 -04:00
Get SQLX to work
This commit is contained in:
parent
242cf8eddd
commit
26a98ae89a
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
@ -2,4 +2,8 @@
|
||||
"rust-analyzer.diagnostics.disabled": [
|
||||
"macro-error"
|
||||
],
|
||||
"rust-analyzer.cargo.noDefaultFeatures": false,
|
||||
"rust-analyzer.cargo.features": [
|
||||
"sqlite"
|
||||
],
|
||||
}
|
588
Cargo.lock
generated
588
Cargo.lock
generated
@ -146,6 +146,24 @@ dependencies = [
|
||||
"event-listener",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-process"
|
||||
version = "1.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02111fd8655a613c25069ea89fc8d9bb89331fa77486eb3bc059ee757cfa481c"
|
||||
dependencies = [
|
||||
"async-io",
|
||||
"autocfg",
|
||||
"blocking",
|
||||
"cfg-if 1.0.0",
|
||||
"event-listener",
|
||||
"futures-lite",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"signal-hook",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-session"
|
||||
version = "3.0.0"
|
||||
@ -164,7 +182,7 @@ dependencies = [
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"sha2 0.9.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -177,6 +195,7 @@ dependencies = [
|
||||
"async-global-executor",
|
||||
"async-io",
|
||||
"async-lock",
|
||||
"async-process",
|
||||
"crossbeam-utils",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
@ -210,6 +229,15 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atoi"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d7c57d12312ff59c811c0643f4d80830505833c9ffaebd193d819392b265be8e"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.0.0"
|
||||
@ -411,6 +439,12 @@ version = "3.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "1.2.0"
|
||||
@ -474,7 +508,7 @@ dependencies = [
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"time",
|
||||
"time 0.1.44",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
@ -566,6 +600,16 @@ version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "94d4706de1b0fa5b132270cddffa8585166037822e260a944fe161acd137ca05"
|
||||
dependencies = [
|
||||
"time 0.3.14",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.2"
|
||||
@ -575,6 +619,31 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "53757d12b596c16c78b83458d732a5d1a17ab3f53f2f7412f6fb57cc8a140ab3"
|
||||
dependencies = [
|
||||
"crc-catalog",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crc-catalog"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2d0165d2900ae6778e36e80bbc4da3b5eefccee9ba939761f9c2882a5d9af3ff"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-queue"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1cd42583b04998a5363558e5f9291ee5a5ff6b49944332103f251e7479a82aa7"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.8.10"
|
||||
@ -667,6 +736,44 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "4.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
|
||||
dependencies = [
|
||||
"dirs-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs-sys"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"redox_users",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dotenvy"
|
||||
version = "0.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da3db6fcad7c1fc4abdd99bf5276a4db30d6a819127903a709ed41e5ff016e84"
|
||||
dependencies = [
|
||||
"dirs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.5.2"
|
||||
@ -682,6 +789,18 @@ dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flume"
|
||||
version = "0.10.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"pin-project",
|
||||
"spin 0.9.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fnv"
|
||||
version = "1.0.7"
|
||||
@ -705,6 +824,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -713,6 +833,28 @@ version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3"
|
||||
|
||||
[[package]]
|
||||
name = "futures-executor"
|
||||
version = "0.3.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-task",
|
||||
"futures-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-intrusive"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"lock_api",
|
||||
"parking_lot",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-io"
|
||||
version = "0.3.21"
|
||||
@ -734,6 +876,17 @@ dependencies = [
|
||||
"waker-fn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-rustls"
|
||||
version = "0.22.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d2411eed028cdf8c8034eaf21f9915f956b6c3abec4d4c7949ee67f0721127bd"
|
||||
dependencies = [
|
||||
"futures-io",
|
||||
"rustls",
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-sink"
|
||||
version = "0.3.21"
|
||||
@ -753,9 +906,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a"
|
||||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-task",
|
||||
"pin-project-lite",
|
||||
"pin-utils",
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -858,6 +1013,18 @@ name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d452c155cb93fecdfb02a73dd57b5d8e442c2063bd7aac72f1bc5e4263a43086"
|
||||
dependencies = [
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "headers"
|
||||
@ -884,6 +1051,15 @@ dependencies = [
|
||||
"http",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
@ -893,6 +1069,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.11.0"
|
||||
@ -967,6 +1149,17 @@ dependencies = [
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8"
|
||||
dependencies = [
|
||||
"matches",
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.1"
|
||||
@ -986,6 +1179,15 @@ dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.8"
|
||||
@ -1028,6 +1230,7 @@ dependencies = [
|
||||
"axum-auth",
|
||||
"ciborium",
|
||||
"clap",
|
||||
"cookie",
|
||||
"csv",
|
||||
"mime_guess",
|
||||
"recipe-store",
|
||||
@ -1036,6 +1239,7 @@ dependencies = [
|
||||
"rust-embed",
|
||||
"secrecy",
|
||||
"serde",
|
||||
"sqlx",
|
||||
"tower",
|
||||
"tower-http",
|
||||
"tracing",
|
||||
@ -1186,6 +1390,17 @@ dependencies = [
|
||||
"zstd-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.24.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "898745e570c7d0453cc1fbc4a701eb6c662ed54e8fec8b7d14be137ebeeb9d14"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libz-sys"
|
||||
version = "1.1.8"
|
||||
@ -1197,6 +1412,16 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.4.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9f80bf5aacaf25cbfc8210d1cfb718f2bf3b11c4c54e5afe36c236853a8ec390"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"scopeguard",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
@ -1321,6 +1546,15 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_threads"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.13.0"
|
||||
@ -1345,6 +1579,31 @@ version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
||||
dependencies = [
|
||||
"instant",
|
||||
"lock_api",
|
||||
"parking_lot_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"instant",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"smallvec",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "password-hash"
|
||||
version = "0.4.2"
|
||||
@ -1502,6 +1761,26 @@ dependencies = [
|
||||
"num-rational",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.6.0"
|
||||
@ -1534,6 +1813,21 @@ dependencies = [
|
||||
"gloo-net",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.16.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"spin 0.5.2",
|
||||
"untrusted",
|
||||
"web-sys",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rocksdb"
|
||||
version = "0.19.0"
|
||||
@ -1574,7 +1868,7 @@ version = "7.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "756feca3afcbb1487a1d01f4ecd94cf8ec98ea074c55a69e7136d29fb6166029"
|
||||
dependencies = [
|
||||
"sha2",
|
||||
"sha2 0.9.9",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
@ -1584,6 +1878,27 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.20.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aab8ee6c7097ed6057f43c187a62418d0c05a4bd5f18b3571db50ee0f9ce033"
|
||||
dependencies = [
|
||||
"log",
|
||||
"ring",
|
||||
"sct",
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustls-pemfile"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0864aeff53f8c05aa08d86e5ef839d3dfcf07aeba2db32f12db0ef716e87bd55"
|
||||
dependencies = [
|
||||
"base64",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.10"
|
||||
@ -1599,6 +1914,22 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "sct"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "secrecy"
|
||||
version = "0.8.0"
|
||||
@ -1676,6 +2007,17 @@ dependencies = [
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "899bf02746a2c92bf1053d9327dadb252b01af1f81f90cdb902411f518bc7215"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cpufeatures",
|
||||
"digest 0.10.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sharded-slab"
|
||||
version = "0.1.4"
|
||||
@ -1691,6 +2033,25 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a253b5e89e2698464fc26b545c9edceb338e18a89effeeecfea192c3025be29d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.7"
|
||||
@ -1716,12 +2077,136 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f6002a767bff9e83f8eeecf883ecb8011875a21ae8da43bffb817a57e78cc09"
|
||||
dependencies = [
|
||||
"lock_api",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlformat"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4"
|
||||
dependencies = [
|
||||
"itertools",
|
||||
"nom",
|
||||
"unicode_categories",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlx"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "788841def501aabde58d3666fcea11351ec3962e6ea75dbcd05c84a71d68bcd1"
|
||||
dependencies = [
|
||||
"sqlx-core",
|
||||
"sqlx-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-core"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c21d3b5e7cadfe9ba7cdc1295f72cc556c750b4419c27c219c0693198901f8e"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"atoi",
|
||||
"bitflags",
|
||||
"byteorder",
|
||||
"bytes",
|
||||
"crc",
|
||||
"crossbeam-queue",
|
||||
"dotenvy",
|
||||
"either",
|
||||
"event-listener",
|
||||
"flume",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-executor",
|
||||
"futures-intrusive",
|
||||
"futures-util",
|
||||
"hashlink",
|
||||
"hex",
|
||||
"indexmap",
|
||||
"itoa 1.0.2",
|
||||
"libc",
|
||||
"libsqlite3-sys",
|
||||
"log",
|
||||
"memchr",
|
||||
"once_cell",
|
||||
"paste",
|
||||
"percent-encoding",
|
||||
"rustls",
|
||||
"rustls-pemfile",
|
||||
"serde",
|
||||
"sha2 0.10.3",
|
||||
"smallvec",
|
||||
"sqlformat",
|
||||
"sqlx-rt",
|
||||
"stringprep",
|
||||
"thiserror",
|
||||
"url",
|
||||
"webpki-roots",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-macros"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4adfd2df3557bddd3b91377fc7893e8fa899e9b4061737cbade4e1bb85f1b45c"
|
||||
dependencies = [
|
||||
"dotenvy",
|
||||
"either",
|
||||
"heck",
|
||||
"hex",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.10.3",
|
||||
"sqlx-core",
|
||||
"sqlx-rt",
|
||||
"syn",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlx-rt"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7be52fc7c96c136cedea840ed54f7d446ff31ad670c9dea95ebcb998530971a3"
|
||||
dependencies = [
|
||||
"async-std",
|
||||
"futures-rustls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "stringprep"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ee348cb74b87454fff4b551cbf727025810a004f88aeacae7f85b87f4e9a1c1"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.10.0"
|
||||
@ -1851,6 +2336,39 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c3f9a28b618c3a6b9251b6908e9c99e04b9e5c02e6581ccbb67d59c34ef7f9b"
|
||||
dependencies = [
|
||||
"itoa 1.0.2",
|
||||
"libc",
|
||||
"num_threads",
|
||||
"time-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42657b1a6f4d817cda8e7a0ace261fe0cc946cf3a80314390b22cc61ae080792"
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec"
|
||||
version = "1.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
|
||||
dependencies = [
|
||||
"tinyvec_macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinyvec_macros"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.20.0"
|
||||
@ -2023,12 +2541,57 @@ dependencies = [
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6"
|
||||
dependencies = [
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
|
||||
|
||||
[[package]]
|
||||
name = "unicode_categories"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.7.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"matches",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.1.2"
|
||||
@ -2184,6 +2747,25 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
|
||||
dependencies = [
|
||||
"ring",
|
||||
"untrusted",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.22.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1c760f0d366a6c24a02ed7816e23e691f5d92291f94d15e836006fd11b04daf"
|
||||
dependencies = [
|
||||
"webpki",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wepoll-ffi"
|
||||
version = "0.1.2"
|
||||
|
3
Makefile
3
Makefile
@ -12,6 +12,9 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
sqlx-prepare: wasm kitches/src/*.rs
|
||||
cd kitchen; cargo sqlx-prepare
|
||||
|
||||
kitchen: wasm kitchen/src/*.rs
|
||||
cd kitchen; cargo build
|
||||
|
||||
|
@ -56,9 +56,7 @@
|
||||
type = "app";
|
||||
program = "${kitchen}/bin/kitchen";
|
||||
};
|
||||
devShell = pkgs.mkShell {
|
||||
buildInputs = [ rust-wasm ] ++ (with pkgs; [wasm-bindgen-cli wasm-pack]);
|
||||
};
|
||||
devShell = pkgs.callPackage ./nix/devShell/default.nix { inherit rust-wasm; };
|
||||
}
|
||||
);
|
||||
}
|
@ -17,9 +17,9 @@ mime_guess = "2.0.4"
|
||||
async-trait = "0.1.57"
|
||||
async-session = "3.0.0"
|
||||
ciborium = "0.2.0"
|
||||
rocksdb = "0.19.0"
|
||||
tower = "0.4.13"
|
||||
serde = "1.0.144"
|
||||
cookie = "0.16.0"
|
||||
|
||||
[dependencies.argon2]
|
||||
version = "0.4.1"
|
||||
@ -50,4 +50,18 @@ features = [ "cargo" ]
|
||||
|
||||
[dependencies.async-std]
|
||||
version = "1.10.0"
|
||||
features = ["tokio1"]
|
||||
features = ["tokio1"]
|
||||
|
||||
[dependencies.sqlx]
|
||||
version = "0.6.1"
|
||||
features = ["sqlite", "runtime-async-std-rustls", "offline"]
|
||||
optional = true
|
||||
|
||||
[dependencies.rocksdb]
|
||||
version = "0.19.0"
|
||||
optional = true
|
||||
|
||||
[features]
|
||||
sqlite = ["dep:sqlx"]
|
||||
rocksdb = ["dep:rocksdb"]
|
||||
default = ["sqlite"]
|
3
kitchen/migrations/20220831185348_initial.down.sql
Normal file
3
kitchen/migrations/20220831185348_initial.down.sql
Normal file
@ -0,0 +1,3 @@
|
||||
-- Add down migration script here
|
||||
drop table sessions;
|
||||
drop table users;
|
3
kitchen/migrations/20220831185348_initial.up.sql
Normal file
3
kitchen/migrations/20220831185348_initial.up.sql
Normal file
@ -0,0 +1,3 @@
|
||||
-- Add migration script here
|
||||
CREATE TABLE sessions(id TEXT PRIMARY KEY, session_value BLOB NOT NULL);
|
||||
CREATE TABLE users(id TEXT PRIMARY KEY, password_hashed TEXT NOT NULL);
|
79
kitchen/sqlx-data.json
Normal file
79
kitchen/sqlx-data.json
Normal file
@ -0,0 +1,79 @@
|
||||
{
|
||||
"db": "SQLite",
|
||||
"104f07472670436d3eee1733578bbf0c92dc4f965d3d13f9bf4bfbc92958c5b6": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "password_hashed",
|
||||
"ordinal": 0,
|
||||
"type_info": "Text"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
false
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
}
|
||||
},
|
||||
"query": "select password_hashed from users where id = ?"
|
||||
},
|
||||
"5d743897fb0d8fd54c3708f1b1c6e416346201faa9e28823c1ba5a421472b1fa": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"nullable": [],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
}
|
||||
},
|
||||
"query": "insert into users (id, password_hashed) values (?, ?)"
|
||||
},
|
||||
"7578157607967a6a4c60f12408c5d9900d15b429a49681a4cae4e02d31c524ec": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"nullable": [],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
}
|
||||
},
|
||||
"query": "delete from sessions where id = ?"
|
||||
},
|
||||
"928a479ca0f765ec7715bf8784c5490e214486edbf5b78fd501823feb328375b": {
|
||||
"describe": {
|
||||
"columns": [
|
||||
{
|
||||
"name": "session_value",
|
||||
"ordinal": 0,
|
||||
"type_info": "Blob"
|
||||
}
|
||||
],
|
||||
"nullable": [
|
||||
false
|
||||
],
|
||||
"parameters": {
|
||||
"Right": 1
|
||||
}
|
||||
},
|
||||
"query": "select session_value from sessions where id = ?"
|
||||
},
|
||||
"9ad4acd9b9d32c9f9f441276aa71a17674fe4d65698848044778bd4aef77d42d": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"nullable": [],
|
||||
"parameters": {
|
||||
"Right": 2
|
||||
}
|
||||
},
|
||||
"query": "insert into sessions (id, session_value) values (?, ?)"
|
||||
},
|
||||
"d84685a82585c5e4ae72c86ba1fe6e4a7241c4c3c9e948213e5849d956132bad": {
|
||||
"describe": {
|
||||
"columns": [],
|
||||
"nullable": [],
|
||||
"parameters": {
|
||||
"Right": 0
|
||||
}
|
||||
},
|
||||
"query": "delete from sessions"
|
||||
}
|
||||
}
|
@ -45,14 +45,14 @@ fn create_app<'a>() -> clap::App<'a> {
|
||||
(@subcommand serve =>
|
||||
(about: "Serve the interface via the web")
|
||||
(@arg recipe_dir: -d --dir +takes_value "Directory containing recipe files to use")
|
||||
(@arg session_dir: --sesion_dir + takes_value "Session store directory to use")
|
||||
(@arg session_dir: --session_dir + takes_value "Session store directory to use")
|
||||
(@arg listen: --listen +takes_value "address and port to listen on 0.0.0.0:3030")
|
||||
)
|
||||
(@subcommand add_user =>
|
||||
(about: "add users to to the interface")
|
||||
(@arg user: -u --user +takes_value +required "username to add")
|
||||
(@arg pass: -p --pass +takes_value +required "password to add for this user")
|
||||
(@arg session_dir: --sesion_dir +takes_value "Session store directory to use")
|
||||
(@arg session_dir: --session_dir +takes_value "Session store directory to use")
|
||||
)
|
||||
)
|
||||
.setting(clap::AppSettings::SubcommandRequiredElseHelp)
|
||||
@ -139,10 +139,13 @@ fn main() {
|
||||
});
|
||||
} else if let Some(matches) = matches.subcommand_matches("add_user") {
|
||||
let session_store_path: PathBuf = get_session_store_path(matches);
|
||||
web::add_user(
|
||||
session_store_path,
|
||||
matches.value_of("user").unwrap().to_owned(),
|
||||
matches.value_of("pass").unwrap().to_owned(),
|
||||
);
|
||||
async_std::task::block_on(async {
|
||||
web::add_user(
|
||||
session_store_path,
|
||||
matches.value_of("user").unwrap().to_owned(),
|
||||
matches.value_of("pass").unwrap().to_owned(),
|
||||
)
|
||||
.await;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -20,22 +20,23 @@ use axum::{
|
||||
response::IntoResponse,
|
||||
};
|
||||
use axum_auth::AuthBasic;
|
||||
use cookie::{Cookie, SameSite};
|
||||
use secrecy::Secret;
|
||||
use tracing::{debug, info, instrument};
|
||||
|
||||
use super::session;
|
||||
use super::session::{self, AuthStore};
|
||||
|
||||
#[instrument(skip_all, fields(user=%auth.0.0))]
|
||||
pub async fn handler(
|
||||
auth: AuthBasic,
|
||||
Extension(session_store): Extension<session::RocksdbInnerStore>,
|
||||
Extension(session_store): Extension<session::SqliteStore>,
|
||||
) -> impl IntoResponse {
|
||||
// NOTE(jwall): It is very important that you do **not** log the password
|
||||
// here. We convert the AuthBasic into UserCreds immediately to help prevent
|
||||
// that. Do not circumvent that protection.
|
||||
let auth = session::UserCreds::from(auth);
|
||||
info!("Handling authentication request");
|
||||
if let Ok(true) = session_store.check_user_creds(&auth) {
|
||||
if let Ok(true) = session_store.check_user_creds(&auth).await {
|
||||
debug!("successfully authenticated user");
|
||||
// 1. Create a session identifier.
|
||||
let mut session = Session::new();
|
||||
@ -44,17 +45,11 @@ pub async fn handler(
|
||||
let cookie_value = session_store.store_session(session).await.unwrap().unwrap();
|
||||
let mut headers = HeaderMap::new();
|
||||
// 3. Construct the Session Cookie.
|
||||
// TODO(jwall): Find or Build a cookie builder.
|
||||
headers.insert(
|
||||
header::SET_COOKIE,
|
||||
format!(
|
||||
"{}={} SameSite=Strict Secure",
|
||||
session::AXUM_SESSION_COOKIE_NAME,
|
||||
cookie_value
|
||||
)
|
||||
.parse()
|
||||
.unwrap(),
|
||||
);
|
||||
let cookie = Cookie::build(session::AXUM_SESSION_COOKIE_NAME, cookie_value)
|
||||
.same_site(SameSite::Strict)
|
||||
.secure(true)
|
||||
.finish();
|
||||
headers.insert(header::SET_COOKIE, cookie.to_string().parse().unwrap());
|
||||
// Respond with 200 OK
|
||||
(StatusCode::OK, headers, "Login Successful")
|
||||
} else {
|
||||
|
@ -29,6 +29,8 @@ use tower::ServiceBuilder;
|
||||
use tower_http::trace::TraceLayer;
|
||||
use tracing::{debug, info, instrument};
|
||||
|
||||
use session::AuthStore;
|
||||
|
||||
mod auth;
|
||||
mod session;
|
||||
|
||||
@ -113,8 +115,9 @@ async fn api_categories(
|
||||
result
|
||||
}
|
||||
|
||||
pub fn add_user(session_store_path: PathBuf, username: String, password: String) {
|
||||
let session_store = session::RocksdbInnerStore::new(session_store_path)
|
||||
pub async fn add_user(session_store_path: PathBuf, username: String, password: String) {
|
||||
let session_store = session::SqliteStore::new(session_store_path)
|
||||
.await
|
||||
.expect("Unable to create session_store");
|
||||
let user_creds = session::UserCreds {
|
||||
id: session::UserId(username),
|
||||
@ -122,6 +125,7 @@ pub fn add_user(session_store_path: PathBuf, username: String, password: String)
|
||||
};
|
||||
session_store
|
||||
.store_user_creds(user_creds)
|
||||
.await
|
||||
.expect("Failed to store user creds");
|
||||
}
|
||||
|
||||
@ -133,7 +137,8 @@ pub async fn ui_main(
|
||||
) {
|
||||
let store = Arc::new(recipe_store::AsyncFileStore::new(recipe_dir_path.clone()));
|
||||
//let dir_path = (&dir_path).clone();
|
||||
let session_store = session::RocksdbInnerStore::new(session_store_path)
|
||||
let session_store = session::SqliteStore::new(session_store_path)
|
||||
.await
|
||||
.expect("Unable to create session_store");
|
||||
let router = Router::new()
|
||||
.route("/", get(|| async { Redirect::temporary("/ui/plan") }))
|
||||
|
@ -18,13 +18,16 @@ use argon2::{
|
||||
password_hash::{rand_core::OsRng, PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
|
||||
Argon2,
|
||||
};
|
||||
use async_session::{async_trait, Session, SessionStore};
|
||||
use async_session::{Session, SessionStore};
|
||||
use async_trait::async_trait;
|
||||
use axum::{
|
||||
extract::{Extension, FromRequest, RequestParts, TypedHeader},
|
||||
headers::Cookie,
|
||||
http::StatusCode,
|
||||
};
|
||||
use ciborium;
|
||||
use cookie::{Cookie as CookieParse, SameSite};
|
||||
#[cfg(feature = "rocksdb")]
|
||||
use rocksdb::{
|
||||
BoundColumnFamily, ColumnFamilyDescriptor, DBWithThreadMode, MultiThreaded, Options,
|
||||
};
|
||||
@ -57,12 +60,40 @@ impl UserCreds {
|
||||
}
|
||||
}
|
||||
|
||||
fn make_id_key(cookie_value: &str) -> async_session::Result<String> {
|
||||
debug!("deserializing cookie");
|
||||
Ok(Session::id_from_cookie_value(cookie_value)?)
|
||||
}
|
||||
|
||||
#[instrument(skip_all, fields(hash=payload))]
|
||||
fn check_pass(payload: &String, pass: &Secret<String>) -> bool {
|
||||
let parsed_hash = PasswordHash::new(&payload).expect("Invalid Password Hash");
|
||||
debug!(password_hash=?parsed_hash, "successfuly obtained password hash");
|
||||
let check = Argon2::default().verify_password(pass.expose_secret().as_bytes(), &parsed_hash);
|
||||
if let Err(err) = &check {
|
||||
debug!(err=?err, "Couldn't verify password");
|
||||
return false;
|
||||
}
|
||||
check.is_ok()
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait AuthStore: SessionStore {
|
||||
/// Check user credentials against the user store.
|
||||
async fn check_user_creds(&self, user_creds: &UserCreds) -> async_session::Result<bool>;
|
||||
|
||||
/// Insert or update user credentials in the user store.
|
||||
async fn store_user_creds(&self, user_creds: UserCreds) -> async_session::Result<()>;
|
||||
}
|
||||
|
||||
#[cfg(feature = "rocksdb")]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RocksdbInnerStore {
|
||||
pub struct RocksdbStore {
|
||||
db: Arc<DBWithThreadMode<MultiThreaded>>,
|
||||
}
|
||||
|
||||
impl RocksdbInnerStore {
|
||||
#[cfg(feature = "rocksdb")]
|
||||
impl RocksdbStore {
|
||||
pub fn new<P: AsRef<Path>>(name: P) -> Result<Self, rocksdb::Error> {
|
||||
let session_cf_opts = Options::default();
|
||||
let session_cf = ColumnFamilyDescriptor::new(SESSION_CF, session_cf_opts);
|
||||
@ -87,57 +118,14 @@ impl RocksdbInnerStore {
|
||||
fn get_users_column_family_handle(&self) -> Option<Arc<BoundColumnFamily>> {
|
||||
self.db.cf_handle(USER_CF)
|
||||
}
|
||||
|
||||
fn make_id_key(cookie_value: &str) -> async_session::Result<String> {
|
||||
Ok(Session::id_from_cookie_value(cookie_value)?)
|
||||
}
|
||||
|
||||
#[instrument(fields(user=%user_creds.id.0), skip_all)]
|
||||
pub fn check_user_creds(&self, user_creds: &UserCreds) -> async_session::Result<bool> {
|
||||
info!("checking credentials for user");
|
||||
let cf_handle = self
|
||||
.get_users_column_family_handle()
|
||||
.expect(&format!("column family {} is missing", USER_CF));
|
||||
if let Some(payload) = self.db.get_cf(&cf_handle, user_creds.id.0.as_bytes())? {
|
||||
debug!("Found user in credential store");
|
||||
let payload = String::from_utf8_lossy(payload.as_slice()).to_string();
|
||||
let parsed_hash = PasswordHash::new(&payload).expect("Invalid Password Hash");
|
||||
debug!(password_hash=?parsed_hash, "successfuly obtained password hash");
|
||||
let check = Argon2::default()
|
||||
.verify_password(user_creds.pass.expose_secret().as_bytes(), &parsed_hash);
|
||||
if let Err(err) = &check {
|
||||
debug!(err=?err, "Couldn't verify password")
|
||||
}
|
||||
return Ok(check.is_ok());
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
#[instrument(fields(user=%user_creds.id.0), skip_all)]
|
||||
pub fn store_user_creds(&self, user_creds: UserCreds) -> async_session::Result<()> {
|
||||
// TODO(jwall): Enforce a password length?
|
||||
info!("storing credentials for user {}", user_creds.id.0);
|
||||
let cf_handle = self
|
||||
.get_users_column_family_handle()
|
||||
.expect(&format!("column family {} is missing", USER_CF));
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let password_hash = Argon2::default()
|
||||
.hash_password(user_creds.pass.expose_secret().as_bytes(), &salt)
|
||||
.expect("failed to hash password");
|
||||
self.db.put_cf(
|
||||
&cf_handle,
|
||||
user_creds.id.0.as_bytes(),
|
||||
password_hash.to_string().as_bytes(),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rocksdb")]
|
||||
#[async_trait]
|
||||
impl SessionStore for RocksdbInnerStore {
|
||||
impl SessionStore for RocksdbStore {
|
||||
#[instrument]
|
||||
async fn load_session(&self, cookie_value: String) -> async_session::Result<Option<Session>> {
|
||||
let id = Self::make_id_key(&cookie_value)?;
|
||||
let id = make_id_key(&cookie_value)?;
|
||||
let cf_handle = self
|
||||
.get_session_column_family_handle()
|
||||
.expect(&format!("column family {} is missing", SESSION_CF));
|
||||
@ -178,6 +166,49 @@ impl SessionStore for RocksdbInnerStore {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rocksdb")]
|
||||
#[async_trait]
|
||||
impl AuthStore for RocksdbStore {
|
||||
#[instrument(fields(user=%user_creds.id.0), skip_all)]
|
||||
async fn check_user_creds(&self, user_creds: &UserCreds) -> async_session::Result<bool> {
|
||||
// TODO(jwall): Make this function asynchronous.
|
||||
info!("checking credentials for user");
|
||||
let cf_handle = self
|
||||
.get_users_column_family_handle()
|
||||
.expect(&format!("column family {} is missing", USER_CF));
|
||||
if let Some(payload) = self
|
||||
.db
|
||||
.get_cf(&cf_handle, user_creds.user_id().as_bytes())?
|
||||
{
|
||||
debug!("Found user in credential store");
|
||||
let payload = String::from_utf8_lossy(payload.as_slice()).to_string();
|
||||
return Ok(check_pass(&payload, &user_creds.pass));
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
// TODO(jwall): Make this function asynchronous.
|
||||
#[instrument(fields(user=%user_creds.id.0), skip_all)]
|
||||
async fn store_user_creds(&self, user_creds: UserCreds) -> async_session::Result<()> {
|
||||
// TODO(jwall): Enforce a password length?
|
||||
// TODO(jwall): Make this function asynchronous.
|
||||
info!("storing credentials for user {}", user_creds.id.0);
|
||||
let cf_handle = self
|
||||
.get_users_column_family_handle()
|
||||
.expect(&format!("column family {} is missing", USER_CF));
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let password_hash = Argon2::default()
|
||||
.hash_password(user_creds.pass.expose_secret().as_bytes(), &salt)
|
||||
.expect("failed to hash password");
|
||||
self.db.put_cf(
|
||||
&cf_handle,
|
||||
user_creds.id.0.as_bytes(),
|
||||
password_hash.to_string().as_bytes(),
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<B> FromRequest<B> for UserIdFromSession
|
||||
where
|
||||
@ -187,7 +218,7 @@ where
|
||||
|
||||
#[instrument(skip_all)]
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
let Extension(session_store) = Extension::<RocksdbInnerStore>::from_request(req)
|
||||
let Extension(session_store) = Extension::<SqliteStore>::from_request(req)
|
||||
.await
|
||||
.expect("No Session store configured!");
|
||||
let cookies = Option::<TypedHeader<Cookie>>::from_request(req)
|
||||
@ -197,20 +228,24 @@ where
|
||||
.as_ref()
|
||||
.and_then(|c| c.get(AXUM_SESSION_COOKIE_NAME))
|
||||
{
|
||||
if let Some(session) = session_store
|
||||
.load_session(session_cookie.to_owned())
|
||||
.await
|
||||
.unwrap()
|
||||
{
|
||||
if let Some(user_id) = session.get::<UserId>("user_id") {
|
||||
return Ok(Self::FoundUserId(user_id));
|
||||
} else {
|
||||
error!("No user id found in session");
|
||||
debug!(?session_cookie, "processing session cookie");
|
||||
match session_store.load_session(session_cookie.to_owned()).await {
|
||||
Ok(Some(session)) => {
|
||||
if let Some(user_id) = session.get::<UserId>("user_id") {
|
||||
return Ok(Self::FoundUserId(user_id));
|
||||
} else {
|
||||
error!("No user id found in session");
|
||||
return Ok(Self::NoUserId);
|
||||
}
|
||||
}
|
||||
Ok(None) => {
|
||||
debug!("no session defined in headers.");
|
||||
return Ok(Self::NoUserId);
|
||||
}
|
||||
Err(e) => {
|
||||
debug!(err=?e, "error deserializing session");
|
||||
return Ok(Self::NoUserId);
|
||||
}
|
||||
} else {
|
||||
debug!("no session defined in headers.");
|
||||
return Ok(Self::NoUserId);
|
||||
}
|
||||
} else {
|
||||
debug!("no cookies defined in headers.");
|
||||
@ -218,3 +253,119 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "sqlite")]
|
||||
use sqlx::{
|
||||
self,
|
||||
sqlite::{SqliteConnectOptions, SqliteJournalMode},
|
||||
SqlitePool,
|
||||
};
|
||||
#[cfg(feature = "sqlite")]
|
||||
use std::str::FromStr;
|
||||
|
||||
#[cfg(feature = "sqlite")]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SqliteStore {
|
||||
pool: Arc<SqlitePool>,
|
||||
url: String,
|
||||
}
|
||||
|
||||
#[cfg(feature = "sqlite")]
|
||||
impl SqliteStore {
|
||||
pub async fn new<P: AsRef<Path>>(path: P) -> sqlx::Result<Self> {
|
||||
let url = format!("sqlite://{}/store.db", path.as_ref().to_string_lossy());
|
||||
let options = SqliteConnectOptions::from_str(&url)?.journal_mode(SqliteJournalMode::Wal);
|
||||
let pool = Arc::new(sqlx::SqlitePool::connect_with(options).await?);
|
||||
Ok(Self { pool, url })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "sqlite")]
|
||||
#[async_trait]
|
||||
impl SessionStore for SqliteStore {
|
||||
#[instrument(fields(conn_string=self.url), skip_all)]
|
||||
async fn load_session(&self, cookie_value: String) -> async_session::Result<Option<Session>> {
|
||||
let id = make_id_key(&cookie_value)?;
|
||||
debug!(id, "fetching session from sqlite");
|
||||
if let Some(payload) =
|
||||
sqlx::query_scalar!("select session_value from sessions where id = ?", id)
|
||||
.fetch_optional(self.pool.as_ref())
|
||||
.await?
|
||||
{
|
||||
debug!(sesion_id = id, "found session key");
|
||||
let session: Session = ciborium::de::from_reader(payload.as_slice())?;
|
||||
return Ok(Some(session));
|
||||
}
|
||||
return Ok(None);
|
||||
}
|
||||
|
||||
#[instrument(fields(conn_string=self.url), skip_all)]
|
||||
async fn store_session(&self, session: Session) -> async_session::Result<Option<String>> {
|
||||
let id = session.id();
|
||||
let mut payload: Vec<u8> = Vec::new();
|
||||
ciborium::ser::into_writer(&session, &mut payload)?;
|
||||
sqlx::query!(
|
||||
"insert into sessions (id, session_value) values (?, ?)",
|
||||
id,
|
||||
payload
|
||||
)
|
||||
.execute(self.pool.as_ref())
|
||||
.await?;
|
||||
debug!(sesion_id = id, "successfully inserted session key");
|
||||
return Ok(session.into_cookie_value());
|
||||
}
|
||||
|
||||
#[instrument(fields(conn_string=self.url), skip_all)]
|
||||
async fn destroy_session(&self, session: Session) -> async_session::Result {
|
||||
let id = session.id();
|
||||
sqlx::query!("delete from sessions where id = ?", id,)
|
||||
.execute(self.pool.as_ref())
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
#[instrument(fields(conn_string=self.url), skip_all)]
|
||||
async fn clear_store(&self) -> async_session::Result {
|
||||
sqlx::query!("delete from sessions")
|
||||
.execute(self.pool.as_ref())
|
||||
.await?;
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "sqlite")]
|
||||
#[async_trait]
|
||||
impl AuthStore for SqliteStore {
|
||||
#[instrument(fields(user=%user_creds.id.0, conn_string=self.url), skip_all)]
|
||||
async fn check_user_creds(&self, user_creds: &UserCreds) -> async_session::Result<bool> {
|
||||
let id = user_creds.user_id().to_owned();
|
||||
if let Some(payload) =
|
||||
sqlx::query_scalar!("select password_hashed from users where id = ?", id)
|
||||
.fetch_optional(self.pool.as_ref())
|
||||
.await?
|
||||
{
|
||||
debug!("Testing password for user");
|
||||
return Ok(check_pass(&payload, &user_creds.pass));
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
#[instrument(fields(user=%user_creds.id.0, conn_string=self.url), skip_all)]
|
||||
async fn store_user_creds(&self, user_creds: UserCreds) -> async_session::Result<()> {
|
||||
let salt = SaltString::generate(&mut OsRng);
|
||||
let password_hash = Argon2::default()
|
||||
.hash_password(user_creds.pass.expose_secret().as_bytes(), &salt)
|
||||
.expect("failed to hash password");
|
||||
let id = user_creds.user_id().to_owned();
|
||||
let password_hashed = password_hash.to_string();
|
||||
debug!("adding password for user");
|
||||
sqlx::query!(
|
||||
"insert into users (id, password_hashed) values (?, ?)",
|
||||
id,
|
||||
password_hashed,
|
||||
)
|
||||
.execute(self.pool.as_ref())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
6
nix/devShell/default.nix
Normal file
6
nix/devShell/default.nix
Normal file
@ -0,0 +1,6 @@
|
||||
{ pkgs, rust-wasm }:
|
||||
with pkgs;
|
||||
mkShell {
|
||||
buildInputs = (if stdenv.isDarwin then [ pkgs.darwin.apple_sdk.frameworks.Security ] else [ ]) ++ (with pkgs; [wasm-bindgen-cli wasm-pack llvm clang rust-wasm]);
|
||||
#buildInputs = with pkgs; [wasm-bindgen-cli wasm-pack];
|
||||
}
|
@ -13,7 +13,7 @@ with pkgs;
|
||||
buildInputs = [ rust-wasm ];
|
||||
# However the crate we are building has it's root in specific crate.
|
||||
src = root;
|
||||
nativeBuildInputs = if stdenv.isDarwin then [ xcbuild ] else [ ];
|
||||
nativeBuildInputs = (if stdenv.isDarwin then [ xcbuild pkgs.darwin.apple_sdk.frameworks.Security ] else [ ]) ++ [llvm clang];
|
||||
cargoBuildOptions = opts: opts ++ ["-p" "${pname}" ];
|
||||
postPatch = ''
|
||||
mkdir -p web/dist
|
||||
|
@ -56,6 +56,7 @@ pub fn login_form() -> View<G> {
|
||||
if username != "" && password != "" {
|
||||
spawn_local_in_scope(async move {
|
||||
debug!("authenticating against ui");
|
||||
// TODO(jwall): Navigate to plan if the below is successful.
|
||||
authenticate(username, password).await;
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user