Compare commits
	
		
			96 Commits
		
	
	
		
			669f843d2d
			...
			20251028
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| a128e4a597 | |||
| 96f3773375 | |||
| 5db16c2355 | |||
| e93e3f4d9c | |||
| 5abe3bfbd5 | |||
| 4deb1a5536 | |||
| 83efd5ac56 | |||
| 89f806a692 | |||
| 58a19c04e7 | |||
| 7d8931c365 | |||
| 05adc38408 | |||
| 97ff967b87 | |||
| c3215e0053 | |||
| fe968d6765 | |||
| 38bd624ef6 | |||
| e32b2be2b8 | |||
| 29f1c4d1f3 | |||
| 27562c4fbf | |||
| d329a8cf36 | |||
| d4253d897d | |||
| b2c91467e5 | |||
| 922cc4e45f | |||
| e0ec825947 | |||
| e82efde2b9 | |||
| 890e1ef1f1 | |||
| 2503500800 | |||
| 988c15e32e | |||
| 5bb6bdccd0 | |||
| 068284c456 | |||
| a9a9c26a3e | |||
| 34ce0fd1ae | |||
| 8ce29bbb63 | |||
| 52bdb70a8a | |||
| 23c53a8548 | |||
| 28efebdff1 | |||
| d44daf0c04 | |||
| 1cdf10d548 | |||
| 0dcb86c538 | |||
| 4fd42d0e17 | |||
| 9afeb3c67e | |||
| 7213096faf | |||
| 5d321e4cac | |||
| 77f7ba94ba | |||
| 830170303a | |||
| e6ad5b0090 | |||
| 7f42b9ca4f | |||
| 2e195cba32 | |||
| f972a0c1fc | |||
| 90991c89be | |||
| 505d76f804 | |||
| 76920f66d7 | |||
| d86d53ad64 | |||
| f63e0dd97b | |||
| e707b41e5e | |||
| 4f432402fb | |||
| ab0310347c | |||
| 06d46408b5 | |||
| ba55b66ed1 | |||
| 0eaca53a16 | |||
| e8e4aab0eb | |||
| 7abbb78dda | |||
| e26faee426 | |||
| a7a761f32a | |||
| c05718b2d7 | |||
| 0e83f64f24 | |||
| 8a14521d6e | |||
| e3e4e8280c | |||
| 03c538cc96 | |||
| 77d3e49a94 | |||
| df40e5e6be | |||
| e5c6f0d372 | |||
| 46c561ca0b | |||
| 4a3c1b62e0 | |||
| 64e9844f65 | |||
| 958a614f19 | |||
| f869bbde07 | |||
| 257c9c2b85 | |||
| 96b3f35ad0 | |||
| 658e6d498b | |||
| 5241115f79 | |||
| 23e8f33069 | |||
| 77c3dc9e94 | |||
| 0a8fc3c805 | |||
| b820ca4b49 | |||
| dc30d65d68 | |||
| dbea05552d | |||
| fc416752db | |||
| 99dd85c973 | |||
| 69cabe650e | |||
| 18e6ee16ae | |||
| 1e5fc7acfe | |||
| e16e1a5a6a | |||
| 80b9ffd4e0 | |||
| 0a8f441ecb | |||
| ee00b31fd0 | |||
| 7b9ada9164 | 
							
								
								
									
										49
									
								
								.drone.yml
									
									
									
									
									
								
							
							
						
						
									
										49
									
								
								.drone.yml
									
									
									
									
									
								
							@@ -4,10 +4,57 @@ type: docker
 | 
			
		||||
name: default
 | 
			
		||||
 | 
			
		||||
steps:
 | 
			
		||||
- name: cargo_check
 | 
			
		||||
# Code quality
 | 
			
		||||
- name: code_quality
 | 
			
		||||
  image: rust
 | 
			
		||||
  volumes:
 | 
			
		||||
    - name: rust_registry
 | 
			
		||||
      path: /usr/local/cargo/registry
 | 
			
		||||
  commands:
 | 
			
		||||
  - rustup component add clippy
 | 
			
		||||
  - cargo clippy -- -D warnings
 | 
			
		||||
  - cargo test
 | 
			
		||||
 | 
			
		||||
# Build source code
 | 
			
		||||
- name: compile
 | 
			
		||||
  image: rust
 | 
			
		||||
  depends_on:
 | 
			
		||||
    - code_quality
 | 
			
		||||
  when:
 | 
			
		||||
    event:
 | 
			
		||||
      - tag
 | 
			
		||||
  volumes:
 | 
			
		||||
    - name: rust_registry
 | 
			
		||||
      path: /usr/local/cargo/registry
 | 
			
		||||
    - name: releases
 | 
			
		||||
      path: /tmp/releases
 | 
			
		||||
  commands:
 | 
			
		||||
    - cargo build --release
 | 
			
		||||
    - ls -lah target/release/basic-oidc
 | 
			
		||||
    - cp target/release/basic-oidc /tmp/releases
 | 
			
		||||
 | 
			
		||||
# Auto-release to Gitea
 | 
			
		||||
- name: gitea_release
 | 
			
		||||
  image: plugins/gitea-release
 | 
			
		||||
  depends_on:
 | 
			
		||||
    - compile
 | 
			
		||||
  when:
 | 
			
		||||
    event:
 | 
			
		||||
      - tag
 | 
			
		||||
  volumes:
 | 
			
		||||
    - name: releases
 | 
			
		||||
      path: /tmp/releases
 | 
			
		||||
  environment:
 | 
			
		||||
    PLUGIN_API_KEY:
 | 
			
		||||
      from_secret: GITEA_API_KEY # needs permission write:repository
 | 
			
		||||
  settings:
 | 
			
		||||
    base_url: https://gitea.communiquons.org
 | 
			
		||||
    files:
 | 
			
		||||
      - /tmp/releases/basic-oidc
 | 
			
		||||
    checksum: sha512
 | 
			
		||||
 | 
			
		||||
volumes:
 | 
			
		||||
  - name: rust_registry
 | 
			
		||||
    temp: { }
 | 
			
		||||
  - name: releases
 | 
			
		||||
    temp: {}
 | 
			
		||||
							
								
								
									
										261
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										261
									
								
								Cargo.lock
									
									
									
										generated
									
									
									
								
							@@ -46,9 +46,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "actix-http"
 | 
			
		||||
version = "3.10.0"
 | 
			
		||||
version = "3.11.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "0fa882656b67966045e4152c634051e70346939fced7117d5f0b52146a7c74c9"
 | 
			
		||||
checksum = "44dfe5c9e0004c623edc65391dfd51daa201e7e30ebd9c9bedf873048ec32bc2"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "actix-codec",
 | 
			
		||||
 "actix-rt",
 | 
			
		||||
