Compare commits
10 commits
21f3f64ad5
...
657e5e6088
Author | SHA1 | Date | |
---|---|---|---|
657e5e6088 | |||
|
db70e8c52a | ||
|
31653ed996 | ||
|
3531853b2c | ||
|
891e8e548b | ||
|
61d05d04e9 | ||
|
8ac090a810 | ||
|
e83bc6d632 | ||
|
a1799af567 | ||
|
74c78ac2d7 |
20 changed files with 764 additions and 48 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -4,3 +4,5 @@
|
||||||
.idea/
|
.idea/
|
||||||
.vscode/
|
.vscode/
|
||||||
result
|
result
|
||||||
|
/config
|
||||||
|
/database
|
381
Cargo.lock
generated
381
Cargo.lock
generated
|
@ -55,6 +55,21 @@ version = "0.2.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
|
checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
|
||||||
|
|
||||||
|
[[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"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.4"
|
version = "0.6.4"
|
||||||
|
@ -164,7 +179,7 @@ dependencies = [
|
||||||
"fuzzy-matcher",
|
"fuzzy-matcher",
|
||||||
"indicatif",
|
"indicatif",
|
||||||
"interim",
|
"interim",
|
||||||
"itertools",
|
"itertools 0.11.0",
|
||||||
"log",
|
"log",
|
||||||
"ratatui",
|
"ratatui",
|
||||||
"rpassword",
|
"rpassword",
|
||||||
|
@ -199,7 +214,7 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
"hex",
|
"hex",
|
||||||
"interim",
|
"interim",
|
||||||
"itertools",
|
"itertools 0.11.0",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
"memchr",
|
"memchr",
|
||||||
|
@ -256,6 +271,7 @@ dependencies = [
|
||||||
"eyre",
|
"eyre",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
"http",
|
"http",
|
||||||
|
"openidconnect",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"semver",
|
"semver",
|
||||||
|
@ -367,6 +383,12 @@ dependencies = [
|
||||||
"rustc-demangle",
|
"rustc-demangle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base16ct"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.13.1"
|
version = "0.13.1"
|
||||||
|
@ -517,6 +539,21 @@ dependencies = [
|
||||||
"cpufeatures",
|
"cpufeatures",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.31"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
|
||||||
|
dependencies = [
|
||||||
|
"android-tzdata",
|
||||||
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
|
"num-traits",
|
||||||
|
"serde",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-targets 0.48.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cipher"
|
name = "cipher"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
|
@ -746,6 +783,18 @@ dependencies = [
|
||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-bigint"
|
||||||
|
version = "0.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "28f85c3514d2a6e64160359b45a3918c3b4178bcbf4ae5d03ab2d02e521c479a"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"rand_core 0.6.4",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-common"
|
name = "crypto-common"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
|
@ -823,6 +872,41 @@ dependencies = [
|
||||||
"syn 2.0.38",
|
"syn 2.0.38",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling"
|
||||||
|
version = "0.20.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"darling_macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_core"
|
||||||
|
version = "0.20.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"ident_case",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"strsim",
|
||||||
|
"syn 2.0.38",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "darling_macro"
|
||||||
|
version = "0.20.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
|
||||||
|
dependencies = [
|
||||||
|
"darling_core",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.38",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "der"
|
name = "der"
|
||||||
version = "0.7.8"
|
version = "0.7.8"
|
||||||
|
@ -934,6 +1018,26 @@ version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dyn-clone"
|
||||||
|
version = "1.0.16"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ecdsa"
|
||||||
|
version = "0.16.8"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4"
|
||||||
|
dependencies = [
|
||||||
|
"der",
|
||||||
|
"digest 0.10.7",
|
||||||
|
"elliptic-curve",
|
||||||
|
"rfc6979",
|
||||||
|
"signature 2.1.0",
|
||||||
|
"spki",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ed25519"
|
name = "ed25519"
|
||||||
version = "1.5.3"
|
version = "1.5.3"
|
||||||
|
@ -989,6 +1093,27 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "elliptic-curve"
|
||||||
|
version = "0.13.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d97ca172ae9dc9f9b779a6e3a65d308f2af74e5b8c921299075bdb4a0370e914"
|
||||||
|
dependencies = [
|
||||||
|
"base16ct",
|
||||||
|
"crypto-bigint",
|
||||||
|
"digest 0.10.7",
|
||||||
|
"ff",
|
||||||
|
"generic-array",
|
||||||
|
"group",
|
||||||
|
"hkdf",
|
||||||
|
"pem-rfc7468",
|
||||||
|
"pkcs8",
|
||||||
|
"rand_core 0.6.4",
|
||||||
|
"sec1",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encode_unicode"
|
name = "encode_unicode"
|
||||||
version = "0.3.6"
|
version = "0.3.6"
|
||||||
|
@ -1076,6 +1201,16 @@ version = "2.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ff"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.6.4",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fiat-crypto"
|
name = "fiat-crypto"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
|
@ -1286,8 +1421,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1296,6 +1433,17 @@ version = "0.28.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
|
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "group"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"
|
||||||
|
dependencies = [
|
||||||
|
"ff",
|
||||||
|
"rand_core 0.6.4",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.3.21"
|
version = "0.3.21"
|
||||||
|
@ -1472,6 +1620,35 @@ dependencies = [
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone"
|
||||||
|
version = "0.1.58"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
|
||||||
|
dependencies = [
|
||||||
|
"android_system_properties",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"iana-time-zone-haiku",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone-haiku"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ident_case"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.4.0"
|
version = "0.4.0"
|
||||||
|
@ -1496,6 +1673,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"hashbrown 0.12.3",
|
"hashbrown 0.12.3",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1506,6 +1684,7 @@ checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.14.2",
|
"hashbrown 0.14.2",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1581,6 +1760,15 @@ dependencies = [
|
||||||
"nom",
|
"nom",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itertools"
|
||||||
|
version = "0.10.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
|
||||||
|
dependencies = [
|
||||||
|
"either",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
@ -1940,6 +2128,26 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "oauth2"
|
||||||
|
version = "4.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c38841cdd844847e3e7c8d29cef9dcfed8877f8f56f9071f77843ecf3baf937f"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.13.1",
|
||||||
|
"chrono",
|
||||||
|
"getrandom 0.2.10",
|
||||||
|
"http",
|
||||||
|
"rand 0.8.5",
|
||||||
|
"reqwest",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_path_to_error",
|
||||||
|
"sha2 0.10.8",
|
||||||
|
"thiserror",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc"
|
name = "objc"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
|
@ -1990,6 +2198,38 @@ version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openidconnect"
|
||||||
|
version = "3.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "62d6050f6a84b81f23c569f5607ad883293e57491036e318fafe6fc4895fadb1"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.13.1",
|
||||||
|
"chrono",
|
||||||
|
"dyn-clone",
|
||||||
|
"ed25519-dalek 2.0.0",
|
||||||
|
"hmac",
|
||||||
|
"http",
|
||||||
|
"itertools 0.10.5",
|
||||||
|
"log",
|
||||||
|
"oauth2",
|
||||||
|
"p256",
|
||||||
|
"p384",
|
||||||
|
"rand 0.8.5",
|
||||||
|
"rsa",
|
||||||
|
"serde",
|
||||||
|
"serde-value",
|
||||||
|
"serde_derive",
|
||||||
|
"serde_json",
|
||||||
|
"serde_path_to_error",
|
||||||
|
"serde_plain",
|
||||||
|
"serde_with",
|
||||||
|
"sha2 0.10.8",
|
||||||
|
"subtle",
|
||||||
|
"thiserror",
|
||||||
|
"url",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-probe"
|
name = "openssl-probe"
|
||||||
version = "0.1.5"
|
version = "0.1.5"
|
||||||
|
@ -2002,6 +2242,15 @@ version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ordered-float"
|
||||||
|
version = "2.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c"
|
||||||
|
dependencies = [
|
||||||
|
"num-traits",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "os_pipe"
|
name = "os_pipe"
|
||||||
version = "1.1.4"
|
version = "1.1.4"
|
||||||
|
@ -2018,6 +2267,30 @@ version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "p256"
|
||||||
|
version = "0.13.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b"
|
||||||
|
dependencies = [
|
||||||
|
"ecdsa",
|
||||||
|
"elliptic-curve",
|
||||||
|
"primeorder",
|
||||||
|
"sha2 0.10.8",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "p384"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209"
|
||||||
|
dependencies = [
|
||||||
|
"ecdsa",
|
||||||
|
"elliptic-curve",
|
||||||
|
"primeorder",
|
||||||
|
"sha2 0.10.8",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
@ -2207,6 +2480,15 @@ dependencies = [
|
||||||
"yansi",
|
"yansi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "primeorder"
|
||||||
|
version = "0.13.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c7dbe9ed3b56368bd99483eb32fe9c17fdd3730aebadc906918ce78d54c7eeb4"
|
||||||
|
dependencies = [
|
||||||
|
"elliptic-curve",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.69"
|
version = "1.0.69"
|
||||||
|
@ -2306,7 +2588,7 @@ dependencies = [
|
||||||
"cassowary",
|
"cassowary",
|
||||||
"crossterm",
|
"crossterm",
|
||||||
"indoc",
|
"indoc",
|
||||||
"itertools",
|
"itertools 0.11.0",
|
||||||
"lru",
|
"lru",
|
||||||
"paste",
|
"paste",
|
||||||
"strum",
|
"strum",
|
||||||
|
@ -2433,9 +2715,20 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
|
"webpki-roots 0.25.2",
|
||||||
"winreg",
|
"winreg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rfc6979"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"
|
||||||
|
dependencies = [
|
||||||
|
"hmac",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ring"
|
name = "ring"
|
||||||
version = "0.16.20"
|
version = "0.16.20"
|
||||||
|
@ -2692,6 +2985,20 @@ dependencies = [
|
||||||
"untrusted 0.9.0",
|
"untrusted 0.9.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sec1"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc"
|
||||||
|
dependencies = [
|
||||||
|
"base16ct",
|
||||||
|
"der",
|
||||||
|
"generic-array",
|
||||||
|
"pkcs8",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "2.9.2"
|
version = "2.9.2"
|
||||||
|
@ -2730,6 +3037,16 @@ dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde-value"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c"
|
||||||
|
dependencies = [
|
||||||
|
"ordered-float",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.171"
|
version = "1.0.171"
|
||||||
|
@ -2762,6 +3079,15 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_plain"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_regex"
|
name = "serde_regex"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -2784,6 +3110,35 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_with"
|
||||||
|
version = "3.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23"
|
||||||
|
dependencies = [
|
||||||
|
"base64 0.21.5",
|
||||||
|
"chrono",
|
||||||
|
"hex",
|
||||||
|
"indexmap 1.9.3",
|
||||||
|
"indexmap 2.0.2",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_with_macros",
|
||||||
|
"time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_with_macros"
|
||||||
|
version = "3.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788"
|
||||||
|
dependencies = [
|
||||||
|
"darling",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.38",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sha1"
|
name = "sha1"
|
||||||
version = "0.10.6"
|
version = "0.10.6"
|
||||||
|
@ -2959,7 +3314,7 @@ version = "0.2.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6b7b278788e7be4d0d29c0f39497a0eef3fba6bbc8e70d8bf7fde46edeaa9e85"
|
checksum = "6b7b278788e7be4d0d29c0f39497a0eef3fba6bbc8e70d8bf7fde46edeaa9e85"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itertools",
|
"itertools 0.11.0",
|
||||||
"nom",
|
"nom",
|
||||||
"unicode_categories",
|
"unicode_categories",
|
||||||
]
|
]
|
||||||
|
@ -3019,7 +3374,7 @@ dependencies = [
|
||||||
"tracing",
|
"tracing",
|
||||||
"url",
|
"url",
|
||||||
"uuid",
|
"uuid",
|
||||||
"webpki-roots",
|
"webpki-roots 0.24.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3695,6 +4050,7 @@ dependencies = [
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
"idna",
|
"idna",
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3902,6 +4258,12 @@ dependencies = [
|
||||||
"rustls-webpki",
|
"rustls-webpki",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webpki-roots"
|
||||||
|
version = "0.25.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "whoami"
|
name = "whoami"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
|
@ -3952,6 +4314,15 @@ version = "0.4.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-core"
|
||||||
|
version = "0.51.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.48.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.45.0"
|
version = "0.45.0"
|
||||||
|
|
|
@ -16,7 +16,7 @@ RUN cargo chef cook --release --recipe-path recipe.json
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN cargo build --release --bin atuin
|
RUN cargo build --release --bin atuin
|
||||||
|
|
||||||
FROM debian:bullseye-20231009-slim AS runtime
|
FROM debian:bullseye-20231030-slim AS runtime
|
||||||
|
|
||||||
RUN useradd -c 'atuin user' atuin && mkdir /config && chown atuin:atuin /config
|
RUN useradd -c 'atuin user' atuin && mkdir /config && chown atuin:atuin /config
|
||||||
# Install ca-certificates for webhooks to work
|
# Install ca-certificates for webhooks to work
|
||||||
|
|
18
README.md
18
README.md
|
@ -248,16 +248,30 @@ antigen bundle atuinsh/atuin@main
|
||||||
|
|
||||||
### bash
|
### bash
|
||||||
|
|
||||||
We need to setup some hooks, so first install bash-preexec:
|
#### [ble.sh](https://github.com/akinomyoga/ble.sh)
|
||||||
|
|
||||||
|
Atuin works best in bash when using [ble.sh](https://github.com/akinomyoga/ble.sh).
|
||||||
|
|
||||||
|
With ble.sh installed, just add atuin to your .bashrc
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo 'eval "$(atuin init bash)"' >> ~/.bashrc
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### [bash-preexec](https://github.com/rcaloras/bash-preexec)
|
||||||
|
|
||||||
|
[Bash-preexec](https://github.com/rcaloras/bash-preexec) can also be used, but you may experience some minor problems with the recorded duration and exit status of some commands.
|
||||||
|
|
||||||
|
To use bash-preexec, download and initialize it
|
||||||
|
|
||||||
|
```bash
|
||||||
curl https://raw.githubusercontent.com/rcaloras/bash-preexec/master/bash-preexec.sh -o ~/.bash-preexec.sh
|
curl https://raw.githubusercontent.com/rcaloras/bash-preexec/master/bash-preexec.sh -o ~/.bash-preexec.sh
|
||||||
echo '[[ -f ~/.bash-preexec.sh ]] && source ~/.bash-preexec.sh' >> ~/.bashrc
|
echo '[[ -f ~/.bash-preexec.sh ]] && source ~/.bash-preexec.sh' >> ~/.bashrc
|
||||||
```
|
```
|
||||||
|
|
||||||
Then setup Atuin
|
Then setup Atuin
|
||||||
|
|
||||||
```
|
```bash
|
||||||
echo 'eval "$(atuin init bash)"' >> ~/.bashrc
|
echo 'eval "$(atuin init bash)"' >> ~/.bashrc
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -33,3 +33,4 @@ tower-http = { version = "0.4", features = ["trace"] }
|
||||||
reqwest = { workspace = true }
|
reqwest = { workspace = true }
|
||||||
argon2 = "0.5.0"
|
argon2 = "0.5.0"
|
||||||
semver = { workspace = true }
|
semver = { workspace = true }
|
||||||
|
openidconnect = "3.4.0"
|
||||||
|
|
|
@ -8,6 +8,7 @@ pub mod history;
|
||||||
pub mod record;
|
pub mod record;
|
||||||
pub mod status;
|
pub mod status;
|
||||||
pub mod user;
|
pub mod user;
|
||||||
|
pub mod oidc;
|
||||||
|
|
||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
|
||||||
|
|
214
atuin-server/src/handlers/oidc.rs
Normal file
214
atuin-server/src/handlers/oidc.rs
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
use axum::{
|
||||||
|
extract::{State, Query},
|
||||||
|
response::Redirect,
|
||||||
|
Json,
|
||||||
|
};
|
||||||
|
use http::StatusCode;
|
||||||
|
use openidconnect::{
|
||||||
|
core::{CoreAuthenticationFlow, CoreClient, CoreProviderMetadata},
|
||||||
|
reqwest::async_http_client,
|
||||||
|
AuthorizationCode, ClientId, ClientSecret, CsrfToken, IssuerUrl, Nonce, RedirectUrl, Scope,
|
||||||
|
TokenResponse,
|
||||||
|
};
|
||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
use tracing::error;
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use super::{ErrorResponse, ErrorResponseStatus, RespExt};
|
||||||
|
use crate::router::AppState;
|
||||||
|
use atuin_server_database::{Database, DbError, models::{NewUser, NewSession}};
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct OIDCGetResponse {
|
||||||
|
pub login_url: String
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn get<DB: Database>(state: State<AppState<DB>>) -> Result<Json<OIDCGetResponse>, ErrorResponseStatus<'static>> {
|
||||||
|
if state.settings.oidc_authority.is_none()
|
||||||
|
|| state.settings.oidc_client_id.is_none()
|
||||||
|
|| state.settings.oidc_client_secret.is_none()
|
||||||
|
{
|
||||||
|
return Err(ErrorResponse::reply("OIDC not supported on this server").with_status(StatusCode::BAD_REQUEST));
|
||||||
|
}
|
||||||
|
|
||||||
|
let url = state
|
||||||
|
.settings
|
||||||
|
.public_url
|
||||||
|
.strip_suffix("/")
|
||||||
|
.unwrap_or(&state.settings.public_url)
|
||||||
|
.to_string()
|
||||||
|
+ "/oidc/login";
|
||||||
|
|
||||||
|
Ok(Json(OIDCGetResponse {
|
||||||
|
// This is dynamic to allow for backwards compatibility later
|
||||||
|
// it also is relative to the client's configured server URL
|
||||||
|
login_url: url,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct LoginQuery {
|
||||||
|
pub callback: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn login<DB: Database>(
|
||||||
|
state: State<AppState<DB>>,
|
||||||
|
params: Query<LoginQuery>,
|
||||||
|
) -> Result<Redirect, ErrorResponseStatus<'static>> {
|
||||||
|
if state.settings.oidc_authority.is_none()
|
||||||
|
|| state.settings.oidc_client_id.is_none()
|
||||||
|
|| state.settings.oidc_client_secret.is_none()
|
||||||
|
{
|
||||||
|
return Err(ErrorResponse::reply("OIDC not supported on this server").with_status(StatusCode::BAD_REQUEST));
|
||||||
|
}
|
||||||
|
|
||||||
|
let provider_metadata = CoreProviderMetadata::discover_async(
|
||||||
|
IssuerUrl::new(state.settings.oidc_authority.clone().unwrap()).or(Err(ErrorResponse::reply("unable to parse configured oidc authority").with_status(StatusCode::INTERNAL_SERVER_ERROR)))?,
|
||||||
|
async_http_client,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.or(Err(ErrorResponse::reply("unable to fetch oidc provider metadata").with_status(StatusCode::INTERNAL_SERVER_ERROR)))?;
|
||||||
|
|
||||||
|
let client = CoreClient::from_provider_metadata(
|
||||||
|
provider_metadata,
|
||||||
|
ClientId::new(state.settings.oidc_client_id.clone().unwrap()),
|
||||||
|
Some(ClientSecret::new(
|
||||||
|
state.settings.oidc_client_secret.clone().unwrap(),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
// Set the URL the user will be redirected to after the authorization process.
|
||||||
|
.set_redirect_uri(
|
||||||
|
RedirectUrl::new(
|
||||||
|
state
|
||||||
|
.settings
|
||||||
|
.public_url
|
||||||
|
.strip_suffix("/")
|
||||||
|
.unwrap_or(&state.settings.public_url)
|
||||||
|
.to_string()
|
||||||
|
+ "/oidc/callback",
|
||||||
|
)
|
||||||
|
.or(Err(ErrorResponse::reply("unable to parse constructed redirect uri").with_status(StatusCode::INTERNAL_SERVER_ERROR)))?,
|
||||||
|
);
|
||||||
|
|
||||||
|
let url = client
|
||||||
|
.authorize_url(
|
||||||
|
CoreAuthenticationFlow::AuthorizationCode,
|
||||||
|
|| CsrfToken::new(params.0.callback),
|
||||||
|
Nonce::new_random,
|
||||||
|
)
|
||||||
|
.add_scopes(vec![Scope::new("profile".to_string()), Scope::new("email".to_string())])
|
||||||
|
.url();
|
||||||
|
|
||||||
|
Ok(Redirect::to(url.0.as_str()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct CallbackQuery {
|
||||||
|
pub code: String,
|
||||||
|
pub state: String
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn callback<DB: Database>(
|
||||||
|
state: State<AppState<DB>>,
|
||||||
|
params: Query<CallbackQuery>,
|
||||||
|
) -> Result<Json<String>, ErrorResponseStatus<'static>> {
|
||||||
|
if state.settings.oidc_authority.is_none()
|
||||||
|
|| state.settings.oidc_client_id.is_none()
|
||||||
|
|| state.settings.oidc_client_secret.is_none()
|
||||||
|
{
|
||||||
|
return Err(ErrorResponse::reply("OIDC not supported on this server").with_status(StatusCode::BAD_REQUEST));
|
||||||
|
}
|
||||||
|
|
||||||
|
let provider_metadata = CoreProviderMetadata::discover_async(
|
||||||
|
IssuerUrl::new(state.settings.oidc_authority.clone().unwrap()).or(Err(ErrorResponse::reply("unable to parse configured oidc authority").with_status(StatusCode::INTERNAL_SERVER_ERROR)))?,
|
||||||
|
async_http_client,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.or(Err(ErrorResponse::reply("unable to fetch oidc provider metadata").with_status(StatusCode::INTERNAL_SERVER_ERROR)))?;
|
||||||
|
|
||||||
|
let client = CoreClient::from_provider_metadata(
|
||||||
|
provider_metadata,
|
||||||
|
ClientId::new(state.settings.oidc_client_id.clone().unwrap()),
|
||||||
|
Some(ClientSecret::new(
|
||||||
|
state.settings.oidc_client_secret.clone().unwrap(),
|
||||||
|
)),
|
||||||
|
).set_redirect_uri(
|
||||||
|
RedirectUrl::new(
|
||||||
|
state
|
||||||
|
.settings
|
||||||
|
.public_url
|
||||||
|
.strip_suffix("/")
|
||||||
|
.unwrap_or(&state.settings.public_url)
|
||||||
|
.to_string()
|
||||||
|
+ "/oidc/callback",
|
||||||
|
)
|
||||||
|
.or(Err(ErrorResponse::reply("unable to parse constructed redirect uri").with_status(StatusCode::INTERNAL_SERVER_ERROR)))?,
|
||||||
|
);
|
||||||
|
|
||||||
|
let token_response = client
|
||||||
|
.exchange_code(AuthorizationCode::new(params.0.code))
|
||||||
|
.request_async(async_http_client)
|
||||||
|
.await
|
||||||
|
.or(Err(ErrorResponse::reply("unable to exchange oidc code for token").with_status(StatusCode::INTERNAL_SERVER_ERROR)))?;
|
||||||
|
|
||||||
|
let id_token = token_response.id_token().unwrap();
|
||||||
|
// TODO actual audience validation
|
||||||
|
let claims = dbg!(id_token
|
||||||
|
.claims(&client.id_token_verifier().require_audience_match(false), |_: Option<&Nonce>| Ok(())))
|
||||||
|
.or(Err(ErrorResponse::reply("unable to validate oidc token").with_status(StatusCode::INTERNAL_SERVER_ERROR)))?;
|
||||||
|
|
||||||
|
let db = &state.0.database;
|
||||||
|
let username = claims.preferred_username().ok_or(ErrorResponse::reply("oidc token did not contain preferred_username").with_status(StatusCode::INTERNAL_SERVER_ERROR))?;
|
||||||
|
let email = claims.email().ok_or(ErrorResponse::reply("oidc token did not contain email").with_status(StatusCode::INTERNAL_SERVER_ERROR))?;
|
||||||
|
// Fetches the existing user ID, or registers them on the spot.
|
||||||
|
let user_id = match db.get_user(username).await {
|
||||||
|
Ok(u) => u.id,
|
||||||
|
Err(DbError::NotFound) => {
|
||||||
|
let new_user = NewUser {
|
||||||
|
email: email.to_string(),
|
||||||
|
username: username.to_string(),
|
||||||
|
password: "".to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match db.add_user(&new_user).await {
|
||||||
|
Ok(id) => id,
|
||||||
|
Err(e) => {
|
||||||
|
error!("failed to add user via oidc: {}", e);
|
||||||
|
return Err(
|
||||||
|
ErrorResponse::reply("failed to add user via oidc").with_status(StatusCode::BAD_REQUEST)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(DbError::Other(e)) => {
|
||||||
|
error!("failed to get user {}: {}", username.as_str(), e);
|
||||||
|
|
||||||
|
return Err(ErrorResponse::reply("database error")
|
||||||
|
.with_status(StatusCode::INTERNAL_SERVER_ERROR));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Creates a new session for the user
|
||||||
|
let token = Uuid::new_v4().as_simple().to_string();
|
||||||
|
let new_session = NewSession {
|
||||||
|
user_id,
|
||||||
|
token: (&token).into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
match db.add_session(&new_session).await {
|
||||||
|
Ok(_) => (),
|
||||||
|
Err(e) => {
|
||||||
|
error!("failed to add session from oidc: {}", e);
|
||||||
|
return Err(ErrorResponse::reply("failed to register user via oidc")
|
||||||
|
.with_status(StatusCode::BAD_REQUEST))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
dbg!(claims);
|
||||||
|
dbg!(username);
|
||||||
|
dbg!(email);
|
||||||
|
|
||||||
|
// TODO - redirect to localhost + client side aspect + clean stuff up
|
||||||
|
|
||||||
|
Ok(Json("it works probably wtf".to_string()))
|
||||||
|
}
|
|
@ -111,6 +111,9 @@ pub fn router<DB: Database>(database: DB, settings: Settings<DB::Settings>) -> R
|
||||||
.route("/user/:username", get(handlers::user::get))
|
.route("/user/:username", get(handlers::user::get))
|
||||||
.route("/account", delete(handlers::user::delete))
|
.route("/account", delete(handlers::user::delete))
|
||||||
.route("/register", post(handlers::user::register))
|
.route("/register", post(handlers::user::register))
|
||||||
|
.route("/oidc", get(handlers::oidc::get))
|
||||||
|
.route("/oidc/login", get(handlers::oidc::login))
|
||||||
|
.route("/oidc/callback", get(handlers::oidc::callback))
|
||||||
.route("/login", post(handlers::user::login));
|
.route("/login", post(handlers::user::login));
|
||||||
|
|
||||||
let path = settings.path.as_str();
|
let path = settings.path.as_str();
|
||||||
|
|
|
@ -18,6 +18,10 @@ pub struct Settings<DbSettings> {
|
||||||
pub page_size: i64,
|
pub page_size: i64,
|
||||||
pub register_webhook_url: Option<String>,
|
pub register_webhook_url: Option<String>,
|
||||||
pub register_webhook_username: String,
|
pub register_webhook_username: String,
|
||||||
|
pub public_url: String,
|
||||||
|
pub oidc_authority: Option<String>,
|
||||||
|
pub oidc_client_id: Option<String>,
|
||||||
|
pub oidc_client_secret: Option<String>,
|
||||||
|
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub db_settings: DbSettings,
|
pub db_settings: DbSettings,
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
libiconv,
|
libiconv,
|
||||||
Security,
|
Security,
|
||||||
SystemConfiguration,
|
SystemConfiguration,
|
||||||
|
AppKit,
|
||||||
}:
|
}:
|
||||||
rustPlatform.buildRustPackage {
|
rustPlatform.buildRustPackage {
|
||||||
name = "atuin";
|
name = "atuin";
|
||||||
|
@ -26,7 +27,7 @@ rustPlatform.buildRustPackage {
|
||||||
|
|
||||||
nativeBuildInputs = [installShellFiles];
|
nativeBuildInputs = [installShellFiles];
|
||||||
|
|
||||||
buildInputs = lib.optionals stdenv.isDarwin [libiconv Security SystemConfiguration];
|
buildInputs = lib.optionals stdenv.isDarwin [libiconv Security SystemConfiguration AppKit];
|
||||||
|
|
||||||
postInstall = ''
|
postInstall = ''
|
||||||
installShellCompletion --cmd atuin \
|
installShellCompletion --cmd atuin \
|
||||||
|
|
|
@ -64,8 +64,10 @@ struct StyleState {
|
||||||
impl State {
|
impl State {
|
||||||
async fn query_results(&mut self, db: &mut dyn Database) -> Result<Vec<History>> {
|
async fn query_results(&mut self, db: &mut dyn Database) -> Result<Vec<History>> {
|
||||||
let results = self.engine.query(&self.search, db).await?;
|
let results = self.engine.query(&self.search, db).await?;
|
||||||
|
|
||||||
self.results_state.select(0);
|
self.results_state.select(0);
|
||||||
self.results_len = results.len();
|
self.results_len = results.len();
|
||||||
|
|
||||||
Ok(results)
|
Ok(results)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -703,7 +705,7 @@ pub async fn history(
|
||||||
|
|
||||||
if index < results.len() {
|
if index < results.len() {
|
||||||
let mut command = results.swap_remove(index).command;
|
let mut command = results.swap_remove(index).command;
|
||||||
if accept && (utils::is_zsh() || utils::is_fish() || utils::is_bash()) {
|
if accept && (utils::is_zsh() || utils::is_fish()) {
|
||||||
command = String::from("__atuin_accept__:") + &command;
|
command = String::from("__atuin_accept__:") + &command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,9 +32,16 @@ impl Cmd {
|
||||||
println!("{base}");
|
println!("{base}");
|
||||||
|
|
||||||
if std::env::var("ATUIN_NOBIND").is_err() {
|
if std::env::var("ATUIN_NOBIND").is_err() {
|
||||||
const BIND_CTRL_R: &str = "bindkey '^r' _atuin_search_widget";
|
const BIND_CTRL_R: &str = r#"bindkey -M emacs '^r' _atuin_search_widget
|
||||||
const BIND_UP_ARROW: &str = "bindkey '^[[A' _atuin_up_search_widget
|
bindkey -M vicmd '^r' _atuin_search_widget
|
||||||
bindkey '^[OA' _atuin_up_search_widget";
|
bindkey -M viins '^r' _atuin_search_widget"#;
|
||||||
|
const BIND_UP_ARROW: &str = r#"bindkey -M emacs '^[[A' _atuin_up_search_widget
|
||||||
|
bindkey -M vicmd '^[[A' _atuin_up_search_widget
|
||||||
|
bindkey -M viins '^[[A' _atuin_up_search_widget
|
||||||
|
bindkey -M emacs '^[OA' _atuin_up_search_widget
|
||||||
|
bindkey -M vicmd '^[OA' _atuin_up_search_widget
|
||||||
|
bindkey -M viins '^[OA' _atuin_up_search_widget
|
||||||
|
bindkey -M vicmd 'k' _atuin_up_search_widget"#;
|
||||||
if !self.disable_ctrl_r {
|
if !self.disable_ctrl_r {
|
||||||
println!("{BIND_CTRL_R}");
|
println!("{BIND_CTRL_R}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
ATUIN_SESSION=$(atuin uuid)
|
ATUIN_SESSION=$(atuin uuid)
|
||||||
export ATUIN_SESSION
|
export ATUIN_SESSION
|
||||||
|
|
||||||
_atuin_preexec() {
|
__atuin_preexec() {
|
||||||
local id
|
local id
|
||||||
id=$(atuin history start -- "$1")
|
id=$(atuin history start -- "$1")
|
||||||
export ATUIN_HISTORY_ID="${id}"
|
export ATUIN_HISTORY_ID="${id}"
|
||||||
}
|
}
|
||||||
|
|
||||||
_atuin_precmd() {
|
__atuin_precmd() {
|
||||||
local EXIT="$?"
|
local EXIT="$?"
|
||||||
|
|
||||||
[[ -z "${ATUIN_HISTORY_ID}" ]] && return
|
[[ -z "${ATUIN_HISTORY_ID}" ]] && return
|
||||||
|
@ -16,6 +16,10 @@ _atuin_precmd() {
|
||||||
export ATUIN_HISTORY_ID=""
|
export ATUIN_HISTORY_ID=""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__atuin_set_ret_value() {
|
||||||
|
return ${1:+"$1"}
|
||||||
|
}
|
||||||
|
|
||||||
__atuin_history() {
|
__atuin_history() {
|
||||||
# shellcheck disable=SC2048,SC2086
|
# shellcheck disable=SC2048,SC2086
|
||||||
HISTORY="$(ATUIN_SHELL_BASH=t ATUIN_LOG=error atuin search $* -i -- "${READLINE_LINE}" 3>&1 1>&2 2>&3)"
|
HISTORY="$(ATUIN_SHELL_BASH=t ATUIN_LOG=error atuin search $* -i -- "${READLINE_LINE}" 3>&1 1>&2 2>&3)"
|
||||||
|
@ -23,25 +27,63 @@ __atuin_history() {
|
||||||
if [[ $HISTORY == __atuin_accept__:* ]]
|
if [[ $HISTORY == __atuin_accept__:* ]]
|
||||||
then
|
then
|
||||||
HISTORY=${HISTORY#__atuin_accept__:}
|
HISTORY=${HISTORY#__atuin_accept__:}
|
||||||
echo "$HISTORY"
|
# Reprint the prompt, accounting for multiple lines
|
||||||
# Need to run the pre/post exec functions manually
|
# shellcheck disable=SC2046
|
||||||
_atuin_preexec "$HISTORY"
|
tput cuu $(echo -n "${PS1@P}" | tr -cd '\n' | wc -c)
|
||||||
|
echo "${PS1@P}$HISTORY"
|
||||||
|
|
||||||
|
if [[ -n "${BLE_VERSION-}" ]]; then
|
||||||
|
blehook/invoke PREEXEC "$HISTORY"
|
||||||
|
else
|
||||||
|
# Assuming bash-preexec
|
||||||
|
# Invoke every function in the preexec array
|
||||||
|
local preexec_function
|
||||||
|
local preexec_function_ret_value
|
||||||
|
local preexec_ret_value=0
|
||||||
|
for preexec_function in "${preexec_functions[@]:-}"; do
|
||||||
|
if type -t "$preexec_function" 1>/dev/null; then
|
||||||
|
__bp_set_ret_value "${__bp_last_ret_value:-}"
|
||||||
|
"$preexec_function" "$HISTORY"
|
||||||
|
preexec_function_ret_value="$?"
|
||||||
|
if [[ "$preexec_function_ret_value" != 0 ]]; then
|
||||||
|
preexec_ret_value="$preexec_function_ret_value"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# shellcheck disable=SC2154
|
||||||
|
__bp_set_ret_value "$preexec_ret_value" "$__bp_last_argument_prev_command"
|
||||||
|
fi
|
||||||
eval "$HISTORY"
|
eval "$HISTORY"
|
||||||
_atuin_precmd
|
exit_status=$?
|
||||||
echo
|
# Execute preprompt commands
|
||||||
|
__atuin_set_ret_value "$exit_status" "$HISTORY"
|
||||||
|
eval "$PROMPT_COMMAND"
|
||||||
|
# Need to reexecute the blehook
|
||||||
|
if [[ -n "${BLE_VERSION-}" ]]; then
|
||||||
|
__atuin_set_ret_value "$exit_status" "$HISTORY"
|
||||||
|
blehook/invoke PRECMD "$?"
|
||||||
|
fi
|
||||||
|
# Add it to the bash history
|
||||||
|
history -s "$HISTORY"
|
||||||
|
# Bash will redraw only the line with the prompt after we finish,
|
||||||
|
# so to work for a multiline prompt we need to print it ourselves,
|
||||||
|
# then move up a line
|
||||||
|
__atuin_set_ret_value "$exit_status" "$HISTORY"
|
||||||
|
echo "${PS1@P}"
|
||||||
|
tput cuu 1
|
||||||
|
__atuin_set_ret_value "$exit_status" "$HISTORY"
|
||||||
READLINE_LINE=""
|
READLINE_LINE=""
|
||||||
READLINE_POINT=${#READLINE_LINE}
|
READLINE_POINT=${#READLINE_LINE}
|
||||||
else
|
else
|
||||||
READLINE_LINE=${HISTORY}
|
READLINE_LINE=${HISTORY}
|
||||||
READLINE_POINT=${#READLINE_LINE}
|
READLINE_POINT=${#READLINE_LINE}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if [[ -n "${BLE_VERSION-}" ]]; then
|
if [[ -n "${BLE_VERSION-}" ]]; then
|
||||||
blehook PRECMD-+=_atuin_precmd
|
blehook PRECMD-+=__atuin_precmd
|
||||||
blehook PREEXEC-+=_atuin_preexec
|
blehook PREEXEC-+=__atuin_preexec
|
||||||
else
|
else
|
||||||
precmd_functions+=(_atuin_precmd)
|
precmd_functions+=(__atuin_precmd)
|
||||||
preexec_functions+=(_atuin_preexec)
|
preexec_functions+=(__atuin_preexec)
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -2,12 +2,12 @@ set -gx ATUIN_SESSION (atuin uuid)
|
||||||
|
|
||||||
function _atuin_preexec --on-event fish_preexec
|
function _atuin_preexec --on-event fish_preexec
|
||||||
if not test -n "$fish_private_mode"
|
if not test -n "$fish_private_mode"
|
||||||
set -gx ATUIN_HISTORY_ID (atuin history start -- "$argv[1]")
|
set -g ATUIN_HISTORY_ID (atuin history start -- "$argv[1]")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function _atuin_postexec --on-event fish_postexec
|
function _atuin_postexec --on-event fish_postexec
|
||||||
set s $status
|
set -l s $status
|
||||||
|
|
||||||
if test -n "$ATUIN_HISTORY_ID"
|
if test -n "$ATUIN_HISTORY_ID"
|
||||||
ATUIN_LOG=error atuin history end --exit $s -- $ATUIN_HISTORY_ID &>/dev/null &
|
ATUIN_LOG=error atuin history end --exit $s -- $ATUIN_HISTORY_ID &>/dev/null &
|
||||||
|
@ -18,22 +18,17 @@ function _atuin_postexec --on-event fish_postexec
|
||||||
end
|
end
|
||||||
|
|
||||||
function _atuin_search
|
function _atuin_search
|
||||||
set h (ATUIN_SHELL_FISH=t ATUIN_LOG=error atuin search $argv -i -- (commandline -b) 3>&1 1>&2 2>&3)
|
set -l ATUIN_H (ATUIN_SHELL_FISH=t ATUIN_LOG=error atuin search $argv -i -- (commandline -b) 3>&1 1>&2 2>&3)
|
||||||
|
|
||||||
if test -n "$h"
|
if test -n "$ATUIN_H"
|
||||||
if string match -qg '__atuin_accept__:*' "$h"
|
if string match --quiet '__atuin_accept__:*' "$ATUIN_H"
|
||||||
set hist (string match -r '__atuin_accept__:(.*|\s*)' "$h" | awk 'NR == 2')
|
set -l ATUIN_HIST (string match --regex '__atuin_accept__:(.*|\s*)' "$ATUIN_H" | awk 'NR == 2')
|
||||||
echo $hist
|
commandline -r "$ATUIN_HIST"
|
||||||
# Need to run the pre/post exec functions manually
|
commandline -f repaint
|
||||||
_atuin_preexec $hist
|
commandline -f execute
|
||||||
eval $hist
|
return
|
||||||
_atuin_postexec
|
|
||||||
# Allow space for repainting the prompt, this will work for prompts up to 2 lines
|
|
||||||
echo
|
|
||||||
echo
|
|
||||||
commandline -r ""
|
|
||||||
else
|
else
|
||||||
commandline -r "$h"
|
commandline -r "$ATUIN_H"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,12 @@ _atuin_search() {
|
||||||
}
|
}
|
||||||
|
|
||||||
_atuin_up_search() {
|
_atuin_up_search() {
|
||||||
_atuin_search --shell-up-key-binding
|
# Only trigger if the buffer is a single line
|
||||||
|
if [[ ! $BUFFER == *$'\n'* ]]; then
|
||||||
|
_atuin_search --shell-up-key-binding
|
||||||
|
else
|
||||||
|
zle up-line
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
add-zsh-hook preexec _atuin_preexec
|
add-zsh-hook preexec _atuin_preexec
|
||||||
|
|
37
docker-compose.dev.yml
Normal file
37
docker-compose.dev.yml
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
version: '3.5'
|
||||||
|
services:
|
||||||
|
atuin:
|
||||||
|
restart: always
|
||||||
|
image: atuinlocal:latest
|
||||||
|
build:
|
||||||
|
context: .
|
||||||
|
dockerfile: Dockerfile
|
||||||
|
network: host
|
||||||
|
command: server start
|
||||||
|
volumes:
|
||||||
|
- "./config:/config"
|
||||||
|
links:
|
||||||
|
- postgresql:db
|
||||||
|
ports:
|
||||||
|
- 8888:8888
|
||||||
|
environment:
|
||||||
|
ATUIN_HOST: "0.0.0.0"
|
||||||
|
ATUIN_OPEN_REGISTRATION: "true"
|
||||||
|
ATUIN_DB_URI: postgres://atuin:really-insecure@db/atuin
|
||||||
|
postgresql:
|
||||||
|
image: postgres:14
|
||||||
|
restart: unless-stopped
|
||||||
|
volumes: # Don't remove permanent storage for index database files!
|
||||||
|
- "./database:/var/lib/postgresql/data/"
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: atuin
|
||||||
|
POSTGRES_PASSWORD: really-insecure
|
||||||
|
POSTGRES_DB: atuin
|
||||||
|
|
||||||
|
networks:
|
||||||
|
default:
|
||||||
|
name: atuinnet
|
||||||
|
ipam:
|
||||||
|
driver: default
|
||||||
|
config:
|
||||||
|
- subnet: 172.20.0.0/16
|
|
@ -112,16 +112,30 @@ antigen bundle atuinsh/atuin@main
|
||||||
|
|
||||||
### bash
|
### bash
|
||||||
|
|
||||||
We need to setup some hooks, so first install bash-preexec:
|
#### [ble.sh](https://github.com/akinomyoga/ble.sh)
|
||||||
|
|
||||||
|
Atuin works best in bash when using [ble.sh](https://github.com/akinomyoga/ble.sh).
|
||||||
|
|
||||||
|
With ble.sh installed, just add atuin to your .bashrc
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo 'eval "$(atuin init bash)"' >> ~/.bashrc
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### [bash-preexec](https://github.com/rcaloras/bash-preexec)
|
||||||
|
|
||||||
|
[Bash-preexec](https://github.com/rcaloras/bash-preexec) can also be used, but you may experience some minor problems with the recorded duration and exit status of some commands.
|
||||||
|
|
||||||
|
To use bash-preexec, download and initialize it
|
||||||
|
|
||||||
|
```bash
|
||||||
curl https://raw.githubusercontent.com/rcaloras/bash-preexec/master/bash-preexec.sh -o ~/.bash-preexec.sh
|
curl https://raw.githubusercontent.com/rcaloras/bash-preexec/master/bash-preexec.sh -o ~/.bash-preexec.sh
|
||||||
echo '[[ -f ~/.bash-preexec.sh ]] && source ~/.bash-preexec.sh' >> ~/.bashrc
|
echo '[[ -f ~/.bash-preexec.sh ]] && source ~/.bash-preexec.sh' >> ~/.bashrc
|
||||||
```
|
```
|
||||||
|
|
||||||
Then setup Atuin
|
Then setup Atuin
|
||||||
|
|
||||||
```
|
```bash
|
||||||
echo 'eval "$(atuin init bash)"' >> ~/.bashrc
|
echo 'eval "$(atuin init bash)"' >> ~/.bashrc
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -164,5 +164,7 @@ curl https://api.atuin.sh/enable -d $(cat ~/.local/share/atuin/session)
|
||||||
|
|
||||||
The response includes the URL to your graph. Feel free to share and/or embed
|
The response includes the URL to your graph. Feel free to share and/or embed
|
||||||
this URL, the token is _not_ a secret, and simply prevents user enumeration.
|
this URL, the token is _not_ a secret, and simply prevents user enumeration.
|
||||||
|
|
||||||
|
## Known issues
|
||||||
|
- SQLite has some issues with ZFS in certain configurations. As Atuin uses SQLite, this may cause your shell to become slow! We have an [issue](https://github.com/atuinsh/atuin/issues/952) to track, with some workarounds
|
||||||
|
- SQLite also does not tend to like network filesystems (eg, NFS)
|
||||||
|
|
|
@ -136,6 +136,8 @@ $env.config = (
|
||||||
|
|
||||||
| Shortcut | Action |
|
| Shortcut | Action |
|
||||||
| ----------------------------------------- | ----------------------------------------------------------------------------- |
|
| ----------------------------------------- | ----------------------------------------------------------------------------- |
|
||||||
|
| enter | Execute selected item |
|
||||||
|
| tab | Select item and edit |
|
||||||
| ctrl + r | Cycle through filter modes |
|
| ctrl + r | Cycle through filter modes |
|
||||||
| ctrl + s | Cycle through search modes |
|
| ctrl + s | Cycle through search modes |
|
||||||
| alt + 1 to alt + 9 | Select item by the number located near it |
|
| alt + 1 to alt + 9 | Select item by the number located near it |
|
||||||
|
@ -155,7 +157,6 @@ $env.config = (
|
||||||
| ctrl + p / ctrl + k / ⬇ | Select the previous item on the list |
|
| ctrl + p / ctrl + k / ⬇ | Select the previous item on the list |
|
||||||
| page down | Scroll search results one page down |
|
| page down | Scroll search results one page down |
|
||||||
| page up | Scroll search results one page up |
|
| page up | Scroll search results one page up |
|
||||||
| enter | Select highlighted item |
|
|
||||||
| ⬇ (with no entry selected) | Return original or return query depending on settings |
|
| ⬇ (with no entry selected) | Return original or return query depending on settings |
|
||||||
| ⬇ | Select the next item on the list |
|
| ⬇ | Select the next item on the list |
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
pkgs = nixpkgs.outputs.legacyPackages.${system};
|
pkgs = nixpkgs.outputs.legacyPackages.${system};
|
||||||
in {
|
in {
|
||||||
packages.atuin = pkgs.callPackage ./atuin.nix {
|
packages.atuin = pkgs.callPackage ./atuin.nix {
|
||||||
inherit (pkgs.darwin.apple_sdk.frameworks) Security SystemConfiguration;
|
inherit (pkgs.darwin.apple_sdk.frameworks) Security SystemConfiguration AppKit;
|
||||||
};
|
};
|
||||||
packages.default = self.outputs.packages.${system}.atuin;
|
packages.default = self.outputs.packages.${system}.atuin;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue