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