Compare commits

2 Commits

Author SHA1 Message Date
e4c9d60814 fear(ci): added woodpecker
All checks were successful
ci/woodpecker/pr/woodpecker Pipeline was successful
2023-06-19 19:22:21 +02:00
65c2703885 feat(extract): wip 2023-06-19 15:54:37 +02:00
21 changed files with 517 additions and 523 deletions

5
.woodpecker.yml Normal file
View File

@@ -0,0 +1,5 @@
pipeline:
test:
image: rust
commands:
- cargo test

364
Cargo.lock generated
View File

@@ -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",

View File

@@ -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"

View File

@@ -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

View File

@@ -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
}

View File

@@ -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"

View File

@@ -1,6 +0,0 @@
mod certs;
mod routes;
mod util;
pub use certs::*;
pub use routes::*;

View File

@@ -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;

View File

@@ -1,6 +0,0 @@
#[macro_export]
macro_rules! env_key {
( $var:expr ) => {
concat!("SSH_CD_", $var)
};
}

View File

@@ -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;
}; };
}; };

View File

@@ -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}/*
''} ''}
''; '';
}); });
}; };

View File

@@ -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";
}; };
}; };
}; };

View File

@@ -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

View File

@@ -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

View File

@@ -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))
}
}

View File

@@ -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
}

View File

@@ -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
View 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(),
})
}
}

View File

@@ -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
View 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(())
}