@@ -59,7 +59,7 @@ dependencies = [
 | 
			
		||||
 "brotli",
 | 
			
		||||
 "bytes",
 | 
			
		||||
 "bytestring",
 | 
			
		||||
 "derive_more 2.0.1",
 | 
			
		||||
 "derive_more",
 | 
			
		||||
 "encoding_rs",
 | 
			
		||||
 "flate2",
 | 
			
		||||
 "foldhash",
 | 
			
		||||
@@ -74,7 +74,7 @@ dependencies = [
 | 
			
		||||
 "mime",
 | 
			
		||||
 "percent-encoding",
 | 
			
		||||
 "pin-project-lite",
 | 
			
		||||
 "rand 0.9.0",
 | 
			
		||||
 "rand 0.9.2",
 | 
			
		||||
 "sha1",
 | 
			
		||||
 "smallvec",
 | 
			
		||||
 "tokio",
 | 
			
		||||
@@ -85,15 +85,15 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "actix-identity"
 | 
			
		||||
version = "0.8.0"
 | 
			
		||||
version = "0.9.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "23b8ddc6f6a8b19c4016aaa13519968da9969bc3bc1c1c883cdb0f25dd6c8cf7"
 | 
			
		||||
checksum = "810f47733f956175bd5b2ae17ae5237fa92bd1b6a4a65f646a7240dbe9ff2728"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "actix-service",
 | 
			
		||||
 "actix-session",
 | 
			
		||||
 "actix-utils",
 | 
			
		||||
 "actix-web",
 | 
			
		||||
 "derive_more 1.0.0",
 | 
			
		||||
 "derive_more",
 | 
			
		||||
 "futures-core",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "tracing",
 | 
			
		||||
@@ -147,9 +147,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "actix-server"
 | 
			
		||||
version = "2.5.1"
 | 
			
		||||
version = "2.6.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "6398974fd4284f4768af07965701efbbb5fdc0616bff20cade1bb14b77675e24"
 | 
			
		||||
checksum = "a65064ea4a457eaf07f2fba30b4c695bf43b721790e9530d26cb6f9019ff7502"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "actix-rt",
 | 
			
		||||
 "actix-service",
 | 
			
		||||
@@ -174,16 +174,16 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "actix-session"
 | 
			
		||||
version = "0.10.1"
 | 
			
		||||
version = "0.11.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "efe6976a74f34f1b6d07a6c05aadc0ed0359304a7781c367fa5b4029418db08f"
 | 
			
		||||
checksum = "400c27fd4cdbe0082b7bbd29ac44a3070cbda1b2114138dc106ba39fe2f90dff"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "actix-service",
 | 
			
		||||
 "actix-utils",
 | 
			
		||||
 "actix-web",
 | 
			
		||||
 "anyhow",
 | 
			
		||||
 "derive_more 1.0.0",
 | 
			
		||||
 "rand 0.8.5",
 | 
			
		||||
 "derive_more",
 | 
			
		||||
 "rand 0.9.2",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_json",
 | 
			
		||||
 "tracing",
 | 
			
		||||
@@ -201,9 +201,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "actix-web"
 | 
			
		||||
version = "4.10.2"
 | 
			
		||||
version = "4.11.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f2e3b15b3dc6c6ed996e4032389e9849d4ab002b1e92fbfe85b5f307d1479b4d"
 | 
			
		||||
checksum = "a597b77b5c6d6a1e1097fddde329a83665e25c5437c696a3a9a4aa514a614dea"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "actix-codec",
 | 
			
		||||
 "actix-http",
 | 
			
		||||
@@ -218,7 +218,7 @@ dependencies = [
 | 
			
		||||
 "bytestring",
 | 
			
		||||
 "cfg-if",
 | 
			
		||||
 "cookie",
 | 
			
		||||
 "derive_more 2.0.1",
 | 
			
		||||
 "derive_more",
 | 
			
		||||
 "encoding_rs",
 | 
			
		||||
 "foldhash",
 | 
			
		||||
 "futures-core",
 | 
			
		||||
@@ -339,12 +339,6 @@ dependencies = [
 | 
			
		||||
 "alloc-no-stdlib",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "android-tzdata"
 | 
			
		||||
version = "0.1.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "android_system_properties"
 | 
			
		||||
version = "0.1.5"
 | 
			
		||||
@@ -430,9 +424,9 @@ checksum = "71938f30533e4d95a6d17aa530939da3842c2ab6f4f84b9dae68447e4129f74a"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "askama"
 | 
			
		||||
version = "0.13.0"
 | 
			
		||||
version = "0.14.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "9a4e46abb203e00ef226442d452769233142bbfdd79c3941e84c8e61c4112543"
 | 
			
		||||
checksum = "f75363874b771be265f4ffe307ca705ef6f3baa19011c149da8674a87f1b75c4"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "askama_derive",
 | 
			
		||||
 "itoa",
 | 
			
		||||
@@ -443,9 +437,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "askama_derive"
 | 
			
		||||
version = "0.13.0"
 | 
			
		||||
version = "0.14.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "54398906821fd32c728135f7b351f0c7494ab95ae421d41b6f5a020e158f28a6"
 | 
			
		||||
checksum = "129397200fe83088e8a68407a8e2b1f826cf0086b21ccdb866a722c8bcd3a94f"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "askama_parser",
 | 
			
		||||
 "basic-toml",
 | 
			
		||||
@@ -460,9 +454,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "askama_parser"
 | 
			
		||||
version = "0.13.0"
 | 
			
		||||
version = "0.14.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "cf315ce6524c857bb129ff794935cf6d42c82a6cff60526fe2a63593de4d0d4f"
 | 
			
		||||
checksum = "d6ab5630b3d5eaf232620167977f95eb51f3432fc76852328774afbd242d4358"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "memchr",
 | 
			
		||||
 "serde",
 | 
			
		||||
@@ -574,12 +568,12 @@ checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "base64urlsafedata"
 | 
			
		||||
version = "0.5.1"
 | 
			
		||||
version = "0.5.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "72f0ad38ce7fbed55985ad5b2197f05cff8324ee6eb6638304e78f0108fae56c"
 | 
			
		||||
checksum = "215ee31f8a88f588c349ce2d20108b2ed96089b96b9c2b03775dc35dd72938e8"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "base64 0.21.7",
 | 
			
		||||
 "paste",
 | 
			
		||||
 "pastey",
 | 
			
		||||
 "serde",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@@ -601,7 +595,6 @@ dependencies = [
 | 
			
		||||
 "clap",
 | 
			
		||||
 "digest",
 | 
			
		||||
 "env_logger",
 | 
			
		||||
 "futures-util",
 | 
			
		||||
 "include_dir",
 | 
			
		||||
 "jwt-simple",
 | 
			
		||||
 "lazy-regex",
 | 
			
		||||
@@ -611,7 +604,7 @@ dependencies = [
 | 
			
		||||
 "mailchecker",
 | 
			
		||||
 "mime_guess",
 | 
			
		||||
 "qrcode-generator",
 | 
			
		||||
 "rand 0.9.0",
 | 
			
		||||
 "rand 0.9.2",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_json",
 | 
			
		||||
 "serde_yaml",
 | 
			
		||||
@@ -634,9 +627,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "bcrypt"
 | 
			
		||||
version = "0.17.0"
 | 
			
		||||
version = "0.17.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "92758ad6077e4c76a6cadbce5005f666df70d4f13b19976b1a8062eef880040f"
 | 
			
		||||
checksum = "abaf6da45c74385272ddf00e1ac074c7d8a6c1a1dda376902bd6a427522a8b2c"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "base64 0.22.1",
 | 
			
		||||
 "blowfish",
 | 
			
		||||
@@ -715,9 +708,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "brotli"
 | 
			
		||||
version = "7.0.0"
 | 
			
		||||
version = "8.0.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd"
 | 
			
		||||
checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "alloc-no-stdlib",
 | 
			
		||||
 "alloc-stdlib",
 | 
			
		||||
@@ -726,9 +719,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "brotli-decompressor"
 | 
			
		||||
version = "4.0.2"
 | 
			
		||||
version = "5.0.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37"
 | 
			
		||||
checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "alloc-no-stdlib",
 | 
			
		||||
 "alloc-stdlib",
 | 
			
		||||
@@ -792,16 +785,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "chrono"
 | 
			
		||||
version = "0.4.40"
 | 
			
		||||
version = "0.4.42"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c"
 | 
			
		||||
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "android-tzdata",
 | 
			
		||||
 "iana-time-zone",
 | 
			
		||||
 "js-sys",
 | 
			
		||||
 "num-traits",
 | 
			
		||||
 "wasm-bindgen",
 | 
			
		||||
 "windows-link",
 | 
			
		||||
 "windows-link 0.2.0",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -816,9 +808,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "clap"
 | 
			
		||||
version = "4.5.34"
 | 
			
		||||
version = "4.5.50"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e958897981290da2a852763fe9cdb89cd36977a5d729023127095fa94d95e2ff"
 | 
			
		||||
checksum = "0c2cfd7bf8a6017ddaa4e32ffe7403d547790db06bd171c1c53926faab501623"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "clap_builder",
 | 
			
		||||
 "clap_derive",
 | 
			
		||||
@@ -826,9 +818,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "clap_builder"
 | 
			
		||||
version = "4.5.34"
 | 
			
		||||
version = "4.5.50"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "83b0f35019843db2160b5bb19ae09b4e6411ac33fc6a712003c33e03090e2489"
 | 
			
		||||
checksum = "0a4c05b9e80c5ccd3a7ef080ad7b6ba7d6fc00a985b8b157197075677c82c7a0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anstream",
 | 
			
		||||
 "anstyle",
 | 
			
		||||
@@ -838,9 +830,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "clap_derive"
 | 
			
		||||
version = "4.5.32"
 | 
			
		||||
version = "4.5.49"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
 | 
			
		||||
checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "heck",
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
@@ -871,23 +863,6 @@ version = "1.0.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "compact_jwt"
 | 
			
		||||
version = "0.4.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "12bbab6445446e8d0b07468a01d0bfdae15879de5c440c5e47ae4ae0e18a1fba"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "base64 0.21.7",
 | 
			
		||||
 "base64urlsafedata",
 | 
			
		||||
 "hex",
 | 
			
		||||
 "openssl",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_json",
 | 
			
		||||
 "tracing",
 | 
			
		||||
 "url",
 | 
			
		||||
 "uuid",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "const-oid"
 | 
			
		||||
version = "0.9.6"
 | 
			
		||||
@@ -967,6 +942,12 @@ version = "0.8.21"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "crunchy"
 | 
			
		||||
version = "0.2.4"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "crypto-bigint"
 | 
			
		||||
version = "0.5.5"
 | 
			
		||||
@@ -1045,34 +1026,13 @@ dependencies = [
 | 
			
		||||
 "powerfmt",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "derive_more"
 | 
			
		||||
version = "1.0.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "derive_more-impl 1.0.0",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "derive_more"
 | 
			
		||||
version = "2.0.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "derive_more-impl 2.0.1",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "derive_more-impl"
 | 
			
		||||
version = "1.0.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
 "syn",
 | 
			
		||||
 "unicode-xid",
 | 
			
		||||
 "derive_more-impl",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -1176,9 +1136,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "env_logger"
 | 
			
		||||
version = "0.11.7"
 | 
			
		||||
version = "0.11.8"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "c3716d7a920fb4fac5d84e9d4bce8ceb321e9414b4409da61b07b75c1e3d0697"
 | 
			
		||||
checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anstream",
 | 
			
		||||
 "anstyle",
 | 
			
		||||
@@ -1276,9 +1236,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "form_urlencoded"
 | 
			
		||||
version = "1.2.1"
 | 
			
		||||
version = "1.2.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
 | 
			
		||||
checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "percent-encoding",
 | 
			
		||||
]
 | 
			
		||||
@@ -1438,9 +1398,13 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "half"
 | 
			
		||||
version = "1.8.3"
 | 
			
		||||
version = "2.6.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "1b43ede17f21864e81be2fa654110bf1e793774238d86ef8555c37e6519c0403"
 | 
			
		||||
checksum = "459196ed295495a68f7d7fe1d84f6c4b7ff0e21fe3017b2f283c6fac3ad803c9"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cfg-if",
 | 
			
		||||
 "crunchy",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "hashbrown"
 | 
			
		||||
@@ -1784,9 +1748,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "idna"
 | 
			
		||||
version = "1.0.3"
 | 
			
		||||
version = "1.1.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e"
 | 
			
		||||
checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "idna_adapter",
 | 
			
		||||
 "smallvec",
 | 
			
		||||
@@ -2020,7 +1984,7 @@ dependencies = [
 | 
			
		||||
 "base64 0.22.1",
 | 
			
		||||
 "bincode",
 | 
			
		||||
 "log",
 | 
			
		||||
 "rand 0.9.0",
 | 
			
		||||
 "rand 0.9.2",
 | 
			
		||||
 "reqwest",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_json",
 | 
			
		||||
@@ -2068,15 +2032,15 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "log"
 | 
			
		||||
version = "0.4.27"
 | 
			
		||||
version = "0.4.28"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
 | 
			
		||||
checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "mailchecker"
 | 
			
		||||
version = "6.0.17"
 | 
			
		||||
version = "6.0.19"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "db3c69370540384985601e4adbbbc3046a658853e4909a4bd744bb390f6f9759"
 | 
			
		||||
checksum = "abad4bc63045f04cfc55aa4c55d4ec0a890c377ce56463bfc2adc2bc059c4b84"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "fast_chemail",
 | 
			
		||||
 "once_cell",
 | 
			
		||||
@@ -2286,9 +2250,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "openssl-sys"
 | 
			
		||||
version = "0.9.106"
 | 
			
		||||
version = "0.9.109"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd"
 | 
			
		||||
checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cc",
 | 
			
		||||
 "libc",
 | 
			
		||||
@@ -2344,10 +2308,10 @@ dependencies = [
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "paste"
 | 
			
		||||
version = "1.0.15"
 | 
			
		||||
name = "pastey"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
 | 
			
		||||
checksum = "b3a8cb46bdc156b1c90460339ae6bfd45ba0394e5effbaa640badb4987fdc261"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "pem-rfc7468"
 | 
			
		||||
@@ -2360,9 +2324,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "percent-encoding"
 | 
			
		||||
version = "2.3.1"
 | 
			
		||||
version = "2.3.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 | 
			
		||||
checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "pin-project-lite"
 | 
			
		||||
@@ -2521,13 +2485,12 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "rand"
 | 
			
		||||
version = "0.9.0"
 | 
			
		||||
version = "0.9.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94"
 | 
			
		||||
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "rand_chacha 0.9.0",
 | 
			
		||||
 "rand_core 0.9.3",
 | 
			
		||||
 "zerocopy",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -2840,28 +2803,38 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde"
 | 
			
		||||
version = "1.0.219"
 | 
			
		||||
version = "1.0.228"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
 | 
			
		||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "serde_core",
 | 
			
		||||
 "serde_derive",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_cbor_2"
 | 
			
		||||
version = "0.12.0-dev"
 | 
			
		||||
version = "0.13.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "b46d75f449e01f1eddbe9b00f432d616fbbd899b809c837d0fbc380496a0dd55"
 | 
			
		||||
checksum = "34aec2709de9078e077090abd848e967abab63c9fb3fdb5d4799ad359d8d482c"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "half",
 | 
			
		||||
 "serde",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_derive"
 | 
			
		||||
version = "1.0.219"
 | 
			
		||||
name = "serde_core"
 | 
			
		||||
version = "1.0.228"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
 | 
			
		||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "serde_derive",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_derive"
 | 
			
		||||
version = "1.0.228"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
@@ -2870,14 +2843,15 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_json"
 | 
			
		||||
version = "1.0.140"
 | 
			
		||||
version = "1.0.145"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
 | 
			
		||||
checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "itoa",
 | 
			
		||||
 "memchr",
 | 
			
		||||
 "ryu",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_core",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -2918,9 +2892,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "sha2"
 | 
			
		||||
version = "0.10.8"
 | 
			
		||||
version = "0.10.9"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
 | 
			
		||||
checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "cfg-if",
 | 
			
		||||
 "cpufeatures",
 | 
			
		||||
@@ -3178,9 +3152,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "tokio"
 | 
			
		||||
version = "1.44.1"
 | 
			
		||||
version = "1.45.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f382da615b842244d4b8738c82ed1275e6c5dd90c459a30941cd07080b06c91a"
 | 
			
		||||
checksum = "2513ca694ef9ede0fb23fe71a4ee4107cb102b9dc1930f6d0fd77aae068ae165"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "backtrace",
 | 
			
		||||
 "bytes",
 | 
			
		||||
@@ -3356,9 +3330,9 @@ checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "url"
 | 
			
		||||
version = "2.5.4"
 | 
			
		||||
version = "2.5.7"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60"
 | 
			
		||||
checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "form_urlencoded",
 | 
			
		||||
 "idna",
 | 
			
		||||
@@ -3398,12 +3372,14 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "uuid"
 | 
			
		||||
version = "1.16.0"
 | 
			
		||||
version = "1.18.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9"
 | 
			
		||||
checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "getrandom 0.3.2",
 | 
			
		||||
 "js-sys",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "wasm-bindgen",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -3540,12 +3516,13 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "webauthn-attestation-ca"
 | 
			
		||||
version = "0.5.1"
 | 
			
		||||
version = "0.5.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "29e77e8859ecb93b00e4a8e56ae45f8a8dd69b1539e3d32cf4cce1db9a3a0b99"
 | 
			
		||||
checksum = "f77a2892ec44032e6c48dad9aad1b05fada09c346ada11d8d32db119b4b4f205"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "base64urlsafedata",
 | 
			
		||||
 "openssl",
 | 
			
		||||
 "openssl-sys",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "tracing",
 | 
			
		||||
 "uuid",
 | 
			
		||||
@@ -3553,9 +3530,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "webauthn-rs"
 | 
			
		||||
version = "0.5.1"
 | 
			
		||||
version = "0.5.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "8b44347ee0d66f222043663a6aaf5ec78022b9b11c3a9ed488c21f2bd5680856"
 | 
			
		||||
checksum = "eb7c3a2f9c8bddd524e47bbd427bcf3a28aa074de55d74470b42a91a41937b8e"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "base64urlsafedata",
 | 
			
		||||
 "serde",
 | 
			
		||||
@@ -3567,17 +3544,17 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "webauthn-rs-core"
 | 
			
		||||
version = "0.5.1"
 | 
			
		||||
version = "0.5.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "2ef48f07ed8f3dfe304d6c48e85317feba0439675f31a13063b2936c9b4eaf0d"
 | 
			
		||||
checksum = "19f1d80f3146382529fe70a3ab5d0feb2413a015204ed7843f9377cd39357fc4"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "base64 0.21.7",
 | 
			
		||||
 "base64urlsafedata",
 | 
			
		||||
 "compact_jwt",
 | 
			
		||||
 "der-parser",
 | 
			
		||||
 "hex",
 | 
			
		||||
 "nom",
 | 
			
		||||
 "openssl",
 | 
			
		||||
 "openssl-sys",
 | 
			
		||||
 "rand 0.8.5",
 | 
			
		||||
 "rand_chacha 0.3.1",
 | 
			
		||||
 "serde",
 | 
			
		||||
@@ -3594,9 +3571,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "webauthn-rs-proto"
 | 
			
		||||
version = "0.5.1"
 | 
			
		||||
version = "0.5.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "14e1367f70e7dc7b83afc971ce8a54d578f4fdf488ea093021180e073744a69f"
 | 
			
		||||
checksum = "9e786894f89facb9aaf1c5f6559670236723c98382e045521c76f3d5ca5047bd"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "base64 0.21.7",
 | 
			
		||||
 "base64urlsafedata",
 | 
			
		||||
@@ -3620,6 +3597,12 @@ version = "0.1.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows-link"
 | 
			
		||||
version = "0.2.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "windows-registry"
 | 
			
		||||
version = "0.4.0"
 | 
			
		||||
@@ -3637,7 +3620,7 @@ version = "0.3.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "windows-link",
 | 
			
		||||
 "windows-link 0.1.1",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@@ -3646,7 +3629,7 @@ version = "0.3.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "windows-link",
 | 
			
		||||
 "windows-link 0.1.1",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										49
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										49
									
								
								Cargo.toml
									
									
									
									
									
								
							@@ -7,36 +7,35 @@ edition = "2024"
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
actix = "0.13.5"
 | 
			
		||||
actix-identity = "0.8.0"
 | 
			
		||||
actix-web = "4.10.2"
 | 
			
		||||
actix-session = { version = "0.10.1", features = ["cookie-session"] }
 | 
			
		||||
actix-identity = "0.9.0"
 | 
			
		||||
actix-web = "4.11.0"
 | 
			
		||||
actix-session = { version = "0.11.0", features = ["cookie-session"] }
 | 
			
		||||
actix-remote-ip = "0.1.0"
 | 
			
		||||
clap = { version = "4.5.34", features = ["derive", "env"] }
 | 
			
		||||
include_dir = "0.7.3"
 | 
			
		||||
log = "0.4.27"
 | 
			
		||||
serde_json = "1.0.128"
 | 
			
		||||
clap = { version = "4.5.50", features = ["derive", "env"] }
 | 
			
		||||
include_dir = "0.7.4"
 | 
			
		||||
log = "0.4.28"
 | 
			
		||||
serde_json = "1.0.145"
 | 
			
		||||
serde_yaml = "0.9.34"
 | 
			
		||||
env_logger = "0.11.3"
 | 
			
		||||
serde = { version = "1.0.210", features = ["derive"] }
 | 
			
		||||
bcrypt = "0.17.0"
 | 
			
		||||
uuid = { version = "1.8.0", features = ["v4"] }
 | 
			
		||||
mime_guess = "2.0.4"
 | 
			
		||||
askama = "0.13.0"
 | 
			
		||||
futures-util = "0.3.30"
 | 
			
		||||
env_logger = "0.11.8"
 | 
			
		||||
serde = { version = "1.0.228", features = ["derive"] }
 | 
			
		||||
bcrypt = "0.17.1"
 | 
			
		||||
uuid = { version = "1.18.1", features = ["v4"] }
 | 
			
		||||
mime_guess = "2.0.5"
 | 
			
		||||
askama = "0.14.0"
 | 
			
		||||
urlencoding = "2.1.3"
 | 
			
		||||
rand = "0.9.0"
 | 
			
		||||
rand = "0.9.2"
 | 
			
		||||
base64 = "0.22.1"
 | 
			
		||||
jwt-simple = { version = "0.12.11", default-features = false, features = ["pure-rust"] }
 | 
			
		||||
jwt-simple = { version = "0.12.12", default-features = false, features = ["pure-rust"] }
 | 
			
		||||
digest = "0.10.7"
 | 
			
		||||
sha2 = "0.10.8"
 | 
			
		||||
lazy-regex = "3.3.0"
 | 
			
		||||
totp_rfc6238 = "0.6.0"
 | 
			
		||||
base32 = "0.5.0"
 | 
			
		||||
sha2 = "0.10.9"
 | 
			
		||||
lazy-regex = "3.4.1"
 | 
			
		||||
totp_rfc6238 = "0.6.1"
 | 
			
		||||
base32 = "0.5.1"
 | 
			
		||||
qrcode-generator = "5.0.0"
 | 
			
		||||
webauthn-rs = { version = "0.5.0", features = ["danger-allow-state-serialisation"] }
 | 
			
		||||
url = "2.5.0"
 | 
			
		||||
webauthn-rs = { version = "0.5.3", features = ["danger-allow-state-serialisation"] }
 | 
			
		||||
url = "2.5.7"
 | 
			
		||||
light-openid = { version = "1.0.4", features = ["crypto-wrapper"] }
 | 
			
		||||
bincode = "2.0.1"
 | 
			
		||||
chrono = "0.4.38"
 | 
			
		||||
lazy_static = "1.4.0"
 | 
			
		||||
mailchecker = "6.0.8"
 | 
			
		||||
chrono = "0.4.42"
 | 
			
		||||
lazy_static = "1.5.0"
 | 
			
		||||
mailchecker = "6.0.19"
 | 
			
		||||
 
 | 
			
		||||
@@ -151,7 +151,7 @@ impl Handler<LocalLoginRequest> for UsersActor {
 | 
			
		||||
    fn handle(&mut self, msg: LocalLoginRequest, _ctx: &mut Self::Context) -> Self::Result {
 | 
			
		||||
        match self.manager.find_by_username_or_email(&msg.login) {
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                log::error!("Failed to find user! {}", e);
 | 
			
		||||
                log::error!("Failed to find user! {e}");
 | 
			
		||||
                MessageResult(LoginResult::Error)
 | 
			
		||||
            }
 | 
			
		||||
            Ok(None) => MessageResult(LoginResult::AccountNotFound),
 | 
			
		||||
@@ -184,7 +184,7 @@ impl Handler<ProviderLoginRequest> for UsersActor {
 | 
			
		||||
    fn handle(&mut self, msg: ProviderLoginRequest, _ctx: &mut Self::Context) -> Self::Result {
 | 
			
		||||
        match self.manager.find_by_email(&msg.email) {
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                log::error!("Failed to find user! {}", e);
 | 
			
		||||
                log::error!("Failed to find user! {e}");
 | 
			
		||||
                MessageResult(LoginResult::Error)
 | 
			
		||||
            }
 | 
			
		||||
            Ok(None) => MessageResult(LoginResult::AccountNotFound),
 | 
			
		||||
@@ -210,7 +210,7 @@ impl Handler<CreateAccount> for UsersActor {
 | 
			
		||||
        match self.manager.create_user_account(msg.0) {
 | 
			
		||||
            Ok(id) => Some(id),
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                log::error!("Failed to create user account! {}", e);
 | 
			
		||||
                log::error!("Failed to create user account! {e}");
 | 
			
		||||
                None
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -227,7 +227,7 @@ impl Handler<ChangePasswordRequest> for UsersActor {
 | 
			
		||||
        {
 | 
			
		||||
            Ok(_) => true,
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                log::error!("Failed to change user password! {:?}", e);
 | 
			
		||||
                log::error!("Failed to change user password! {e:?}");
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -241,7 +241,7 @@ impl Handler<Add2FAFactor> for UsersActor {
 | 
			
		||||
        match self.manager.add_2fa_factor(&msg.0, msg.1) {
 | 
			
		||||
            Ok(_) => true,
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                log::error!("Failed to add 2FA factor! {}", e);
 | 
			
		||||
                log::error!("Failed to add 2FA factor! {e}");
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -255,7 +255,7 @@ impl Handler<Remove2FAFactor> for UsersActor {
 | 
			
		||||
        match self.manager.remove_2fa_factor(&msg.0, msg.1) {
 | 
			
		||||
            Ok(_) => true,
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                log::error!("Failed to remove 2FA factor! {}", e);
 | 
			
		||||
                log::error!("Failed to remove 2FA factor! {e}");
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -272,7 +272,7 @@ impl Handler<AddSuccessful2FALogin> for UsersActor {
 | 
			
		||||
        {
 | 
			
		||||
            Ok(_) => true,
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                log::error!("Failed to save successful 2FA authentication! {}", e);
 | 
			
		||||
                log::error!("Failed to save successful 2FA authentication! {e}");
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -309,10 +309,7 @@ impl Handler<SetAuthorizedAuthenticationSources> for UsersActor {
 | 
			
		||||
        {
 | 
			
		||||
            Ok(_) => true,
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                log::error!(
 | 
			
		||||
                    "Failed to set authorized authentication sources for user! {}",
 | 
			
		||||
                    e
 | 
			
		||||
                );
 | 
			
		||||
                log::error!("Failed to set authorized authentication sources for user! {e}");
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -325,7 +322,7 @@ impl Handler<SetGrantedClients> for UsersActor {
 | 
			
		||||
        match self.manager.set_granted_2fa_clients(&msg.0, msg.1) {
 | 
			
		||||
            Ok(_) => true,
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                log::error!("Failed to set granted 2FA clients! {}", e);
 | 
			
		||||
                log::error!("Failed to set granted 2FA clients! {e}");
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -339,7 +336,7 @@ impl Handler<GetUserRequest> for UsersActor {
 | 
			
		||||
        MessageResult(GetUserResult(match self.manager.find_by_user_id(&msg.0) {
 | 
			
		||||
            Ok(r) => r,
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                log::error!("Failed to find user by id! {}", e);
 | 
			
		||||
                log::error!("Failed to find user by id! {e}");
 | 
			
		||||
                None
 | 
			
		||||
            }
 | 
			
		||||
        }))
 | 
			
		||||
@@ -353,7 +350,7 @@ impl Handler<VerifyUserPasswordRequest> for UsersActor {
 | 
			
		||||
        self.manager
 | 
			
		||||
            .verify_user_password(&msg.0, &msg.1)
 | 
			
		||||
            .unwrap_or_else(|e| {
 | 
			
		||||
                log::error!("Failed to verify user password! {}", e);
 | 
			
		||||
                log::error!("Failed to verify user password! {e}");
 | 
			
		||||
                false
 | 
			
		||||
            })
 | 
			
		||||
    }
 | 
			
		||||
@@ -367,7 +364,7 @@ impl Handler<FindUserByUsername> for UsersActor {
 | 
			
		||||
            self.manager
 | 
			
		||||
                .find_by_username_or_email(&msg.0)
 | 
			
		||||
                .unwrap_or_else(|e| {
 | 
			
		||||
                    log::error!("Failed to find user by username or email! {}", e);
 | 
			
		||||
                    log::error!("Failed to find user by username or email! {e}");
 | 
			
		||||
                    None
 | 
			
		||||
                }),
 | 
			
		||||
        ))
 | 
			
		||||
@@ -381,7 +378,7 @@ impl Handler<GetAllUsers> for UsersActor {
 | 
			
		||||
        match self.manager.get_entire_users_list() {
 | 
			
		||||
            Ok(r) => r,
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                log::error!("Failed to get entire users list! {}", e);
 | 
			
		||||
                log::error!("Failed to get entire users list! {e}");
 | 
			
		||||
                vec![]
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -395,7 +392,7 @@ impl Handler<UpdateUserSettings> for UsersActor {
 | 
			
		||||
        match self.manager.set_general_user_settings(msg.0) {
 | 
			
		||||
            Ok(_) => true,
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                log::error!("Failed to update general user information! {:?}", e);
 | 
			
		||||
                log::error!("Failed to update general user information! {e:?}");
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -409,7 +406,7 @@ impl Handler<DeleteUserRequest> for UsersActor {
 | 
			
		||||
        match self.manager.delete_account(&msg.0) {
 | 
			
		||||
            Ok(_) => true,
 | 
			
		||||
            Err(e) => {
 | 
			
		||||
                log::error!("Failed to delete user account! {}", e);
 | 
			
		||||
                log::error!("Failed to delete user account! {e}");
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ pub async fn auth_webauthn(
 | 
			
		||||
            HttpResponse::Ok().body("You are authenticated!")
 | 
			
		||||
        }
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to authenticate user using webauthn! {:?}", e);
 | 
			
		||||
            log::error!("Failed to authenticate user using webauthn! {e:?}");
 | 
			
		||||
            logger.log(Action::LoginWebauthnAttempt {
 | 
			
		||||
                success: false,
 | 
			
		||||
                user_id,
 | 
			
		||||
 
 | 
			
		||||
@@ -190,12 +190,7 @@ pub async fn login_route(
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            c => {
 | 
			
		||||
                log::warn!(
 | 
			
		||||
                    "Failed login for ip {:?} /  username {}: {:?}",
 | 
			
		||||
                    remote_ip,
 | 
			
		||||
                    login,
 | 
			
		||||
                    c
 | 
			
		||||
                );
 | 
			
		||||
                log::warn!("Failed login for ip {remote_ip:?} /  username {login}: {c:?}");
 | 
			
		||||
                logger.log(Action::FailedLoginWithBadCredentials(&login));
 | 
			
		||||
                danger = Some("Login failed.".to_string());
 | 
			
		||||
 | 
			
		||||
@@ -474,7 +469,7 @@ pub async fn login_with_webauthn(
 | 
			
		||||
    let challenge = match manager.start_authentication(&user.uid, &pub_keys) {
 | 
			
		||||
        Ok(c) => c,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to generate webauthn challenge! {:?}", e);
 | 
			
		||||
            log::error!("Failed to generate webauthn challenge! {e:?}");
 | 
			
		||||
            return HttpResponse::InternalServerError().body(build_fatal_error_page(
 | 
			
		||||
                "Failed to generate webauthn challenge",
 | 
			
		||||
            ));
 | 
			
		||||
@@ -484,7 +479,7 @@ pub async fn login_with_webauthn(
 | 
			
		||||
    let challenge_json = match serde_json::to_string(&challenge.login_challenge) {
 | 
			
		||||
        Ok(r) => r,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to serialize challenge! {:?}", e);
 | 
			
		||||
            log::error!("Failed to serialize challenge! {e:?}");
 | 
			
		||||
            return HttpResponse::InternalServerError().body("Failed to serialize challenge!");
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 
 | 
			
		||||
@@ -111,12 +111,7 @@ pub struct AuthorizeQuery {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn error_redirect(query: &AuthorizeQuery, error: &str, description: &str) -> HttpResponse {
 | 
			
		||||
    log::warn!(
 | 
			
		||||
        "Failed to process sign in request ({} => {}): {:?}",
 | 
			
		||||
        error,
 | 
			
		||||
        description,
 | 
			
		||||
        query
 | 
			
		||||
    );
 | 
			
		||||
    log::warn!("Failed to process sign in request ({error} => {description}): {query:?}");
 | 
			
		||||
    HttpResponse::Found()
 | 
			
		||||
        .append_header((
 | 
			
		||||
            "Location",
 | 
			
		||||
@@ -243,7 +238,7 @@ pub async fn authorize(
 | 
			
		||||
                .await
 | 
			
		||||
                .unwrap();
 | 
			
		||||
 | 
			
		||||
            log::trace!("New OpenID session: {:#?}", session);
 | 
			
		||||
            log::trace!("New OpenID session: {session:#?}");
 | 
			
		||||
            logger.log(Action::NewOpenIDSession { client: &client });
 | 
			
		||||
 | 
			
		||||
            Ok(HttpResponse::Found()
 | 
			
		||||
@@ -319,12 +314,7 @@ struct ErrorResponse {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub fn error_response<D: Debug>(query: &D, error: &str, description: &str) -> HttpResponse {
 | 
			
		||||
    log::warn!(
 | 
			
		||||
        "request failed: {} - {} => '{:#?}'",
 | 
			
		||||
        error,
 | 
			
		||||
        description,
 | 
			
		||||
        query
 | 
			
		||||
    );
 | 
			
		||||
    log::warn!("request failed: {error} - {description} => '{query:#?}'");
 | 
			
		||||
    HttpResponse::BadRequest().json(ErrorResponse {
 | 
			
		||||
        error: error.to_string(),
 | 
			
		||||
        error_description: description.to_string(),
 | 
			
		||||
@@ -389,7 +379,7 @@ pub async fn token(
 | 
			
		||||
                let decode = String::from_utf8_lossy(&match BASE64_STANDARD.decode(token) {
 | 
			
		||||
                    Ok(d) => d,
 | 
			
		||||
                    Err(e) => {
 | 
			
		||||
                        log::error!("Failed to decode authorization header: {:?}", e);
 | 
			
		||||
                        log::error!("Failed to decode authorization header: {e:?}");
 | 
			
		||||
                        return Ok(error_response(
 | 
			
		||||
                            &query,
 | 
			
		||||
                            "invalid_request",
 | 
			
		||||
 
 | 
			
		||||
@@ -96,14 +96,14 @@ pub async fn start_login(
 | 
			
		||||
    let config = match ProviderConfigurationHelper::get_configuration(&provider).await {
 | 
			
		||||
        Ok(c) => c,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to load provider configuration! {}", e);
 | 
			
		||||
            log::error!("Failed to load provider configuration! {e}");
 | 
			
		||||
            return HttpResponse::InternalServerError().body(build_fatal_error_page(
 | 
			
		||||
                "Failed to load provider configuration!",
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    log::debug!("Provider configuration: {:?}", config);
 | 
			
		||||
    log::debug!("Provider configuration: {config:?}");
 | 
			
		||||
 | 
			
		||||
    let url = config.auth_url(&provider, &state);
 | 
			
		||||
    log::debug!("Redirect user on {url} for authentication",);
 | 
			
		||||
@@ -210,7 +210,7 @@ pub async fn finish_login(
 | 
			
		||||
    let provider_config = match ProviderConfigurationHelper::get_configuration(&provider).await {
 | 
			
		||||
        Ok(c) => c,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to load provider configuration! {}", e);
 | 
			
		||||
            log::error!("Failed to load provider configuration! {e}");
 | 
			
		||||
            return HttpResponse::InternalServerError().body(build_fatal_error_page(
 | 
			
		||||
                "Failed to load provider configuration!",
 | 
			
		||||
            ));
 | 
			
		||||
@@ -222,7 +222,7 @@ pub async fn finish_login(
 | 
			
		||||
    let token = match token {
 | 
			
		||||
        Ok(t) => t,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to retrieve login token! {:?}", e);
 | 
			
		||||
            log::error!("Failed to retrieve login token! {e:?}");
 | 
			
		||||
 | 
			
		||||
            bruteforce
 | 
			
		||||
                .send(bruteforce_actor::RecordFailedAttempt {
 | 
			
		||||
@@ -247,7 +247,7 @@ pub async fn finish_login(
 | 
			
		||||
    let user_info = match provider_config.get_userinfo(&token).await {
 | 
			
		||||
        Ok(info) => info,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to retrieve user information! {:?}", e);
 | 
			
		||||
            log::error!("Failed to retrieve user information! {e:?}");
 | 
			
		||||
 | 
			
		||||
            logger.log(Action::ProviderFailedGetUserInfo {
 | 
			
		||||
                provider: &provider,
 | 
			
		||||
 
 | 
			
		||||
@@ -94,7 +94,7 @@ pub async fn save_webauthn_factor(
 | 
			
		||||
    let key = match manager.finish_registration(&user, &form.0.opaque_state, form.0.credential) {
 | 
			
		||||
        Ok(k) => k,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to register security key! {:?}", e);
 | 
			
		||||
            log::error!("Failed to register security key! {e:?}");
 | 
			
		||||
            return HttpResponse::InternalServerError().body("Failed to register key!");
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 
 | 
			
		||||
@@ -68,7 +68,7 @@ pub async fn add_totp_factor_route(_critical: CriticalRoute, user: CurrentUser)
 | 
			
		||||
    let qr_code = match qr_code {
 | 
			
		||||
        Ok(q) => q,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to generate QrCode! {:?}", e);
 | 
			
		||||
            log::error!("Failed to generate QrCode! {e:?}");
 | 
			
		||||
            return HttpResponse::InternalServerError().body("Failed to generate QrCode!");
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
@@ -95,7 +95,7 @@ pub async fn add_webauthn_factor_route(
 | 
			
		||||
    let registration_request = match manager.start_register(&user) {
 | 
			
		||||
        Ok(r) => r,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to request new key! {:?}", e);
 | 
			
		||||
            log::error!("Failed to request new key! {e:?}");
 | 
			
		||||
            return HttpResponse::InternalServerError()
 | 
			
		||||
                .body("Failed to generate request for registration!");
 | 
			
		||||
        }
 | 
			
		||||
@@ -104,7 +104,7 @@ pub async fn add_webauthn_factor_route(
 | 
			
		||||
    let challenge_json = match serde_json::to_string(®istration_request.creation_challenge) {
 | 
			
		||||
        Ok(r) => r,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to serialize challenge! {:?}", e);
 | 
			
		||||
            log::error!("Failed to serialize challenge! {e:?}");
 | 
			
		||||
            return HttpResponse::InternalServerError().body("Failed to serialize challenge!");
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 
 | 
			
		||||
@@ -156,8 +156,7 @@ impl Action<'_> {
 | 
			
		||||
                    .to_string()
 | 
			
		||||
            }
 | 
			
		||||
            Action::ProviderFailedGetToken { state, code } => format!(
 | 
			
		||||
                "could not complete login from provider because the id_token could not be retrieved! (state={:?} code = {code})",
 | 
			
		||||
                state
 | 
			
		||||
                "could not complete login from provider because the id_token could not be retrieved! (state={state:?} code = {code})"
 | 
			
		||||
            ),
 | 
			
		||||
            Action::ProviderFailedGetUserInfo { provider } => format!(
 | 
			
		||||
                "could not get user information from userinfo endpoint of provider {}!",
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,14 @@ pub struct AppConfig {
 | 
			
		||||
    #[clap(short, long, env)]
 | 
			
		||||
    pub storage_path: String,
 | 
			
		||||
 | 
			
		||||
    /// Overwrite clients list file path, if the file is not to be found in storage path
 | 
			
		||||
    #[clap(long, env)]
 | 
			
		||||
    pub clients_list_file_path: Option<String>,
 | 
			
		||||
 | 
			
		||||
    /// Overwrite providers list file path, if the file is not to be found in storage path
 | 
			
		||||
    #[clap(long, env)]
 | 
			
		||||
    pub providers_list_file_path: Option<String>,
 | 
			
		||||
 | 
			
		||||
    /// App token token
 | 
			
		||||
    #[clap(short, long, env, default_value = "")]
 | 
			
		||||
    pub token_key: String,
 | 
			
		||||
@@ -32,7 +40,7 @@ pub struct AppConfig {
 | 
			
		||||
 | 
			
		||||
    /// IP location service API
 | 
			
		||||
    ///
 | 
			
		||||
    /// Up instance of IP location service : https://gitlab.com/pierre42100/iplocationserver
 | 
			
		||||
    /// Operating instance of IP location service : https://gitlab.com/pierre42100/iplocationserver
 | 
			
		||||
    ///
 | 
			
		||||
    /// Example: "https://api.geoip.rs"
 | 
			
		||||
    #[arg(long, short, env)]
 | 
			
		||||
@@ -71,11 +79,17 @@ impl AppConfig {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn clients_file(&self) -> PathBuf {
 | 
			
		||||
        self.storage_path().join(CLIENTS_LIST_FILE)
 | 
			
		||||
        match &self.clients_list_file_path {
 | 
			
		||||
            None => self.storage_path().join(CLIENTS_LIST_FILE),
 | 
			
		||||
            Some(p) => Path::new(p).to_path_buf(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn providers_file(&self) -> PathBuf {
 | 
			
		||||
        self.storage_path().join(PROVIDERS_LIST_FILE)
 | 
			
		||||
        match &self.providers_list_file_path {
 | 
			
		||||
            None => self.storage_path().join(PROVIDERS_LIST_FILE),
 | 
			
		||||
            Some(p) => Path::new(p).to_path_buf(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn full_url(&self, uri: &str) -> String {
 | 
			
		||||
 
 | 
			
		||||
@@ -125,7 +125,7 @@ impl Client {
 | 
			
		||||
 | 
			
		||||
pub type ClientManager = EntityManager<Client>;
 | 
			
		||||
 | 
			
		||||
impl EntityManager<Client> {
 | 
			
		||||
impl ClientManager {
 | 
			
		||||
    pub fn find_by_id(&self, u: &ClientID) -> Option<Client> {
 | 
			
		||||
        for entry in self.iter() {
 | 
			
		||||
            if entry.id.eq(u) {
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ impl CodeChallenge {
 | 
			
		||||
                encoded.eq(&self.code_challenge)
 | 
			
		||||
            }
 | 
			
		||||
            s => {
 | 
			
		||||
                log::error!("Unknown code challenge method: {}", s);
 | 
			
		||||
                log::error!("Unknown code challenge method: {s}");
 | 
			
		||||
                false
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -40,8 +40,8 @@ mod test {
 | 
			
		||||
            code_challenge: "text1".to_string(),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        assert_eq!(true, chal.verify_code("text1"));
 | 
			
		||||
        assert_eq!(false, chal.verify_code("text2"));
 | 
			
		||||
        assert!(chal.verify_code("text1"));
 | 
			
		||||
        assert!(!chal.verify_code("text2"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
@@ -51,8 +51,8 @@ mod test {
 | 
			
		||||
            code_challenge: "uSOvC48D8TMh6RgW-36XppMlMgys-6KAE_wEIev9W2g".to_string(),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        assert_eq!(true, chal.verify_code("HIwht3lCHfnsruA+7Sq8NP2mPj5cBZe0Ewf23eK9UQhK4TdCIt3SK7Fr/giCdnfjxYQILOPG2D562emggAa2lA=="));
 | 
			
		||||
        assert_eq!(false, chal.verify_code("text1"));
 | 
			
		||||
        assert!(chal.verify_code("HIwht3lCHfnsruA+7Sq8NP2mPj5cBZe0Ewf23eK9UQhK4TdCIt3SK7Fr/giCdnfjxYQILOPG2D562emggAa2lA=="));
 | 
			
		||||
        assert!(!chal.verify_code("text1"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
@@ -62,10 +62,7 @@ mod test {
 | 
			
		||||
            code_challenge: "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM".to_string(),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            true,
 | 
			
		||||
            chal.verify_code("dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk")
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(false, chal.verify_code("text1"));
 | 
			
		||||
        assert!(chal.verify_code("dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"));
 | 
			
		||||
        assert!(!chal.verify_code("text1"));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ impl SessionIdentity<'_> {
 | 
			
		||||
            .map(|f| match f {
 | 
			
		||||
                Ok(d) => Some(d),
 | 
			
		||||
                Err(e) => {
 | 
			
		||||
                    log::warn!("Failed to deserialize session data! {:?}", e);
 | 
			
		||||
                    log::warn!("Failed to deserialize session data! {e:?}");
 | 
			
		||||
                    None
 | 
			
		||||
                }
 | 
			
		||||
            })
 | 
			
		||||
@@ -65,7 +65,7 @@ impl SessionIdentity<'_> {
 | 
			
		||||
 | 
			
		||||
        log::debug!("Will set user session data.");
 | 
			
		||||
        if let Err(e) = Identity::login(&req.extensions(), s) {
 | 
			
		||||
            log::error!("Failed to set session data! {}", e);
 | 
			
		||||
            log::error!("Failed to set session data! {e}");
 | 
			
		||||
        }
 | 
			
		||||
        log::debug!("Did set user session data.");
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,3 @@
 | 
			
		||||
use std::io::ErrorKind;
 | 
			
		||||
 | 
			
		||||
use base32::Alphabet;
 | 
			
		||||
use rand::Rng;
 | 
			
		||||
use totp_rfc6238::{HashAlgorithm, TotpGenerator};
 | 
			
		||||
@@ -90,8 +88,7 @@ impl TotpKey {
 | 
			
		||||
 | 
			
		||||
        let key = match base32::decode(BASE32_ALPHABET, &self.encoded) {
 | 
			
		||||
            None => {
 | 
			
		||||
                return Err(Box::new(std::io::Error::new(
 | 
			
		||||
                    ErrorKind::Other,
 | 
			
		||||
                return Err(Box::new(std::io::Error::other(
 | 
			
		||||
                    "Failed to decode base32 secret!",
 | 
			
		||||
                )));
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -18,7 +18,7 @@ impl EntityManager<User> {
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if let Err(e) = self.replace_entries(|u| u.uid.eq(id), &update(user)) {
 | 
			
		||||
            log::error!("Failed to update user information! {:?}", e);
 | 
			
		||||
            log::error!("Failed to update user information! {e:?}");
 | 
			
		||||
            return Err(e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -34,7 +34,7 @@ fn verify_password<P: AsRef<[u8]>>(pwd: P, hash: &str) -> bool {
 | 
			
		||||
    match bcrypt::verify(pwd, hash) {
 | 
			
		||||
        Ok(r) => r,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::warn!("Failed to verify password! {:?}", e);
 | 
			
		||||
            log::warn!("Failed to verify password! {e:?}");
 | 
			
		||||
            false
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
use std::io::ErrorKind;
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
 | 
			
		||||
use actix_web::web;
 | 
			
		||||
@@ -109,17 +108,11 @@ impl WebAuthManager {
 | 
			
		||||
    ) -> Res<WebauthnPubKey> {
 | 
			
		||||
        let state: RegisterKeyOpaqueData = self.crypto_wrapper.decrypt(opaque_state)?;
 | 
			
		||||
        if state.user_id != user.uid {
 | 
			
		||||
            return Err(Box::new(std::io::Error::new(
 | 
			
		||||
                ErrorKind::Other,
 | 
			
		||||
                "Invalid user for pubkey!",
 | 
			
		||||
            )));
 | 
			
		||||
            return Err(Box::new(std::io::Error::other("Invalid user for pubkey!")));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if state.expire < time() {
 | 
			
		||||
            return Err(Box::new(std::io::Error::new(
 | 
			
		||||
                ErrorKind::Other,
 | 
			
		||||
                "Challenge has expired!",
 | 
			
		||||
            )));
 | 
			
		||||
            return Err(Box::new(std::io::Error::other("Challenge has expired!")));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let res = self.core.finish_passkey_registration(
 | 
			
		||||
@@ -157,17 +150,11 @@ impl WebAuthManager {
 | 
			
		||||
    ) -> Res {
 | 
			
		||||
        let state: AuthStateOpaqueData = self.crypto_wrapper.decrypt(opaque_state)?;
 | 
			
		||||
        if &state.user_id != user_id {
 | 
			
		||||
            return Err(Box::new(std::io::Error::new(
 | 
			
		||||
                ErrorKind::Other,
 | 
			
		||||
                "Invalid user for pubkey!",
 | 
			
		||||
            )));
 | 
			
		||||
            return Err(Box::new(std::io::Error::other("Invalid user for pubkey!")));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if state.expire < time() {
 | 
			
		||||
            return Err(Box::new(std::io::Error::new(
 | 
			
		||||
                ErrorKind::Other,
 | 
			
		||||
                "Challenge has expired!",
 | 
			
		||||
            )));
 | 
			
		||||
            return Err(Box::new(std::io::Error::other("Challenge has expired!")));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        self.core.finish_passkey_authentication(
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ use std::sync::Arc;
 | 
			
		||||
 | 
			
		||||
use actix::Actor;
 | 
			
		||||
use actix_identity::IdentityMiddleware;
 | 
			
		||||
use actix_identity::config::LogoutBehaviour;
 | 
			
		||||
use actix_identity::config::LogoutBehavior;
 | 
			
		||||
use actix_remote_ip::RemoteIPConfig;
 | 
			
		||||
use actix_session::SessionMiddleware;
 | 
			
		||||
use actix_session::storage::CookieSessionStore;
 | 
			
		||||
@@ -51,7 +51,7 @@ async fn main() -> std::io::Result<()> {
 | 
			
		||||
 | 
			
		||||
    // Create initial user if required
 | 
			
		||||
    if users.is_empty() {
 | 
			
		||||
        log::info!("Create default {} user", DEFAULT_ADMIN_USERNAME);
 | 
			
		||||
        log::info!("Create default {DEFAULT_ADMIN_USERNAME} user");
 | 
			
		||||
        let default_admin = User {
 | 
			
		||||
            username: DEFAULT_ADMIN_USERNAME.to_string(),
 | 
			
		||||
            authorized_clients: None,
 | 
			
		||||
@@ -100,7 +100,7 @@ async fn main() -> std::io::Result<()> {
 | 
			
		||||
        .build();
 | 
			
		||||
 | 
			
		||||
        let identity_middleware = IdentityMiddleware::builder()
 | 
			
		||||
            .logout_behaviour(LogoutBehaviour::PurgeSession)
 | 
			
		||||
            .logout_behavior(LogoutBehavior::PurgeSession)
 | 
			
		||||
            .visit_deadline(Some(Duration::from_secs(MAX_INACTIVITY_DURATION)))
 | 
			
		||||
            .login_deadline(Some(Duration::from_secs(MAX_SESSION_DURATION)))
 | 
			
		||||
            .build();
 | 
			
		||||
 
 | 
			
		||||
@@ -89,25 +89,21 @@ where
 | 
			
		||||
        Box::pin(async move {
 | 
			
		||||
            // Check if POST request comes from another website (block invalid origins)
 | 
			
		||||
            let origin = req.headers().get(header::ORIGIN);
 | 
			
		||||
            if req.method() == Method::POST && req.path() != TOKEN_URI && req.path() != USERINFO_URI
 | 
			
		||||
            if req.method() == Method::POST
 | 
			
		||||
                && req.path() != TOKEN_URI
 | 
			
		||||
                && req.path() != USERINFO_URI
 | 
			
		||||
                && let Some(o) = origin
 | 
			
		||||
                && !o
 | 
			
		||||
                    .to_str()
 | 
			
		||||
                    .unwrap_or("bad")
 | 
			
		||||
                    .eq(&AppConfig::get().website_origin)
 | 
			
		||||
            {
 | 
			
		||||
                if let Some(o) = origin {
 | 
			
		||||
                    if !o
 | 
			
		||||
                        .to_str()
 | 
			
		||||
                        .unwrap_or("bad")
 | 
			
		||||
                        .eq(&AppConfig::get().website_origin)
 | 
			
		||||
                    {
 | 
			
		||||
                        log::warn!(
 | 
			
		||||
                            "Blocked POST request from invalid origin! Origin given {:?}",
 | 
			
		||||
                            o
 | 
			
		||||
                        );
 | 
			
		||||
                        return Ok(req.into_response(
 | 
			
		||||
                            HttpResponse::Unauthorized()
 | 
			
		||||
                                .body("POST request from invalid origin!")
 | 
			
		||||
                                .map_into_right_body(),
 | 
			
		||||
                        ));
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
                log::warn!("Blocked POST request from invalid origin! Origin given {o:?}");
 | 
			
		||||
                return Ok(req.into_response(
 | 
			
		||||
                    HttpResponse::Unauthorized()
 | 
			
		||||
                        .body("POST request from invalid origin!")
 | 
			
		||||
                        .map_into_right_body(),
 | 
			
		||||
                ));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if req.path().starts_with("/.git") {
 | 
			
		||||
@@ -133,8 +129,8 @@ where
 | 
			
		||||
                _ => ConnStatus::SignedOut,
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            log::trace!("Connection data: {:#?}", session_data);
 | 
			
		||||
            log::debug!("Connection status: {:?}", session);
 | 
			
		||||
            log::trace!("Connection data: {session_data:#?}");
 | 
			
		||||
            log::debug!("Connection status: {session:?}");
 | 
			
		||||
 | 
			
		||||
            // Redirect user to login page
 | 
			
		||||
            if !session.is_auth()
 | 
			
		||||
 
 | 
			
		||||
@@ -47,7 +47,7 @@ mod test {
 | 
			
		||||
        unsafe {
 | 
			
		||||
            env::set_var(VAR_ONE, "good");
 | 
			
		||||
        }
 | 
			
		||||
        let src = format!("This is ${{{}}}", VAR_ONE);
 | 
			
		||||
        let src = format!("This is ${{{VAR_ONE}}}");
 | 
			
		||||
        assert_eq!("This is good", apply_env_vars(&src));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -55,7 +55,7 @@ mod test {
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_invalid_var_syntax() {
 | 
			
		||||
        let src = format!("This is ${{{}}}", VAR_INVALID);
 | 
			
		||||
        let src = format!("This is ${{{VAR_INVALID}}}");
 | 
			
		||||
        assert_eq!(src, apply_env_vars(&src));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user