diff --git a/.vscode/settings.json b/.vscode/settings.json index 1532414..f6831eb 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,14 +3,18 @@ "anstyle", "Aspe", "Aspm", + "gpgme", "josekit", "keygrip", "keywrap", + "NOPAD", + "Pinentry", "PKCS", "Pkey", "printdoc", "subkey", "subkeys", + "userid", "writedoc" ] } \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 59b5a3c..4d8baee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -23,6 +23,17 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "aes" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + [[package]] name = "ahash" version = "0.7.6" @@ -198,7 +209,11 @@ dependencies = [ "clap-stdin", "data-encoding", "dialoguer", + "elliptic-curve", + "gpgme", "indoc", + "josekit", + "pgp", "sea-orm", "sea-orm-migration", "thiserror", @@ -281,6 +296,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.21.2" @@ -304,6 +325,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "bitfield" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" + [[package]] name = "bitflags" version = "1.3.2" @@ -340,6 +367,25 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + [[package]] name = "borsh" version = "0.10.3" @@ -385,6 +431,32 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "bstr" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6798148dccfbff0fae41c7574d2fa8f1ef3492fba0face179de5d8d447d67b05" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "buffer-redux" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2886ea01509598caac116942abd33ab5a88fa32acdf7e4abfa0fc489ca520c9" +dependencies = [ + "memchr", + "safemem", +] + +[[package]] +name = "build-rs" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00b8763668c99f8d9101b8a0dd82106f58265464531a79b2cef0d9a30c17dd2" + [[package]] name = "bumpalo" version = "3.13.0" @@ -425,6 +497,25 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +[[package]] +name = "camellia" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3264e2574e9ef2b53ce6f536dea83a69ac0bc600b762d1523ff83fe07230ce30" +dependencies = [ + "byteorder", + "cipher", +] + +[[package]] +name = "cast5" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b07d673db1ccf000e90f54b819db9e75a8348d6eb056e9b8ab53231b7a9911" +dependencies = [ + "cipher", +] + [[package]] name = "cc" version = "1.0.79" @@ -437,6 +528,25 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" +[[package]] +name = "cfb-mode" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "738b8d467867f80a71351933f70461f5b56f24d5c93e0cf216e59229c968d330" +dependencies = [ + "cipher", +] + +[[package]] +name = "cfg-expr" +version = "0.15.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b40ccee03b5175c18cde8f37e7d2a33bcef6f8ec8f7cc0d81090d1bb380949c9" +dependencies = [ + "smallvec", + "target-lexicon", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -456,6 +566,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clap" version = "3.2.25" @@ -572,6 +692,21 @@ dependencies = [ "windows-sys 0.45.0", ] +[[package]] +name = "const-oid" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "795bc6e66a8e340f075fcf6227e417a2dc976b92b91f3cdc778bb858778b6747" + +[[package]] +name = "conv" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" +dependencies = [ + "custom_derive", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -597,6 +732,12 @@ dependencies = [ "libc", ] +[[package]] +name = "crc24" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd121741cf3eb82c08dd3023eb55bf2665e5f60ec20f89760cf836ae4562e6a0" + [[package]] name = "crc32fast" version = "1.3.2" @@ -625,6 +766,18 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "crypto-bigint" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4c2f4e1afd912bc40bfd6fed5d9dc1f288e0ba01bfcc835cc5bc3eb13efe15" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -635,12 +788,142 @@ dependencies = [ "typenum", ] +[[package]] +name = "cstr-argument" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bd9c8e659a473bce955ae5c35b116af38af11a7acb0b480e01f3ed348aeb40" +dependencies = [ + "cfg-if", + "memchr", +] + +[[package]] +name = "curve25519-dalek" +version = "4.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436ace70fc06e06f7f689d2624dc4e2f0ea666efb5aa704215f7249ae6e047a7" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "platforms", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.22", +] + +[[package]] +name = "custom_derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" + +[[package]] +name = "darling" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" +dependencies = [ + "darling_core", + "quote", + "syn 1.0.109", +] + [[package]] name = "data-encoding" version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +[[package]] +name = "der" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7ed52955ce76b1554f509074bb357d3fb8ac9b51288a65a3fd480d1dfba946" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "derive_builder" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_builder_macro" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e" +dependencies = [ + "derive_builder_core", + "syn 1.0.109", +] + +[[package]] +name = "des" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" +dependencies = [ + "cipher", +] + [[package]] name = "dialoguer" version = "0.10.4" @@ -660,6 +943,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -670,12 +954,70 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "ecdsa" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "ed25519" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fb04eee5d9d907f29e80ee6b0e78f7e2c82342c63e3580d8c4f69d9d5aad963" +dependencies = [ + "pkcs8", + "signature", +] + +[[package]] +name = "ed25519-dalek" +version = "2.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faa8e9049d5d72bfc12acbc05914731b5322f79b5e2f195e9f2d705fca22ab4c" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2", + "zeroize", +] + [[package]] name = "either" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +[[package]] +name = "elliptic-curve" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "email_address" version = "0.2.4" @@ -742,6 +1084,22 @@ dependencies = [ "instant", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" + [[package]] name = "flate2" version = "1.0.26" @@ -761,7 +1119,7 @@ dependencies = [ "futures-core", "futures-sink", "pin-project", - "spin", + "spin 0.9.8", ] [[package]] @@ -895,6 +1253,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -914,6 +1273,58 @@ version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +[[package]] +name = "gpg-error" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89aaeddbfb92313378c58e98abadaaa34082b3855f1d455576eeeda08bd592c" +dependencies = [ + "libgpg-error-sys", +] + +[[package]] +name = "gpgme" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57539732fbe58eacdb984734b72b470ed0bca3ab7a49813271878567025ac44f" +dependencies = [ + "bitflags", + "cfg-if", + "conv", + "cstr-argument", + "gpg-error", + "gpgme-sys", + "libc", + "memoffset", + "once_cell", + "smallvec", + "static_assertions", +] + +[[package]] +name = "gpgme-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "509223d659c06e4a26229437d6ac917723f02d31917c86c6ecd50e8369741cf7" +dependencies = [ + "build-rs", + "libc", + "libgpg-error-sys", + "system-deps", + "winreg", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + [[package]] name = "h2" version = "0.3.20" @@ -1011,6 +1422,24 @@ dependencies = [ "serde", ] +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + [[package]] name = "home" version = "0.5.5" @@ -1114,6 +1543,21 @@ dependencies = [ "cc", ] +[[package]] +name = "idea" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "075557004419d7f2031b8bb7f44bb43e55a83ca7b63076a8fb8fe75753836477" +dependencies = [ + "cipher", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "idna" version = "0.4.0" @@ -1150,6 +1594,15 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f2cb48b81b1dc9f39676bf99f5499babfec7cd8fe14307f7b3d747208fb5690" +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array", +] + [[package]] name = "instant" version = "0.1.12" @@ -1252,11 +1705,23 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] + [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin 0.5.2", +] [[package]] name = "libc" @@ -1264,6 +1729,23 @@ version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" +[[package]] +name = "libgpg-error-sys" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c97079310f39c835d3bd73578379d040f779614bb331c7ffbb6630fee6420290" +dependencies = [ + "build-rs", + "system-deps", + "winreg", +] + +[[package]] +name = "libm" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" + [[package]] name = "libsqlite3-sys" version = "0.24.2" @@ -1306,12 +1788,30 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "md-5" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6365506850d44bff6e2fbcb5176cf63650e48bd45ef2fe2665ae1570e0f4b9ca" +dependencies = [ + "digest", +] + [[package]] name = "memchr" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + [[package]] name = "mime" version = "0.3.17" @@ -1389,6 +1889,35 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "serde", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.22", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -1399,6 +1928,17 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.15" @@ -1406,6 +1946,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", + "libm", ] [[package]] @@ -1506,6 +2047,30 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + [[package]] name = "parking_lot" version = "0.11.2" @@ -1548,12 +2113,73 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "percent-encoding" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +[[package]] +name = "pgp" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27e1f8e085bfa9b85763fe3ddaacbe90a09cd847b3833129153a6cb063bbe132" +dependencies = [ + "aes", + "base64", + "bitfield", + "block-padding", + "blowfish", + "bstr", + "buffer-redux", + "byteorder", + "camellia", + "cast5", + "cfb-mode", + "chrono", + "cipher", + "crc24", + "curve25519-dalek", + "derive_builder", + "des", + "digest", + "ed25519-dalek", + "elliptic-curve", + "flate2", + "generic-array", + "hex", + "idea", + "log", + "md-5", + "nom", + "num-bigint-dig", + "num-derive", + "num-traits", + "p256", + "p384", + "rand", + "ripemd", + "rsa", + "sha1", + "sha2", + "sha3", + "signature", + "smallvec", + "thiserror", + "twofish", + "x25519-dalek", + "zeroize", +] + [[package]] name = "pin-project" version = "1.1.0" @@ -1586,25 +2212,61 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" +[[package]] +name = "platforms" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d7ddaed09e0eb771a79ab0fd64609ba0afb0a8366421957936ad14cbd13630" + [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "primeorder" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c2fcef82c0ec6eefcc179b978446c399b3cdf73c392c35604e399eee6df1ee3" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro-crate" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" dependencies = [ - "toml", + "toml 0.5.11", ] [[package]] @@ -1801,6 +2463,25 @@ dependencies = [ "winreg", ] +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest", +] + [[package]] name = "rkyv" version = "0.7.42" @@ -1829,6 +2510,28 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "rsa" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8" +dependencies = [ + "byteorder", + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-iter", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + [[package]] name = "rust_decimal" version = "1.30.0" @@ -1853,6 +2556,15 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + [[package]] name = "rustix" version = "0.37.20" @@ -1879,6 +2591,12 @@ version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" +[[package]] +name = "safemem" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" + [[package]] name = "same-file" version = "1.0.6" @@ -2072,6 +2790,20 @@ version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "security-framework" version = "2.9.1" @@ -2095,6 +2827,12 @@ dependencies = [ "libc", ] +[[package]] +name = "semver" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" + [[package]] name = "serde" version = "1.0.164" @@ -2137,6 +2875,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -2149,6 +2896,17 @@ dependencies = [ "serde", ] +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + [[package]] name = "sha2" version = "0.10.7" @@ -2160,6 +2918,16 @@ dependencies = [ "digest", ] +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + [[package]] name = "sharded-slab" version = "0.1.4" @@ -2175,6 +2943,16 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "simdutf8" version = "0.1.4" @@ -2206,6 +2984,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + [[package]] name = "spin" version = "0.9.8" @@ -2215,6 +2999,16 @@ dependencies = [ "lock_api", ] +[[package]] +name = "spki" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "sqlformat" version = "0.2.1" @@ -2316,6 +3110,12 @@ dependencies = [ "tokio-native-tls", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + [[package]] name = "stringprep" version = "0.1.2" @@ -2360,12 +3160,31 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "system-deps" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30c2de8a4d8f4b823d634affc9cd2a74ec98c53a756f317e529a48046cbf71f3" +dependencies = [ + "cfg-expr", + "heck 0.4.1", + "pkg-config", + "toml 0.7.6", + "version-compare", +] + [[package]] name = "tap" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "target-lexicon" +version = "0.12.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2faeef5759ab89935255b1a4cd98e0baf99d1085e37d36599c625dac49ae8e" + [[package]] name = "tempfile" version = "3.6.0" @@ -2531,6 +3350,40 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" +dependencies = [ + "indexmap 2.0.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + [[package]] name = "tower-service" version = "0.3.2" @@ -2591,6 +3444,15 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" +[[package]] +name = "twofish" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a78e83a30223c757c3947cd144a31014ff04298d8719ae10d03c31c0448c8013" +dependencies = [ + "cipher", +] + [[package]] name = "typenum" version = "1.16.0" @@ -2669,6 +3531,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "version-compare" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579a42fc0b8e0c63b76519a339be31bed574929511fa53c1a3acae26eb258f29" + [[package]] name = "version_check" version = "0.9.4" @@ -2963,6 +3831,15 @@ version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +[[package]] +name = "winnow" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bd122eb777186e60c3fdf765a58ac76e41c582f1f535fbf3314434c6b58f3f7" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.10.1" @@ -2981,6 +3858,18 @@ dependencies = [ "tap", ] +[[package]] +name = "x25519-dalek" +version = "2.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7fae07da688e17059d5886712c933bb0520f15eff2e09cfa18e30968f4e63a" +dependencies = [ + "curve25519-dalek", + "rand_core", + "serde", + "zeroize", +] + [[package]] name = "xdg" version = "2.5.0" @@ -2995,3 +3884,17 @@ name = "zeroize" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.22", +] diff --git a/Cargo.toml b/Cargo.toml index 0ac541c..3a1c83e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,6 +27,14 @@ sea-orm-migration = "0.11.3" async-trait = "0.1.68" tokio = "1.29.1" clap-stdin = "0.2.0" +gpgme = { version = "0.11.0", optional = true } +pgp = { version = "0.10.2", optional = true } +josekit = { version = "0.8.3", optional = true } +elliptic-curve = { version = "0.13.5", optional = true } + +[features] +gpg-compat = ["dep:gpgme", "dep:pgp", "dep:josekit", "dep:elliptic-curve"] +default = ["gpg-compat"] [profile.release] strip = true diff --git a/src/commands/keys/import_gpg.rs b/src/commands/keys/import_gpg.rs new file mode 100644 index 0000000..805fbae --- /dev/null +++ b/src/commands/keys/import_gpg.rs @@ -0,0 +1,272 @@ +#![cfg(feature = "gpg-compat")] + +use std::{io::Write, sync::Arc}; + +use anyhow::{anyhow, bail, Context}; +use argon2::{password_hash::SaltString, Argon2, PasswordHasher}; +use clap::Parser; +use data_encoding::{BASE64URL_NOPAD, BASE64_NOPAD}; +use dialoguer::{theme::ColorfulTheme, Password}; +use elliptic_curve::sec1::{Coordinates, ToEncodedPoint}; +use gpgme::{Context as GpgContext, PassphraseRequest}; +use pgp::{ + crypto::ecc_curve::ECCCurve, + types::{EcdsaPublicParams, KeyTrait, PlainSecretParams, PublicParams, SecretParams}, +}; +use sea_orm::{ActiveValue, EntityTrait}; +use tokio::runtime::Runtime; + +use crate::{commands::AspmSubcommand, entities::keys}; + +/// A command to import a key from GPG, by fingerprint. The password used to store the key will be the exact same as the password used to decrypt the key from GPG, and the key alias will be the primary UID (or only UID) from the GPG key. +#[derive(Parser, Debug)] +pub struct KeysImportGpgCommand { + /// The full fingerprint of the GPG key to import. In order to import a subkey, the subkey's fingerprint much be provided, rather than the primary key's. + fingerprint: String, +} + +#[async_trait::async_trait] +impl AspmSubcommand for KeysImportGpgCommand { + fn execute_sync(&self, state: crate::AspmState, runtime: Runtime) -> Result<(), anyhow::Error> { + let mut ctx = GpgContext::from_protocol(gpgme::Protocol::OpenPgp) + .context("Unable to create GPG context")?; + ctx.set_pinentry_mode(gpgme::PinentryMode::Loopback) + .context("Unable to set GPG pinentry mode")?; + + let mut found_key = None::; + for key in ctx + .secret_keys() + .context("Unable to fetch GPG secret keys")? + { + let Ok(key) = key else { + continue + }; + + if key.fingerprint().unwrap_or("") != self.fingerprint + && key + .subkeys() + .all(|subkey| subkey.fingerprint().unwrap_or("") != self.fingerprint) + { + continue; + } + + found_key = Some(key); + break; + } + let Some(found_key) = found_key else { + eprintln!("No key was found matching the provided fingerprint"); + std::process::exit(1); + }; + + // For some reason, when exporting secret keys, GPG will prompt for a password but then still + // export the key in an encrypted form. In order to prevent a password needing to be entered + // twice (one for GPG and one to decrypt the data), the password is prompted once here and stored. + let password = Arc::new( + Password::with_theme(&ColorfulTheme::default()) + .with_prompt("Please enter the password for this key. This is both used to decrypt the OpenPGP key, and then to re-encrypt it in the aspm format") + .interact() + .context("Unable to prompt on stderr")?, + ); + let password_ref = password.clone(); + + let data = ctx.with_passphrase_provider( + move |_: PassphraseRequest, out: &mut dyn Write| { + out.write_all(password_ref.as_bytes())?; + Ok(()) + }, + |ctx| { + let mut data: gpgme::Data<'_> = + gpgme::Data::new().context("Unable to create GPG data object")?; + let export_result = ctx.export( + [found_key.fingerprint().unwrap()], + gpgme::ExportMode::SECRET, + &mut data, + ); + match export_result { + Ok(data) => data, + Err(e) => match e.code() { + 11 => { + eprintln!("Wrong password"); + std::process::exit(1); + } + _ => { + return Err::, anyhow::Error>(e.into()) + .context("Unable to export secret key from GPG") + } + }, + }; + data.try_into_bytes() + .ok_or(anyhow!("Unable to retrieve byte data from gpg data object")) + }, + )?; + + let mut parsed = pgp::from_bytes_many(data.as_slice()); + let parsed = parsed.nth(0).context("Invalid GPG data")?; + + let Ok(key) = parsed else { + bail!("GPG data was unable to be parsed"); + }; + + let key = key.into_secret(); + let Some(uid) = key + .details + .users + .iter() + .find(|uid| uid.is_primary()) + .or_else(|| { + if key.details.users.len() == 1 { + Some(&key.details.users[0]) + } else { + None + } + }) else { + eprintln!("Key being imported has no primary uid. This must be set, as it is used for the key alias."); + std::process::exit(1); + }; + let (algorithm, public_params, secret_params) = { + if key + .primary_key + .fingerprint() + .iter() + .map(|byte| format!("{:02X}", byte)) + .collect::>() + .join("") == self.fingerprint + { + ( + key.primary_key.algorithm(), + key.primary_key.public_params(), + key.primary_key.secret_params(), + ) + } else { + let subkey = &key + .secret_subkeys + .iter() + .find(|subkey| { + subkey + .fingerprint() + .iter() + .map(|byte| format!("{:02X}", byte)) + .collect::>() + .join("") == self.fingerprint + }) + .context("Unable to find subkey after parsing")? + .key; + ( + subkey.algorithm(), + subkey.public_params(), + subkey.secret_params(), + ) + } + }; + + let unlocked = match secret_params { + SecretParams::Plain(params) => params.clone(), + SecretParams::Encrypted(params) => { + let password_ref = password.clone(); + params + .unlock(move || password_ref.to_string(), algorithm, public_params) + .context("Unable to parse key secret params")? + } + }; + let asp_key = match &unlocked { + PlainSecretParams::ECDSA(priv_mpi) => { + let public_key = match public_params { + PublicParams::ECDSA(public_params) => { + if let EcdsaPublicParams::P256 { key, p: _ } = public_params { + key + } else { + eprintln!("GPG key uses an unsupported elliptic curve type. Only Ed25519 and P-256 curves are supported."); + std::process::exit(1); + } + } + _ => bail!("Key had EdDSA secret params, but not EdDSA public params"), + }; + asp::keys::AspKey::from_jwk( + josekit::jwk::Jwk::from_map({ + let mut map = josekit::Map::new(); + map.insert("kty".to_string(), "EC".into()); + map.insert("crv".to_string(), "P-256".into()); + map.insert( + "d".to_string(), + BASE64URL_NOPAD.encode(priv_mpi.as_bytes()).into(), + ); + + let encoded = public_key.to_encoded_point(false); + let Coordinates::Uncompressed { x, y } = encoded.coordinates() else { + bail!("EC key coordinates were not uncompressed") + }; + map.insert("x".to_string(), BASE64URL_NOPAD.encode(x.as_slice()).into()); + map.insert("y".to_string(), BASE64URL_NOPAD.encode(y.as_slice()).into()); + map + }) + .context("Unable to construct JWK map")?, + )? + } + PlainSecretParams::EdDSA(priv_mpi) => { + let pub_mpi = match public_params { + PublicParams::EdDSA { curve, q: pub_mpi } => { + if let ECCCurve::Ed25519 = curve { + pub_mpi + } else { + eprintln!("GPG key uses an unsupported elliptic curve type. Only Ed25519 and P-256 curves are supported."); + std::process::exit(1); + } + } + _ => bail!("Key had EdDSA secret params, but not EdDSA public params"), + }; + asp::keys::AspKey::from_jwk( + josekit::jwk::Jwk::from_map({ + let mut map = josekit::Map::new(); + map.insert("kty".to_string(), "OKP".into()); + map.insert("crv".to_string(), "Ed25519".into()); + map.insert( + "d".to_string(), + BASE64URL_NOPAD.encode(priv_mpi.as_bytes()).into(), + ); + + map.insert( + "x".to_string(), + BASE64URL_NOPAD.encode(pub_mpi.as_bytes()).into(), + ); + + map + }) + .context("Unable to construct JWK map")?, + )? + } + _ => { + eprintln!("GPG key is of unsupported type. Only Ed25519 and EC p-256 keys can be imported"); + std::process::exit(1); + } + }; + + let argon_salt = SaltString::from_b64( + &BASE64_NOPAD.encode(asp_key.fingerprint.to_uppercase().as_bytes()), + ) + .context("Unable to derive argon2 salt")?; + let argon2 = Argon2::default(); + let hash = argon2 + .hash_password(password.as_bytes(), &argon_salt) + .or(Err(anyhow!("Unable to derive encryption key")))?; + let aes_key = hash.hash.context("Unable to derive encryption key")?; + let aes_key = &aes_key.as_bytes()[0..32]; + + let encrypted = asp_key.export_encrypted(aes_key)?; + + let entry = keys::ActiveModel { + fingerprint: ActiveValue::Set(asp_key.fingerprint.clone()), + key_type: ActiveValue::Set(asp_key.key_type.into()), + alias: ActiveValue::Set(format!("{uid}", uid = uid.id.id())), + encrypted: ActiveValue::Set(encrypted), + }; + // Because GPGME's context object is not 'Send', normal .await can't be used here, so this just blocks as a workaround + let res = runtime + .block_on(async { keys::Entity::insert(entry).exec(&state.db).await }) + .context("Unable to add key to database")?; + if res.last_insert_id != asp_key.fingerprint { + bail!("The key was unable to be saved to the database") + } + + Ok(()) + } +} diff --git a/src/commands/keys/mod.rs b/src/commands/keys/mod.rs index 0a49a52..61d601a 100644 --- a/src/commands/keys/mod.rs +++ b/src/commands/keys/mod.rs @@ -2,6 +2,8 @@ use clap::{Parser, Subcommand}; pub mod export; pub mod generate; +#[cfg(feature = "gpg-compat")] +pub mod import_gpg; pub mod list; /// A subcommand to allow the management of keys, which can then be used to create, modify, or delete profiles. @@ -16,4 +18,6 @@ pub enum KeysSubcommands { Generate(generate::KeysGenerateCommand), List(list::KeysListCommand), Export(export::KeysExportCommand), + #[cfg(feature = "gpg-compat")] + ImportGpg(import_gpg::KeysImportGpgCommand), } diff --git a/src/commands/mod.rs b/src/commands/mod.rs index c719a8b..da24253 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -2,13 +2,19 @@ pub mod keys; use clap::Parser; use sea_orm::{ColumnTrait, Condition, DatabaseConnection, EntityTrait, QueryFilter, QueryOrder}; +use tokio::runtime::Runtime; use crate::entities::keys::{Column as KeysColumn, Entity as KeysEntity, Model as KeysModel}; use crate::AspmState; #[async_trait::async_trait] pub trait AspmSubcommand: Parser { - async fn execute(&self, state: AspmState) -> Result<(), anyhow::Error>; + async fn execute(&self, _state: AspmState) -> Result<(), anyhow::Error> { + panic!("Not implemented") + } + fn execute_sync(&self, _state: AspmState, _runtime: Runtime) -> Result<(), anyhow::Error> { + panic!("Not implemented") + } } #[async_trait::async_trait] diff --git a/src/main.rs b/src/main.rs index 1089d0d..e724ed5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,6 +43,9 @@ struct AspmCommand { /// 3. OS default #[arg(short, long, value_name = "FILE")] data_dir: Option, + /// If this flag is provided, errors will be returned extra verbose, for debugging purposes + #[arg(short, long)] + verbose: bool, /// The subcommand to use #[command(subcommand)] subcommand: AspmSubcommands, @@ -77,55 +80,76 @@ pub enum AspmSubcommands { Keys(commands::keys::KeysSubcommand), } -#[tokio::main] -async fn main() { - if let Err(e) = cli().await { - eprintln!("An error occurred while running that command:\n{e}"); +fn main() { + let parsed = AspmCommand::parse(); + let verbose = parsed.verbose; + + if let Err(e) = cli(parsed) { + match verbose { + true => { + eprintln!("An error occurred while running that command:\n{e:?}"); + } + false => eprintln!("An error occurred while running that command:\n{e}"), + } + std::process::exit(2); } } -async fn cli() -> Result<(), anyhow::Error> { - let parsed = AspmCommand::parse(); +fn cli(parsed: AspmCommand) -> Result<(), anyhow::Error> { + let runtime = tokio::runtime::Builder::new_multi_thread() + .enable_all() + .build() + .unwrap(); - // Check the data dir (read and write) - let data_dir = parsed.data_dir.unwrap_or( - std::env::var("ASPM_DATA_DIR").map(|s| s.into()).unwrap_or( - app_dirs2::get_app_root(AppDataType::UserData, &APP_INFO) - .map_err(|e| AspmError::Unknown(e.into()))?, - ), - ); - std::fs::create_dir_all(&data_dir).or(Err(AspmError::DataDirCreate))?; - std::fs::read_dir(&data_dir).or(Err(AspmError::DataDirRead))?; - - // Construct the database in the dir - let db = Database::connect(DATABASE_URL.replace("DB_PATH", &{ - let mut new = data_dir.clone(); - new.push("db.sqlite"); - new.to_str() - .context("Unable to parse database path into string") - .map(|s| s.to_string()) - }?)) - .await - .context("Unable to open database")?; - - let schema_manager = SchemaManager::new(&db); - Migrator::up(&db, None) + let state = runtime.block_on(async { + // Check the data dir (read and write) + let data_dir = parsed.data_dir.unwrap_or( + std::env::var("ASPM_DATA_DIR").map(|s| s.into()).unwrap_or( + app_dirs2::get_app_root(AppDataType::UserData, &APP_INFO) + .map_err(|e| AspmError::Unknown(e.into()))?, + ), + ); + std::fs::create_dir_all(&data_dir).or(Err(AspmError::DataDirCreate))?; + std::fs::read_dir(&data_dir).or(Err(AspmError::DataDirRead))?; + // Construct the database in the dir + let db = Database::connect(DATABASE_URL.replace("DB_PATH", &{ + let mut new = data_dir.clone(); + new.push("db.sqlite"); + new.to_str() + .context("Unable to parse database path into string") + .map(|s| s.to_string()) + }?)) .await - .context("Unable to migrate database")?; - assert!(schema_manager - .has_table("keys") - .await - .context("Unable to check database for keys table")?); + .context("Unable to open database")?; + let schema_manager = SchemaManager::new(&db); + Migrator::up(&db, None) + .await + .context("Unable to migrate database")?; + assert!(schema_manager + .has_table("keys") + .await + .context("Unable to check database for keys table")?); - // Make the state - let state = AspmState { data_dir, db }; + // Make the state + let state = AspmState { data_dir, db }; + + Ok::(state) + })?; // Call the subcommand match &parsed.subcommand { AspmSubcommands::Keys(subcommand) => match &subcommand.subcommand { - KeysSubcommands::Generate(subcommand) => subcommand.execute(state).await, - KeysSubcommands::List(subcommand) => subcommand.execute(state).await, - KeysSubcommands::Export(subcommand) => subcommand.execute(state).await, + KeysSubcommands::Generate(subcommand) => { + runtime.block_on(async { subcommand.execute(state).await }) + } + KeysSubcommands::List(subcommand) => { + runtime.block_on(async { subcommand.execute(state).await }) + } + KeysSubcommands::Export(subcommand) => { + runtime.block_on(async { subcommand.execute(state).await }) + } + #[cfg(feature = "gpg-compat")] + KeysSubcommands::ImportGpg(subcommand) => subcommand.execute_sync(state, runtime), }, } }