diff --git a/.gitignore b/.gitignore
index 0db7192..027175b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@
zig-out
.zig-cache
freebsd.txt
+/sparse-server/db.sqlite*
diff --git a/Cargo.lock b/Cargo.lock
index 599ba14..d62d436 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -26,6 +26,12 @@ dependencies = [
"memchr",
]
+[[package]]
+name = "allocator-api2"
+version = "0.2.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
+
[[package]]
name = "android-tzdata"
version = "0.1.1"
@@ -90,6 +96,15 @@ dependencies = [
"syn 2.0.96",
]
+[[package]]
+name = "atoi"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f28d99ec8bfea296261ca1af174f24225171fea9664ba9003cbebee704810528"
+dependencies = [
+ "num-traits",
+]
+
[[package]]
name = "atomic-waker"
version = "1.1.2"
@@ -234,7 +249,7 @@ dependencies = [
"miniz_oxide",
"object",
"rustc-demangle",
- "windows-targets",
+ "windows-targets 0.52.6",
]
[[package]]
@@ -243,6 +258,12 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
+[[package]]
+name = "base64ct"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
+
[[package]]
name = "bindgen"
version = "0.69.5"
@@ -277,6 +298,9 @@ name = "bitflags"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
+dependencies = [
+ "serde",
+]
[[package]]
name = "block-buffer"
@@ -346,7 +370,7 @@ dependencies = [
"js-sys",
"num-traits",
"wasm-bindgen",
- "windows-targets",
+ "windows-targets 0.52.6",
]
[[package]]
@@ -424,6 +448,12 @@ dependencies = [
"wasm-bindgen",
]
+[[package]]
+name = "const-oid"
+version = "0.9.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
+
[[package]]
name = "const_format"
version = "0.2.34"
@@ -474,6 +504,30 @@ dependencies = [
"libc",
]
+[[package]]
+name = "crc"
+version = "3.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636"
+dependencies = [
+ "crc-catalog",
+]
+
+[[package]]
+name = "crc-catalog"
+version = "2.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5"
+
+[[package]]
+name = "crossbeam-queue"
+version = "0.3.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115"
+dependencies = [
+ "crossbeam-utils",
+]
+
[[package]]
name = "crossbeam-utils"
version = "0.8.21"
@@ -557,6 +611,17 @@ dependencies = [
"syn 2.0.96",
]
+[[package]]
+name = "der"
+version = "0.7.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0"
+dependencies = [
+ "const-oid",
+ "pem-rfc7468",
+ "zeroize",
+]
+
[[package]]
name = "derive-where"
version = "1.2.7"
@@ -575,7 +640,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
+ "const-oid",
"crypto-common",
+ "subtle",
]
[[package]]
@@ -589,6 +656,12 @@ dependencies = [
"syn 2.0.96",
]
+[[package]]
+name = "dotenvy"
+version = "0.15.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
+
[[package]]
name = "drain_filter_polyfill"
version = "0.1.3"
@@ -600,6 +673,9 @@ name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
+dependencies = [
+ "serde",
+]
[[package]]
name = "either_of"
@@ -635,6 +711,17 @@ dependencies = [
"windows-sys 0.59.0",
]
+[[package]]
+name = "etcetera"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "136d1b5283a1ab77bd9257427ffd09d8667ced0570b6f938942bc7568ed5b943"
+dependencies = [
+ "cfg-if",
+ "home",
+ "windows-sys 0.48.0",
+]
+
[[package]]
name = "event-listener"
version = "5.4.0"
@@ -656,12 +743,35 @@ dependencies = [
"pin-project-lite",
]
+[[package]]
+name = "fastrand"
+version = "2.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
+
+[[package]]
+name = "flume"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da0e4dd2a88388a1f4ccc7c9ce104604dab68d9f408dc34cd45823d5a9069095"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+ "spin",
+]
+
[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+[[package]]
+name = "foldhash"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f"
+
[[package]]
name = "form_urlencoded"
version = "1.2.1"
@@ -714,6 +824,17 @@ dependencies = [
"num_cpus",
]
+[[package]]
+name = "futures-intrusive"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f"
+dependencies = [
+ "futures-core",
+ "lock_api",
+ "parking_lot",
+]
+
[[package]]
name = "futures-io"
version = "0.3.31"
@@ -866,6 +987,20 @@ name = "hashbrown"
version = "0.15.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289"
+dependencies = [
+ "allocator-api2",
+ "equivalent",
+ "foldhash",
+]
+
+[[package]]
+name = "hashlink"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
+dependencies = [
+ "hashbrown 0.15.2",
+]
[[package]]
name = "heck"
@@ -876,6 +1011,12 @@ dependencies = [
"unicode-segmentation",
]
+[[package]]
+name = "heck"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
+
[[package]]
name = "hermit-abi"
version = "0.1.19"
@@ -891,6 +1032,30 @@ version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
+[[package]]
+name = "hkdf"
+version = "0.12.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7"
+dependencies = [
+ "hmac",
+]
+
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest",
+]
+
[[package]]
name = "home"
version = "0.5.11"
@@ -1245,6 +1410,9 @@ name = "lazy_static"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+dependencies = [
+ "spin",
+]
[[package]]
name = "lazycell"
@@ -1503,7 +1671,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [
"cfg-if",
- "windows-targets",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "libm"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa"
+
+[[package]]
+name = "libsqlite3-sys"
+version = "0.30.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2e99fb7a497b1e3339bc746195567ed8d3e24945ecd636e3619d20b9de9e9149"
+dependencies = [
+ "cc",
+ "pkg-config",
+ "vcpkg",
]
[[package]]
@@ -1578,6 +1763,16 @@ version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
+[[package]]
+name = "md-5"
+version = "0.10.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf"
+dependencies = [
+ "cfg-if",
+ "digest",
+]
+
[[package]]
name = "memchr"
version = "2.7.4"
@@ -1677,6 +1872,43 @@ dependencies = [
"winapi",
]
+[[package]]
+name = "num-bigint-dig"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151"
+dependencies = [
+ "byteorder",
+ "lazy_static",
+ "libm",
+ "num-integer",
+ "num-iter",
+ "num-traits",
+ "rand",
+ "smallvec",
+ "zeroize",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-iter"
+version = "0.1.45"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
[[package]]
name = "num-traits"
version = "0.2.19"
@@ -1684,6 +1916,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
+ "libm",
]
[[package]]
@@ -1763,7 +1996,18 @@ dependencies = [
"libc",
"redox_syscall",
"smallvec",
- "windows-targets",
+ "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]]
@@ -1778,6 +2022,18 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3"
+[[package]]
+name = "pbkdf2"
+version = "0.12.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2"
+dependencies = [
+ "digest",
+ "hmac",
+ "password-hash",
+ "sha2",
+]
+
[[package]]
name = "pcap-sys"
version = "0.1.0"
@@ -1790,6 +2046,15 @@ dependencies = [
"tokio-stream",
]
+[[package]]
+name = "pem-rfc7468"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412"
+dependencies = [
+ "base64ct",
+]
+
[[package]]
name = "percent-encoding"
version = "2.3.1"
@@ -1828,6 +2093,33 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+[[package]]
+name = "pkcs1"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f"
+dependencies = [
+ "der",
+ "pkcs8",
+ "spki",
+]
+
+[[package]]
+name = "pkcs8"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7"
+dependencies = [
+ "der",
+ "spki",
+]
+
+[[package]]
+name = "pkg-config"
+version = "0.3.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
+
[[package]]
name = "ppv-lite86"
version = "0.2.20"
@@ -2104,6 +2396,37 @@ dependencies = [
"windows-sys 0.52.0",
]
+[[package]]
+name = "rpassword"
+version = "7.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f"
+dependencies = [
+ "libc",
+ "rtoolbox",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
+name = "rsa"
+version = "0.9.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519"
+dependencies = [
+ "const-oid",
+ "digest",
+ "num-bigint-dig",
+ "num-integer",
+ "num-traits",
+ "pkcs1",
+ "pkcs8",
+ "rand_core",
+ "signature",
+ "spki",
+ "subtle",
+ "zeroize",
+]
+
[[package]]
name = "rstml"
version = "0.12.1"
@@ -2119,6 +2442,16 @@ dependencies = [
"thiserror 2.0.11",
]
+[[package]]
+name = "rtoolbox"
+version = "0.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e"
+dependencies = [
+ "libc",
+ "windows-sys 0.48.0",
+]
+
[[package]]
name = "rustc-demangle"
version = "0.1.24"
@@ -2361,6 +2694,17 @@ dependencies = [
"digest",
]
+[[package]]
+name = "sha2"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest",
+]
+
[[package]]
name = "sharded-slab"
version = "0.1.7"
@@ -2376,6 +2720,16 @@ version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+[[package]]
+name = "signature"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
+dependencies = [
+ "digest",
+ "rand_core",
+]
+
[[package]]
name = "slab"
version = "0.4.9"
@@ -2399,6 +2753,9 @@ name = "smallvec"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+dependencies = [
+ "serde",
+]
[[package]]
name = "socket2"
@@ -2439,16 +2796,22 @@ dependencies = [
"anyhow",
"axum",
"axum-server",
+ "chrono",
"codee",
"console_error_panic_hook",
"futures",
"futures-util",
+ "hex",
"http",
"leptos",
"leptos-use",
"leptos_axum",
"leptos_meta",
"leptos_router",
+ "pbkdf2",
+ "rpassword",
+ "sha2",
+ "sqlx",
"structopt",
"thiserror 1.0.69",
"tokio",
@@ -2474,6 +2837,210 @@ name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+dependencies = [
+ "lock_api",
+]
+
+[[package]]
+name = "spki"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
+dependencies = [
+ "base64ct",
+ "der",
+]
+
+[[package]]
+name = "sqlx"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4410e73b3c0d8442c5f99b425d7a435b5ee0ae4167b3196771dd3f7a01be745f"
+dependencies = [
+ "sqlx-core",
+ "sqlx-macros",
+ "sqlx-mysql",
+ "sqlx-postgres",
+ "sqlx-sqlite",
+]
+
+[[package]]
+name = "sqlx-core"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a007b6936676aa9ab40207cde35daab0a04b823be8ae004368c0793b96a61e0"
+dependencies = [
+ "bytes",
+ "chrono",
+ "crc",
+ "crossbeam-queue",
+ "either",
+ "event-listener",
+ "futures-core",
+ "futures-intrusive",
+ "futures-io",
+ "futures-util",
+ "hashbrown 0.15.2",
+ "hashlink",
+ "indexmap",
+ "log",
+ "memchr",
+ "once_cell",
+ "percent-encoding",
+ "serde",
+ "serde_json",
+ "sha2",
+ "smallvec",
+ "thiserror 2.0.11",
+ "tokio",
+ "tokio-stream",
+ "tracing",
+ "url",
+]
+
+[[package]]
+name = "sqlx-macros"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3112e2ad78643fef903618d78cf0aec1cb3134b019730edb039b69eaf531f310"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "sqlx-core",
+ "sqlx-macros-core",
+ "syn 2.0.96",
+]
+
+[[package]]
+name = "sqlx-macros-core"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e9f90acc5ab146a99bf5061a7eb4976b573f560bc898ef3bf8435448dd5e7ad"
+dependencies = [
+ "dotenvy",
+ "either",
+ "heck 0.5.0",
+ "hex",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "serde_json",
+ "sha2",
+ "sqlx-core",
+ "sqlx-mysql",
+ "sqlx-postgres",
+ "sqlx-sqlite",
+ "syn 2.0.96",
+ "tempfile",
+ "tokio",
+ "url",
+]
+
+[[package]]
+name = "sqlx-mysql"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4560278f0e00ce64938540546f59f590d60beee33fffbd3b9cd47851e5fff233"
+dependencies = [
+ "atoi",
+ "base64",
+ "bitflags 2.8.0",
+ "byteorder",
+ "bytes",
+ "chrono",
+ "crc",
+ "digest",
+ "dotenvy",
+ "either",
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-util",
+ "generic-array",
+ "hex",
+ "hkdf",
+ "hmac",
+ "itoa",
+ "log",
+ "md-5",
+ "memchr",
+ "once_cell",
+ "percent-encoding",
+ "rand",
+ "rsa",
+ "serde",
+ "sha1",
+ "sha2",
+ "smallvec",
+ "sqlx-core",
+ "stringprep",
+ "thiserror 2.0.11",
+ "tracing",
+ "whoami",
+]
+
+[[package]]
+name = "sqlx-postgres"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c5b98a57f363ed6764d5b3a12bfedf62f07aa16e1856a7ddc2a0bb190a959613"
+dependencies = [
+ "atoi",
+ "base64",
+ "bitflags 2.8.0",
+ "byteorder",
+ "chrono",
+ "crc",
+ "dotenvy",
+ "etcetera",
+ "futures-channel",
+ "futures-core",
+ "futures-util",
+ "hex",
+ "hkdf",
+ "hmac",
+ "home",
+ "itoa",
+ "log",
+ "md-5",
+ "memchr",
+ "once_cell",
+ "rand",
+ "serde",
+ "serde_json",
+ "sha2",
+ "smallvec",
+ "sqlx-core",
+ "stringprep",
+ "thiserror 2.0.11",
+ "tracing",
+ "whoami",
+]
+
+[[package]]
+name = "sqlx-sqlite"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f85ca71d3a5b24e64e1d08dd8fe36c6c95c339a896cc33068148906784620540"
+dependencies = [
+ "atoi",
+ "chrono",
+ "flume",
+ "futures-channel",
+ "futures-core",
+ "futures-executor",
+ "futures-intrusive",
+ "futures-util",
+ "libsqlite3-sys",
+ "log",
+ "percent-encoding",
+ "serde",
+ "serde_urlencoded",
+ "sqlx-core",
+ "tracing",
+ "url",
+]
[[package]]
name = "stable_deref_trait"
@@ -2481,6 +3048,17 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
+[[package]]
+name = "stringprep"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7b4df3d392d81bd458a8a621b8bffbd2302a12ffe288a9d931670948749463b1"
+dependencies = [
+ "unicode-bidi",
+ "unicode-normalization",
+ "unicode-properties",
+]
+
[[package]]
name = "strsim"
version = "0.8.0"
@@ -2510,7 +3088,7 @@ version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dcb5ae327f9cc13b68763b5749770cb9e048a99bd9dfdfa58d0cf05d5f64afe0"
dependencies = [
- "heck",
+ "heck 0.3.3",
"proc-macro-error",
"proc-macro2",
"quote",
@@ -2606,6 +3184,20 @@ dependencies = [
"web-sys",
]
+[[package]]
+name = "tempfile"
+version = "3.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
+dependencies = [
+ "cfg-if",
+ "fastrand",
+ "getrandom",
+ "once_cell",
+ "rustix",
+ "windows-sys 0.59.0",
+]
+
[[package]]
name = "textwrap"
version = "0.11.0"
@@ -2684,6 +3276,21 @@ dependencies = [
"zerovec",
]
+[[package]]
+name = "tinyvec"
+version = "1.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "022db8904dfa342efe721985167e9fcd16c29b226db4397ed752a761cfce81e8"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
[[package]]
name = "tokio"
version = "1.43.0"
@@ -3009,12 +3616,33 @@ version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
+[[package]]
+name = "unicode-bidi"
+version = "0.3.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
+
[[package]]
name = "unicode-ident"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11cd88e12b17c6494200a9c1b683a04fcac9573ed74cd1b62aeb2727c5592243"
+[[package]]
+name = "unicode-normalization"
+version = "0.1.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "unicode-properties"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0"
+
[[package]]
name = "unicode-segmentation"
version = "1.12.0"
@@ -3089,6 +3717,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
[[package]]
name = "vec_map"
version = "0.8.2"
@@ -3117,6 +3751,12 @@ version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+[[package]]
+name = "wasite"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b"
+
[[package]]
name = "wasm-bindgen"
version = "0.2.100"
@@ -3223,6 +3863,16 @@ dependencies = [
"rustix",
]
+[[package]]
+name = "whoami"
+version = "1.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d"
+dependencies = [
+ "redox_syscall",
+ "wasite",
+]
+
[[package]]
name = "winapi"
version = "0.3.9"
@@ -3260,7 +3910,16 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
dependencies = [
- "windows-targets",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets 0.48.5",
]
[[package]]
@@ -3269,7 +3928,7 @@ version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
dependencies = [
- "windows-targets",
+ "windows-targets 0.52.6",
]
[[package]]
@@ -3278,7 +3937,22 @@ version = "0.59.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
dependencies = [
- "windows-targets",
+ "windows-targets 0.52.6",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
]
[[package]]
@@ -3287,28 +3961,46 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
+ "windows_aarch64_gnullvm 0.52.6",
+ "windows_aarch64_msvc 0.52.6",
+ "windows_i686_gnu 0.52.6",
"windows_i686_gnullvm",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "windows_i686_msvc 0.52.6",
+ "windows_x86_64_gnu 0.52.6",
+ "windows_x86_64_gnullvm 0.52.6",
+ "windows_x86_64_msvc 0.52.6",
]
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
[[package]]
name = "windows_aarch64_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
[[package]]
name = "windows_i686_gnu"
version = "0.52.6"
@@ -3321,24 +4013,48 @@ version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
[[package]]
name = "windows_i686_msvc"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
[[package]]
name = "windows_x86_64_gnu"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.52.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
[[package]]
name = "windows_x86_64_msvc"
version = "0.52.6"
diff --git a/flake.nix b/flake.nix
index 1d059e1..7fc2d45 100644
--- a/flake.nix
+++ b/flake.nix
@@ -71,8 +71,9 @@
dart-sass
binaryen
];
- freebsd = [ pkgsCross.x86_64-freebsd.buildPackages.clang ];
- windows = [
+ freebsd = buildTools.linux
+ ++ [ pkgsCross.x86_64-freebsd.buildPackages.clang ];
+ windows = buildTools.linux ++ [
pkgsCross.mingwW64.stdenv.cc
pkgsCross.mingwW64.windows.pthreads
];
@@ -88,6 +89,9 @@
# Cargo lint tools
taplo
cargo-deny
+
+ # Web server tools
+ sqlx-cli
];
craneLib = (crane.mkLib pkgs).overrideToolchain (p:
@@ -143,7 +147,7 @@
default = craneLib.devShell (buildEnvironment // {
name = "sparse-default";
- packages = buildTools.all ++ devShellTools
+ packages = buildTools.linux ++ devShellTools
++ [ setup-zig-freebsd setup-dev-environment ];
# Added to make development easier
@@ -157,6 +161,27 @@
"../../target/x86_64-unknown-freebsd/debug/sparse-unix-beacon";
SPARSE_BEACON_WINDOWS =
"../../target/x86_64-pc-windows-gnu/debug/sparse-windows-beacon.exe";
+
+ shellHook = ''
+ export DATABASE_URL="sqlite://$(${pkgs.git}/bin/git rev-parse --show-toplevel)/sparse-server/db.sqlite"
+ '';
+ });
+
+ windows = craneLib.devShell (buildEnvironment // {
+ name = "sparse-default";
+
+ packages = buildTools.windows ++ devShellTools
+ ++ [ setup-zig-freebsd setup-dev-environment ];
+
+ # No point adding above environment variables, since web server can't
+ # be built with windows tools available
+ });
+
+ freebsd = craneLib.devShell (buildEnvironment // {
+ name = "sparse-default";
+
+ packages = buildTools.freebsd ++ devShellTools
+ ++ [ setup-zig-freebsd setup-dev-environment ];
});
};
});
diff --git a/sparse-server/.sqlx/query-86f197e514e8d55b95a71ab52b5901e939ee2c9e832ed1fae2661ad770d3ad60.json b/sparse-server/.sqlx/query-86f197e514e8d55b95a71ab52b5901e939ee2c9e832ed1fae2661ad770d3ad60.json
new file mode 100644
index 0000000..9f2d4fc
--- /dev/null
+++ b/sparse-server/.sqlx/query-86f197e514e8d55b95a71ab52b5901e939ee2c9e832ed1fae2661ad770d3ad60.json
@@ -0,0 +1,26 @@
+{
+ "db_name": "SQLite",
+ "query": "SELECT user_id, user_name FROM users;",
+ "describe": {
+ "columns": [
+ {
+ "name": "user_id",
+ "ordinal": 0,
+ "type_info": "Integer"
+ },
+ {
+ "name": "user_name",
+ "ordinal": 1,
+ "type_info": "Text"
+ }
+ ],
+ "parameters": {
+ "Right": 0
+ },
+ "nullable": [
+ false,
+ false
+ ]
+ },
+ "hash": "86f197e514e8d55b95a71ab52b5901e939ee2c9e832ed1fae2661ad770d3ad60"
+}
diff --git a/sparse-server/Cargo.toml b/sparse-server/Cargo.toml
index 66ddd8f..81bbc84 100644
--- a/sparse-server/Cargo.toml
+++ b/sparse-server/Cargo.toml
@@ -28,8 +28,14 @@ tokio-stream = { version = "0.1", optional = true }
futures-util = { version = "0.3", optional = true }
tracing = { version = "0.1", optional = true }
web-sys = { version = "0.3", features = ["WebSocket"] }
-leptos-use = { version = "0.15", default_features = false, features = ["use_websocket"] }
+leptos-use = { version = "0.15", default-features = false, features = ["use_websocket"] }
codee = "0.2"
+sqlx = { version = "0.8", default-features = false, features = ["chrono", "macros", "migrate", "runtime-tokio", "sqlite", "sqlx-sqlite"], optional = true }
+chrono = "0.4"
+rpassword = { version = "7.3", optional = true }
+pbkdf2 = { version = "0.12", features = ["simple", "sha2"], optional = true }
+sha2 = { version = "0.10", optional = true }
+hex = { version = "0.4", optional = true }
[features]
hydrate = ["leptos/hydrate"]
@@ -45,6 +51,11 @@ ssr = [
"dep:tokio-stream",
"dep:futures-util",
"dep:tracing",
+ "dep:sqlx",
+ "dep:rpassword",
+ "dep:pbkdf2",
+ "dep:sha2",
+ "dep:hex",
"leptos/ssr",
"leptos_meta/ssr",
"leptos_router/ssr",
diff --git a/sparse-server/build.rs b/sparse-server/build.rs
index d4809bd..24c677a 100644
--- a/sparse-server/build.rs
+++ b/sparse-server/build.rs
@@ -1,3 +1,6 @@
+// generated by `sqlx migrate build-script`
fn main() {
+ // trigger recompilation when a new migration is added
include!("../build_common.rs");
+ println!("cargo:rerun-if-changed=migrations");
}
diff --git a/sparse-server/migrations/20250124053720_users.sql b/sparse-server/migrations/20250124053720_users.sql
new file mode 100644
index 0000000..2203b11
--- /dev/null
+++ b/sparse-server/migrations/20250124053720_users.sql
@@ -0,0 +1,16 @@
+-- Add migration script here
+CREATE TABLE users (
+ user_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
+ user_name varchar(255) NOT NULL,
+ password_salt char(64) NOT NULL,
+ password_hash char(64) NOT NULL
+);
+
+CREATE TABLE sessions (
+ session_id char(64) NOT NULL,
+ user_id int NOT NULL,
+ expires int NOT NULL,
+
+ PRIMARY KEY (session_id),
+ FOREIGN KEY (user_id) REFERENCES users
+);
diff --git a/sparse-server/src/app.rs b/sparse-server/src/app.rs
index 538f1cc..4188a33 100644
--- a/sparse-server/src/app.rs
+++ b/sparse-server/src/app.rs
@@ -53,6 +53,7 @@ pub fn App() -> impl IntoView {
+
diff --git a/sparse-server/src/cli.rs b/sparse-server/src/cli.rs
index a809885..a7313c1 100644
--- a/sparse-server/src/cli.rs
+++ b/sparse-server/src/cli.rs
@@ -1,9 +1,22 @@
use std::path::PathBuf;
use structopt::StructOpt;
+pub mod user;
+
#[derive(StructOpt, Debug, Clone)]
#[structopt(name = "sparse-server")]
pub struct Options {
+ /// The location of the database to use. If not present,
+ /// sparse will read the DATABASE_URL environment variable
+ #[structopt(short = "d")]
+ pub db_location: Option,
+
+ /// During the startup of the program, sparse will produce an error
+ /// if the database doesn't exist. Use this flag to instead create a new
+ /// database
+ #[structopt(short = "i")]
+ pub init_ok: bool,
+
#[structopt(subcommand)]
pub command: Option,
}
@@ -11,6 +24,34 @@ pub struct Options {
#[derive(StructOpt, Debug, Clone)]
#[structopt()]
pub enum Command {
+ /// Run the web and API server
Serve {},
- Init {},
+
+ /// Extract the public key and print it to standard out
+ ExtractPubKey {},
+
+ /// Perform user management
+ User {
+ #[structopt(subcommand)]
+ command: UserCommand,
+ },
+}
+
+#[derive(StructOpt, Debug, Clone)]
+#[structopt()]
+pub enum UserCommand {
+ /// List available users to sign in as
+ List {},
+
+ /// Create a new user
+ Create {
+ #[structopt(short = "n")]
+ user_name: String,
+ },
+
+ /// Reset the password for a user who forgot their password
+ ResetPassword {
+ #[structopt(short = "I")]
+ user_id: i16,
+ },
}
diff --git a/sparse-server/src/cli/user.rs b/sparse-server/src/cli/user.rs
new file mode 100644
index 0000000..8e033cb
--- /dev/null
+++ b/sparse-server/src/cli/user.rs
@@ -0,0 +1,75 @@
+use std::process::ExitCode;
+
+use futures_util::StreamExt;
+use sqlx::{Database, query, sqlite::SqlitePool};
+
+use crate::cli::UserCommand as UC;
+
+pub async fn handle_user_command(user_command: UC, db: SqlitePool) -> anyhow::Result {
+ match user_command {
+ UC::List {} => list_users(db).await,
+ UC::Create { user_name } => create_user(db, user_name).await,
+ UC::ResetPassword { user_id } => reset_password(&db, user_id).await
+ }
+}
+
+async fn list_users(db: SqlitePool) -> anyhow::Result {
+ println!("\n\nListing users:");
+
+ let mut results = query!("SELECT user_id, user_name FROM users;").fetch(&db);
+ while let Some(Ok(user)) = results.next().await {
+ println!("\t{:?}: {}", user.user_id, user.user_name);
+ }
+
+ Ok(ExitCode::SUCCESS)
+}
+
+async fn create_user(db: SqlitePool, name: String) -> anyhow::Result {
+ let mut tx = db.begin().await?;
+
+ let previous_user_check = sqlx::query_scalar!(
+ "SELECT COUNT(*) FROM users WHERE user_name = ?",
+ name
+ )
+ .fetch_one(&mut *tx)
+ .await?;
+
+ if previous_user_check > 0 {
+ eprintln!("Error! User already exists!");
+ return Ok(ExitCode::FAILURE);
+ }
+
+ let new_id = query!(
+ r#"INSERT INTO users (user_name, password_salt, password_hash) VALUES (?, "", "")"#,
+ name
+ )
+ .execute(&mut *tx)
+ .await?
+ .last_insert_rowid();
+
+ reset_password(&mut *tx, new_id as i16).await?;
+
+ tx.commit().await?;
+
+ println!("User successfully created!");
+
+ Ok(ExitCode::SUCCESS)
+}
+
+async fn reset_password<'a, E>(db: E, id: i16) -> anyhow::Result
+where
+ E: sqlx::Executor<'a, Database = sqlx::Sqlite>
+{
+ let password1 = rpassword::prompt_password("Enter new password: ")?;
+ let password2 = rpassword::prompt_password("Enter password again: ")?;
+
+ if password1 != password2 {
+ Err(anyhow::anyhow!("Passwords do not match!"))?
+ }
+
+ crate::db::user::reset_password(db, id, password1).await?;
+
+ println!("Password set successfully!");
+
+ Ok(ExitCode::SUCCESS)
+}
diff --git a/sparse-server/src/db.rs b/sparse-server/src/db.rs
index d321fbf..4173097 100644
--- a/sparse-server/src/db.rs
+++ b/sparse-server/src/db.rs
@@ -1,2 +1,15 @@
-mod beacons;
-mod users;
+#[cfg(feature = "ssr")]
+pub mod user;
+
+pub struct User {
+ pub user_id: i16,
+ pub user_name: String,
+ pub password_salt: String,
+ pub password_hash: String,
+}
+
+pub struct Sessions {
+ pub session_id: String,
+ pub user_id: i16,
+ pub expires: chrono::DateTime,
+}
diff --git a/sparse-server/src/db/beacons.rs b/sparse-server/src/db/beacons.rs
deleted file mode 100644
index 8b13789..0000000
--- a/sparse-server/src/db/beacons.rs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/sparse-server/src/db/user.rs b/sparse-server/src/db/user.rs
new file mode 100644
index 0000000..d18b822
--- /dev/null
+++ b/sparse-server/src/db/user.rs
@@ -0,0 +1,35 @@
+use sqlx::{sqlite::SqlitePool, Database};
+use pbkdf2::{pbkdf2_hmac_array, password_hash::{rand_core::OsRng, SaltString}};
+use sha2::Sha256;
+
+const PASSWORD_ITERATIONS: u32 = 100_000;
+
+pub async fn reset_password<'a, E>(pool: E, id: i16, password: String) -> anyhow::Result<()>
+where
+ E: sqlx::Executor<'a, Database = sqlx::Sqlite>
+{
+ let salt = SaltString::generate(&mut OsRng);
+
+ let key = pbkdf2_hmac_array::(
+ password.as_bytes(),
+ salt.as_str().as_bytes(),
+ PASSWORD_ITERATIONS
+ );
+
+ let salt_string = hex::encode(salt.as_str().as_bytes());
+ let password_string = hex::encode(&key[..]);
+
+ tracing::debug!("New password hash: {password_string}");
+ tracing::debug!("New password salt: {salt_string}");
+
+ sqlx::query!(
+ "UPDATE users SET password_hash = ?, password_salt = ? WHERE user_id = ?",
+ password_string,
+ salt_string,
+ id
+ )
+ .execute(pool)
+ .await?;
+
+ Ok(())
+}
diff --git a/sparse-server/src/db/users.rs b/sparse-server/src/db/users.rs
deleted file mode 100644
index 8b13789..0000000
--- a/sparse-server/src/db/users.rs
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/sparse-server/src/lib.rs b/sparse-server/src/lib.rs
index 151489d..6ff12ee 100644
--- a/sparse-server/src/lib.rs
+++ b/sparse-server/src/lib.rs
@@ -1,5 +1,7 @@
pub mod app;
+pub mod users;
+
#[cfg(feature = "hydrate")]
#[wasm_bindgen::prelude::wasm_bindgen]
pub fn hydrate() {
diff --git a/sparse-server/src/main.rs b/sparse-server/src/main.rs
index 868f8ab..6b8ad73 100644
--- a/sparse-server/src/main.rs
+++ b/sparse-server/src/main.rs
@@ -15,28 +15,82 @@ mod cli;
mod webserver;
#[cfg(feature = "ssr")]
-mod db;
+pub mod users;
+
+pub mod db;
#[cfg(feature = "ssr")]
#[tokio::main]
-async fn main() -> anyhow::Result<()> {
+async fn main() -> anyhow::Result {
+ use std::{path::PathBuf, process::ExitCode, str::FromStr};
+
use structopt::StructOpt;
+ use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
+ use sqlx::sqlite::{SqlitePool, SqliteConnectOptions};
+
+ tracing_subscriber::registry()
+ .with(
+ tracing_subscriber::EnvFilter::try_from_default_env()
+ .unwrap_or_else(|_| format!("{}=debug", env!("CARGO_CRATE_NAME")).into()),
+ )
+ .with(tracing_subscriber::fmt::layer())
+ .init();
let options = cli::Options::from_args();
+ let db_location = options.db_location.clone()
+ .or(std::env::var("DATABASE_URL")
+ .map(|p| p.replace("sqlite://", ""))
+ .map(PathBuf::from)
+ .ok())
+ .unwrap_or(PathBuf::from("./db.sqlite"));
+
+ tracing::info!("Using database {}", db_location.display());
+
+ let db_exists = std::fs::metadata(&db_location);
+
+ let run_init = if let Err(e) = db_exists {
+ if !options.init_ok {
+ tracing::error!("Database doesn't exist, and initialization not allowed!");
+ tracing::error!("{:?}", e);
+ return Ok(ExitCode::FAILURE)
+ }
+
+ tracing::info!("Database doesn't exist, readying initialization");
+ true
+ } else {
+ false
+ };
+
+ let pool = SqlitePool::connect_with(
+ SqliteConnectOptions::from_str(&format!("sqlite://{}", db_location.to_string_lossy()))?
+ .create_if_missing(options.init_ok)
+ ).await?;
+
+ tracing::info!("Running database migrations...");
+
+ sqlx::migrate!()
+ .run(&pool)
+ .await?;
+
+ tracing::info!("Done running database migrations!");
+
match options.command.clone() {
Some(cli::Command::Serve { }) => {
- webserver::serve_web(options).await?;
+ tracing::info!("Performing requested action, acting as web server");
+ webserver::serve_web(options, pool).await
}
- Some(cli::Command::Init { }) => {
-
+ Some(cli::Command::ExtractPubKey { }) => {
+ Ok(ExitCode::SUCCESS)
+ }
+ Some(cli::Command::User { command }) => {
+ cli::user::handle_user_command(command, pool).await
}
None => {
- webserver::serve_web(options).await?;
+ tracing::info!("Performing default action of acting as web server");
+ webserver::serve_web(options, pool).await
}
}
-
- Ok(())
}
#[cfg(not(feature = "ssr"))]
diff --git a/sparse-server/src/users.rs b/sparse-server/src/users.rs
new file mode 100644
index 0000000..8795f5a
--- /dev/null
+++ b/sparse-server/src/users.rs
@@ -0,0 +1,8 @@
+use leptos::prelude::*;
+
+#[component]
+pub fn UserView() -> impl IntoView {
+ view! {
+ "User view"
+ }
+}
diff --git a/sparse-server/src/webserver.rs b/sparse-server/src/webserver.rs
index 8d331df..a84bb40 100644
--- a/sparse-server/src/webserver.rs
+++ b/sparse-server/src/webserver.rs
@@ -1,3 +1,13 @@
+use std::process::ExitCode;
+
+use sqlx::sqlite::SqlitePool;
+use axum::Router;
+use leptos::logging::log;
+use leptos::prelude::*;
+use leptos_axum::{generate_route_list, LeptosRoutes};
+use sparse_server::app::*;
+
+
pub async fn websocket(ws: axum::extract::ws::WebSocketUpgrade) -> axum::response::Response {
ws.on_upgrade(handle_websocket)
}
@@ -32,22 +42,7 @@ async fn handle_websocket(mut socket: axum::extract::ws::WebSocket) {
}
}
-pub async fn serve_web(options: crate::cli::Options) -> anyhow::Result<()> {
- use axum::Router;
- use leptos::logging::log;
- use leptos::prelude::*;
- use leptos_axum::{generate_route_list, LeptosRoutes};
- use sparse_server::app::*;
- use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
-
- tracing_subscriber::registry()
- .with(
- tracing_subscriber::EnvFilter::try_from_default_env()
- .unwrap_or_else(|_| format!("{}=debug", env!("CARGO_CRATE_NAME")).into()),
- )
- .with(tracing_subscriber::fmt::layer())
- .init();
-
+pub async fn serve_web(options: crate::cli::Options, db: SqlitePool) -> anyhow::Result {
let conf = get_configuration(None).unwrap();
let addr = conf.leptos_options.site_addr;
let leptos_options = conf.leptos_options;
@@ -69,5 +64,5 @@ pub async fn serve_web(options: crate::cli::Options) -> anyhow::Result<()> {
let listener = tokio::net::TcpListener::bind(&addr).await?;
axum::serve(listener, app.into_make_service()).await?;
- Ok(())
+ Ok(ExitCode::SUCCESS)
}
diff --git a/unix-loader/src/abi.h b/unix-loader/src/abi.h
index 35019b5..00091cd 100644
--- a/unix-loader/src/abi.h
+++ b/unix-loader/src/abi.h
@@ -28,7 +28,9 @@ typedef struct Parameters {
unsigned short privkey_size;
unsigned short privkey_cert_size;
unsigned short beacon_name_length;
+ unsigned short domain_name_length;
char pubkey_cert[1024];
char beacon_identifier[64];
char beacon_name[128];
+ char domain_name[128];
} Parameters_t;