Set up client tests
These are definitely temporary tests, as testing the lcient API will become more difficult and require more infrastructure as real data starts entering the system.
This commit is contained in:
parent
182020e136
commit
41bb21c254
324
Cargo.lock
generated
324
Cargo.lock
generated
@ -29,18 +29,6 @@ version = "1.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
|
checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ahash"
|
|
||||||
version = "0.8.11"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"once_cell",
|
|
||||||
"version_check 0.9.5",
|
|
||||||
"zerocopy",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.3"
|
version = "1.1.3"
|
||||||
@ -137,16 +125,6 @@ version = "1.0.95"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
|
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "assert-json-diff"
|
|
||||||
version = "2.0.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "47e4f2b81832e72834d7518d8487a0396a28cc408186a2e8854c0f98011faf12"
|
|
||||||
dependencies = [
|
|
||||||
"serde 1.0.217",
|
|
||||||
"serde_json",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-channel"
|
name = "async-channel"
|
||||||
version = "1.9.0"
|
version = "1.9.0"
|
||||||
@ -301,12 +279,6 @@ dependencies = [
|
|||||||
"uuid 0.4.0",
|
"uuid 0.4.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "auto-future"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3c1e7e457ea78e524f48639f551fd79703ac3f2237f5ecccdf4708f8a75ad373"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "0.1.8"
|
version = "0.1.8"
|
||||||
@ -324,14 +296,14 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "axum"
|
name = "axum"
|
||||||
version = "0.7.9"
|
version = "0.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f"
|
checksum = "6d6fd624c75e18b3b4c6b9caf42b1afe24437daaee904069137d8bab077be8b8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
|
||||||
"axum-core",
|
"axum-core",
|
||||||
"axum-macros",
|
"axum-macros",
|
||||||
"bytes",
|
"bytes",
|
||||||
|
"form_urlencoded",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 1.2.0",
|
"http 1.2.0",
|
||||||
"http-body 1.0.1",
|
"http-body 1.0.1",
|
||||||
@ -359,11 +331,10 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "axum-core"
|
name = "axum-core"
|
||||||
version = "0.4.5"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199"
|
checksum = "df1362f362fd16024ae199c1970ce98f9661bf5ef94b9808fee734bc3698b733"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 1.2.0",
|
"http 1.2.0",
|
||||||
@ -380,45 +351,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "axum-macros"
|
name = "axum-macros"
|
||||||
version = "0.4.2"
|
version = "0.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "57d123550fa8d071b7255cb0cc04dc302baa6c8c4a79f55701552684d8399bce"
|
checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.96",
|
"syn 2.0.96",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "axum-test"
|
|
||||||
version = "16.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "63e3a443d2608936a02a222da7b746eb412fede7225b3030b64fe9be99eab8dc"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"assert-json-diff",
|
|
||||||
"auto-future",
|
|
||||||
"axum",
|
|
||||||
"bytes",
|
|
||||||
"bytesize",
|
|
||||||
"cookie 0.18.1",
|
|
||||||
"http 1.2.0",
|
|
||||||
"http-body-util",
|
|
||||||
"hyper 1.5.2",
|
|
||||||
"hyper-util",
|
|
||||||
"mime 0.3.17",
|
|
||||||
"pretty_assertions",
|
|
||||||
"reserve-port",
|
|
||||||
"rust-multipart-rfc7578_2",
|
|
||||||
"serde 1.0.217",
|
|
||||||
"serde_json",
|
|
||||||
"serde_urlencoded",
|
|
||||||
"smallvec",
|
|
||||||
"tokio",
|
|
||||||
"tower",
|
|
||||||
"url 2.5.4",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "az"
|
name = "az"
|
||||||
version = "1.2.1"
|
version = "1.2.1"
|
||||||
@ -577,12 +518,6 @@ version = "1.9.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
|
checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "bytesize"
|
|
||||||
version = "1.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cairo-rs"
|
name = "cairo-rs"
|
||||||
version = "0.18.5"
|
version = "0.18.5"
|
||||||
@ -646,7 +581,7 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|||||||
name = "changeset"
|
name = "changeset"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"uuid 1.12.0",
|
"uuid 0.8.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -812,16 +747,6 @@ dependencies = [
|
|||||||
"version_check 0.9.5",
|
"version_check 0.9.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cookie"
|
|
||||||
version = "0.18.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747"
|
|
||||||
dependencies = [
|
|
||||||
"time 0.3.37",
|
|
||||||
"version_check 0.9.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cookie-factory"
|
name = "cookie-factory"
|
||||||
version = "0.3.3"
|
version = "0.3.3"
|
||||||
@ -1046,12 +971,6 @@ dependencies = [
|
|||||||
"powerfmt",
|
"powerfmt",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "diff"
|
|
||||||
version = "0.1.13"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.10.7"
|
version = "0.10.7"
|
||||||
@ -1220,18 +1139,6 @@ dependencies = [
|
|||||||
"zune-inflate",
|
"zune-inflate",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fallible-iterator"
|
|
||||||
version = "0.3.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fallible-streaming-iterator"
|
|
||||||
version = "0.1.9"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.3.0"
|
version = "2.3.0"
|
||||||
@ -1267,7 +1174,7 @@ dependencies = [
|
|||||||
"bytes",
|
"bytes",
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"cookie 0.17.0",
|
"cookie",
|
||||||
"cool_asserts",
|
"cool_asserts",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"hex-string",
|
"hex-string",
|
||||||
@ -1656,6 +1563,18 @@ dependencies = [
|
|||||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "getrandom"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"wasi 0.13.3+wasi-0.2.2",
|
||||||
|
"windows-targets 0.52.6",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gif"
|
name = "gif"
|
||||||
version = "0.11.4"
|
version = "0.11.4"
|
||||||
@ -1983,15 +1902,6 @@ dependencies = [
|
|||||||
"crunchy",
|
"crunchy",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashbrown"
|
|
||||||
version = "0.14.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
|
||||||
dependencies = [
|
|
||||||
"ahash",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashbrown"
|
name = "hashbrown"
|
||||||
version = "0.15.2"
|
version = "0.15.2"
|
||||||
@ -2003,22 +1913,13 @@ dependencies = [
|
|||||||
"foldhash",
|
"foldhash",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hashlink"
|
|
||||||
version = "0.9.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af"
|
|
||||||
dependencies = [
|
|
||||||
"hashbrown 0.14.5",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hashlink"
|
name = "hashlink"
|
||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
|
checksum = "7382cf6263419f2d8df38c55d7da83da5c18aef87fc7a7fc1fb1e344edfe14c1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hashbrown 0.15.2",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2255,7 +2156,6 @@ dependencies = [
|
|||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"tokio",
|
"tokio",
|
||||||
"want",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2278,16 +2178,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
|
checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http 1.2.0",
|
"http 1.2.0",
|
||||||
"http-body 1.0.1",
|
"http-body 1.0.1",
|
||||||
"hyper 1.5.2",
|
"hyper 1.5.2",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"tracing",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2510,25 +2407,6 @@ dependencies = [
|
|||||||
"tiff 0.9.1",
|
"tiff 0.9.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "include_dir"
|
|
||||||
version = "0.7.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd"
|
|
||||||
dependencies = [
|
|
||||||
"include_dir_macros",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "include_dir_macros"
|
|
||||||
version = "0.7.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indent_write"
|
name = "indent_write"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
@ -2542,7 +2420,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
|
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.15.2",
|
"hashbrown",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -2852,9 +2730,9 @@ checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matchit"
|
name = "matchit"
|
||||||
version = "0.7.3"
|
version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94"
|
checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "md-5"
|
name = "md-5"
|
||||||
@ -3555,16 +3433,6 @@ dependencies = [
|
|||||||
"zerocopy",
|
"zerocopy",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pretty_assertions"
|
|
||||||
version = "1.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d"
|
|
||||||
dependencies = [
|
|
||||||
"diff",
|
|
||||||
"yansi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pretty_env_logger"
|
name = "pretty_env_logger"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
@ -3766,7 +3634,7 @@ version = "0.6.4"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.2.15",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3956,16 +3824,6 @@ dependencies = [
|
|||||||
"winreg",
|
"winreg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "reserve-port"
|
|
||||||
version = "2.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9838134a2bfaa8e1f40738fcc972ac799de6e0e06b5157acb95fc2b05a0ea283"
|
|
||||||
dependencies = [
|
|
||||||
"lazy_static",
|
|
||||||
"thiserror 1.0.69",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "result-extended"
|
name = "result-extended"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -3993,47 +3851,6 @@ dependencies = [
|
|||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rusqlite"
|
|
||||||
version = "0.32.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7753b721174eb8ff87a9a0e799e2d7bc3749323e773db92e0984debb00019d6e"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags 2.8.0",
|
|
||||||
"fallible-iterator",
|
|
||||||
"fallible-streaming-iterator",
|
|
||||||
"hashlink 0.9.1",
|
|
||||||
"libsqlite3-sys",
|
|
||||||
"smallvec",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rusqlite_migration"
|
|
||||||
version = "1.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "923b42e802f7dc20a0a6b5e097ba7c83fe4289da07e49156fecf6af08aa9cd1c"
|
|
||||||
dependencies = [
|
|
||||||
"include_dir",
|
|
||||||
"log 0.4.25",
|
|
||||||
"rusqlite",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rust-multipart-rfc7578_2"
|
|
||||||
version = "0.6.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "03b748410c0afdef2ebbe3685a6a862e2ee937127cdaae623336a459451c8d57"
|
|
||||||
dependencies = [
|
|
||||||
"bytes",
|
|
||||||
"futures-core",
|
|
||||||
"futures-util",
|
|
||||||
"http 0.2.12",
|
|
||||||
"mime 0.3.17",
|
|
||||||
"mime_guess 2.0.5",
|
|
||||||
"rand 0.8.5",
|
|
||||||
"thiserror 1.0.69",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustc-demangle"
|
name = "rustc-demangle"
|
||||||
version = "0.1.24"
|
version = "0.1.24"
|
||||||
@ -4271,6 +4088,20 @@ dependencies = [
|
|||||||
"version_check 0.9.5",
|
"version_check 0.9.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "server"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"axum",
|
||||||
|
"result-extended",
|
||||||
|
"serde 1.0.217",
|
||||||
|
"thiserror 2.0.11",
|
||||||
|
"tokio",
|
||||||
|
"tower-http",
|
||||||
|
"typeshare",
|
||||||
|
"uuid 1.13.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sgf"
|
name = "sgf"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -4446,8 +4277,8 @@ dependencies = [
|
|||||||
"futures-intrusive",
|
"futures-intrusive",
|
||||||
"futures-io",
|
"futures-io",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"hashbrown 0.15.2",
|
"hashbrown",
|
||||||
"hashlink 0.10.0",
|
"hashlink",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"log 0.4.25",
|
"log 0.4.25",
|
||||||
"memchr",
|
"memchr",
|
||||||
@ -4737,7 +4568,7 @@ checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"fastrand",
|
"fastrand",
|
||||||
"getrandom",
|
"getrandom 0.2.15",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
@ -5279,12 +5110,6 @@ dependencies = [
|
|||||||
"percent-encoding 2.3.1",
|
"percent-encoding 2.3.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "urlencoding"
|
|
||||||
version = "2.1.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "utf-8"
|
name = "utf-8"
|
||||||
version = "0.7.6"
|
version = "0.7.6"
|
||||||
@ -5325,17 +5150,17 @@ version = "0.8.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.2.15",
|
||||||
"serde 1.0.217",
|
"serde 1.0.217",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "1.12.0"
|
version = "1.13.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4"
|
checksum = "ced87ca4be083373936a67f8de945faa23b6b42384bd5b64434850802c6dccd0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"getrandom",
|
"getrandom 0.3.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -5368,37 +5193,6 @@ version = "0.9.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "visions"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"async-std",
|
|
||||||
"async-trait",
|
|
||||||
"authdb",
|
|
||||||
"axum",
|
|
||||||
"axum-test",
|
|
||||||
"chrono",
|
|
||||||
"cool_asserts",
|
|
||||||
"futures",
|
|
||||||
"include_dir",
|
|
||||||
"lazy_static",
|
|
||||||
"mime 0.3.17",
|
|
||||||
"mime_guess 2.0.5",
|
|
||||||
"pretty_env_logger",
|
|
||||||
"result-extended",
|
|
||||||
"rusqlite",
|
|
||||||
"rusqlite_migration",
|
|
||||||
"serde 1.0.217",
|
|
||||||
"serde_json",
|
|
||||||
"thiserror 2.0.11",
|
|
||||||
"tokio",
|
|
||||||
"tokio-stream",
|
|
||||||
"tower-http",
|
|
||||||
"typeshare",
|
|
||||||
"urlencoding",
|
|
||||||
"uuid 1.12.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wait-timeout"
|
name = "wait-timeout"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
@ -5458,6 +5252,15 @@ version = "0.11.0+wasi-snapshot-preview1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasi"
|
||||||
|
version = "0.13.3+wasi-0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2"
|
||||||
|
dependencies = [
|
||||||
|
"wit-bindgen-rt",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wasite"
|
name = "wasite"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
@ -5768,6 +5571,15 @@ dependencies = [
|
|||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wit-bindgen-rt"
|
||||||
|
version = "0.33.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.8.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "write16"
|
name = "write16"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
@ -5780,12 +5592,6 @@ version = "0.5.5"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "yansi"
|
|
||||||
version = "1.0.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yansi-term"
|
name = "yansi-term"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
@ -10,3 +10,7 @@ tasks:
|
|||||||
- npm install typescript
|
- npm install typescript
|
||||||
- typeshare --lang typescript --output-file gen/types.ts ../server/src
|
- typeshare --lang typescript --output-file gen/types.ts ../server/src
|
||||||
- npx tsc
|
- npx tsc
|
||||||
|
|
||||||
|
test:
|
||||||
|
cmds:
|
||||||
|
- npx jest src/
|
||||||
|
7
visions/client/jest.config.js
Normal file
7
visions/client/jest.config.js
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
/** @type {import('ts-jest').JestConfigWithTsJest} **/
|
||||||
|
module.exports = {
|
||||||
|
testEnvironment: "node",
|
||||||
|
transform: {
|
||||||
|
"^.+.tsx?$": ["ts-jest",{}],
|
||||||
|
},
|
||||||
|
};
|
7379
visions/client/package-lock.json
generated
7379
visions/client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -14,6 +14,8 @@
|
|||||||
"tabWidth": 4
|
"tabWidth": 4
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/jest": "^29.5.14",
|
||||||
|
"jest": "^29.7.0",
|
||||||
"prettier": "^3.5.1",
|
"prettier": "^3.5.1",
|
||||||
"ts-jest": "^29.2.5",
|
"ts-jest": "^29.2.5",
|
||||||
"typescript": "^5.7.3"
|
"typescript": "^5.7.3"
|
||||||
|
97
visions/client/src/client.test.ts
Normal file
97
visions/client/src/client.test.ts
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
import { Connection } from './client'
|
||||||
|
|
||||||
|
describe('what happens in an authentication', () => {
|
||||||
|
it('handles a successful response', async () => {
|
||||||
|
let client = new Connection(new URL('http://127.0.0.1:8001'))
|
||||||
|
let response = await client.auth('vakarian', 'aoeu')
|
||||||
|
expect(response).toEqual({
|
||||||
|
status: 'ok',
|
||||||
|
content: 'vakarian-session-id',
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('handles an authentication failure', async () => {
|
||||||
|
let client = new Connection(new URL('http://127.0.0.1:8001'))
|
||||||
|
{
|
||||||
|
let response = await client.auth('vakarian', '')
|
||||||
|
expect(response).toEqual({ status: 'unauthorized' })
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let response = await client.auth('grunt', '')
|
||||||
|
expect(response).toEqual({ status: 'unauthorized' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('handles a password-reset condition', async () => {
|
||||||
|
let client = new Connection(new URL('http://127.0.0.1:8001'))
|
||||||
|
{
|
||||||
|
let response = await client.auth('shephard', 'aoeu')
|
||||||
|
expect(response).toEqual({
|
||||||
|
status: 'password-reset',
|
||||||
|
content: 'shephard-session-id',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let response = await client.auth('shephard', '')
|
||||||
|
expect(response).toEqual({ status: 'unauthorized' })
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it('lists users on an authenticated connection', async () => {
|
||||||
|
let client = new Connection(new URL('http://127.0.0.1:8001'))
|
||||||
|
{
|
||||||
|
let authResponse = await client.auth('vakarian', 'aoeu')
|
||||||
|
if (authResponse.status === 'ok') {
|
||||||
|
let sessionId = authResponse.content
|
||||||
|
let response = await client.listUsers(sessionId)
|
||||||
|
expect(response).toEqual({
|
||||||
|
status: 'ok',
|
||||||
|
content: [
|
||||||
|
{
|
||||||
|
id: 'vakarian-id',
|
||||||
|
name: 'vakarian',
|
||||||
|
status: { type: 'ok', content: undefined },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'shephard-id',
|
||||||
|
name: 'shephard',
|
||||||
|
status: {
|
||||||
|
type: 'password-reset',
|
||||||
|
content: '2050-01-01 00:00:00',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'tali-id',
|
||||||
|
name: 'tali',
|
||||||
|
status: { type: 'locked', content: undefined },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
throw new Error('authorization should have been ok')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let authResponse = await client.auth('shephard', 'aoeu')
|
||||||
|
if (authResponse.status === 'password-reset') {
|
||||||
|
let sessionId = authResponse.content
|
||||||
|
let response = await client.listUsers(sessionId)
|
||||||
|
expect(response).toEqual({ status: 'unauthorized' })
|
||||||
|
} else {
|
||||||
|
throw new Error('authorization should have been password-reset')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
let response = await client.listUsers('');
|
||||||
|
expect(response).toEqual({ status: 'unauthorized' })
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let authResponse = await client.auth('shephard', 'aoeu')
|
||||||
|
let response = await client.listUsers(authResponse.content);
|
||||||
|
expect(response).toEqual({ status: 'password-reset' })
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
})
|
||||||
|
})
|
@ -1,20 +1,22 @@
|
|||||||
import { VResponse, SessionId } from '../gen/types'
|
import { VResponse, SessionId, UserOverview } from '../gen/types'
|
||||||
|
|
||||||
export interface Client {
|
export interface Client {
|
||||||
auth: (
|
auth: (
|
||||||
username: string,
|
username: string,
|
||||||
password: string,
|
password: string,
|
||||||
) => Promise<ClientResponse<SessionId>>
|
) => Promise<ClientResponse<SessionId>>
|
||||||
|
|
||||||
|
listUsers: (sessionId: SessionId) => Promise<ClientResponse<UserOverview[]>>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ClientResponse<A> =
|
export type ClientResponse<A> =
|
||||||
| { status: 'ok'; content: VResponse<A> }
|
| { status: 'ok'; content: A }
|
||||||
|
| { status: 'password-reset'; content: SessionId }
|
||||||
| { status: 'unauthorized' }
|
| { status: 'unauthorized' }
|
||||||
| { status: 'unexpected'; code: number }
|
| { status: 'unexpected'; code: number }
|
||||||
|
|
||||||
export class Connection implements Client {
|
export class Connection implements Client {
|
||||||
private base: URL
|
private base: URL
|
||||||
// private sessionId: string | undefined;
|
|
||||||
|
|
||||||
constructor(baseUrl: URL) {
|
constructor(baseUrl: URL) {
|
||||||
this.base = baseUrl
|
this.base = baseUrl
|
||||||
@ -25,14 +27,46 @@ export class Connection implements Client {
|
|||||||
password: string,
|
password: string,
|
||||||
): Promise<ClientResponse<SessionId>> {
|
): Promise<ClientResponse<SessionId>> {
|
||||||
const url = new URL(this.base)
|
const url = new URL(this.base)
|
||||||
url.pathname = `/api/v1/auth`
|
url.pathname = `/api/test/auth`
|
||||||
const response = await fetch(url, {
|
const response = await fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: [['Content-Type', 'application/json']],
|
headers: [['Content-Type', 'application/json']],
|
||||||
body: JSON.stringify({ username: username, password: password }),
|
body: JSON.stringify({ username: username, password: password }),
|
||||||
})
|
})
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
return await response.json()
|
let resp = await response.json()
|
||||||
|
switch (resp.type) {
|
||||||
|
case 'success':
|
||||||
|
return { status: 'ok', content: resp.content }
|
||||||
|
case 'password-reset':
|
||||||
|
return { status: 'password-reset', content: resp.content }
|
||||||
|
}
|
||||||
|
return { status: 'ok', content: resp }
|
||||||
|
} else if (response.status == 401) {
|
||||||
|
return { status: 'unauthorized' }
|
||||||
|
} else {
|
||||||
|
return { status: 'unexpected', code: response.status }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async listUsers(
|
||||||
|
sessionId: SessionId,
|
||||||
|
): Promise<ClientResponse<UserOverview[]>> {
|
||||||
|
const url = new URL(this.base)
|
||||||
|
url.pathname = `/api/test/list-users`
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: [['Authorization', `Bearer ${sessionId}`]],
|
||||||
|
})
|
||||||
|
if (response.ok) {
|
||||||
|
let resp = await response.json()
|
||||||
|
switch (resp.type) {
|
||||||
|
case 'success':
|
||||||
|
return { status: 'ok', content: resp.content }
|
||||||
|
case 'password-reset':
|
||||||
|
return { status: 'password-reset', content: resp.content }
|
||||||
|
}
|
||||||
|
return { status: 'ok', content: resp }
|
||||||
} else if (response.status == 401) {
|
} else if (response.status == 401) {
|
||||||
return { status: 'unauthorized' }
|
return { status: 'unauthorized' }
|
||||||
} else {
|
} else {
|
||||||
|
@ -10,3 +10,5 @@ tokio = { version = "1.43.0", features = ["full", "rt"] }
|
|||||||
tower-http = { version = "0.6.2", features = ["cors"] }
|
tower-http = { version = "0.6.2", features = ["cors"] }
|
||||||
typeshare = "1.0.4"
|
typeshare = "1.0.4"
|
||||||
uuid = { version = "1.13.1", features = ["v4"] }
|
uuid = { version = "1.13.1", features = ["v4"] }
|
||||||
|
result-extended = { path = "../../result-extended" }
|
||||||
|
thiserror = "2.0.11"
|
||||||
|
@ -1,19 +1,39 @@
|
|||||||
use axum::{http::{Method, StatusCode}, routing::{get, post}, Json, Router};
|
use std::future::Future;
|
||||||
|
|
||||||
|
use axum::{
|
||||||
|
http::{
|
||||||
|
header::{AUTHORIZATION, CONTENT_TYPE},
|
||||||
|
HeaderMap, Method, StatusCode,
|
||||||
|
},
|
||||||
|
routing::{get, post},
|
||||||
|
Json, Router,
|
||||||
|
};
|
||||||
|
use result_extended::{error, ok, ResultExt};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use thiserror::Error;
|
||||||
use tower_http::cors::{Any, CorsLayer};
|
use tower_http::cors::{Any, CorsLayer};
|
||||||
use typeshare::typeshare;
|
use typeshare::typeshare;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
#[serde(tag = "type", content = "content", rename_all = "kebab-case")]
|
||||||
|
#[typeshare]
|
||||||
|
enum AccountStatus {
|
||||||
|
Ok,
|
||||||
|
PasswordReset(String),
|
||||||
|
Locked,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
#[typeshare]
|
#[typeshare]
|
||||||
struct AuthRequest {
|
struct AuthRequest {
|
||||||
username: String,
|
username: String,
|
||||||
password: String
|
password: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||||
#[typeshare]
|
#[typeshare]
|
||||||
pub struct SessionId(String);
|
struct SessionId(String);
|
||||||
|
|
||||||
impl SessionId {
|
impl SessionId {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
@ -37,42 +57,183 @@ impl From<String> for SessionId {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
|
||||||
|
#[typeshare]
|
||||||
|
struct UserId(String);
|
||||||
|
|
||||||
|
impl UserId {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(format!("{}", Uuid::new_v4().hyphenated()))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn as_str(&self) -> &str {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for UserId {
|
||||||
|
fn from(s: &str) -> Self {
|
||||||
|
Self(s.to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for UserId {
|
||||||
|
fn from(s: String) -> Self {
|
||||||
|
Self(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
#[serde(tag = "type", content = "content")]
|
#[typeshare]
|
||||||
|
struct UserOverview {
|
||||||
|
id: UserId,
|
||||||
|
name: String,
|
||||||
|
status: AccountStatus,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
#[serde(tag = "type", content = "content", rename_all = "kebab-case")]
|
||||||
#[typeshare]
|
#[typeshare]
|
||||||
enum VResponse<A> {
|
enum VResponse<A> {
|
||||||
Success(A),
|
Success(A),
|
||||||
PasswordReset(A),
|
PasswordReset(SessionId),
|
||||||
|
Nothing,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[axum::debug_handler]
|
#[axum::debug_handler]
|
||||||
async fn check_password(request: Json<AuthRequest>) -> (StatusCode, Json<Option<VResponse<SessionId>>>) {
|
async fn check_password(
|
||||||
|
request: Json<AuthRequest>,
|
||||||
|
) -> (StatusCode, Json<Option<VResponse<SessionId>>>) {
|
||||||
let Json(request) = request;
|
let Json(request) = request;
|
||||||
if request.username == "vakarian" && request.password == "aoeu" {
|
if request.username == "vakarian" && request.password == "aoeu" {
|
||||||
(StatusCode::OK, Json(Some(VResponse::Success("vakarian-session-id".into()))))
|
(
|
||||||
|
StatusCode::OK,
|
||||||
|
Json(Some(VResponse::Success("vakarian-session-id".into()))),
|
||||||
|
)
|
||||||
} else if request.username == "shephard" && request.password == "aoeu" {
|
} else if request.username == "shephard" && request.password == "aoeu" {
|
||||||
(StatusCode::OK, Json(Some(VResponse::PasswordReset("shephard-session-id".into()))))
|
(
|
||||||
|
StatusCode::OK,
|
||||||
|
Json(Some(VResponse::PasswordReset("shephard-session-id".into()))),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
(StatusCode::UNAUTHORIZED, Json(None))
|
(StatusCode::UNAUTHORIZED, Json(None))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
enum AppError {
|
||||||
|
#[error("no user authorized")]
|
||||||
|
Unauthorized,
|
||||||
|
#[error("bad request")]
|
||||||
|
BadRequest,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
enum FatalError {
|
||||||
|
#[error("on unknown fatal error occurred")]
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl result_extended::FatalError for FatalError {}
|
||||||
|
|
||||||
|
fn parse_session_header(headers: HeaderMap) -> ResultExt<Option<SessionId>, AppError, FatalError> {
|
||||||
|
match headers.get("Authorization") {
|
||||||
|
Some(token) => {
|
||||||
|
match token
|
||||||
|
.to_str()
|
||||||
|
.unwrap()
|
||||||
|
.split(" ")
|
||||||
|
.collect::<Vec<&str>>()
|
||||||
|
.as_slice()
|
||||||
|
{
|
||||||
|
[_schema, token] => ok(Some(SessionId::from(*token))),
|
||||||
|
_ => error(AppError::BadRequest),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => ok(None),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn auth_required<B, F, Fut>(headers: HeaderMap, f: F) -> (StatusCode, Json<VResponse<B>>)
|
||||||
|
where
|
||||||
|
F: Fn() -> Fut,
|
||||||
|
Fut: Future<Output = (StatusCode, B)>,
|
||||||
|
{
|
||||||
|
match parse_session_header(headers) {
|
||||||
|
ResultExt::Ok(Some(session_id)) => {
|
||||||
|
if session_id == "vakarian-session-id".into() {
|
||||||
|
let (code, result) = f().await;
|
||||||
|
(code, Json(VResponse::Success(result)))
|
||||||
|
} else if session_id == "shephard-id".into() {
|
||||||
|
(StatusCode::OK, Json(VResponse::PasswordReset("shephard-session-id".into())))
|
||||||
|
} else {
|
||||||
|
(StatusCode::UNAUTHORIZED, Json(VResponse::Nothing))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ResultExt::Ok(None) => (StatusCode::UNAUTHORIZED, Json(VResponse::Nothing)),
|
||||||
|
ResultExt::Err(AppError::Unauthorized) => (StatusCode::UNAUTHORIZED, Json(VResponse::Nothing)),
|
||||||
|
ResultExt::Err(AppError::BadRequest) => (StatusCode::BAD_REQUEST, Json(VResponse::Nothing)),
|
||||||
|
ResultExt::Fatal(err) => {
|
||||||
|
panic!("{}", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route(
|
.route(
|
||||||
"/api/v1/health",
|
"/api/test/health",
|
||||||
get(|| async { (StatusCode::OK, Json(None::<String>)) }),
|
get(|| async { (StatusCode::OK, Json(None::<String>)) }),
|
||||||
).layer(
|
)
|
||||||
|
.layer(
|
||||||
CorsLayer::new()
|
CorsLayer::new()
|
||||||
.allow_methods([Method::GET]).allow_origin(Any),
|
.allow_methods([Method::GET])
|
||||||
|
.allow_origin(Any),
|
||||||
)
|
)
|
||||||
.route(
|
.route(
|
||||||
"/api/v1/auth",
|
"/api/test/auth",
|
||||||
post(|req: Json<AuthRequest>| check_password(req)),
|
post(|req: Json<AuthRequest>| check_password(req)),
|
||||||
).layer(
|
)
|
||||||
|
.layer(
|
||||||
CorsLayer::new()
|
CorsLayer::new()
|
||||||
.allow_methods([Method::POST]).allow_origin(Any),
|
.allow_methods([Method::POST])
|
||||||
|
.allow_origin(Any),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/api/test/list-users",
|
||||||
|
get(|headers: HeaderMap| {
|
||||||
|
auth_required(headers, || async {
|
||||||
|
(
|
||||||
|
StatusCode::OK,
|
||||||
|
Some(vec![
|
||||||
|
UserOverview {
|
||||||
|
id: "vakarian-id".into(),
|
||||||
|
name: "vakarian".to_owned(),
|
||||||
|
status: AccountStatus::Ok,
|
||||||
|
},
|
||||||
|
UserOverview {
|
||||||
|
id: "shephard-id".into(),
|
||||||
|
name: "shephard".to_owned(),
|
||||||
|
status: AccountStatus::PasswordReset(
|
||||||
|
"2050-01-01 00:00:00".to_owned(),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
UserOverview {
|
||||||
|
id: "tali-id".into(),
|
||||||
|
name: "tali".to_owned(),
|
||||||
|
status: AccountStatus::Locked,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.layer(
|
||||||
|
CorsLayer::new()
|
||||||
|
.allow_headers([AUTHORIZATION])
|
||||||
|
.allow_methods([Method::GET])
|
||||||
|
.allow_origin(Any),
|
||||||
);
|
);
|
||||||
let listener = tokio::net::TcpListener::bind("127.0.0.1:8001")
|
let listener = tokio::net::TcpListener::bind("127.0.0.1:8001")
|
||||||
.await
|
.await
|
||||||
|
@ -1,53 +0,0 @@
|
|||||||
import { Client, ReqResponse, SessionId } from "./client";
|
|
||||||
|
|
||||||
class MockClient implements Client {
|
|
||||||
users: { [_: string]: string }
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.users = { 'vakarian': 'aoeu', 'shephard': 'aoeu' }
|
|
||||||
}
|
|
||||||
|
|
||||||
async auth(username: string, password: string): Promise<ReqResponse<SessionId>> {
|
|
||||||
if (this.users[username] == password) {
|
|
||||||
if (username == 'shephard') {
|
|
||||||
return { type: 'password-reset' }
|
|
||||||
}
|
|
||||||
return { type: "ok", content: "auth-successful" }
|
|
||||||
} else {
|
|
||||||
return { type: "error", content: 401 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("what happens in an authentication", () => {
|
|
||||||
it("handles a successful response", async () => {
|
|
||||||
let client = new MockClient()
|
|
||||||
let response = await client.auth("vakarian", "aoeu")
|
|
||||||
expect(response).toEqual({ type: "ok", content: "auth-successful" })
|
|
||||||
})
|
|
||||||
|
|
||||||
it("handles an authentication failure", async () => {
|
|
||||||
let client = new MockClient();
|
|
||||||
{
|
|
||||||
let response = await client.auth("vakarian", "")
|
|
||||||
expect(response).toEqual({ type: "error", content: 401 });
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
let response = await client.auth("grunt", "")
|
|
||||||
expect(response).toEqual({ type: "error", content: 401 });
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
it("handles a password-reset condition", async () => {
|
|
||||||
let client = new MockClient();
|
|
||||||
{
|
|
||||||
let response = await client.auth("shephard", "aoeu")
|
|
||||||
expect(response).toEqual({ type: "password-reset" });
|
|
||||||
}
|
|
||||||
{
|
|
||||||
let response = await client.auth("shephard", "")
|
|
||||||
expect(response).toEqual({ type: "error", content: 401 });
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
@ -1,11 +0,0 @@
|
|||||||
export type UserId = string;
|
|
||||||
export type SessionId = string;
|
|
||||||
|
|
||||||
export type ReqResponse<A> = { type: "ok", content: A } | { type: "password-reset" } | { type: "error", content: number }
|
|
||||||
|
|
||||||
export interface Client {
|
|
||||||
auth: (username: string, password: string) => Promise<ReqResponse<SessionId>>
|
|
||||||
// createUser: (sessionId: SessionId, username: string) => Promise<ReqResponse<UserId>>
|
|
||||||
// deleteUser: (sessionId: SessionId, userId: string) => Promise<ReqResponse<void>>
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user