Compare commits
2 Commits
e3b920fcd5
...
extract
Author | SHA1 | Date | |
---|---|---|---|
e4c9d60814 | |||
65c2703885
|
5
.woodpecker.yml
Normal file
5
.woodpecker.yml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
pipeline:
|
||||||
|
test:
|
||||||
|
image: rust
|
||||||
|
commands:
|
||||||
|
- cargo test
|
364
Cargo.lock
generated
364
Cargo.lock
generated
@@ -13,15 +13,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.68"
|
version = "1.0.66"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2cb2f989d18dd141ab8ae82f64d1a8cdd37e0840f73a406896cf5e99502fab61"
|
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.62"
|
version = "0.1.59"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "689894c2db1ea643a50834b999abf1c110887402542955ff5451dab8f861f9ed"
|
checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -36,9 +36,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "axum"
|
name = "axum"
|
||||||
version = "0.6.3"
|
version = "0.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "678c5130a507ae3a7c797f9a17393c14849300b8440eac47cdb90a5bdcb3a543"
|
checksum = "08b108ad2665fa3f6e6a517c3d80ec3e77d224c47d605167aefaa5d7ef97fa48"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"axum-core",
|
"axum-core",
|
||||||
@@ -69,9 +69,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "axum-core"
|
name = "axum-core"
|
||||||
version = "0.3.2"
|
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 = "1cae3e661676ffbacb30f1a824089a8c9150e71017f7e1e38f2aa32009188d34"
|
checksum = "79b8558f5a0581152dc94dcd289132a1d377494bdeafcd41869b3258e3e2ad92"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -86,9 +86,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "axum-extra"
|
name = "axum-extra"
|
||||||
version = "0.4.2"
|
version = "0.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f9a320103719de37b7b4da4c8eb629d4573f6bcfd3dfe80d3208806895ccf81d"
|
checksum = "256d21542ab2ccf04a433fdb025a466ca5c28ec6c63ee69d1e71b41b475efbac"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"axum",
|
||||||
"axum-macros",
|
"axum-macros",
|
||||||
@@ -108,9 +108,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "axum-macros"
|
name = "axum-macros"
|
||||||
version = "0.3.1"
|
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 = "cc7d7c3e69f305217e317a28172aab29f275667f2e1c15b87451e134fe27c7b1"
|
checksum = "e4df0fc33ada14a338b799002f7e8657711422b25d4e16afb032708d6b185621"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
@@ -126,9 +126,9 @@ checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.21.0"
|
version = "0.13.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
|
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64ct"
|
name = "base64ct"
|
||||||
@@ -162,9 +162,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.12.0"
|
version = "3.11.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535"
|
checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
@@ -180,9 +180,9 @@ checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.0.78"
|
version = "1.0.77"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
|
checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
@@ -207,9 +207,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "4.1.1"
|
version = "4.0.29"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4ec7a4128863c188deefe750ac1d1dfe66c236909f845af04beed823638dc1b2"
|
checksum = "4d63b9e9c07271b9957ad22c173bae2a4d9a81127680962039296abcd2f8251d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"clap_derive",
|
"clap_derive",
|
||||||
@@ -222,9 +222,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_derive"
|
name = "clap_derive"
|
||||||
version = "4.1.0"
|
version = "4.0.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
|
checksum = "0177313f9f02afc995627906bbd8967e2be069f5261954222dac78290c2b9014"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"heck",
|
"heck",
|
||||||
"proc-macro-error",
|
"proc-macro-error",
|
||||||
@@ -235,9 +235,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap_lex"
|
name = "clap_lex"
|
||||||
version = "0.3.1"
|
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 = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade"
|
checksum = "0d4198f73e42b4936b35b5bb248d81d2b595ecb170da0bac7655c54eedfa8da8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"os_str_bytes",
|
"os_str_bytes",
|
||||||
]
|
]
|
||||||
@@ -320,9 +320,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cxx"
|
name = "cxx"
|
||||||
version = "1.0.87"
|
version = "1.0.83"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b61a7545f753a88bcbe0a70de1fcc0221e10bfc752f576754fa91e663db1622e"
|
checksum = "bdf07d07d6531bfcdbe9b8b739b104610c6508dcc4d63b410585faf338241daf"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"cxxbridge-flags",
|
"cxxbridge-flags",
|
||||||
@@ -332,9 +332,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cxx-build"
|
name = "cxx-build"
|
||||||
version = "1.0.87"
|
version = "1.0.83"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f464457d494b5ed6905c63b0c4704842aba319084a0a3561cdc1359536b53200"
|
checksum = "d2eb5b96ecdc99f72657332953d4d9c50135af1bac34277801cc3937906ebd39"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"codespan-reporting",
|
"codespan-reporting",
|
||||||
@@ -347,15 +347,15 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cxxbridge-flags"
|
name = "cxxbridge-flags"
|
||||||
version = "1.0.87"
|
version = "1.0.83"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "43c7119ce3a3701ed81aca8410b9acf6fc399d2629d057b87e2efa4e63a3aaea"
|
checksum = "ac040a39517fd1674e0f32177648334b0f4074625b5588a64519804ba0553b12"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cxxbridge-macro"
|
name = "cxxbridge-macro"
|
||||||
version = "1.0.87"
|
version = "1.0.83"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "65e07508b90551e610910fa648a1878991d367064997a596135b86df30daf07e"
|
checksum = "1362b0ddcfc4eb0a1f57b68bd77dd99f0e826958a96abd0ae9bd092e114ffed6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -364,9 +364,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "der"
|
name = "der"
|
||||||
version = "0.6.1"
|
version = "0.6.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de"
|
checksum = "13dd2ae565c0a381dde7fade45fce95984c568bdcb4700a4fdbe3175e0380b2f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"const-oid",
|
"const-oid",
|
||||||
"pem-rfc7468",
|
"pem-rfc7468",
|
||||||
@@ -408,9 +408,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ed25519"
|
name = "ed25519"
|
||||||
version = "1.5.3"
|
version = "1.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7"
|
checksum = "1e9c280362032ea4203659fc489832d0204ef09f247a0506f170dafcac08c369"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"signature",
|
"signature",
|
||||||
]
|
]
|
||||||
@@ -777,9 +777,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.9.2"
|
version = "1.9.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
|
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"hashbrown",
|
"hashbrown",
|
||||||
@@ -796,37 +796,37 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "io-lifetimes"
|
name = "io-lifetimes"
|
||||||
version = "1.0.4"
|
version = "1.0.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e"
|
checksum = "46112a93252b123d31a119a8d1a1ac19deac4fac6e0e8b0df58f0d4e5870e63c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.7.1"
|
version = "2.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "30e22bd8629359895450b59ea7a776c850561b96a3b1d31321c1949d9e6c9146"
|
checksum = "f88c5561171189e69df9d98bcf18fd5f9558300f7ea7b801eb8a0fd748bd8745"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is-terminal"
|
name = "is-terminal"
|
||||||
version = "0.4.2"
|
version = "0.4.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
|
checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi",
|
"hermit-abi",
|
||||||
"io-lifetimes",
|
"io-lifetimes",
|
||||||
"rustix",
|
"rustix",
|
||||||
"windows-sys",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "1.0.5"
|
version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
|
checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
@@ -868,9 +868,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.139"
|
version = "0.2.137"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libm"
|
name = "libm"
|
||||||
@@ -880,18 +880,18 @@ checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "link-cplusplus"
|
name = "link-cplusplus"
|
||||||
version = "1.0.8"
|
version = "1.0.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5"
|
checksum = "9272ab7b96c9046fbc5bc56c06c117cb639fe2d509df0c421cad82d2915cf369"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "linux-raw-sys"
|
name = "linux-raw-sys"
|
||||||
version = "0.1.4"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
@@ -929,7 +929,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
"windows-sys",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1011,9 +1011,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "once_cell"
|
name = "once_cell"
|
||||||
version = "1.17.0"
|
version = "1.16.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
|
checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "opaque-debug"
|
name = "opaque-debug"
|
||||||
@@ -1023,9 +1023,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl"
|
name = "openssl"
|
||||||
version = "0.10.45"
|
version = "0.10.43"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b102428fd03bc5edf97f62620f7298614c45cedf287c271e7ed450bbaf83f2e1"
|
checksum = "020433887e44c27ff16365eaa2d380547a94544ad509aff6eb5b6e3e0b27b376"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
@@ -1055,9 +1055,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-sys"
|
name = "openssl-sys"
|
||||||
version = "0.9.80"
|
version = "0.9.78"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "23bbbf7854cd45b83958ebe919f0e8e516793727652e27fda10a8384cfc790b7"
|
checksum = "07d5c8cb6e57b3a3612064d7b18b117912b4ce70955c2504d4b741c9e244b132"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"cc",
|
"cc",
|
||||||
@@ -1207,18 +1207,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.50"
|
version = "1.0.47"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
|
checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.23"
|
version = "1.0.21"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
|
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
]
|
]
|
||||||
@@ -1314,9 +1314,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "reqwest"
|
name = "reqwest"
|
||||||
version = "0.11.14"
|
version = "0.11.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "21eed90ec8570952d53b772ecf8f206aa1ec9a3d76b2521c56c42973f2d91ee9"
|
checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -1383,44 +1383,45 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.36.7"
|
version = "0.36.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03"
|
checksum = "cb93e85278e08bb5788653183213d3a60fc242b10cb9be96586f5a73dcb67c23"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"errno",
|
"errno",
|
||||||
"io-lifetimes",
|
"io-lifetimes",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys",
|
"linux-raw-sys",
|
||||||
"windows-sys",
|
"windows-sys 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.11"
|
version = "1.0.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5583e89e108996506031660fe09baa5011b9dd0341b89029313006d1fb508d70"
|
checksum = "97477e48b4cf8603ad5f7aaf897467cf42ab4218a38ef76fb14c2d6773a6d6a8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.12"
|
version = "1.0.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
|
checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "schannel"
|
name = "schannel"
|
||||||
version = "0.1.21"
|
version = "0.1.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
|
checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys",
|
"lazy_static",
|
||||||
|
"windows-sys 0.36.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scratch"
|
name = "scratch"
|
||||||
version = "1.0.3"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2"
|
checksum = "9c8132065adcfd6e02db789d9285a0deb2f3fcb04002865ab67d5fb103533898"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "sec1"
|
name = "sec1"
|
||||||
@@ -1438,9 +1439,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "2.8.0"
|
version = "2.7.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "645926f31b250a2dca3c232496c2d898d91036e45ca0e97e0e2390c54e11be36"
|
checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"core-foundation",
|
"core-foundation",
|
||||||
@@ -1451,9 +1452,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework-sys"
|
name = "security-framework-sys"
|
||||||
version = "2.8.0"
|
version = "2.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4"
|
checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -1461,9 +1462,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.152"
|
version = "1.0.148"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
|
checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
@@ -1480,9 +1481,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.152"
|
version = "1.0.148"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
|
checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1491,9 +1492,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.91"
|
version = "1.0.89"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
|
checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
@@ -1502,9 +1503,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_path_to_error"
|
name = "serde_path_to_error"
|
||||||
version = "0.1.9"
|
version = "0.1.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "26b04f22b563c91331a10074bda3dd5492e3cc39d56bd557e91c0af42b6c7341"
|
checksum = "184c643044780f7ceb59104cef98a5a6f12cb2288a7bc701ab93a362b49fd47d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
@@ -1606,46 +1607,7 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ssh-cert-dist-client"
|
name = "ssh-cert-dist"
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"async-trait",
|
|
||||||
"axum-extra",
|
|
||||||
"chrono",
|
|
||||||
"clap",
|
|
||||||
"rand 0.8.5",
|
|
||||||
"reqwest",
|
|
||||||
"serde",
|
|
||||||
"ssh-cert-dist-common",
|
|
||||||
"ssh-key",
|
|
||||||
"tempfile",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
|
||||||
"tracing",
|
|
||||||
"tracing-subscriber",
|
|
||||||
"url",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ssh-cert-dist-common"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"async-trait",
|
|
||||||
"axum",
|
|
||||||
"axum-extra",
|
|
||||||
"serde",
|
|
||||||
"ssh-key",
|
|
||||||
"tempfile",
|
|
||||||
"thiserror",
|
|
||||||
"tokio",
|
|
||||||
"tracing",
|
|
||||||
"tracing-subscriber",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ssh-cert-dist-server"
|
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
@@ -1656,8 +1618,8 @@ dependencies = [
|
|||||||
"clap",
|
"clap",
|
||||||
"jwt-compact",
|
"jwt-compact",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"ssh-cert-dist-common",
|
|
||||||
"ssh-key",
|
"ssh-key",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
@@ -1666,13 +1628,13 @@ dependencies = [
|
|||||||
"tower-http",
|
"tower-http",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ssh-encoding"
|
name = "ssh-encoding"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/a-dma/SSH.git?branch=u2f_signatures#ce0c34c935acd2caf7174d33039ec1c4557119de"
|
||||||
checksum = "19cfdc32e0199062113edf41f344fbf784b8205a94600233c84eb838f45191e1"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64ct",
|
"base64ct",
|
||||||
"pem-rfc7468",
|
"pem-rfc7468",
|
||||||
@@ -1682,8 +1644,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "ssh-key"
|
name = "ssh-key"
|
||||||
version = "0.5.1"
|
version = "0.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/a-dma/SSH.git?branch=u2f_signatures#ce0c34c935acd2caf7174d33039ec1c4557119de"
|
||||||
checksum = "288d8f5562af5a3be4bda308dd374b2c807b940ac370b5efa1c99311da91d9a1"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ed25519-dalek",
|
"ed25519-dalek",
|
||||||
"num-bigint-dig",
|
"num-bigint-dig",
|
||||||
@@ -1713,9 +1674,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.107"
|
version = "1.0.104"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
|
checksum = "4ae548ec36cf198c0ef7710d3c230987c2d6d7bd98ad6edc0274462724c585ce"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1756,27 +1717,27 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "termcolor"
|
name = "termcolor"
|
||||||
version = "1.2.0"
|
version = "1.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
|
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "1.0.38"
|
version = "1.0.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0"
|
checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl",
|
"thiserror-impl",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "1.0.38"
|
version = "1.0.37"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f"
|
checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1820,9 +1781,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.24.2"
|
version = "1.22.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb"
|
checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -1833,14 +1794,14 @@ dependencies = [
|
|||||||
"socket2",
|
"socket2",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"tracing",
|
"tracing",
|
||||||
"windows-sys",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-macros"
|
name = "tokio-macros"
|
||||||
version = "1.8.2"
|
version = "1.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
|
checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -1889,9 +1850,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tower-http"
|
name = "tower-http"
|
||||||
version = "0.3.5"
|
version = "0.3.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858"
|
checksum = "3c530c8675c1dbf98facee631536fa116b5fb6382d7dd6dc1b118d970eafe3ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -1980,27 +1941,27 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "try-lock"
|
name = "try-lock"
|
||||||
version = "0.2.4"
|
version = "0.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
|
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.16.0"
|
version = "1.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
|
checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.10"
|
version = "0.3.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d54675592c1dbefd78cbd98db9bacd89886e1ca50692a0692baefffdeb92dd58"
|
checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.6"
|
version = "1.0.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-normalization"
|
name = "unicode-normalization"
|
||||||
@@ -2187,6 +2148,19 @@ 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-sys"
|
||||||
|
version = "0.36.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
|
||||||
|
dependencies = [
|
||||||
|
"windows_aarch64_msvc 0.36.1",
|
||||||
|
"windows_i686_gnu 0.36.1",
|
||||||
|
"windows_i686_msvc 0.36.1",
|
||||||
|
"windows_x86_64_gnu 0.36.1",
|
||||||
|
"windows_x86_64_msvc 0.36.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.42.0"
|
version = "0.42.0"
|
||||||
@@ -2194,55 +2168,85 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows_aarch64_gnullvm",
|
"windows_aarch64_gnullvm",
|
||||||
"windows_aarch64_msvc",
|
"windows_aarch64_msvc 0.42.0",
|
||||||
"windows_i686_gnu",
|
"windows_i686_gnu 0.42.0",
|
||||||
"windows_i686_msvc",
|
"windows_i686_msvc 0.42.0",
|
||||||
"windows_x86_64_gnu",
|
"windows_x86_64_gnu 0.42.0",
|
||||||
"windows_x86_64_gnullvm",
|
"windows_x86_64_gnullvm",
|
||||||
"windows_x86_64_msvc",
|
"windows_x86_64_msvc 0.42.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.42.1"
|
version = "0.42.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
|
checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.42.1"
|
version = "0.36.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
|
checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_aarch64_msvc"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.42.1"
|
version = "0.36.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
|
checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_gnu"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.42.1"
|
version = "0.36.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
|
checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_i686_msvc"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.42.1"
|
version = "0.36.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
|
checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_gnu"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.42.1"
|
version = "0.42.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
|
checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.42.1"
|
version = "0.36.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
|
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows_x86_64_msvc"
|
||||||
|
version = "0.42.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winreg"
|
name = "winreg"
|
||||||
@@ -2264,9 +2268,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zeroize_derive"
|
name = "zeroize_derive"
|
||||||
version = "1.3.3"
|
version = "1.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "44bf07cb3e50ea2003396695d58bf46bc9887a1f362260446fad6bc4e79bd36c"
|
checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
47
Cargo.toml
47
Cargo.toml
@@ -1,8 +1,43 @@
|
|||||||
[workspace]
|
[package]
|
||||||
|
name = "ssh-cert-dist"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["shimun <shimun@shimun.net>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
members = [
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
"common",
|
|
||||||
"server",
|
[features]
|
||||||
"client",
|
default = [ "client", "reload", "info", "authorized" ]
|
||||||
]
|
reload = []
|
||||||
|
authorized =[ "dep:jwt-compact" ]
|
||||||
|
index = []
|
||||||
|
info = [ "axum/json", "ssh-key/serde" ]
|
||||||
|
client = [ "dep:url", "dep:reqwest" ]
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
anyhow = "1.0.66"
|
||||||
|
async-trait = "0.1.59"
|
||||||
|
axum = { version = "0.6.1", features = ["http2"] }
|
||||||
|
axum-extra = { version = "0.4.1", features = ["typed-routing"] }
|
||||||
|
chrono = "0.4.23"
|
||||||
|
clap = { version = "4.0.29", features = ["env", "derive"] }
|
||||||
|
jwt-compact = { version = "0.6.0", features = ["serde_cbor", "std", "clock"], optional = true }
|
||||||
|
rand = "0.8.5"
|
||||||
|
reqwest = { version = "0.11.13", optional = true }
|
||||||
|
serde = { version = "1.0.148", features = ["derive"] }
|
||||||
|
ssh-key = { version = "0.5.1", features = ["ed25519", "p256", "p384", "rsa", "signature"] }
|
||||||
|
thiserror = "1.0.37"
|
||||||
|
tokio = { version = "1.22.0", features = ["io-std", "test-util", "tracing", "macros", "fs"] }
|
||||||
|
tower = { version = "0.4.13", features = ["util"] }
|
||||||
|
tower-http = { version = "0.3.4", features = ["map-request-body", "trace"] }
|
||||||
|
tracing = { version = "0.1.37", features = ["release_max_level_debug"] }
|
||||||
|
tracing-subscriber = "0.3.16"
|
||||||
|
url = { version = "2.3.1", optional = true }
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
ssh-key = { git = "https://github.com/a-dma/SSH.git", branch = "u2f_signatures" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
tempfile = "3.3.0"
|
||||||
|
|
||||||
|
@@ -1,32 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "ssh-cert-dist-client"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["shimun <shimun@shimun.net>"]
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "ssh-cert-dist"
|
|
||||||
path = "src/main.rs"
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
anyhow = "1.0.66"
|
|
||||||
async-trait = "0.1.59"
|
|
||||||
axum-extra = { version = "0.4.1", features = ["typed-routing"] }
|
|
||||||
chrono = "0.4.23"
|
|
||||||
clap = { version = "4.0.29", features = ["env", "derive"] }
|
|
||||||
rand = "0.8.5"
|
|
||||||
reqwest = { version = "0.11.13" }
|
|
||||||
serde = { version = "1.0.148", features = ["derive"] }
|
|
||||||
ssh-key = { version = "0.5.1", features = ["ed25519", "p256", "p384", "rsa", "signature"] }
|
|
||||||
thiserror = "1.0.37"
|
|
||||||
tokio = { version = "1.22.0", features = ["io-std", "test-util", "tracing", "macros", "fs"] }
|
|
||||||
tracing = { version = "0.1.37", features = ["release_max_level_debug"] }
|
|
||||||
tracing-subscriber = "0.3.16"
|
|
||||||
url = { version = "2.3.1" }
|
|
||||||
ssh-cert-dist-common = { path = "../common" }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
tempfile = "3.3.0"
|
|
||||||
|
|
||||||
[profile.relese]
|
|
||||||
opt-level = 1
|
|
@@ -1,10 +0,0 @@
|
|||||||
use clap::Parser;
|
|
||||||
|
|
||||||
mod client;
|
|
||||||
|
|
||||||
#[tokio::main(flavor = "current_thread")]
|
|
||||||
async fn main() -> anyhow::Result<()> {
|
|
||||||
tracing_subscriber::fmt::init();
|
|
||||||
|
|
||||||
client::run(client::ClientCommand::parse()).await
|
|
||||||
}
|
|
@@ -1,23 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "ssh-cert-dist-common"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["shimun <shimun@shimun.net>"]
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
anyhow = "1.0.66"
|
|
||||||
async-trait = "0.1.59"
|
|
||||||
axum = { version = "0.6.1" }
|
|
||||||
axum-extra = { version = "0.4.1", features = ["typed-routing"] }
|
|
||||||
serde = { version = "1.0.148", features = ["derive"] }
|
|
||||||
ssh-key = { version = "0.5.1", features = ["ed25519", "p256", "p384", "rsa", "signature"] }
|
|
||||||
thiserror = "1.0.37"
|
|
||||||
tokio = { version = "1.22.0", features = ["io-std", "test-util", "tracing", "macros", "fs"] }
|
|
||||||
tracing = { version = "0.1.37", features = ["release_max_level_debug"] }
|
|
||||||
tracing-subscriber = "0.3.16"
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
tempfile = "3.3.0"
|
|
||||||
|
|
@@ -1,6 +0,0 @@
|
|||||||
mod certs;
|
|
||||||
mod routes;
|
|
||||||
mod util;
|
|
||||||
|
|
||||||
pub use certs::*;
|
|
||||||
pub use routes::*;
|
|
@@ -1,28 +0,0 @@
|
|||||||
use axum_extra::routing::TypedPath;
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
#[derive(TypedPath, Deserialize)]
|
|
||||||
#[typed_path("/certs")]
|
|
||||||
pub struct CertList;
|
|
||||||
|
|
||||||
#[derive(TypedPath, Deserialize)]
|
|
||||||
#[typed_path("/certs/:identifier")]
|
|
||||||
pub struct GetCert {
|
|
||||||
pub identifier: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(TypedPath, Deserialize)]
|
|
||||||
#[typed_path("/certs/:identifier/info")]
|
|
||||||
pub struct GetCertInfo {
|
|
||||||
pub identifier: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(TypedPath, Deserialize)]
|
|
||||||
#[typed_path("/certs/:identifier")]
|
|
||||||
pub struct PostCertInfo {
|
|
||||||
pub identifier: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(TypedPath)]
|
|
||||||
#[typed_path("/cert")]
|
|
||||||
pub struct PutCert;
|
|
@@ -1,6 +0,0 @@
|
|||||||
#[macro_export]
|
|
||||||
macro_rules! env_key {
|
|
||||||
( $var:expr ) => {
|
|
||||||
concat!("SSH_CD_", $var)
|
|
||||||
};
|
|
||||||
}
|
|
39
flake.nix
39
flake.nix
@@ -13,7 +13,7 @@
|
|||||||
outputs = inputs @ { self, nixpkgs, utils, naersk, ... }:
|
outputs = inputs @ { self, nixpkgs, utils, naersk, ... }:
|
||||||
let
|
let
|
||||||
root = inputs.source or self;
|
root = inputs.source or self;
|
||||||
pname = "ssh-cert-dist";
|
pname = (builtins.fromTOML (builtins.readFile (root + "/Cargo.toml"))).package.name;
|
||||||
# toolchains: stable, beta, default(nightly)
|
# toolchains: stable, beta, default(nightly)
|
||||||
toolchain = pkgs:
|
toolchain = pkgs:
|
||||||
if inputs ? fenix then inputs.fenix.packages."${pkgs.system}".complete.toolchain
|
if inputs ? fenix then inputs.fenix.packages."${pkgs.system}".complete.toolchain
|
||||||
@@ -24,28 +24,15 @@
|
|||||||
in
|
in
|
||||||
rec {
|
rec {
|
||||||
# `nix build`
|
# `nix build`
|
||||||
packages."${pname}-server" = (self.overlay pkgs pkgs)."${pname}-server";
|
packages.${pname} = (self.overlay pkgs pkgs).${pname};
|
||||||
packages."${pname}-client" = (self.overlay pkgs pkgs)."${pname}-client";
|
|
||||||
|
|
||||||
packages."${pname}-client-snap" = pkgs.snapTools.makeSnap {
|
|
||||||
meta = {
|
|
||||||
name = pname;
|
|
||||||
architectures = [ "amd64" ];
|
|
||||||
confinement = "strict";
|
|
||||||
apps.hello.command = apps."${pname}-client".program;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
packages.dockerImage = pkgs.runCommandLocal "docker-${pname}.tar.gz" { } "${apps.streamDockerImage.program} | gzip --fast > $out";
|
packages.dockerImage = pkgs.runCommandLocal "docker-${pname}.tar.gz" { } "${apps.streamDockerImage.program} | gzip --fast > $out";
|
||||||
|
|
||||||
packages.default = packages."${pname}-client";
|
packages.default = packages.${pname};
|
||||||
|
|
||||||
# `nix run`
|
# `nix run`
|
||||||
apps."${pname}-server" = utils.lib.mkApp {
|
apps.${pname} = utils.lib.mkApp {
|
||||||
drv = packages."${pname}-server";
|
drv = packages.${pname};
|
||||||
};
|
|
||||||
apps."${pname}-client" = utils.lib.mkApp {
|
|
||||||
drv = packages."${pname}-client";
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# `nix run .#streamDockerImage | docker load`
|
# `nix run .#streamDockerImage | docker load`
|
||||||
@@ -54,12 +41,12 @@
|
|||||||
name = pname;
|
name = pname;
|
||||||
tag = self.shortRev or "latest";
|
tag = self.shortRev or "latest";
|
||||||
config = {
|
config = {
|
||||||
Entrypoint = apps."${pname}-server".program;
|
Entrypoint = apps.default.program;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
exePath = "";
|
exePath = "";
|
||||||
};
|
};
|
||||||
apps.default = apps."${pname}-client";
|
apps.default = apps.${pname};
|
||||||
|
|
||||||
# `nix flake check`
|
# `nix flake check`
|
||||||
checks = {
|
checks = {
|
||||||
@@ -91,7 +78,7 @@
|
|||||||
rustc --version
|
rustc --version
|
||||||
printf "\nbuild inputs: ${pkgs.lib.concatStringsSep ", " (map (bi: bi.name) (buildInputs ++ nativeBuildInputs))}"
|
printf "\nbuild inputs: ${pkgs.lib.concatStringsSep ", " (map (bi: bi.name) (buildInputs ++ nativeBuildInputs))}"
|
||||||
function server() {
|
function server() {
|
||||||
cargo watch -x "run --bin ssh-cert-dist-server --all-features -- ''${@}"
|
cargo watch -x "run --all-features -- server ''${@}"
|
||||||
}
|
}
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
@@ -116,15 +103,9 @@
|
|||||||
];
|
];
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
"${pname}-server" =
|
"${pname}" =
|
||||||
naersk-lib.buildPackage {
|
naersk-lib.buildPackage {
|
||||||
name = "${pname}-server";
|
inherit pname root buildInputs nativeBuildInputs;
|
||||||
inherit root buildInputs nativeBuildInputs;
|
|
||||||
};
|
|
||||||
"${pname}-client" =
|
|
||||||
naersk-lib.buildPackage {
|
|
||||||
name = "${pname}-client";
|
|
||||||
inherit root buildInputs nativeBuildInputs;
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -13,14 +13,15 @@ in
|
|||||||
Environment = "RUST_LOG=debug";
|
Environment = "RUST_LOG=debug";
|
||||||
ExecStart = toString (pkgs.writeShellApplication {
|
ExecStart = toString (pkgs.writeShellApplication {
|
||||||
name = "ssh-cert-dist-${options.name}";
|
name = "ssh-cert-dist-${options.name}";
|
||||||
runtimeInputs = [ cfg.package ];
|
runtimeInputs = [ pkgs.ssh-cert-dist ];
|
||||||
text = ''
|
text = ''
|
||||||
${optionalString options.fetch ''
|
${optionalString options.fetch ''
|
||||||
ssh-cert-dist fetch --cert-dir '${path}' --api-endpoint '${cfg.endpoint}'
|
ssh-cert-dist client fetch --cert-dir '${path}' --api-endpoint '${cfg.endpoint}'
|
||||||
''}
|
''}
|
||||||
${optionalString options.upload ''
|
${optionalString options.upload ''
|
||||||
ssh-cert-dist upload --api-endpoint '${cfg.endpoint}' ${path}/*
|
ssh-cert-dist client upload --api-endpoint '${cfg.endpoint}' ${path}/*
|
||||||
''}
|
''}
|
||||||
|
|
||||||
'';
|
'';
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@@ -14,7 +14,7 @@ in
|
|||||||
};
|
};
|
||||||
package = mkOption {
|
package = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
default = pkgs.ssh-cert-dist-server;
|
default = pkgs.ssh-cert-dist;
|
||||||
};
|
};
|
||||||
ca = mkOption {
|
ca = mkOption {
|
||||||
type = types.path;
|
type = types.path;
|
||||||
@@ -57,7 +57,7 @@ in
|
|||||||
chown ${cfg.user}:${cfg.group} ${cfg.dataDir}
|
chown ${cfg.user}:${cfg.group} ${cfg.dataDir}
|
||||||
''}";
|
''}";
|
||||||
User = cfg.user;
|
User = cfg.user;
|
||||||
ExecStart = "${cfg.package}/bin/ssh-cert-dist-server";
|
ExecStart = "${cfg.package}/bin/ssh-cert-dist server";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@@ -22,7 +22,7 @@
|
|||||||
};
|
};
|
||||||
packageOption = mkOption {
|
packageOption = mkOption {
|
||||||
type = types.package;
|
type = types.package;
|
||||||
default = pkgs.ssh-cert-dist-client;
|
default = pkgs.ssh-cert-dist;
|
||||||
};
|
};
|
||||||
|
|
||||||
in
|
in
|
||||||
|
@@ -1,40 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "ssh-cert-dist-server"
|
|
||||||
version = "0.1.0"
|
|
||||||
authors = ["shimun <shimun@shimun.net>"]
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[features]
|
|
||||||
default = [ "reload", "info", "authorized" ]
|
|
||||||
reload = []
|
|
||||||
authorized =[ "dep:jwt-compact" ]
|
|
||||||
index = []
|
|
||||||
info = [ "axum/json", "ssh-key/serde" ]
|
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
|
||||||
anyhow = "1.0.66"
|
|
||||||
async-trait = "0.1.59"
|
|
||||||
axum = { version = "0.6.1", features = ["http2"] }
|
|
||||||
axum-extra = { version = "0.4.1", features = ["typed-routing"] }
|
|
||||||
chrono = "0.4.23"
|
|
||||||
clap = { version = "4.0.29", features = ["env", "derive"] }
|
|
||||||
jwt-compact = { version = "0.6.0", features = ["serde_cbor", "std", "clock"], optional = true }
|
|
||||||
rand = "0.8.5"
|
|
||||||
serde = { version = "1.0.148", features = ["derive"] }
|
|
||||||
ssh-key = { version = "0.5.1", features = ["ed25519", "p256", "p384", "rsa", "signature"] }
|
|
||||||
thiserror = "1.0.37"
|
|
||||||
tokio = { version = "1.22.0", features = ["io-std", "test-util", "tracing", "macros", "fs"] }
|
|
||||||
tower = { version = "0.4.13", features = ["util"] }
|
|
||||||
tower-http = { version = "0.3.4", features = ["map-request-body", "trace"] }
|
|
||||||
tracing = { version = "0.1.37", features = ["release_max_level_debug"] }
|
|
||||||
tracing-subscriber = "0.3.16"
|
|
||||||
ssh-cert-dist-common = { path = "../common" }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
|
||||||
tempfile = "3.3.0"
|
|
||||||
|
|
||||||
[profile.release]
|
|
||||||
opt-level = 1
|
|
@@ -1,49 +0,0 @@
|
|||||||
use super::ApiError;
|
|
||||||
use anyhow::Context;
|
|
||||||
use axum::{async_trait, body::BoxBody, extract::FromRequest, http::Request};
|
|
||||||
use ssh_key::{Certificate, SshSig};
|
|
||||||
use tracing::trace;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct CertificateBody(pub Certificate);
|
|
||||||
|
|
||||||
// we must implement `FromRequest` (and not `FromRequestParts`) to consume the body
|
|
||||||
#[async_trait]
|
|
||||||
impl<S> FromRequest<S, BoxBody> for CertificateBody
|
|
||||||
where
|
|
||||||
S: Send + Sync,
|
|
||||||
{
|
|
||||||
type Rejection = ApiError;
|
|
||||||
|
|
||||||
async fn from_request(req: Request<BoxBody>, state: &S) -> Result<Self, Self::Rejection> {
|
|
||||||
let body = String::from_request(req, state)
|
|
||||||
.await
|
|
||||||
.context("failed to extract body")?;
|
|
||||||
|
|
||||||
let cert = Certificate::from_openssh(&body)
|
|
||||||
.with_context(|| format!("failed to parse '{}'", body))?;
|
|
||||||
trace!(%body, "extracted certificate");
|
|
||||||
Ok(Self(cert))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct SignatureBody(pub SshSig);
|
|
||||||
|
|
||||||
#[async_trait]
|
|
||||||
impl<S> FromRequest<S, BoxBody> for SignatureBody
|
|
||||||
where
|
|
||||||
S: Send + Sync,
|
|
||||||
{
|
|
||||||
type Rejection = ApiError;
|
|
||||||
|
|
||||||
async fn from_request(req: Request<BoxBody>, state: &S) -> Result<Self, Self::Rejection> {
|
|
||||||
let body = String::from_request(req, state)
|
|
||||||
.await
|
|
||||||
.context("failed to extract body")?;
|
|
||||||
|
|
||||||
let sig = SshSig::from_pem(&body).with_context(|| format!("failed to parse '{}'", body))?;
|
|
||||||
trace!(%body, "extracted signature");
|
|
||||||
Ok(Self(sig))
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,10 +0,0 @@
|
|||||||
use clap::Parser;
|
|
||||||
|
|
||||||
mod api;
|
|
||||||
|
|
||||||
#[tokio::main(flavor = "current_thread")]
|
|
||||||
async fn main() -> anyhow::Result<()> {
|
|
||||||
tracing_subscriber::fmt::init();
|
|
||||||
|
|
||||||
api::run(api::ApiArgs::parse()).await
|
|
||||||
}
|
|
@@ -4,27 +4,33 @@ use std::collections::HashMap;
|
|||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
use std::path::{self, PathBuf};
|
use std::path::{self, PathBuf};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::SystemTime;
|
use std::time::{Duration, SystemTime};
|
||||||
|
|
||||||
|
use crate::certs::{load_cert_by_id, read_certs, read_pubkey, store_cert};
|
||||||
|
use crate::env_key;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use axum::body;
|
use axum::body;
|
||||||
|
use axum::extract::rejection::QueryRejection;
|
||||||
use axum::extract::{Query, State};
|
use axum::extract::{Query, State};
|
||||||
use ssh_cert_dist_common::*;
|
|
||||||
|
|
||||||
use axum::{http::StatusCode, response::IntoResponse, Json, Router};
|
use axum::{http::StatusCode, response::IntoResponse, Json, Router};
|
||||||
use axum_extra::routing::RouterExt;
|
use axum_extra::routing::{
|
||||||
|
RouterExt, // for `Router::typed_*`
|
||||||
|
TypedPath,
|
||||||
|
};
|
||||||
use clap::{Args, Parser};
|
use clap::{Args, Parser};
|
||||||
use jwt_compact::alg::{Hs256, Hs256Key};
|
use jwt_compact::alg::{Hs256, Hs256Key};
|
||||||
use jwt_compact::{AlgorithmExt, Token, UntrustedToken};
|
use jwt_compact::{AlgorithmExt, Token, UntrustedToken};
|
||||||
use rand::{thread_rng, Rng};
|
use rand::{thread_rng, Rng};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use ssh_key::{Certificate, Fingerprint, PublicKey};
|
use ssh_key::private::Ed25519Keypair;
|
||||||
|
use ssh_key::{certificate, Certificate, PrivateKey, PublicKey};
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use tower::ServiceBuilder;
|
use tower::ServiceBuilder;
|
||||||
use tower_http::{trace::TraceLayer, ServiceBuilderExt};
|
use tower_http::{trace::TraceLayer, ServiceBuilderExt};
|
||||||
use tracing::{debug, info, trace};
|
use tracing::{debug, info, trace};
|
||||||
|
|
||||||
use self::extract::{CertificateBody, SignatureBody};
|
use self::extract::{AsJWTVerifier, CertificateBody, JWTAuthenticated, JWTString, SignatureBody};
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
pub struct ApiArgs {
|
pub struct ApiArgs {
|
||||||
@@ -81,6 +87,13 @@ struct ApiState {
|
|||||||
jwt_key: Hs256Key,
|
jwt_key: Hs256Key,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AsJWTVerifier for ApiState {
|
||||||
|
type Algo = Hs256;
|
||||||
|
fn as_secret(&self) -> &<Self::Algo as jwt_compact::Algorithm>::VerifyingKey {
|
||||||
|
&self.jwt_key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ApiState {
|
impl ApiState {
|
||||||
async fn new(
|
async fn new(
|
||||||
cert_dir: impl AsRef<path::Path>,
|
cert_dir: impl AsRef<path::Path>,
|
||||||
@@ -172,6 +185,12 @@ pub enum ApiError {
|
|||||||
AuthenticationRequired(String),
|
AuthenticationRequired(String),
|
||||||
#[error("invalid ssh signature")]
|
#[error("invalid ssh signature")]
|
||||||
InvalidSignature,
|
InvalidSignature,
|
||||||
|
#[error("invalid jwt")]
|
||||||
|
JWTVerify(#[from] jwt_compact::ValidationError),
|
||||||
|
#[error("invalid jwt")]
|
||||||
|
JWTParse(#[from] jwt_compact::ParseError),
|
||||||
|
#[error("{0}")]
|
||||||
|
Query(#[from] QueryRejection),
|
||||||
}
|
}
|
||||||
|
|
||||||
type ApiResult<T> = Result<T, ApiError>;
|
type ApiResult<T> = Result<T, ApiError>;
|
||||||
@@ -197,7 +216,10 @@ async fn fallback_404() -> ApiResult<()> {
|
|||||||
Err(ApiError::CertificateNotFound)
|
Err(ApiError::CertificateNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "index")]
|
#[derive(TypedPath, Deserialize)]
|
||||||
|
#[typed_path("/certs")]
|
||||||
|
pub struct CertList;
|
||||||
|
|
||||||
async fn list_certs(
|
async fn list_certs(
|
||||||
_: CertList,
|
_: CertList,
|
||||||
State(ApiState { certs, .. }): State<ApiState>,
|
State(ApiState { certs, .. }): State<ApiState>,
|
||||||
@@ -213,12 +235,18 @@ async fn list_certs(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(tag = "aud", rename = "get")]
|
#[serde(tag = "aud", rename = "get")]
|
||||||
struct AuthClaims {
|
struct AuthClaims {
|
||||||
identifier: String,
|
identifier: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(TypedPath, Deserialize)]
|
||||||
|
#[typed_path("/certs/:identifier")]
|
||||||
|
pub struct GetCert {
|
||||||
|
pub identifier: String,
|
||||||
|
}
|
||||||
|
|
||||||
/// Retrieve an certificate for identifier
|
/// Retrieve an certificate for identifier
|
||||||
/// TODO: add option to require auth
|
/// TODO: add option to require auth
|
||||||
/// return Unauthorized with an challenge
|
/// return Unauthorized with an challenge
|
||||||
@@ -233,7 +261,7 @@ async fn get_certs_identifier(
|
|||||||
..
|
..
|
||||||
}): State<ApiState>,
|
}): State<ApiState>,
|
||||||
) -> ApiResult<String> {
|
) -> ApiResult<String> {
|
||||||
use jwt_compact::{Claims, Header, TimeOptions};
|
use jwt_compact::{AlgorithmExt, Claims, Header, TimeOptions};
|
||||||
|
|
||||||
if client_auth {
|
if client_auth {
|
||||||
let claims = Claims::new(AuthClaims { identifier })
|
let claims = Claims::new(AuthClaims { identifier })
|
||||||
@@ -250,58 +278,30 @@ async fn get_certs_identifier(
|
|||||||
Ok(cert.to_openssh().context("to openssh")?)
|
Ok(cert.to_openssh().context("to openssh")?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(TypedPath, Deserialize)]
|
||||||
|
#[typed_path("/certs/:identifier/info")]
|
||||||
|
pub struct GetCertInfo {
|
||||||
|
pub identifier: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "info")]
|
#[cfg(feature = "info")]
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
struct CertInfo {
|
struct CertInfo {
|
||||||
principals: Vec<String>,
|
principals: Vec<String>,
|
||||||
ca: PublicKey,
|
ca: PublicKey,
|
||||||
ca_hash: Fingerprint,
|
|
||||||
identity: PublicKey,
|
identity: PublicKey,
|
||||||
identity_hash: Fingerprint,
|
|
||||||
key_id: String,
|
key_id: String,
|
||||||
expiry: SystemTime,
|
expiry: SystemTime,
|
||||||
renew_command: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&Certificate> for CertInfo {
|
impl From<&Certificate> for CertInfo {
|
||||||
fn from(cert: &Certificate) -> Self {
|
fn from(cert: &Certificate) -> Self {
|
||||||
let validity = cert
|
|
||||||
.valid_after_time()
|
|
||||||
.duration_since(cert.valid_before_time())
|
|
||||||
.unwrap();
|
|
||||||
let validity_days = validity.as_secs() / ((60 * 60) * 24);
|
|
||||||
let host_key = if cert.cert_type().is_host() {
|
|
||||||
" -h"
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
};
|
|
||||||
let opts = cert
|
|
||||||
.critical_options()
|
|
||||||
.iter()
|
|
||||||
.map(|(opt, val)| {
|
|
||||||
if val.is_empty() {
|
|
||||||
opt.clone()
|
|
||||||
} else {
|
|
||||||
format!("{opt}={val}")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.map(|arg| format!("-O {arg}"))
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(" ");
|
|
||||||
let renew_command = format!(
|
|
||||||
"ssh-keygen -s ./ca_key {host_key} -I {} -n {} -V {validity_days}d {opts}",
|
|
||||||
cert.key_id(),
|
|
||||||
cert.valid_principals().join(",")
|
|
||||||
);
|
|
||||||
CertInfo {
|
CertInfo {
|
||||||
principals: cert.valid_principals().to_vec(),
|
principals: cert.valid_principals().to_vec(),
|
||||||
ca: cert.signature_key().clone().into(),
|
ca: cert.signature_key().clone().into(),
|
||||||
ca_hash: cert.signature_key().fingerprint(ssh_key::HashAlg::Sha256),
|
|
||||||
identity: cert.public_key().clone().into(),
|
identity: cert.public_key().clone().into(),
|
||||||
identity_hash: cert.public_key().fingerprint(ssh_key::HashAlg::Sha256),
|
|
||||||
key_id: cert.key_id().to_string(),
|
key_id: cert.key_id().to_string(),
|
||||||
expiry: cert.valid_before_time(),
|
expiry: cert.valid_before_time(),
|
||||||
renew_command,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -326,27 +326,39 @@ async fn get_cert_info(
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(TypedPath, Deserialize)]
|
||||||
|
#[typed_path("/certs/:identifier")]
|
||||||
|
pub struct PostCertInfo {
|
||||||
|
pub identifier: String,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct PostCertsQuery {
|
struct PostCertsQuery {
|
||||||
challenge: String,
|
challenge: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Into<JWTString> for Query<PostCertsQuery> {
|
||||||
|
fn into(self) -> JWTString {
|
||||||
|
self.0.challenge.into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// POST with signed challenge
|
/// POST with signed challenge
|
||||||
async fn post_certs_identifier(
|
async fn post_certs_identifier(
|
||||||
PostCertInfo { identifier }: PostCertInfo,
|
PostCertInfo { identifier }: PostCertInfo,
|
||||||
State(ApiState { certs, jwt_key, .. }): State<ApiState>,
|
State(ApiState { certs, jwt_key, .. }): State<ApiState>,
|
||||||
|
JWTAuthenticated {
|
||||||
|
data: AuthClaims {
|
||||||
|
identifier: authenticated_identifier,
|
||||||
|
},
|
||||||
|
..
|
||||||
|
}: JWTAuthenticated<AuthClaims, ApiState, Query<PostCertsQuery>, ApiError>,
|
||||||
Query(PostCertsQuery { challenge }): Query<PostCertsQuery>,
|
Query(PostCertsQuery { challenge }): Query<PostCertsQuery>,
|
||||||
SignatureBody(sig): SignatureBody,
|
SignatureBody(sig): SignatureBody,
|
||||||
) -> ApiResult<String> {
|
) -> ApiResult<String> {
|
||||||
let certs = certs.lock().await;
|
let certs = certs.lock().await;
|
||||||
let cert = certs.get(&identifier).ok_or(ApiError::InvalidSignature)?;
|
let cert = certs.get(&identifier).ok_or(ApiError::InvalidSignature)?;
|
||||||
let token: Token<AuthClaims> = Hs256
|
if authenticated_identifier != identifier {
|
||||||
.validate_integrity(
|
|
||||||
&UntrustedToken::new(&challenge).context("jwt parse")?,
|
|
||||||
&jwt_key,
|
|
||||||
)
|
|
||||||
.map_err(|_| ApiError::InvalidSignature)?;
|
|
||||||
if token.claims().custom.identifier != identifier {
|
|
||||||
return Err(ApiError::InvalidSignature);
|
return Err(ApiError::InvalidSignature);
|
||||||
}
|
}
|
||||||
let pubkey: PublicKey = cert.public_key().clone().into();
|
let pubkey: PublicKey = cert.public_key().clone().into();
|
||||||
@@ -361,6 +373,10 @@ async fn post_certs_identifier(
|
|||||||
Ok(cert.to_openssh().context("to openssh")?)
|
Ok(cert.to_openssh().context("to openssh")?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(TypedPath)]
|
||||||
|
#[typed_path("/cert")]
|
||||||
|
pub struct PutCert;
|
||||||
|
|
||||||
/// Upload an cert with an higher serial than the previous
|
/// Upload an cert with an higher serial than the previous
|
||||||
async fn put_cert_update(
|
async fn put_cert_update(
|
||||||
_: PutCert,
|
_: PutCert,
|
||||||
@@ -409,14 +425,12 @@ async fn put_cert_update(
|
|||||||
let identity = cert.key_id();
|
let identity = cert.key_id();
|
||||||
info!(%identity, ?principals, "updating certificate");
|
info!(%identity, ?principals, "updating certificate");
|
||||||
certs.lock().await.insert(cert.key_id().to_string(), cert);
|
certs.lock().await.insert(cert.key_id().to_string(), cert);
|
||||||
Ok(format!("{prev_serial} -> {serial}"))
|
Ok(format!("{} -> {}", prev_serial, serial))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use ssh_key::{certificate, private::Ed25519Keypair, PrivateKey};
|
|
||||||
use std::env::temp_dir;
|
use std::env::temp_dir;
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@@ -436,7 +450,7 @@ mod tests {
|
|||||||
Ed25519Keypair::from_seed(&[1u8; 32])
|
Ed25519Keypair::from_seed(&[1u8; 32])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn user_cert(ca: Ed25519Keypair, user_key: PublicKey, validity: Duration) -> Certificate {
|
fn user_cert(ca: Ed25519Keypair, user_key: PublicKey) -> Certificate {
|
||||||
let ca_private: PrivateKey = ca.into();
|
let ca_private: PrivateKey = ca.into();
|
||||||
let unix_time = |time: SystemTime| -> u64 {
|
let unix_time = |time: SystemTime| -> u64 {
|
||||||
time.duration_since(SystemTime::UNIX_EPOCH)
|
time.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
@@ -447,7 +461,7 @@ mod tests {
|
|||||||
[0u8; 16],
|
[0u8; 16],
|
||||||
user_key,
|
user_key,
|
||||||
unix_time(SystemTime::now()),
|
unix_time(SystemTime::now()),
|
||||||
unix_time(SystemTime::now() + validity),
|
unix_time(SystemTime::now() + Duration::from_secs(30)),
|
||||||
);
|
);
|
||||||
|
|
||||||
builder
|
builder
|
||||||
@@ -469,49 +483,24 @@ mod tests {
|
|||||||
cert_dir: dbg!(temp_dir()),
|
cert_dir: dbg!(temp_dir()),
|
||||||
validation_args: Default::default(),
|
validation_args: Default::default(),
|
||||||
client_auth: false,
|
client_auth: false,
|
||||||
jwt_key: Hs256Key::new([0u8; 16]),
|
jwt_key: Hs256Key::new(&[0u8; 16]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_certificate() {
|
fn test_certificate() {
|
||||||
let valid_cert = user_cert(ca_key(), user_key().public.into(), Duration::from_secs(30));
|
let valid_cert = user_cert(ca_key(), user_key().public.into());
|
||||||
let ca_pub: PublicKey = ca_pub();
|
let ca_pub: PublicKey = ca_pub();
|
||||||
assert!(valid_cert
|
assert!(valid_cert
|
||||||
.validate(&[ca_pub.fingerprint(Default::default())])
|
.validate(&[ca_pub.fingerprint(Default::default())])
|
||||||
.is_ok());
|
.is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn update_cert() {
|
|
||||||
let state = api_state();
|
|
||||||
let ca = ca_key();
|
|
||||||
let user: PublicKey = user_key().public.into();
|
|
||||||
let (cert_first, cert_newer, cert_outdated) = {
|
|
||||||
(
|
|
||||||
user_cert(ca.clone(), user.clone(), Duration::from_secs(30)),
|
|
||||||
user_cert(ca.clone(), user.clone(), Duration::from_secs(60)),
|
|
||||||
user_cert(ca.clone(), user.clone(), Duration::from_secs(3)),
|
|
||||||
)
|
|
||||||
};
|
|
||||||
let res = put_cert_update(PutCert, State(state.clone()), CertificateBody(cert_first)).await;
|
|
||||||
assert!(res.is_ok());
|
|
||||||
let res = put_cert_update(PutCert, State(state.clone()), CertificateBody(cert_newer)).await;
|
|
||||||
assert!(res.is_ok());
|
|
||||||
let res = put_cert_update(
|
|
||||||
PutCert,
|
|
||||||
State(state.clone()),
|
|
||||||
CertificateBody(cert_outdated),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
assert!(res.is_err());
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn routes() -> anyhow::Result<()> {
|
async fn routes() -> anyhow::Result<()> {
|
||||||
let state = api_state();
|
let state = api_state();
|
||||||
let valid_cert = user_cert(ca_key(), user_key().public.into(), Duration::from_secs(30));
|
let valid_cert = user_cert(ca_key(), user_key().public.into());
|
||||||
let invalid_cert = user_cert(ca_key2(), user_key().public.into(), Duration::from_secs(30));
|
let invalid_cert = user_cert(ca_key2(), user_key().public.into());
|
||||||
let res = put_cert_update(
|
let res = put_cert_update(
|
||||||
PutCert,
|
PutCert,
|
||||||
State(state.clone()),
|
State(state.clone()),
|
||||||
@@ -568,6 +557,9 @@ mod tests {
|
|||||||
identifier: "test_cert".into(),
|
identifier: "test_cert".into(),
|
||||||
},
|
},
|
||||||
State(state.clone()),
|
State(state.clone()),
|
||||||
|
JWTAuthenticated::from(AuthClaims {
|
||||||
|
identifier: "test_cert".into(),
|
||||||
|
}),
|
||||||
Query(PostCertsQuery { challenge }),
|
Query(PostCertsQuery { challenge }),
|
||||||
SignatureBody(sig),
|
SignatureBody(sig),
|
||||||
)
|
)
|
149
src/api/extract.rs
Normal file
149
src/api/extract.rs
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
use super::ApiError;
|
||||||
|
use anyhow::Context;
|
||||||
|
use axum::{
|
||||||
|
async_trait,
|
||||||
|
body::BoxBody,
|
||||||
|
extract::{FromRequest, FromRequestParts},
|
||||||
|
http::Request,
|
||||||
|
response::IntoResponse,
|
||||||
|
};
|
||||||
|
use jwt_compact::{
|
||||||
|
alg::{SigningKey, VerifyingKey},
|
||||||
|
AlgorithmSignature, ParseError, Token, UntrustedToken, ValidationError,
|
||||||
|
};
|
||||||
|
use jwt_compact::{Algorithm, AlgorithmExt};
|
||||||
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
|
use ssh_key::{Certificate, SshSig};
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::{fmt::Debug, ops::Deref};
|
||||||
|
use tracing::trace;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct CertificateBody(pub Certificate);
|
||||||
|
|
||||||
|
// we must implement `FromRequest` (and not `FromRequestParts`) to consume the body
|
||||||
|
#[async_trait]
|
||||||
|
impl<S> FromRequest<S, BoxBody> for CertificateBody
|
||||||
|
where
|
||||||
|
S: Send + Sync,
|
||||||
|
{
|
||||||
|
type Rejection = ApiError;
|
||||||
|
|
||||||
|
async fn from_request(req: Request<BoxBody>, state: &S) -> Result<Self, Self::Rejection> {
|
||||||
|
let body = String::from_request(req, state)
|
||||||
|
.await
|
||||||
|
.context("failed to extract body")?;
|
||||||
|
|
||||||
|
let cert = Certificate::from_openssh(&body)
|
||||||
|
.with_context(|| format!("failed to parse '{}'", body))?;
|
||||||
|
trace!(%body, "extracted certificate");
|
||||||
|
Ok(Self(cert))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct SignatureBody(pub SshSig);
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<S> FromRequest<S, BoxBody> for SignatureBody
|
||||||
|
where
|
||||||
|
S: Send + Sync,
|
||||||
|
{
|
||||||
|
type Rejection = ApiError;
|
||||||
|
|
||||||
|
async fn from_request(req: Request<BoxBody>, state: &S) -> Result<Self, Self::Rejection> {
|
||||||
|
let body = String::from_request(req, state)
|
||||||
|
.await
|
||||||
|
.context("failed to extract body")?;
|
||||||
|
|
||||||
|
let sig = SshSig::from_pem(&body).with_context(|| format!("failed to parse '{}'", body))?;
|
||||||
|
trace!(%body, "extracted signature");
|
||||||
|
Ok(Self(sig))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait AsJWTVerifier: Send + Sync {
|
||||||
|
type Algo: Algorithm + Default;
|
||||||
|
fn as_secret(&self) -> &<Self::Algo as Algorithm>::VerifyingKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct JWTString(String);
|
||||||
|
|
||||||
|
impl From<String> for JWTString {
|
||||||
|
fn from(s: String) -> Self {
|
||||||
|
Self(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct JWTAuthenticated<T, S, Q, E> {
|
||||||
|
pub data: T,
|
||||||
|
_marker: PhantomData<(Q, S, E)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, S, Q, E> From<T> for JWTAuthenticated<T, S, Q, E> {
|
||||||
|
fn from(data: T) -> Self {
|
||||||
|
Self {
|
||||||
|
data,
|
||||||
|
_marker: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, S, Q, E> Deref for JWTAuthenticated<T, S, Q, E> {
|
||||||
|
type Target = T;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<
|
||||||
|
T: Serialize + DeserializeOwned + Clone + Debug,
|
||||||
|
S: AsJWTVerifier,
|
||||||
|
Q: FromRequestParts<S> + Debug + Into<JWTString>,
|
||||||
|
E: From<<Q as FromRequestParts<S>>::Rejection>
|
||||||
|
+ From<ValidationError>
|
||||||
|
+ From<ParseError>
|
||||||
|
+ Debug
|
||||||
|
+ Send
|
||||||
|
+ Sync,
|
||||||
|
> JWTAuthenticated<T, S, Q, E>
|
||||||
|
{
|
||||||
|
pub fn new(data: T) -> Self {
|
||||||
|
Self {
|
||||||
|
data,
|
||||||
|
_marker: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl<
|
||||||
|
T: Serialize + DeserializeOwned + Clone + Debug,
|
||||||
|
S: AsJWTVerifier,
|
||||||
|
Q: FromRequestParts<S> + Debug + Into<JWTString>,
|
||||||
|
E: From<<Q as FromRequestParts<S>>::Rejection>
|
||||||
|
+ From<ValidationError>
|
||||||
|
+ From<ParseError>
|
||||||
|
+ Debug
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ IntoResponse,
|
||||||
|
> FromRequestParts<S> for JWTAuthenticated<T, S, Q, E>
|
||||||
|
{
|
||||||
|
type Rejection = E;
|
||||||
|
|
||||||
|
async fn from_request_parts(
|
||||||
|
parts: &mut axum::http::request::Parts,
|
||||||
|
state: &S,
|
||||||
|
) -> Result<Self, Self::Rejection> {
|
||||||
|
let JWTString(token) = Q::from_request_parts(parts, state).await?.into();
|
||||||
|
let token = UntrustedToken::new(&token)?;
|
||||||
|
let verified: Token<T> =
|
||||||
|
<S::Algo as Default>::default().validate_integrity(&token, &state.as_secret())?;
|
||||||
|
Ok(Self {
|
||||||
|
data: verified.claims().custom.clone(),
|
||||||
|
_marker: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@@ -1,17 +1,20 @@
|
|||||||
use anyhow::bail;
|
use anyhow::bail;
|
||||||
use axum_extra::routing::TypedPath;
|
use axum_extra::routing::TypedPath;
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Args, Parser, Subcommand};
|
||||||
use reqwest::{Client, StatusCode};
|
use reqwest::{Client, StatusCode};
|
||||||
use ssh_key::Certificate;
|
use ssh_key::Certificate;
|
||||||
|
use std::io::{stdin, stdout};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
use tokio::fs;
|
use tokio::fs;
|
||||||
use tokio::io::{stdin, AsyncBufReadExt, BufReader};
|
|
||||||
use tracing::{debug, error, info, instrument, trace};
|
use tracing::{debug, error, info, instrument, trace};
|
||||||
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use ssh_cert_dist_common::*;
|
use crate::api::PutCert;
|
||||||
|
use crate::certs::load_cert;
|
||||||
|
use crate::env_key;
|
||||||
|
use crate::{api::GetCert, certs::read_dir};
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
pub struct ClientArgs {
|
pub struct ClientArgs {
|
||||||
@@ -27,9 +30,7 @@ pub struct ClientArgs {
|
|||||||
pub struct FetchArgs {
|
pub struct FetchArgs {
|
||||||
#[clap(flatten)]
|
#[clap(flatten)]
|
||||||
args: ClientArgs,
|
args: ClientArgs,
|
||||||
#[clap(short = 'k', long = "key-update", env = env_key!("KEY_UPDATE"))]
|
#[clap(short = 'c', long = "cert-dir", env = env_key!("CERT_DIR") )]
|
||||||
prohibit_key_update: bool,
|
|
||||||
#[clap(short = 'c', long = "cert-dir", env = env_key!("CERT_DIR"))]
|
|
||||||
cert_dir: PathBuf,
|
cert_dir: PathBuf,
|
||||||
/// minimum time in days between now and expiry to consider checking
|
/// minimum time in days between now and expiry to consider checking
|
||||||
#[clap(short = 'd', long = "days", default_value = "60", env = env_key!("MIN_DELTA_DAYS"))]
|
#[clap(short = 'd', long = "days", default_value = "60", env = env_key!("MIN_DELTA_DAYS"))]
|
||||||
@@ -45,7 +46,7 @@ pub struct UploadArgs {
|
|||||||
files: Vec<PathBuf>,
|
files: Vec<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Args)]
|
||||||
pub struct ClientCommand {
|
pub struct ClientCommand {
|
||||||
#[clap(subcommand)]
|
#[clap(subcommand)]
|
||||||
cmd: ClientCommands,
|
cmd: ClientCommands,
|
||||||
@@ -111,7 +112,6 @@ async fn upload_cert(client: Client, url: Url, cert: Certificate) -> anyhow::Res
|
|||||||
async fn fetch(
|
async fn fetch(
|
||||||
FetchArgs {
|
FetchArgs {
|
||||||
cert_dir,
|
cert_dir,
|
||||||
prohibit_key_update,
|
|
||||||
min_delta_days: min_delta,
|
min_delta_days: min_delta,
|
||||||
args: ClientArgs { api, interactive },
|
args: ClientArgs { api, interactive },
|
||||||
}: FetchArgs,
|
}: FetchArgs,
|
||||||
@@ -137,13 +137,8 @@ async fn fetch(
|
|||||||
let client = client.clone();
|
let client = client.clone();
|
||||||
tokio::spawn(async move { fetch_cert(client, url, cert).await })
|
tokio::spawn(async move { fetch_cert(client, url, cert).await })
|
||||||
});
|
});
|
||||||
let mut stdin = BufReader::new(stdin()).lines();
|
|
||||||
for cert in updates {
|
for cert in updates {
|
||||||
if let Ok(Some((cert, update))) = cert.await? {
|
if let Ok(Some((cert, update))) = cert.await? {
|
||||||
if prohibit_key_update && cert.public_key() != update.public_key() {
|
|
||||||
debug!(?update, "skipping cert due to key change");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if interactive {
|
if interactive {
|
||||||
println!("certificate update: {}", cert.key_id());
|
println!("certificate update: {}", cert.key_id());
|
||||||
println!(
|
println!(
|
||||||
@@ -152,8 +147,9 @@ async fn fetch(
|
|||||||
update.valid_before()
|
update.valid_before()
|
||||||
);
|
);
|
||||||
println!("update? : (y/n)");
|
println!("update? : (y/n)");
|
||||||
let yes = stdin.next_line().await?;
|
let mut yes = String::with_capacity(3);
|
||||||
if !matches!(yes, Some(line) if line.starts_with(['y', 'Y'])) {
|
stdin().read_line(&mut yes)?;
|
||||||
|
if !yes.starts_with(['y', 'Y']) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
35
src/main.rs
Normal file
35
src/main.rs
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
use api::ApiArgs;
|
||||||
|
use clap::Parser;
|
||||||
|
#[cfg(feature = "client")]
|
||||||
|
use client::ClientCommand;
|
||||||
|
|
||||||
|
mod api;
|
||||||
|
mod certs;
|
||||||
|
#[cfg(feature = "client")]
|
||||||
|
mod client;
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! env_key {
|
||||||
|
( $var:expr ) => {
|
||||||
|
concat!("SSH_CD_", $var)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
enum Command {
|
||||||
|
Server(ApiArgs),
|
||||||
|
#[cfg(feature = "client")]
|
||||||
|
Client(ClientCommand),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main(flavor = "current_thread")]
|
||||||
|
async fn main() -> anyhow::Result<()> {
|
||||||
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
|
match Command::parse() {
|
||||||
|
Command::Server(args) => api::run(args).await?,
|
||||||
|
#[cfg(feature = "client")]
|
||||||
|
Command::Client(args) => client::run(args).await?,
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
Reference in New Issue
Block a user