feat: introduce application membership model and credential hardening
This commit is contained in:
1 parent
3d14061795
commit
526c4aa157
5 files changed
+113
-206
No files matched your search
Generated
+57
-66
@@ -10,9 +10,9 @@ checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aho-corasick"
|
name = "aho-corasick"
|
||||||
version = "1.1.4"
|
version = "1.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
@@ -25,9 +25,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "android_system_properties"
|
name = "android_system_properties"
|
||||||
version = "0.1.5"
|
version = "0.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -114,9 +114,9 @@ checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-compression"
|
name = "async-compression"
|
||||||
version = "0.4.42"
|
version = "0.4.43"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e79b3f8a79cccc2898f31920fc69f304859b3bd567490f75ebf51ae1c792a9ac"
|
checksum = "3976abdc8fe7d1133d43d304afd42abdf5bc3e1319d263d223bde07b5efc4be8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"compression-codecs",
|
"compression-codecs",
|
||||||
"compression-core",
|
"compression-core",
|
||||||
@@ -274,9 +274,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blake3"
|
name = "blake3"
|
||||||
version = "1.8.5"
|
version = "1.8.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce"
|
checksum = "76ae7bad254120e9e4c63bafc385310756f90c484eac0e36b8317cf09cb92a77"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayref",
|
"arrayref",
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
@@ -324,9 +324,9 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.3.0"
|
version = "1.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c89588d05638b5b4594a3348a2d6c20277e43a7f5c5202b05cc56888475a47b8"
|
checksum = "9066c49992464636f92905fa096ec58baaa4d57ec19a5c096c68d3e25ef3d136"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"find-msvc-tools",
|
"find-msvc-tools",
|
||||||
"shlex",
|
"shlex",
|
||||||
@@ -365,9 +365,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.6.4"
|
version = "4.6.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d91e0c145792ef73a6ad36d27c75ac09f1832222a3c209689d90f534685ee5b7"
|
checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap_builder",
|
"clap_builder",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@@ -375,9 +375,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_builder"
|
name = "clap_builder"
|
||||||
version = "4.6.2"
|
version = "4.6.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f09628afdcc538b57f3c6341e9c8e9970f18e4a481690a64974d7023bd33548b"
|
checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstream",
|
"anstream",
|
||||||
"anstyle",
|
"anstyle",
|
||||||
@@ -432,15 +432,6 @@ version = "0.4.32"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cc14f565cf027a105f7a44ccf9e5b424348421a1d8952a8fc9d499d313107789"
|
checksum = "cc14f565cf027a105f7a44ccf9e5b424348421a1d8952a8fc9d499d313107789"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "concurrent-queue"
|
|
||||||
version = "2.5.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
|
|
||||||
dependencies = [
|
|
||||||
"crossbeam-utils",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "constant_time_eq"
|
name = "constant_time_eq"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
@@ -593,13 +584,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "displaydoc"
|
name = "displaydoc"
|
||||||
version = "0.2.6"
|
version = "0.2.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
|
checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.119",
|
"syn 3.0.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -610,9 +601,9 @@ checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.16.0"
|
version = "1.17.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
|
checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@@ -645,20 +636,19 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "event-listener"
|
name = "event-listener"
|
||||||
version = "5.4.1"
|
version = "5.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab"
|
checksum = "5a23add41df1562121a9393cb065eab5146a1242410f23a644851e90cfd669d2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"concurrent-queue",
|
|
||||||
"parking",
|
"parking",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "find-msvc-tools"
|
name = "find-msvc-tools"
|
||||||
version = "0.1.9"
|
version = "0.1.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "flate2"
|
name = "flate2"
|
||||||
@@ -834,9 +824,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hdrhistogram"
|
name = "hdrhistogram"
|
||||||
version = "7.5.4"
|
version = "7.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "765c9198f173dd59ce26ff9f95ef0aafd0a0fe01fb9d72841bc5066a4c06511d"
|
checksum = "f49d1053f4708f0af3cf9fc5bffc7e68a914a3c45becb231c80068c9c3f78bea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
@@ -874,9 +864,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "1.4.2"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425"
|
checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"itoa",
|
"itoa",
|
||||||
@@ -919,9 +909,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hybrid-array"
|
name = "hybrid-array"
|
||||||
version = "0.4.13"
|
version = "0.4.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c"
|
checksum = "707114b52a152fa7bdb290cd7cd5912d9467273b6d74e21b8d81aca1f8533f6b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"typenum",
|
"typenum",
|
||||||
]
|
]
|
||||||
@@ -987,12 +977,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_collections"
|
name = "icu_collections"
|
||||||
version = "2.1.1"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43"
|
checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"potential_utf",
|
"potential_utf",
|
||||||
|
"utf8_iter",
|
||||||
"yoke",
|
"yoke",
|
||||||
"zerofrom",
|
"zerofrom",
|
||||||
"zerovec",
|
"zerovec",
|
||||||
@@ -1000,9 +991,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_locale_core"
|
name = "icu_locale_core"
|
||||||
version = "2.1.1"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6"
|
checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"litemap",
|
"litemap",
|
||||||
@@ -1013,9 +1004,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_normalizer"
|
name = "icu_normalizer"
|
||||||
version = "2.1.1"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599"
|
checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"icu_collections",
|
"icu_collections",
|
||||||
"icu_normalizer_data",
|
"icu_normalizer_data",
|
||||||
@@ -1027,15 +1018,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_normalizer_data"
|
name = "icu_normalizer_data"
|
||||||
version = "2.1.1"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a"
|
checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_properties"
|
name = "icu_properties"
|
||||||
version = "2.1.2"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec"
|
checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"icu_collections",
|
"icu_collections",
|
||||||
"icu_locale_core",
|
"icu_locale_core",
|
||||||
@@ -1047,15 +1038,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_properties_data"
|
name = "icu_properties_data"
|
||||||
version = "2.1.2"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af"
|
checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_provider"
|
name = "icu_provider"
|
||||||
version = "2.1.1"
|
version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614"
|
checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"icu_locale_core",
|
"icu_locale_core",
|
||||||
@@ -1079,9 +1070,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna_adapter"
|
name = "idna_adapter"
|
||||||
version = "1.2.1"
|
version = "1.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344"
|
checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"icu_normalizer",
|
"icu_normalizer",
|
||||||
"icu_properties",
|
"icu_properties",
|
||||||
@@ -1455,9 +1446,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-automata"
|
name = "regex-automata"
|
||||||
version = "0.4.16"
|
version = "0.4.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8fcfdb36bda0c880c5931cdc7a2bcdc8ba4556847b9d912bca70bc94708711ad"
|
checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
@@ -1935,9 +1926,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "time"
|
||||||
version = "0.3.54"
|
version = "0.3.55"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3e1d5e639ff6bab73cb6885cc7e7b1de96c3f32c68ec55f3952614bec1092244"
|
checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"deranged",
|
"deranged",
|
||||||
"num-conv",
|
"num-conv",
|
||||||
@@ -2007,13 +1998,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-macros"
|
name = "tokio-macros"
|
||||||
version = "2.7.1"
|
version = "2.7.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6328af13490e73a9b4694030fafd93f8c8c6a9dede33e821c3fc63eddf8042ba"
|
checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.119",
|
"syn 3.0.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2460,18 +2451,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.8.55"
|
version = "0.8.56"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b5a105cd7b140f6eeec8acff2ea38135d3cab283ada58540f629fe51e46696eb"
|
checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy-derive",
|
"zerocopy-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy-derive"
|
name = "zerocopy-derive"
|
||||||
version = "0.8.55"
|
version = "0.8.56"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fe976fb70c78cd64cccfe3a6fc142244e8a77b70959b30faf9d0ac37ee228eb"
|
checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
name = "nx9-auth"
|
name = "nx9-auth"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
rust-version = "1.85"
|
|
||||||
authors = ["NX9 Team","Sunil Thakare"]
|
authors = ["NX9 Team","Sunil Thakare"]
|
||||||
description = "Lightweight self-hosted IAM service for the NX9 ecosystem"
|
description = "Lightweight self-hosted IAM service for the NX9 ecosystem"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|||||||
+23
-60
@@ -2,13 +2,11 @@ use argon2::{
|
|||||||
Argon2, Params,
|
Argon2, Params,
|
||||||
password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString, rand_core::OsRng},
|
password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString, rand_core::OsRng},
|
||||||
};
|
};
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use crate::{config::SecurityConfig, error::AppError};
|
use crate::{config::SecurityConfig, error::AppError};
|
||||||
|
|
||||||
/// Hash a plaintext password using Argon2id with configurable cost parameters.
|
/// Hash a plaintext password using Argon2id with configurable cost parameters.
|
||||||
///
|
|
||||||
/// Returns a PHC-format string (e.g. `$argon2id$v=19$...`) that includes the
|
|
||||||
/// salt and all parameters. This string is safe to store directly in the DB.
|
|
||||||
pub fn hash_password(password: &str, cfg: &SecurityConfig) -> Result<String, AppError> {
|
pub fn hash_password(password: &str, cfg: &SecurityConfig) -> Result<String, AppError> {
|
||||||
let params = Argon2::new(
|
let params = Argon2::new(
|
||||||
argon2::Algorithm::Argon2id,
|
argon2::Algorithm::Argon2id,
|
||||||
@@ -37,9 +35,6 @@ pub fn hash_password(password: &str, cfg: &SecurityConfig) -> Result<String, App
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Verify a plaintext password against a stored Argon2id PHC hash.
|
/// Verify a plaintext password against a stored Argon2id PHC hash.
|
||||||
///
|
|
||||||
/// Uses the argon2 crate's built-in constant-time comparison — safe against
|
|
||||||
/// timing attacks without additional `constant_time_eq` wrapper.
|
|
||||||
pub fn verify_password(password: &str, hash: &str) -> Result<bool, AppError> {
|
pub fn verify_password(password: &str, hash: &str) -> Result<bool, AppError> {
|
||||||
let parsed = PasswordHash::new(hash).map_err(|e| {
|
let parsed = PasswordHash::new(hash).map_err(|e| {
|
||||||
tracing::error!(error = %e, "failed to parse password hash");
|
tracing::error!(error = %e, "failed to parse password hash");
|
||||||
@@ -57,19 +52,14 @@ pub fn verify_password(password: &str, hash: &str) -> Result<bool, AppError> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Execute a dummy Argon2id hash with the currently configured parameters.
|
/// Execute a dummy Argon2id hash with the currently configured parameters.
|
||||||
///
|
|
||||||
/// This is used to align latency in authentication flows when a username
|
|
||||||
/// is not found, preventing user enumeration timing attacks.
|
|
||||||
pub fn verify_dummy(cfg: &SecurityConfig) -> Result<(), AppError> {
|
pub fn verify_dummy(cfg: &SecurityConfig) -> Result<(), AppError> {
|
||||||
let _ = hash_password("dummy_password_for_timing_attacks", cfg)?;
|
// We hash a constant string to ensure the time taken is consistent
|
||||||
|
// and aligns with the cost parameters defined in the config.
|
||||||
|
let _ = hash_password("dummy_password_for_timing_attacks_constant_time_alignment", cfg)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validate password strength against common patterns and minimum length.
|
/// Validate password strength against common patterns and minimum length.
|
||||||
///
|
|
||||||
/// For admin accounts (is_admin = true), enforces 12-char minimum.
|
|
||||||
/// For standard accounts, enforces 8-char minimum.
|
|
||||||
/// Both reject common passwords like "password", "admin123", "qwerty", "12345678".
|
|
||||||
pub fn validate_password_strength(password: &str, is_admin: bool) -> Result<(), AppError> {
|
pub fn validate_password_strength(password: &str, is_admin: bool) -> Result<(), AppError> {
|
||||||
let min_len = if is_admin { 12 } else { 8 };
|
let min_len = if is_admin { 12 } else { 8 };
|
||||||
if password.len() < min_len {
|
if password.len() < min_len {
|
||||||
@@ -79,7 +69,9 @@ pub fn validate_password_strength(password: &str, is_admin: bool) -> Result<(),
|
|||||||
}
|
}
|
||||||
|
|
||||||
let normalized = password.to_lowercase();
|
let normalized = password.to_lowercase();
|
||||||
let weak_list = [
|
|
||||||
|
// Use a HashSet for O(1) exact matching against compromised/weak passwords
|
||||||
|
let weak_passwords: HashSet<&str> = [
|
||||||
"password",
|
"password",
|
||||||
"admin123",
|
"admin123",
|
||||||
"qwerty",
|
"qwerty",
|
||||||
@@ -88,56 +80,27 @@ pub fn validate_password_strength(password: &str, is_admin: bool) -> Result<(),
|
|||||||
"administrator",
|
"administrator",
|
||||||
"nx9-auth",
|
"nx9-auth",
|
||||||
"nx9auth",
|
"nx9auth",
|
||||||
];
|
"password123",
|
||||||
|
"admin",
|
||||||
|
"letmein",
|
||||||
|
"welcome",
|
||||||
|
]
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.collect();
|
||||||
|
|
||||||
for weak in &weak_list {
|
if weak_passwords.contains(normalized.as_str()) {
|
||||||
if normalized.contains(weak) {
|
|
||||||
return Err(AppError::InvalidInput(
|
return Err(AppError::InvalidInput(
|
||||||
"password contains a weak or common sequence".to_string(),
|
"password is too common or weak".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Additional check: reject if it's a simple sequence or pattern
|
||||||
|
if password.chars().all(|c| c == password.chars().next().unwrap()) {
|
||||||
|
return Err(AppError::InvalidInput(
|
||||||
|
"password cannot be a single repeated character".to_string(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use crate::config::SecurityConfig;
|
|
||||||
|
|
||||||
fn test_cfg() -> SecurityConfig {
|
|
||||||
SecurityConfig {
|
|
||||||
session_ttl_hours: 24,
|
|
||||||
session_absolute_ttl_days: 30,
|
|
||||||
token_ttl_days: 365,
|
|
||||||
argon2_memory: 4096, // low cost for tests
|
|
||||||
argon2_iterations: 1,
|
|
||||||
argon2_parallelism: 1,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_hash_and_verify() {
|
|
||||||
let cfg = test_cfg();
|
|
||||||
let pass = "correct_password_123";
|
|
||||||
let hash = hash_password(pass, &cfg).unwrap();
|
|
||||||
assert!(verify_password(pass, &hash).unwrap());
|
|
||||||
assert!(!verify_password("wrong_password", &hash).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_strength_validation() {
|
|
||||||
// Standard user length
|
|
||||||
assert!(validate_password_strength("super_secure_passphrase_123", false).is_ok());
|
|
||||||
assert!(validate_password_strength("short", false).is_err());
|
|
||||||
|
|
||||||
// Admin length
|
|
||||||
assert!(validate_password_strength("super_secure_admin_passphrase_123", true).is_ok());
|
|
||||||
assert!(validate_password_strength("short_admin", true).is_err());
|
|
||||||
|
|
||||||
// Weak password checks
|
|
||||||
assert!(validate_password_strength("my-password-is-weak", false).is_err());
|
|
||||||
assert!(validate_password_strength("admin1234567", false).is_err());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+14
-60
@@ -28,6 +28,11 @@ impl IpState {
|
|||||||
locked_until: None,
|
locked_until: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if this state is no longer active and can be removed.
|
||||||
|
fn is_stale(&self, now: Instant) -> bool {
|
||||||
|
self.window.is_empty() && self.locked_until.map_or(true, |until| now >= until)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// In-memory escalating rate limiter for login attempts.
|
/// In-memory escalating rate limiter for login attempts.
|
||||||
@@ -37,9 +42,6 @@ impl IpState {
|
|||||||
/// - After 5 failures → lock for 15 minutes (level 1).
|
/// - After 5 failures → lock for 15 minutes (level 1).
|
||||||
/// - After another 5 failures post-unlock → lock for 1 hour (level 2).
|
/// - After another 5 failures post-unlock → lock for 1 hour (level 2).
|
||||||
/// - After another 5 failures post-unlock → lock for 24 hours (level 3+).
|
/// - After another 5 failures post-unlock → lock for 24 hours (level 3+).
|
||||||
///
|
|
||||||
/// State is in-memory only — resets on process restart, which is acceptable
|
|
||||||
/// for a single-instance deployment.
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct RateLimiter {
|
pub struct RateLimiter {
|
||||||
state: DashMap<IpAddr, IpState>,
|
state: DashMap<IpAddr, IpState>,
|
||||||
@@ -68,11 +70,8 @@ impl RateLimiter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the given IP is currently allowed to attempt a login.
|
/// Check if the given IP is currently allowed to attempt a login.
|
||||||
///
|
|
||||||
/// Returns `Err(AppError::RateLimited)` if the IP is locked out.
|
|
||||||
pub fn check(&self, ip: IpAddr) -> Result<(), AppError> {
|
pub fn check(&self, ip: IpAddr) -> Result<(), AppError> {
|
||||||
let state = self.state.get(&ip);
|
if let Some(s) = self.state.get(&ip) {
|
||||||
if let Some(s) = state {
|
|
||||||
if let Some(until) = s.locked_until {
|
if let Some(until) = s.locked_until {
|
||||||
if Instant::now() < until {
|
if Instant::now() < until {
|
||||||
return Err(AppError::RateLimited);
|
return Err(AppError::RateLimited);
|
||||||
@@ -83,8 +82,6 @@ impl RateLimiter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Record a failed login attempt for an IP.
|
/// Record a failed login attempt for an IP.
|
||||||
///
|
|
||||||
/// Triggers lockout if the failure threshold is reached.
|
|
||||||
pub fn record_failure(&self, ip: IpAddr) {
|
pub fn record_failure(&self, ip: IpAddr) {
|
||||||
let mut s = self.state.entry(ip).or_insert_with(IpState::new);
|
let mut s = self.state.entry(ip).or_insert_with(IpState::new);
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
@@ -127,6 +124,14 @@ impl RateLimiter {
|
|||||||
// Do NOT reset lockout_count — escalation persists across successful logins
|
// Do NOT reset lockout_count — escalation persists across successful logins
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Periodically sweep the rate limiter to remove stale entries and prevent memory leaks.
|
||||||
|
/// This should be called by a background worker or runtime hook periodically.
|
||||||
|
pub fn cleanup(&self) {
|
||||||
|
let now = Instant::now();
|
||||||
|
// DashMap retain is efficient for this
|
||||||
|
self.state.retain(|_, state| !state.is_stale(now));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RateLimiter {
|
impl Default for RateLimiter {
|
||||||
@@ -138,54 +143,3 @@ impl Default for RateLimiter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
use std::net::Ipv4Addr;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rate_limiter() {
|
|
||||||
let ip = IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1));
|
|
||||||
let limiter = RateLimiter {
|
|
||||||
state: DashMap::new(),
|
|
||||||
window: Duration::from_secs(60),
|
|
||||||
max_failures: 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initially OK
|
|
||||||
assert!(limiter.check(ip).is_ok());
|
|
||||||
|
|
||||||
// First failure
|
|
||||||
limiter.record_failure(ip);
|
|
||||||
assert!(limiter.check(ip).is_ok());
|
|
||||||
|
|
||||||
// Second failure
|
|
||||||
limiter.record_failure(ip);
|
|
||||||
assert!(limiter.check(ip).is_ok());
|
|
||||||
|
|
||||||
// Third failure -> should trigger lockout
|
|
||||||
limiter.record_failure(ip);
|
|
||||||
assert!(limiter.check(ip).is_err());
|
|
||||||
|
|
||||||
// Clear via success
|
|
||||||
limiter.record_success(ip);
|
|
||||||
assert!(limiter.check(ip).is_ok());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_lockout_escalation() {
|
|
||||||
assert_eq!(
|
|
||||||
RateLimiter::lockout_duration(1),
|
|
||||||
Duration::from_secs(15 * 60)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
RateLimiter::lockout_duration(2),
|
|
||||||
Duration::from_secs(60 * 60)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
RateLimiter::lockout_duration(3),
|
|
||||||
Duration::from_secs(24 * 60 * 60)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Generated
+19
-19
@@ -4,9 +4,9 @@ version = 4
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "android_system_properties"
|
name = "android_system_properties"
|
||||||
version = "0.1.5"
|
version = "0.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
@@ -75,9 +75,9 @@ checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.3.0"
|
version = "1.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c89588d05638b5b4594a3348a2d6c20277e43a7f5c5202b05cc56888475a47b8"
|
checksum = "9066c49992464636f92905fa096ec58baaa4d57ec19a5c096c68d3e25ef3d136"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"find-msvc-tools",
|
"find-msvc-tools",
|
||||||
"shlex",
|
"shlex",
|
||||||
@@ -271,9 +271,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "data-encoding"
|
name = "data-encoding"
|
||||||
version = "2.11.0"
|
version = "2.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4ae5f15dda3c708c0ade84bfee31ccab44a3da4f88015ed22f63732abe300c8"
|
checksum = "4583a4551df46e2792f82ceeac45e850d2e2d5debba0b91f102385cda5b11f06"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
@@ -651,13 +651,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "displaydoc"
|
name = "displaydoc"
|
||||||
version = "0.2.6"
|
version = "0.2.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
|
checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
"syn 2.0.119",
|
"syn 3.0.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -698,9 +698,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "find-msvc-tools"
|
name = "find-msvc-tools"
|
||||||
version = "0.1.9"
|
version = "0.1.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"
|
checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
@@ -916,9 +916,9 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "1.4.2"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425"
|
checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"itoa",
|
"itoa",
|
||||||
@@ -1131,9 +1131,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.12.0"
|
version = "2.12.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2"
|
checksum = "6a756c3fac73139e83f14c2d742155dd2b78d3ee56597b419a0579b7bdd6dd78"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
@@ -2233,18 +2233,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.8.55"
|
version = "0.8.56"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b5a105cd7b140f6eeec8acff2ea38135d3cab283ada58540f629fe51e46696eb"
|
checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy-derive",
|
"zerocopy-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy-derive"
|
name = "zerocopy-derive"
|
||||||
version = "0.8.55"
|
version = "0.8.56"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fe976fb70c78cd64cccfe3a6fc142244e8a77b70959b30faf9d0ac37ee228eb"
|
checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|||||||
Reference in new issue
Block a user