sequoia-sq-0.37.0/.cargo_vcs_info.json0000644000000001360000000000100132120ustar { "git": { "sha1": "8752cc462fff2a9ca08fe507d70cf8c81aae8da4" }, "path_in_vcs": "" }sequoia-sq-0.37.0/.ci/all_commits.sh000075500000000000000000000014771046102023000153260ustar 00000000000000#!/usr/bin/env bash # Test all commits on this branch but the last one. # # Used in the all_commits ci job to ensure all commits build # and tests pass at least for the sequoia-openpgp crate. # Use dummy identity to make git rebase happy. git config user.name "C.I. McTestface" git config user.email "ci.mctestface@example.com" # If the previous commit already is on main we're done. git merge-base --is-ancestor HEAD~ origin/main && echo "All commits tested already" && exit 0 # Leave out the last commit - it has already been checked. git checkout HEAD~ git rebase origin/main \ --exec 'echo ===; echo ===; echo ===; git log -n 1;' \ --exec 'cargo test -p sequoia-sq' && echo "All commits passed tests" && exit 0 # The rebase failed - probably because a test failed. git rebase --abort; exit 1 sequoia-sq-0.37.0/.gitattributes000064400000000000000000000000231046102023000146700ustar 00000000000000* text=auto eol=lf sequoia-sq-0.37.0/.gitignore000064400000000000000000000001131046102023000137650ustar 00000000000000/target/ **/*.rs.bk *~ .gdb_history .dir-locals.el /*.html /*.pdf writelocksequoia-sq-0.37.0/.gitlab-ci.yml000064400000000000000000000035121046102023000144370ustar 00000000000000stages: - pre-check - build - test - deploy include: - component: "gitlab.com/sequoia-pgp/common-ci/sequoia-pipeline@main" variables: SEQUOIA_CRYPTO_POLICY: "" docker-build-push: # Official docker image. image: docker:stable stage: build services: - docker:dind tags: - docker - self-hosted before_script: - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY script: - > docker build --no-cache --target sq --tag "$IMAGE":latest . # smoke test - docker run "$IMAGE":latest --help - docker push "$IMAGE":latest after_script: [] only: refs: - /docker/i # refs containing 'docker' keyword - tags - web - schedules variables: CI_REGISTRY: "registry.gitlab.com" IMAGE: "$CI_REGISTRY/sequoia-pgp/sequoia-sq" DOCKER_HOST: tcp://docker:2376 pages: stage: deploy image: 192.168.122.1:5000/sequoia-pgp/build-docker-image/trixie-pandoc:latest script: - ASSET_OUT_DIR=/tmp/assets cargo doc --no-deps -p sequoia-sq - mkdir public - mv -v target/doc public/impl - for M in /tmp/assets/man-pages/*; do pandoc -s $M -L src/man-pandoc.lua -H src/man-pandoc.inc.html -o $M.html ; done - mkdir public/man - mv -v /tmp/assets/man-pages/*.html public/man - mkdir public/subplot - pandoc -s -o public/subplot/sq-subplot.html sq-subplot.md - pandoc -s -o public/subplot/sq-subplot.pdf sq-subplot.md - echo "/sequoia-sq/ /sequoia-sq/man/sq.1.html 302" > public/_redirects - echo "/sequoia-sq/impl /sequoia-sq/impl/sq/index.html 302" >> public/_redirects - echo "/sequoia-sq/man /sequoia-sq/man/sq.1.html 302" >> public/_redirects - echo "/sequoia-sq/subplot /sequoia-sq/subplot/sq-subplot.html 302" >> public/_redirects artifacts: paths: - public only: - main sequoia-sq-0.37.0/Cargo.lock0000644000003641420000000000100111770ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "addr2line" version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] [[package]] name = "adler" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] name = "aead" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ "crypto-common", "generic-array", ] [[package]] name = "aes" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", "cpufeatures", "zeroize", ] [[package]] name = "aes-gcm" version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" dependencies = [ "aead", "aes", "cipher", "ctr", "ghash", "subtle", ] [[package]] name = "ahash" version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "once_cell", "version_check", "zerocopy", ] [[package]] name = "aho-corasick" version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "aligned" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "377e4c0ba83e4431b10df45c1d4666f178ea9c552cac93e60c3a88bf32785923" dependencies = [ "as-slice", ] [[package]] name = "android-tzdata" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" [[package]] name = "android_system_properties" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" dependencies = [ "libc", ] [[package]] name = "anstream" version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" dependencies = [ "anstyle", "anstyle-parse", "anstyle-query", "anstyle-wincon", "colorchoice", "is_terminal_polyfill", "utf8parse", ] [[package]] name = "anstyle" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" [[package]] name = "anstyle-parse" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "anstyle-wincon" version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" dependencies = [ "anstyle", "windows-sys 0.52.0", ] [[package]] name = "anyhow" version = "1.0.76" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59d2a3357dde987206219e78ecfbbb6e8dad06cbb65292758d3270e6254f7355" [[package]] name = "as-slice" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "516b6b4f0e40d50dcda9365d53964ec74560ad4284da2e7fc97122cd83174516" dependencies = [ "stable_deref_trait", ] [[package]] name = "ascii-canvas" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" dependencies = [ "term", ] [[package]] name = "assert_cmd" version = "2.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00ad3f3a942eee60335ab4342358c161ee296829e0d16ff42fc1d6cb07815467" dependencies = [ "anstyle", "bstr", "doc-comment", "predicates", "predicates-core", "predicates-tree", "wait-timeout", ] [[package]] name = "async-trait" version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", "syn 2.0.66", ] [[package]] name = "autocfg" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cc23269a4f8976d0a4d2e7109211a419fe30e8d88d677cd60b6bc79c5732e0a" dependencies = [ "addr2line", "cc", "cfg-if", "libc", "miniz_oxide", "object", "rustc-demangle", ] [[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.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bindgen" version = "0.68.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726e4313eb6ec35d2730258ad4e15b547ee75d6afaa1361a922e78e59b7d8078" dependencies = [ "bitflags 2.5.0", "cexpr", "clang-sys", "lazy_static", "lazycell", "peeking_take_while", "proc-macro2", "quote", "regex", "rustc-hash", "shlex", "syn 2.0.66", ] [[package]] name = "bit-set" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" [[package]] name = "block-buffer" version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 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 = "botan" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "350081af1a3c6883f8a1f863ac553bfe6922589aad60008a70947765ed57c53e" dependencies = [ "botan-sys", ] [[package]] name = "botan-sys" version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f49dde1b8ebd2996cc41c55c39f6ef8b54e38148d8973aeba0792b87b1621ca" [[package]] name = "bstr" version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" dependencies = [ "memchr", "regex-automata 0.4.7", "serde", ] [[package]] name = "buffered-reader" version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd098763fdb64579407a8c83cf0d751e6d4a7e161d0114c89cc181a2ca760ec8" dependencies = [ "bzip2", "flate2", "lazy_static", "libc", ] [[package]] name = "bumpalo" version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "byteorder" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "bzip2" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" dependencies = [ "bzip2-sys", "libc", ] [[package]] name = "bzip2-sys" version = "0.1.11+1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" dependencies = [ "cc", "libc", "pkg-config", ] [[package]] name = "camellia" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3264e2574e9ef2b53ce6f536dea83a69ac0bc600b762d1523ff83fe07230ce30" dependencies = [ "byteorder", "cipher", ] [[package]] name = "capnp" version = "0.19.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de71387912cac7dd3cb7c219e09628411620a18061bba58c71453c26ae7bf66a" dependencies = [ "embedded-io", ] [[package]] name = "capnp-futures" version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fac483cb34e3bc0be251dba7ce318f465143dd18f948c7bd7ad035f6fecfb1b" dependencies = [ "capnp", "futures", ] [[package]] name = "capnp-rpc" version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b692f9454566fa16c5897a5d329e77496b6c8012777025f18cc82f7a65617e" dependencies = [ "capnp", "capnp-futures", "futures", ] [[package]] name = "capnpc" version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c75ba30e0f08582d53c2f3710cf4bb65ff562614b1ba86906d7391adffe189ec" dependencies = [ "capnp", ] [[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.99" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" [[package]] name = "cexpr" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" dependencies = [ "nom", ] [[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-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", "js-sys", "num-traits", "wasm-bindgen", "windows-targets 0.52.5", ] [[package]] name = "cipher" version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ "crypto-common", "inout", "zeroize", ] [[package]] name = "clang-sys" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", "libloading", ] [[package]] name = "clap" version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" dependencies = [ "clap_builder", "clap_derive", ] [[package]] name = "clap_builder" version = "4.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" dependencies = [ "anstream", "anstyle", "clap_lex", "strsim", "terminal_size", ] [[package]] name = "clap_complete" version = "4.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abb745187d7f4d76267b37485a65e0149edd0e91a4cfcdd3f27524ad86cee9f3" dependencies = [ "clap", ] [[package]] name = "clap_derive" version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", "quote", "syn 2.0.66", ] [[package]] name = "clap_lex" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "cmac" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8543454e3c3f5126effff9cd44d562af4e31fb8ce1cc0d3dcd8f084515dbc1aa" dependencies = [ "cipher", "dbl", "digest", ] [[package]] name = "colorchoice" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" [[package]] name = "console" version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", "windows-sys 0.52.0", ] [[package]] name = "const-oid" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "core-foundation" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", ] [[package]] name = "core-foundation-sys" version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crc32fast" version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1137cd7e7fc0fb5d3c5a8678be38ec56e819125d8d7907411fe24ccb943faca8" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-epoch", "crossbeam-queue", "crossbeam-utils", ] [[package]] name = "crossbeam-channel" version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-queue" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df0346b5d5e76ac2fe4e327c5fd1118d6be7c51dfb18f9b7922923f287471e35" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-bigint" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", "rand_core", "subtle", "zeroize", ] [[package]] name = "crypto-common" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "rand_core", "typenum", ] [[package]] name = "ctor" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" dependencies = [ "quote", "syn 2.0.66", ] [[package]] name = "ctr" version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ "cipher", ] [[package]] name = "curve25519-dalek" version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a677b8922c94e01bdbb12126b0bc852f00447528dee1782229af9c720c3f348" dependencies = [ "cfg-if", "cpufeatures", "curve25519-dalek-derive", "digest", "fiat-crypto", "platforms", "rustc_version", "subtle", "zeroize", ] [[package]] name = "curve25519-dalek-derive" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", "syn 2.0.66", ] [[package]] name = "cvt" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2ae9bf77fbf2d39ef573205d554d87e86c12f1994e9ea335b0651b9b278bcf1" dependencies = [ "cfg-if", ] [[package]] name = "data-encoding" version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "dbl" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd2735a791158376708f9347fe8faba9667589d82427ef3aed6794a8981de3d9" dependencies = [ "generic-array", ] [[package]] name = "der" version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" dependencies = [ "const-oid", "pem-rfc7468", "zeroize", ] [[package]] name = "deranged" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" dependencies = [ "powerfmt", ] [[package]] name = "des" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" dependencies = [ "cipher", ] [[package]] name = "deunicode" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "339544cc9e2c4dc3fc7149fd630c5f22263a4fdf18a98afd0075784968b5cf00" [[package]] name = "difflib" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" [[package]] name = "digest" version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", "const-oid", "crypto-common", "subtle", ] [[package]] name = "dircpy" version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29259db751c34980bfc44100875890c507f585323453b91936960ab1104272ca" dependencies = [ "jwalk", "log", "walkdir", ] [[package]] name = "directories" version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" dependencies = [ "dirs-sys", ] [[package]] name = "dirs" version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-next" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ "cfg-if", "dirs-sys-next", ] [[package]] name = "dirs-sys" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", "option-ext", "redox_users", "windows-sys 0.48.0", ] [[package]] name = "dirs-sys-next" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users", "winapi", ] [[package]] name = "displaydoc" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", "syn 2.0.66", ] [[package]] name = "doc-comment" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "dot-writer" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1b11bd5e7e98406c6ff39fbc94d6e910a489b978ce7f17c19fce91a1195b7a" [[package]] name = "dsa" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48bc224a9084ad760195584ce5abb3c2c34a225fa312a128ad245a6b412b7689" dependencies = [ "digest", "num-bigint-dig", "num-traits", "pkcs8", "rfc6979", "sha2", "signature", "zeroize", ] [[package]] name = "dyn-clone" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" [[package]] name = "eax" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9954fabd903b82b9d7a68f65f97dc96dd9ad368e40ccc907a7c19d53e6bfac28" dependencies = [ "aead", "cipher", "cmac", "ctr", "subtle", ] [[package]] name = "ecb" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a8bfa975b1aec2145850fcaa1c6fe269a16578c44705a532ae3edc92b8881c7" dependencies = [ "cipher", ] [[package]] name = "ecdsa" version = "0.16.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" dependencies = [ "der", "digest", "elliptic-curve", "rfc6979", "signature", "spki", ] [[package]] name = "ed25519" version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" dependencies = [ "pkcs8", "signature", ] [[package]] name = "ed25519-dalek" version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", "rand_core", "serde", "sha2", "subtle", "zeroize", ] [[package]] name = "either" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" [[package]] name = "elliptic-curve" version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ "base16ct", "crypto-bigint", "digest", "ff", "generic-array", "group", "hkdf", "pem-rfc7468", "pkcs8", "rand_core", "sec1", "subtle", "zeroize", ] [[package]] name = "embedded-io" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" [[package]] name = "ena" version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" dependencies = [ "log", ] [[package]] name = "encode_unicode" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] [[package]] name = "endian-type" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" [[package]] name = "enum-as-inner" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" dependencies = [ "heck", "proc-macro2", "quote", "syn 2.0.66", ] [[package]] name = "enumber" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e94171909dd76d846c1ee9d14704de157cf77d01560c883f74ddd1f74c5bdbf" dependencies = [ "quote", "syn 2.0.66", ] [[package]] name = "env_logger" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" dependencies = [ "humantime", "is-terminal", "log", "regex", "termcolor", ] [[package]] name = "equivalent" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "fallible-iterator" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" [[package]] name = "fallible-streaming-iterator" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a" [[package]] name = "fastrand" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "fd-lock" version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e5768da2206272c81ef0b5e951a41862938a6070da63bcea197899942d3b947" dependencies = [ "cfg-if", "rustix", "windows-sys 0.52.0", ] [[package]] name = "fehler" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d5729fe49ba028cd550747b6e62cd3d841beccab5390aa398538c31a2d983635" dependencies = [ "fehler-macros", ] [[package]] name = "fehler-macros" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccb5acb1045ebbfa222e2c50679e392a71dd77030b78fb0189f2d9c5974400f9" dependencies = [ "proc-macro2", "quote", "syn 1.0.109", ] [[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.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "file_diff" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31a7a908b8f32538a2143e59a6e4e2508988832d5d4d6f7c156b3cbc762643a5" [[package]] name = "filetime" version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", "redox_syscall 0.4.1", "windows-sys 0.52.0", ] [[package]] name = "fixedbitset" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", ] [[package]] name = "float-cmp" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" dependencies = [ "num-traits", ] [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foreign-types" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ "foreign-types-shared", ] [[package]] name = "foreign-types-shared" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "fs2" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" dependencies = [ "libc", "winapi", ] [[package]] name = "fs_at" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "982f82cc75107eef84f417ad6c53ae89bf65b561937ca4a3b3b0fd04d0aa2425" dependencies = [ "aligned", "cfg-if", "cvt", "libc", "nix", "windows-sys 0.48.0", ] [[package]] name = "futures" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", "futures-executor", "futures-io", "futures-sink", "futures-task", "futures-util", ] [[package]] name = "futures-channel" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", ] [[package]] name = "futures-core" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", "futures-util", ] [[package]] name = "futures-io" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", "syn 2.0.66", ] [[package]] name = "futures-sink" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", "futures-io", "futures-macro", "futures-sink", "futures-task", "memchr", "pin-project-lite", "pin-utils", "slab", ] [[package]] name = "generator" version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" dependencies = [ "cc", "libc", "log", "rustversion", "windows", ] [[package]] name = "generic-array" version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", "zeroize", ] [[package]] name = "gethostname" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0176e0459c2e4a1fe232f984bca6890e681076abb9934f6cea7c326f3fc47818" dependencies = [ "libc", "windows-targets 0.48.5", ] [[package]] name = "getopts" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" dependencies = [ "unicode-width", ] [[package]] name = "getrandom" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", "libc", "wasi", "wasm-bindgen", ] [[package]] name = "ghash" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" dependencies = [ "opaque-debug", "polyval", ] [[package]] name = "gimli" version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "git-testament" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "710c78d2b68e46e62f5ba63ba0a7a2986640f37f9ecc07903b9ad4e7b2dbfc8e" dependencies = [ "git-testament-derive", ] [[package]] name = "git-testament-derive" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b31494efbbe1a6730f6943759c21b92c8dc431cb4df177e6f2a6429c3c96842" dependencies = [ "log", "proc-macro2", "quote", "syn 2.0.66", "time", ] [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "globset" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" dependencies = [ "aho-corasick", "bstr", "log", "regex-automata 0.4.7", "regex-syntax 0.8.4", ] [[package]] name = "globwalk" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" dependencies = [ "bitflags 2.5.0", "ignore", "walkdir", ] [[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.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", "futures-core", "futures-sink", "futures-util", "http", "indexmap 2.2.6", "slab", "tokio", "tokio-util", "tracing", ] [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", ] [[package]] name = "hashlink" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" dependencies = [ "hashbrown 0.14.5", ] [[package]] name = "heck" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" [[package]] name = "hermit-abi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "hickory-client" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bab9683b08d8f8957a857b0236455d80e1886eaa8c6178af556aa7871fb61b55" dependencies = [ "cfg-if", "data-encoding", "futures-channel", "futures-util", "hickory-proto", "once_cell", "radix_trie", "rand", "thiserror", "tokio", "tracing", ] [[package]] name = "hickory-proto" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" dependencies = [ "async-trait", "cfg-if", "data-encoding", "enum-as-inner", "futures-channel", "futures-io", "futures-util", "idna 0.4.0", "ipnet", "once_cell", "openssl", "rand", "thiserror", "tinyvec", "tokio", "tracing", "url", ] [[package]] name = "hickory-resolver" version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" dependencies = [ "cfg-if", "futures-util", "hickory-proto", "ipconfig", "lru-cache", "once_cell", "parking_lot", "rand", "resolv-conf", "smallvec", "thiserror", "tokio", "tracing", ] [[package]] name = "hkdf" version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" 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 = "hostname" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" dependencies = [ "libc", "match_cfg", "winapi", ] [[package]] name = "html-escape" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6d1ad449764d627e22bfd7cd5e8868264fc9236e07c752972b4080cd351cb476" dependencies = [ "utf8-width", ] [[package]] name = "http" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", "itoa", ] [[package]] name = "http-body" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", "pin-project-lite", ] [[package]] name = "httparse" version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0e7a4dd27b9476dc40cb050d3632d3bba3a70ddbff012285f7f8559a1e7e545" [[package]] name = "httpdate" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humansize" version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6cb51c9a029ddc91b07a787f1d86b53ccfa49b0e86688c946ebe8d3555685dd7" dependencies = [ "libm", ] [[package]] name = "humantime" version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" version = "0.14.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f361cde2f109281a220d4307746cdfd5ee3f410da58a70377762396775634b33" dependencies = [ "bytes", "futures-channel", "futures-core", "futures-util", "h2", "http", "http-body", "httparse", "httpdate", "itoa", "pin-project-lite", "socket2", "tokio", "tower-service", "tracing", "want", ] [[package]] name = "hyper-tls" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", "hyper", "native-tls", "tokio", "tokio-native-tls", ] [[package]] name = "iana-time-zone" version = "0.1.60" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", "windows-core", ] [[package]] name = "iana-time-zone-haiku" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ "cc", ] [[package]] name = "icu_collections" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" dependencies = [ "displaydoc", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_locid" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" dependencies = [ "displaydoc", "litemap", "tinystr", "writeable", "zerovec", ] [[package]] name = "icu_locid_transform" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" dependencies = [ "displaydoc", "icu_locid", "icu_locid_transform_data", "icu_provider", "tinystr", "zerovec", ] [[package]] name = "icu_locid_transform_data" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" [[package]] name = "icu_normalizer" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" dependencies = [ "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", "icu_provider", "smallvec", "utf16_iter", "utf8_iter", "write16", "zerovec", ] [[package]] name = "icu_normalizer_data" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" [[package]] name = "icu_properties" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f8ac670d7422d7f76b32e17a5db556510825b29ec9154f235977c9caba61036" dependencies = [ "displaydoc", "icu_collections", "icu_locid_transform", "icu_properties_data", "icu_provider", "tinystr", "zerovec", ] [[package]] name = "icu_properties_data" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" [[package]] name = "icu_provider" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" dependencies = [ "displaydoc", "icu_locid", "icu_provider_macros", "stable_deref_trait", "tinystr", "writeable", "yoke", "zerofrom", "zerovec", ] [[package]] name = "icu_provider_macros" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", "syn 2.0.66", ] [[package]] name = "idea" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "075557004419d7f2031b8bb7f44bb43e55a83ca7b63076a8fb8fe75753836477" dependencies = [ "cipher", ] [[package]] name = "idna" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", ] [[package]] name = "idna" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", ] [[package]] name = "idna" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4716a3a0933a1d01c2f72450e89596eb51dd34ef3c211ccd875acdf1f8fe47ed" dependencies = [ "icu_normalizer", "icu_properties", "smallvec", "utf8_iter", ] [[package]] name = "ignore" version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" dependencies = [ "crossbeam-deque", "globset", "log", "memchr", "regex-automata 0.4.7", "same-file", "walkdir", "winapi-util", ] [[package]] name = "indexmap" version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", "hashbrown 0.12.3", ] [[package]] name = "indexmap" version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.5", ] [[package]] name = "indicatif" version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" dependencies = [ "console", "instant", "number_prefix", "portable-atomic", "unicode-width", ] [[package]] name = "inout" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ "block-padding", "generic-array", ] [[package]] name = "instant" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] [[package]] name = "ipconfig" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ "socket2", "widestring", "windows-sys 0.48.0", "winreg", ] [[package]] name = "ipnet" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is-terminal" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ "hermit-abi", "libc", "windows-sys 0.52.0", ] [[package]] name = "is_terminal_polyfill" version = "1.70.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" [[package]] name = "itertools" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" dependencies = [ "either", ] [[package]] name = "itoa" version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] [[package]] name = "jwalk" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2735847566356cd2179a2a38264839308f7079fa96e6bd5a42d740460e003c56" dependencies = [ "crossbeam", "rayon", ] [[package]] name = "lalrpop" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" dependencies = [ "ascii-canvas", "bit-set", "ena", "itertools", "lalrpop-util", "petgraph", "regex", "regex-syntax 0.8.4", "string_cache", "term", "tiny-keccak", "unicode-xid", "walkdir", ] [[package]] name = "lalrpop-util" version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" dependencies = [ "regex-automata 0.4.7", ] [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" dependencies = [ "spin", ] [[package]] name = "lazycell" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libloading" version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c2a198fb6b0eada2a8df47933734e6d35d350665a33a3593d7164fa52c75c19" dependencies = [ "cfg-if", "windows-targets 0.48.5", ] [[package]] name = "libm" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libredox" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.5.0", "libc", ] [[package]] name = "libsqlite3-sys" version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c10584274047cb335c23d3e61bcef8e323adae7c5c8c760540f73610177fc3f" dependencies = [ "cc", "pkg-config", "vcpkg", ] [[package]] name = "line-col" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e69cdf6b85b5c8dce514f694089a2cf8b1a702f6cd28607bcb3cf296c9778db" [[package]] name = "linked-hash-map" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "linux-raw-sys" version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "litemap" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" [[package]] name = "lock_api" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", ] [[package]] name = "log" version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "loom" version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" dependencies = [ "cfg-if", "generator", "scoped-tls", "serde", "serde_json", "tracing", "tracing-subscriber", ] [[package]] name = "lru-cache" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" dependencies = [ "linked-hash-map", ] [[package]] name = "match_cfg" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" [[package]] name = "matchers" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" dependencies = [ "regex-automata 0.1.10", ] [[package]] name = "md-5" version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" dependencies = [ "cfg-if", "digest", ] [[package]] name = "memchr" version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memsec" version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa0916b001582d253822171bd23f4a0229d32b9507fae236f5da8cad515ba7c" [[package]] name = "memsec" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c797b9d6bb23aab2fc369c65f871be49214f5c759af65bde26ffaaa2b646b492" [[package]] name = "mime" version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "minimal-lexical" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" dependencies = [ "adler", ] [[package]] name = "mio" version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", "wasi", "windows-sys 0.48.0", ] [[package]] name = "native-tls" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" dependencies = [ "libc", "log", "openssl", "openssl-probe", "openssl-sys", "schannel", "security-framework", "security-framework-sys", "tempfile", ] [[package]] name = "nettle" version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44e6ff4a94e5d34a1fd5abbd39418074646e2fa51b257198701330f22fcd6936" dependencies = [ "getrandom", "libc", "nettle-sys", "thiserror", "typenum", ] [[package]] name = "nettle-sys" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b495053a10a19a80e3a26bf1212e92e29350797b5f5bdc58268c3f3f818e66ec" dependencies = [ "bindgen", "cc", "libc", "pkg-config", "tempfile", "vcpkg", ] [[package]] name = "new_debug_unreachable" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" [[package]] name = "nibble_vec" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" dependencies = [ "smallvec", ] [[package]] name = "nix" version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ "bitflags 1.3.2", "cfg-if", "libc", ] [[package]] name = "nom" version = "7.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" dependencies = [ "memchr", "minimal-lexical", ] [[package]] name = "normalize-line-endings" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "normpath" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "972dec05f98e7c787ede35d7a9ea4735eb7788c299287352757b3def6cc1f7b5" dependencies = [ "windows-sys 0.45.0", ] [[package]] name = "nu-ansi-term" version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" dependencies = [ "overload", "winapi", ] [[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", "smallvec", "zeroize", ] [[package]] name = "num-conv" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-integer" version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ "num-traits", ] [[package]] name = "num-iter" version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", "num-traits", ] [[package]] name = "num-traits" version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", "libm", ] [[package]] name = "num_cpus" version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ "hermit-abi", "libc", ] [[package]] name = "number_prefix" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "576dfe1fc8f9df304abb159d767a29d0476f7750fbf8aa7ad07816004a207434" dependencies = [ "memchr", ] [[package]] name = "once_cell" version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openpgp-cert-d" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c94a97687feb8838a6b2b47dbad623f269788f27f3fab90b1dc4a575295def1e" dependencies = [ "anyhow", "dirs", "fd-lock", "libc", "sha1collisiondetection", "tempfile", "thiserror", "walkdir", ] [[package]] name = "openssl" version = "0.10.64" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95a0481286a310808298130d22dd1fef0fa571e05a8f44ec801801e84b216b1f" dependencies = [ "bitflags 2.5.0", "cfg-if", "foreign-types", "libc", "once_cell", "openssl-macros", "openssl-sys", ] [[package]] name = "openssl-macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", "syn 2.0.66", ] [[package]] name = "openssl-probe" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" version = "0.9.102" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c597637d56fbc83893a35eb0dd04b2b8e7a50c91e64e9493e398b5df4fb45fa2" dependencies = [ "cc", "libc", "pkg-config", "vcpkg", ] [[package]] name = "option-ext" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" [[package]] name = "overload" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] name = "p256" version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" dependencies = [ "ecdsa", "elliptic-curve", "primeorder", "sha2", ] [[package]] name = "parking_lot" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", ] [[package]] name = "parking_lot_core" version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall 0.5.2", "smallvec", "windows-targets 0.52.5", ] [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "peeking_take_while" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[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.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" dependencies = [ "memchr", "thiserror", "ucd-trie", ] [[package]] name = "pest_derive" version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" dependencies = [ "pest", "pest_generator", ] [[package]] name = "pest_generator" version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", "syn 2.0.66", ] [[package]] name = "pest_meta" version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" dependencies = [ "once_cell", "pest", "sha2", ] [[package]] name = "petgraph" version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", "indexmap 2.2.6", ] [[package]] name = "phf_shared" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" dependencies = [ "siphasher", ] [[package]] name = "pikchr" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b430b470a0dfac4e22cd248210e3ef005346acd1ada670d74d6bdcdbab0dc96e" dependencies = [ "cc", "libc", ] [[package]] name = "pin-project-lite" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" 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.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "platforms" version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db23d408679286588f4d4644f965003d056e3dd5abcaaa938116871d7ce2fee7" [[package]] name = "polyval" version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", "cpufeatures", "opaque-debug", "universal-hash", ] [[package]] name = "portable-atomic" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" [[package]] name = "powerfmt" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "precomputed-hash" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" [[package]] name = "predicates" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8" dependencies = [ "anstyle", "difflib", "float-cmp", "normalize-line-endings", "predicates-core", "regex", ] [[package]] name = "predicates-core" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" [[package]] name = "predicates-tree" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" dependencies = [ "predicates-core", "termtree", ] [[package]] name = "primeorder" version = "0.13.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" dependencies = [ "elliptic-curve", ] [[package]] name = "proc-macro2" version = "1.0.85" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23" dependencies = [ "unicode-ident", ] [[package]] name = "pulldown-cmark" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b" dependencies = [ "bitflags 2.5.0", "getopts", "memchr", "unicase", ] [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] [[package]] name = "radix_trie" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" dependencies = [ "endian-type", "nibble_vec", ] [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "rayon" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", ] [[package]] name = "rayon-core" version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", ] [[package]] name = "redox_syscall" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_syscall" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ "bitflags 2.5.0", ] [[package]] name = "redox_users" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ "getrandom", "libredox", "thiserror", ] [[package]] name = "regex" version = "1.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" dependencies = [ "aho-corasick", "memchr", "regex-automata 0.4.7", "regex-syntax 0.8.4", ] [[package]] name = "regex-automata" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ "regex-syntax 0.6.29", ] [[package]] name = "regex-automata" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", "regex-syntax 0.8.4", ] [[package]] name = "regex-syntax" version = "0.6.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" [[package]] name = "remove_dir_all" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23895cfadc1917fed9c6ed76a8c2903615fa3704f7493ff82b364c6540acc02b" dependencies = [ "aligned", "cfg-if", "cvt", "fs_at", "lazy_static", "libc", "normpath", "windows-sys 0.45.0", ] [[package]] name = "reqwest" version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "base64 0.21.7", "bytes", "encoding_rs", "futures-core", "futures-util", "h2", "http", "http-body", "hyper", "hyper-tls", "ipnet", "js-sys", "log", "mime", "native-tls", "once_cell", "percent-encoding", "pin-project-lite", "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "sync_wrapper", "system-configuration", "tokio", "tokio-native-tls", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", "winreg", ] [[package]] name = "resolv-conf" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" dependencies = [ "hostname", "quick-error", ] [[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 = "roadmap" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a129e44a647b309ed394a092e21eabcb58537802c6912920ef4ea76239421234" dependencies = [ "anyhow", "serde", "serde_yaml 0.8.26", "textwrap", "thiserror", ] [[package]] name = "roff" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b833d8d034ea094b1ea68aa6d5c740e0d04bad9d16568d08ba6f76823a114316" [[package]] name = "rpassword" version = "7.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" dependencies = [ "libc", "rtoolbox", "windows-sys 0.48.0", ] [[package]] name = "rsa" version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" dependencies = [ "const-oid", "digest", "num-bigint-dig", "num-integer", "num-traits", "pkcs1", "pkcs8", "rand_core", "signature", "spki", "subtle", "zeroize", ] [[package]] name = "rtoolbox" version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" dependencies = [ "libc", "windows-sys 0.48.0", ] [[package]] name = "rusqlite" version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b838eba278d213a8beaf485bd313fd580ca4505a00d5871caeb1457c55322cae" dependencies = [ "bitflags 2.5.0", "fallible-iterator", "fallible-streaming-iterator", "hashlink", "libsqlite3-sys", "smallvec", ] [[package]] name = "rustc-demangle" version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[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.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", "windows-sys 0.52.0", ] [[package]] name = "rustls-pemfile" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ "base64 0.21.7", ] [[package]] name = "rustversion" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "ryu" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" dependencies = [ "winapi-util", ] [[package]] name = "schannel" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "scoped-tls" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" [[package]] name = "scopeguard" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[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.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ "bitflags 2.5.0", "core-foundation", "core-foundation-sys", "libc", "security-framework-sys", ] [[package]] name = "security-framework-sys" version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" dependencies = [ "core-foundation-sys", "libc", ] [[package]] name = "semver" version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "sequoia-autocrypt" version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e24fc0ec87c156a35f24fc153ab694e0f37cd6fa87c1cf5005c9f4fa5e10415b" dependencies = [ "base64 0.21.7", "sequoia-openpgp", ] [[package]] name = "sequoia-cert-store" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41c48ce5b9596be3d68d197e6b2a9f7ec787d49a8dd5a758ffc53e2b381cd0e4" dependencies = [ "anyhow", "crossbeam", "dirs", "gethostname", "num_cpus", "openpgp-cert-d", "rayon", "rusqlite", "sequoia-net", "sequoia-openpgp", "smallvec", "thiserror", "tokio", "url", ] [[package]] name = "sequoia-directories" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b01dd48960c5cf8617ab77e5c9f8ebeb55a1d694e3eabf830fa70453ffa637d5" dependencies = [ "anyhow", "directories", "same-file", "tempfile", "thiserror", ] [[package]] name = "sequoia-gpg-agent" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b1df6f0a2de8dfdef7a4ea49d096237eb1a3081b3e235eb61255d654257a6de" dependencies = [ "anyhow", "chrono", "futures", "lalrpop", "lalrpop-util", "libc", "sequoia-ipc", "sequoia-openpgp", "stfu8", "tempfile", "thiserror", "tokio", ] [[package]] name = "sequoia-ipc" version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4a7e644ec9e1055fde8dcdaa65c58fa4636c615b5e955a9b1942444145e308a" dependencies = [ "anyhow", "buffered-reader", "capnp-rpc", "ctor", "dirs", "fs2", "lalrpop", "lalrpop-util", "lazy_static", "libc", "memsec 0.7.0", "rand", "sequoia-openpgp", "socket2", "tempfile", "thiserror", "tokio", "tokio-util", "winapi", ] [[package]] name = "sequoia-keystore" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8556f1dd77d72fbe9c2dfcd2985eb9eaf87b7e6c8e0181a27be23e6c8778886f" dependencies = [ "anyhow", "capnp", "capnpc", "dirs", "env_logger", "lazy_static", "log", "paste", "sequoia-directories", "sequoia-ipc", "sequoia-keystore-backend", "sequoia-keystore-gpg-agent", "sequoia-keystore-softkeys", "sequoia-openpgp", "thiserror", "tokio", "tokio-util", ] [[package]] name = "sequoia-keystore-backend" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e7a7a4b148f8ea2083f0fec111208ea43a1c1529fe29a2add58251aa0554ee0" dependencies = [ "anyhow", "async-trait", "env_logger", "futures", "lazy_static", "log", "sequoia-openpgp", "tempfile", "thiserror", "tokio", ] [[package]] name = "sequoia-keystore-gpg-agent" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0bc3da475399420b544a2749f75318503d12ef1a355ab6d63bdd48d5c242192f" dependencies = [ "anyhow", "async-trait", "futures", "lazy_static", "log", "openpgp-cert-d", "sequoia-gpg-agent", "sequoia-ipc", "sequoia-keystore-backend", "sequoia-openpgp", "tokio", ] [[package]] name = "sequoia-keystore-softkeys" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bb53ee667b0e10a44bff1b2dbb7ee76ba5c765bf5f3456b1916ce47d44511f3" dependencies = [ "anyhow", "async-trait", "dirs", "futures", "lazy_static", "log", "sequoia-keystore-backend", "sequoia-openpgp", ] [[package]] name = "sequoia-net" version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6abf810ba698339f332b946b485cc815c13a0f750189009bc10514c71fba814b" dependencies = [ "anyhow", "base64 0.21.7", "futures-util", "hickory-client", "hickory-resolver", "http", "hyper", "hyper-tls", "libc", "percent-encoding", "reqwest", "sequoia-openpgp", "tempfile", "thiserror", "tokio", "url", "z-base-32", ] [[package]] name = "sequoia-openpgp" version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06f82708c8568218b8544b4abbba1f6483067dca0a946a54991c1d3f424dcade" dependencies = [ "aes", "aes-gcm", "anyhow", "base64 0.22.1", "block-padding", "blowfish", "botan", "buffered-reader", "bzip2", "camellia", "cast5", "cfb-mode", "chrono", "cipher", "des", "digest", "dsa", "dyn-clone", "eax", "ecb", "ecdsa", "ed25519", "ed25519-dalek", "flate2", "getrandom", "idea", "idna 0.5.0", "lalrpop", "lalrpop-util", "lazy_static", "libc", "md-5", "memsec 0.6.3", "nettle", "num-bigint-dig", "once_cell", "openssl", "openssl-sys", "p256", "rand", "rand_core", "regex", "regex-syntax 0.8.4", "ripemd", "rsa", "sha1collisiondetection", "sha2", "thiserror", "twofish", "typenum", "win-crypto-ng", "winapi", "x25519-dalek", "xxhash-rust", ] [[package]] name = "sequoia-policy-config" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "757d45d308f2bd9c0d6fdd640f320998ad24856bdf2890ddd28d3c3b85808274" dependencies = [ "anyhow", "chrono", "sequoia-openpgp", "serde", "thiserror", "toml", ] [[package]] name = "sequoia-sq" version = "0.37.0" dependencies = [ "anyhow", "assert_cmd", "buffered-reader", "cfg-if", "chrono", "clap", "clap_complete", "dircpy", "dirs", "dot-writer", "fehler", "humantime", "indicatif", "itertools", "libc", "once_cell", "predicates", "regex", "roff", "rpassword", "sequoia-autocrypt", "sequoia-cert-store", "sequoia-directories", "sequoia-keystore", "sequoia-net", "sequoia-openpgp", "sequoia-policy-config", "sequoia-wot", "serde", "serde_json", "subplot-build", "subplotlib", "tempfile", "termcolor", "terminal_size", "textwrap", "thiserror", "tokio", ] [[package]] name = "sequoia-wot" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "486e5d22de6407e3f8b57104da7d1e34d60fc4101c2af0c49d1435542c0b3ddb" dependencies = [ "anyhow", "chrono", "crossbeam", "enumber", "num_cpus", "sequoia-cert-store", "sequoia-openpgp", "sequoia-policy-config", "thiserror", ] [[package]] name = "serde" version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde-aux" version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d2e8bfba469d06512e11e3311d4d051a4a387a5b42d010404fecf3200321c95" dependencies = [ "serde", "serde_json", ] [[package]] name = "serde_derive" version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", "syn 2.0.66", ] [[package]] name = "serde_json" version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", "serde", ] [[package]] name = "serde_urlencoded" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", "itoa", "ryu", "serde", ] [[package]] name = "serde_yaml" version = "0.8.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" dependencies = [ "indexmap 1.9.3", "ryu", "serde", "yaml-rust", ] [[package]] name = "serde_yaml" version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ "indexmap 2.2.6", "itoa", "ryu", "serde", "unsafe-libyaml", ] [[package]] name = "sha1collisiondetection" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f606421e4a6012877e893c399822a4ed4b089164c5969424e1b9d1e66e6964b" dependencies = [ "const-oid", "digest", "generic-array", ] [[package]] name = "sha2" version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", "digest", ] [[package]] name = "sharded-slab" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] [[package]] name = "shell-words" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "shlex" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signature" version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", "rand_core", ] [[package]] name = "siphasher" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "slab" version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" dependencies = [ "autocfg", ] [[package]] name = "slug" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bd94acec9c8da640005f8e135a39fc0372e74535e6b368b7a04b875f784c8c4" dependencies = [ "deunicode", "wasm-bindgen", ] [[package]] name = "smallvec" version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "smawk" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" [[package]] name = "socket2" version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", ] [[package]] name = "spin" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spki" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der", ] [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "state" version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbe866e1e51e8260c9eed836a042a5e7f6726bb2b411dffeaa712e19c388f23b" dependencies = [ "loom", ] [[package]] name = "stfu8" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e51f1e89f093f99e7432c491c382b88a6860a5adbe6bf02574bf0a08efff1978" [[package]] name = "string_cache" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" dependencies = [ "new_debug_unreachable", "once_cell", "parking_lot", "phf_shared", "precomputed-hash", ] [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" [[package]] name = "subplot" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2c5723f41235a3deefab3cfd6164a5b780802f596fa97eb40dfcf3c39c36b21" dependencies = [ "anyhow", "base64 0.21.7", "clap", "env_logger", "file_diff", "git-testament", "html-escape", "lazy_static", "line-col", "log", "pikchr", "pulldown-cmark", "regex", "roadmap", "serde", "serde-aux", "serde_json", "serde_yaml 0.9.34+deprecated", "tempfile", "tempfile-fast", "tera", "thiserror", "time", "walkdir", ] [[package]] name = "subplot-build" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd58ff7123e83e5a5ed5bcdcd9f6f23226eea5b08bc310e129cad5d24b18fabe" dependencies = [ "subplot", "tempfile", "tracing", ] [[package]] name = "subplotlib" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fc3c17998cc92ec00493a7d1c0d0256f8977c7baed553777ba347dd6d1c3ccf" dependencies = [ "base64 0.21.7", "fehler", "filetime", "fs2", "glob", "lazy_static", "regex", "remove_dir_all", "shell-words", "state", "subplot-build", "subplotlib-derive", "tempfile", "time", "unescape", ] [[package]] name = "subplotlib-derive" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0234a041a912954e3cc81230b9f64f6a471c4297e65053e6ad733bb3e473bc60" dependencies = [ "fehler", "proc-macro2", "quote", "syn 2.0.66", ] [[package]] name = "subtle" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "syn" version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "sync_wrapper" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "synstructure" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", "syn 2.0.66", ] [[package]] name = "system-configuration" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", "core-foundation", "system-configuration-sys", ] [[package]] name = "system-configuration-sys" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" dependencies = [ "core-foundation-sys", "libc", ] [[package]] name = "tempfile" version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", "rustix", "windows-sys 0.52.0", ] [[package]] name = "tempfile-fast" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a74be8531b1a9d607004a32b8f50dd8093b09ec6b0a6af004e33051068e87af6" dependencies = [ "libc", "rand", "tempfile", ] [[package]] name = "tera" version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab9d851b45e865f178319da0abdbfe6acbc4328759ff18dafc3a41c16b4cd2ee" dependencies = [ "globwalk", "humansize", "lazy_static", "percent-encoding", "pest", "pest_derive", "rand", "regex", "serde", "serde_json", "slug", "unic-segment", ] [[package]] name = "term" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" dependencies = [ "dirs-next", "rustversion", "winapi", ] [[package]] name = "termcolor" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "terminal_size" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" dependencies = [ "rustix", "windows-sys 0.48.0", ] [[package]] name = "termtree" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "textwrap" version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7b3e525a49ec206798b40326a44121291b530c963cfb01018f63e135bac543d" dependencies = [ "smawk", "unicode-linebreak", "unicode-width", ] [[package]] name = "thiserror" version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", "syn 2.0.66", ] [[package]] name = "thread_local" version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ "cfg-if", "once_cell", ] [[package]] name = "time" version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", "serde", "time-core", "time-macros", ] [[package]] name = "time-core" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ "num-conv", "time-core", ] [[package]] name = "tiny-keccak" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" dependencies = [ "crunchy", ] [[package]] name = "tinystr" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" dependencies = [ "displaydoc", "zerovec", ] [[package]] name = "tinyvec" version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] [[package]] name = "tinyvec_macros" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", "libc", "mio", "num_cpus", "pin-project-lite", "socket2", "tokio-macros", "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", "syn 2.0.66", ] [[package]] name = "tokio-native-tls" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" dependencies = [ "native-tls", "tokio", ] [[package]] name = "tokio-util" version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", "futures-io", "futures-sink", "pin-project-lite", "tokio", ] [[package]] name = "toml" version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] [[package]] name = "tower-service" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ "pin-project-lite", "tracing-attributes", "tracing-core", ] [[package]] name = "tracing-attributes" version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", "syn 2.0.66", ] [[package]] name = "tracing-core" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", "valuable", ] [[package]] name = "tracing-log" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" dependencies = [ "log", "once_cell", "tracing-core", ] [[package]] name = "tracing-subscriber" version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "matchers", "nu-ansi-term", "once_cell", "regex", "sharded-slab", "smallvec", "thread_local", "tracing", "tracing-core", "tracing-log", ] [[package]] name = "try-lock" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[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.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "ucd-trie" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" [[package]] name = "unescape" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccb97dac3243214f8d8507998906ca3e2e0b900bf9bf4870477f125b82e68f6e" [[package]] name = "unic-char-property" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" dependencies = [ "unic-char-range", ] [[package]] name = "unic-char-range" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" [[package]] name = "unic-common" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" [[package]] name = "unic-segment" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4ed5d26be57f84f176157270c112ef57b86debac9cd21daaabbe56db0f88f23" dependencies = [ "unic-ucd-segment", ] [[package]] name = "unic-ucd-segment" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2079c122a62205b421f499da10f3ee0f7697f012f55b675e002483c73ea34700" dependencies = [ "unic-char-property", "unic-char-range", "unic-ucd-version", ] [[package]] name = "unic-ucd-version" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" dependencies = [ "unic-common", ] [[package]] name = "unicase" version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" dependencies = [ "version_check", ] [[package]] name = "unicode-bidi" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-linebreak" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" [[package]] name = "unicode-normalization" version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "unicode-width" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "universal-hash" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ "crypto-common", "subtle", ] [[package]] name = "unsafe-libyaml" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "url" version = "2.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7c25da092f0a868cdf09e8674cd3b7ef3a7d92a24253e663a2fb85e2496de56" dependencies = [ "form_urlencoded", "idna 1.0.0", "percent-encoding", ] [[package]] name = "utf16_iter" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" [[package]] name = "utf8-width" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" [[package]] name = "utf8parse" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "valuable" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" [[package]] name = "vcpkg" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wait-timeout" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" dependencies = [ "libc", ] [[package]] name = "walkdir" version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", ] [[package]] name = "want" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ "try-lock", ] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", "syn 2.0.66", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", "syn 2.0.66", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] name = "widestring" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" [[package]] name = "win-crypto-ng" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99abfb435a71e54ab2971d8d8c32f1a7e006cdbf527f71743b1d45b93517bb92" dependencies = [ "cipher", "doc-comment", "rand_core", "winapi", "zeroize", ] [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ "windows-sys 0.52.0", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-core" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ "windows-targets 0.52.5", ] [[package]] name = "windows-sys" version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ "windows-targets 0.42.2", ] [[package]] name = "windows-sys" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ "windows-targets 0.48.5", ] [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets 0.52.5", ] [[package]] name = "windows-targets" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ "windows_aarch64_gnullvm 0.42.2", "windows_aarch64_msvc 0.42.2", "windows_i686_gnu 0.42.2", "windows_i686_msvc 0.42.2", "windows_x86_64_gnu 0.42.2", "windows_x86_64_gnullvm 0.42.2", "windows_x86_64_msvc 0.42.2", ] [[package]] name = "windows-targets" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ "windows_aarch64_gnullvm 0.48.5", "windows_aarch64_msvc 0.48.5", "windows_i686_gnu 0.48.5", "windows_i686_msvc 0.48.5", "windows_x86_64_gnu 0.48.5", "windows_x86_64_gnullvm 0.48.5", "windows_x86_64_msvc 0.48.5", ] [[package]] name = "windows-targets" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ "windows_aarch64_gnullvm 0.52.5", "windows_aarch64_msvc 0.52.5", "windows_i686_gnu 0.52.5", "windows_i686_gnullvm", "windows_i686_msvc 0.52.5", "windows_x86_64_gnu 0.52.5", "windows_x86_64_gnullvm 0.52.5", "windows_x86_64_msvc 0.52.5", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" [[package]] name = "windows_i686_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winreg" version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ "cfg-if", "windows-sys 0.48.0", ] [[package]] name = "write16" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" [[package]] name = "writeable" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "x25519-dalek" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" dependencies = [ "curve25519-dalek", "rand_core", "zeroize", ] [[package]] name = "xxhash-rust" version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "927da81e25be1e1a2901d59b81b37dd2efd1fc9c9345a55007f09bf5a2d3ee03" [[package]] name = "yaml-rust" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] [[package]] name = "yoke" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" dependencies = [ "serde", "stable_deref_trait", "yoke-derive", "zerofrom", ] [[package]] name = "yoke-derive" version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" dependencies = [ "proc-macro2", "quote", "syn 2.0.66", "synstructure", ] [[package]] name = "z-base-32" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21bf7b4a78668416e1e8a332334e26fb2f377afe707f0c6feaf6ed5f9100133b" [[package]] name = "zerocopy" version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", "syn 2.0.66", ] [[package]] name = "zerofrom" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" dependencies = [ "proc-macro2", "quote", "syn 2.0.66", "synstructure", ] [[package]] name = "zeroize" version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 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.66", ] [[package]] name = "zerovec" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb2cc8827d6c0994478a15c53f374f46fbd41bea663d809b14744bc42e6b109c" dependencies = [ "yoke", "zerofrom", "zerovec-derive", ] [[package]] name = "zerovec-derive" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97cf56601ee5052b4417d90c8755c6683473c926039908196cf35d99f893ebe7" dependencies = [ "proc-macro2", "quote", "syn 2.0.66", ] sequoia-sq-0.37.0/Cargo.toml0000644000000113050000000000100112100ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.70" name = "sequoia-sq" version = "0.37.0" authors = [ "Azul ", "Heiko Schaefer ", "Igor Matuszewski ", "Justus Winter ", "Kai Michaelis ", "Lars Wirzenius ", "Neal H. Walfield ", "Nora Widdecke ", "Wiktor Kwapisiewicz ", ] build = "build.rs" description = "Command-line frontends for Sequoia" homepage = "https://sequoia-pgp.org/" documentation = "https://docs.rs/sequoia-sq" readme = "README.md" keywords = [ "cryptography", "openpgp", "pgp", "encryption", "signing", ] categories = [ "cryptography", "authentication", "command-line-utilities", ] license = "LGPL-2.0-or-later" repository = "https://gitlab.com/sequoia-pgp/sequoia-sq" [profile.release] debug = true [[bin]] name = "sq" path = "src/main.rs" bench = false [dependencies.anyhow] version = "1.0.18" [dependencies.buffered-reader] version = "1.3.1" features = ["compression"] default-features = false [dependencies.chrono] version = "0.4.10" [dependencies.clap] version = "4" features = [ "derive", "env", "string", "wrap_help", ] [dependencies.dirs] version = "5" [dependencies.dot-writer] version = "0.1.3" optional = true [dependencies.humantime] version = "2" [dependencies.indicatif] version = "0.17" [dependencies.itertools] version = ">=0.10, <0.13" [dependencies.once_cell] version = "1.17" [dependencies.rpassword] version = "7.0" [dependencies.sequoia-autocrypt] version = "0.25" default-features = false [dependencies.sequoia-cert-store] version = "0.6.0" [dependencies.sequoia-directories] version = "0.1" [dependencies.sequoia-keystore] version = "0.5" [dependencies.sequoia-net] version = "0.28" default-features = false [dependencies.sequoia-openpgp] version = "1.18" features = ["compression"] default-features = false [dependencies.sequoia-policy-config] version = "0.6" [dependencies.sequoia-wot] version = "0.12" default-features = false [dependencies.serde] version = "1.0.137" features = ["derive"] [dependencies.serde_json] version = "1.0.80" [dependencies.tempfile] version = "3.1" [dependencies.termcolor] version = "1.2.0" [dependencies.terminal_size] version = ">=0.2.6, <0.4" [dependencies.textwrap] version = ">=0.15, <0.17" [dependencies.thiserror] version = "1" [dependencies.tokio] version = "1.13.1" [dev-dependencies.assert_cmd] version = "2" [dev-dependencies.dircpy] version = "0.3" [dev-dependencies.fehler] version = "1.0.0" [dev-dependencies.libc] version = "0.2" [dev-dependencies.predicates] version = ">=2, <4" [dev-dependencies.regex] version = "1" [dev-dependencies.subplotlib] version = ">=0.7, <0.10" [build-dependencies.anyhow] version = "1.0.18" [build-dependencies.buffered-reader] version = "1.0.0" features = ["compression"] default-features = false [build-dependencies.cfg-if] version = "1" [build-dependencies.chrono] version = "0.4.10" [build-dependencies.clap] version = "4" features = [ "derive", "env", "string", "wrap_help", ] [build-dependencies.clap_complete] version = "4" [build-dependencies.dirs] version = "5" [build-dependencies.roff] version = "0.2.1" [build-dependencies.sequoia-directories] version = "0.1" [build-dependencies.sequoia-net] version = "0.28" default-features = false [build-dependencies.sequoia-openpgp] version = "1.17" default-features = false [build-dependencies.serde] version = "1.0.137" features = ["derive"] [build-dependencies.subplot-build] version = ">=0.7, <0.10" optional = true [build-dependencies.terminal_size] version = ">=0.2.6, <0.4" [build-dependencies.textwrap] version = ">=0.15, <0.17" [features] crypto-botan = ["sequoia-openpgp/crypto-botan"] crypto-botan2 = ["sequoia-openpgp/crypto-botan2"] crypto-cng = ["sequoia-openpgp/crypto-cng"] crypto-nettle = ["sequoia-openpgp/crypto-nettle"] crypto-openssl = ["sequoia-openpgp/crypto-openssl"] crypto-rust = ["sequoia-openpgp/crypto-rust"] default = [ "crypto-nettle", "dot-writer", ] subplot = ["subplot-build"] [badges.gitlab] repository = "sequoia-pgp/sequoia-sq" [badges.maintenance] status = "actively-developed" sequoia-sq-0.37.0/Cargo.toml.orig000064400000000000000000000063051046102023000146750ustar 00000000000000[package] name = "sequoia-sq" description = "Command-line frontends for Sequoia" version = "0.37.0" authors = [ "Azul ", "Heiko Schaefer ", "Igor Matuszewski ", "Justus Winter ", "Kai Michaelis ", "Lars Wirzenius ", "Neal H. Walfield ", "Nora Widdecke ", "Wiktor Kwapisiewicz ", ] build = "build.rs" documentation = "https://docs.rs/sequoia-sq" homepage = "https://sequoia-pgp.org/" repository = "https://gitlab.com/sequoia-pgp/sequoia-sq" readme = "README.md" keywords = ["cryptography", "openpgp", "pgp", "encryption", "signing"] categories = ["cryptography", "authentication", "command-line-utilities"] license = "LGPL-2.0-or-later" edition = "2021" rust-version = "1.70" [badges] gitlab = { repository = "sequoia-pgp/sequoia-sq" } maintenance = { status = "actively-developed" } [dependencies] buffered-reader = { version = "1.3.1", default-features = false, features = ["compression"] } dirs = "5" dot-writer = { version = "0.1.3", optional = true } sequoia-directories = "0.1" sequoia-openpgp = { version = "1.18", default-features = false, features = ["compression"] } sequoia-autocrypt = { version = "0.25", default-features = false } sequoia-net = { version = "0.28", default-features = false } sequoia-policy-config = "0.6" anyhow = "1.0.18" chrono = "0.4.10" clap = { version = "4", features = ["derive", "env", "string", "wrap_help"] } humantime = "2" indicatif = "0.17" itertools = ">=0.10, <0.13" once_cell = "1.17" sequoia-cert-store = "0.6.0" sequoia-keystore = { version = "0.5" } sequoia-wot = { version = "0.12", default-features = false } tempfile = "3.1" thiserror = "1" tokio = { version = "1.13.1" } rpassword = "7.0" serde_json = "1.0.80" serde = { version = "1.0.137", features = ["derive"] } terminal_size = ">=0.2.6, <0.4" termcolor = "1.2.0" textwrap = ">=0.15, <0.17" [build-dependencies] anyhow = "1.0.18" buffered-reader = { version = "1.0.0", default-features = false, features = ["compression"] } clap = { version = "4", features = ["derive", "env", "string", "wrap_help"] } clap_complete = "4" chrono = "0.4.10" dirs = "5" roff = "0.2.1" serde = { version = "1.0.137", features = ["derive"] } sequoia-directories = "0.1" sequoia-openpgp = { version = "1.17", default-features = false } sequoia-net = { version = "0.28", default-features = false } subplot-build = { version = ">=0.7, <0.10", optional = true } textwrap = ">=0.15, <0.17" cfg-if = "1" terminal_size = ">=0.2.6, <0.4" [dev-dependencies] dircpy = "0.3" subplotlib = ">=0.7, <0.10" fehler = "1.0.0" assert_cmd = "2" predicates = ">=2, <4" regex = "1" libc = "0.2" [[bin]] name = "sq" path = "src/main.rs" bench = false [features] default = [ "crypto-nettle", "dot-writer", ] crypto-nettle = ["sequoia-openpgp/crypto-nettle"] crypto-openssl = ["sequoia-openpgp/crypto-openssl"] crypto-botan = ["sequoia-openpgp/crypto-botan"] crypto-botan2 = ["sequoia-openpgp/crypto-botan2"] crypto-cng = ["sequoia-openpgp/crypto-cng"] crypto-rust = ["sequoia-openpgp/crypto-rust"] subplot = ["subplot-build"] [profile.release] debug = true sequoia-sq-0.37.0/Dockerfile000064400000000000000000000034751046102023000140050ustar 00000000000000# See https://gitlab.com/sequoia-pgp/sequoia/-/blob/main/README.md#debian # for system requirements FROM debian:trixie AS build # create a sandbox user for the build (in ~builder) and install (in /opt) # give it permissions to the build dir and home # upgrade everything # add dependencies, as specified by the Sequoia README.md file RUN groupadd builder && \ useradd --no-log-init --create-home --gid builder builder && \ apt-get update && \ apt-get upgrade --assume-yes && \ apt-get install --assume-yes --no-install-recommends \ ca-certificates \ capnproto \ cargo \ git \ libclang-dev \ libsqlite3-dev \ libssl-dev \ make \ nettle-dev \ pkg-config \ rustc \ && \ apt-get clean && \ chown builder /opt COPY --chown=builder:builder . /home/builder/sequoia # switch to the sandbox user USER builder # retry build because cargo sometimes segfaults during download (#918854) # # the `build-release` target is used instead of the default because # `install` calls it after anyways RUN cd /home/builder/sequoia && \ CARGO_TARGET_DIR=/tmp/target cargo build -p sequoia-sq --release && \ install --strip -D --target-directory /opt/usr/local/bin \ /tmp/target/release/sq FROM debian:trixie-slim AS sq-base RUN groupadd user && \ useradd --no-log-init -g user user && \ mkdir /home/user && \ chown -R user:user /home/user && \ apt-get update && \ apt-get upgrade --assume-yes && \ apt-get install --assume-yes ca-certificates libssl3 libsqlite3-0 && \ apt-get clean && \ rm -fr -- /var/lib/apt/lists/* /var/cache/* FROM sq-base AS sq COPY --from=build /opt/usr/local/bin/sq /usr/local/bin/sq COPY --from=build /etc/ssl/certs /etc/ssl/certs ENTRYPOINT ["/usr/local/bin/sq"] sequoia-sq-0.37.0/LICENSE.txt000064400000000000000000000627421046102023000136400ustar 00000000000000Sequoia PGP sq is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Sequoia PGP sq is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. --- GNU LIBRARY GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the library GPL. It is numbered 2 because it goes with version 2 of the ordinary GPL.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Library General Public License, applies to some specially designated Free Software Foundation software, and to any other libraries whose authors decide to use it. You can use it for your libraries, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library, or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link a program with the library, you must provide complete object files to the recipients so that they can relink them with the library, after making changes to the library and recompiling it. And you must show them these terms so they know their rights. Our method of protecting your rights has two steps: (1) copyright the library, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the library. Also, for each distributor's protection, we want to make certain that everyone understands that there is no warranty for this free library. If the library is modified by someone else and passed on, we want its recipients to know that what they have is not the original version, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that companies distributing free software will individually obtain patent licenses, thus in effect transforming the program into proprietary software. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License, which was designed for utility programs. This license, the GNU Library General Public License, applies to certain designated libraries. This license is quite different from the ordinary one; be sure to read it in full, and don't assume that anything in it is the same as in the ordinary license. The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such. Because of this blurred distinction, using the ordinary General Public License for libraries did not effectively promote software sharing, because most developers did not use the libraries. We concluded that weaker conditions might promote sharing better. However, unrestricted linking of non-free programs would deprive the users of those programs of all benefit from the free status of the libraries themselves. This Library General Public License is intended to permit developers of non-free programs to use free libraries, while preserving your freedom as a user of such programs to change the free libraries that are incorporated in them. (We have not seen how to achieve this as regards changes in header files, but we have achieved it as regards changes in the actual functions of the Library.) The hope is that this will lead to faster development of free libraries. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library. Note that it is possible for a library to be covered by the ordinary General Public License rather than by this special one. GNU LIBRARY GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Library General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also compile or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. c) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. d) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Library General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! sequoia-sq-0.37.0/NEWS000064400000000000000000000351531046102023000125100ustar 00000000000000 -*- org -*- #+TITLE: sequoia-sq NEWS – history of user-visible changes #+STARTUP: content hidestars * Changes in 0.37.0 ** Notable changes - Remove PKS support. - `sq key userid add` can now use the certificate store and the keystore. - `sq key userid add` no longer accepts positional arguments. The user ID is provided by the `--userid` argument, and the certificate by `--cert` or `--cert-file`. - Drop the `--certificate-file` argument from `sq key revoke`, `sq key subkey revoke`, and `sq key userid revoke` drop the `--certificate-file`. (The certificate can still be specified using `--cert-file`.) - Rename the `--revocation-file` argument to `--revoker-file` in `sq key revoke`, `sq key subkey revoke`, and `sq key userid revoke`. - `sq key revoke --cert-file`, `sq key revoke --revoker-file` `sq key subkey revoke --cert-file`, `sq key subkey revoke --revoker-file`, `sq key userid revoke --cert-file`, and `sq key userid revoke --revoker-file` now accept `-`, which means to read from stdin. - `sq key revoke`, `sq key subkey revoke`, and `sq key userid revoke` now reads from the certificate store when using `--cert` or --revoker`. When `--cert` is used, and `--output` is not specified, the resulting revocation certificate is saved to the certificate store. - The user ID argument to `sq key userid revoke` is no longer a positional argument, but must be specified with `--userid`. - Change `sq cert lint` to not read from stdin by default. - In `sq cert lint`, change the certificate file parameter from a positional parameter to a named parameter, `--cert-file`. - `sq cert lint` can now use the certificate store and the keystore. - In `sq key subkey add`, change the certificate file parameter from a positional parameter to a named parameter, `--cert-file`. - `sq key subkey add` now reads from the certificate store when using `--cert`. When `--cert` is used, and `--output` is not specified, the new subkey is saved to the key store. - In `sq key expire`, change the certificate file parameter from a positional parameter to a named parameter, `--cert-file`. - Split the functionality to update a subkey's expiration time off of `sq key expire` and into `sq key subkey expire`. - Rename `sq key subkey expire`'s `--subkey` argument to `--key`. - `sq key expire` and `sq key subkey expire` can now use the cert store and the key store. - Add the `--password-file` argument to the `sq sign` command to allow the user to prefill the password cache with a password from a file. - In `sq key password`, change the certificate file parameter from a positional parameter to a named parameter, `--cert-file`. - `sq pki certify`'s certifier parameter interprets `-` as meaning it should read the certificate from stdin. - In `sq pki certify`, change the certifier file parameter from a positional parameter to a named parameter, `--certifier-file`. - `sq pki certify` can now use the cert store and the key store. - In `sq key adopt`, change the certificate file parameter from a positional parameter to a named parameter, `--cert-file`. - `sq key adopt` can now use the cert store and the key store. - In `sq key attest-certifications`, change the certificate file parameter from a positional parameter to a named parameter, `--cert-file`. - In `sq key attest-certifications`, don't make `--all` the default, but require the user to specify it (or `--none`) explicitly. - `sq key attest-certifications` can now use the cert store and the key store. - Rename the `--expiry` argument to `--expiration`. - Rename `sq key password`'s `--clear` argument to `--clear-password`. - Add a top-level `--password-file` argument to seed the password cache. Remove `sq key password`'s `--old-password-file`, and `sq sign`'s `--password-file` local arguments in favor of this argument. * Changes in 0.36.0 - Missing * Changes in 0.35.0 - Missing * Changes in 0.34.0 ** Notable changes - `sq` now uses `sequoia-keystore` for secret key operations. When decrypting a message, `sq` will automatically ask the keystore to decrypt the message. `sq sign --signer-key` can be used to specify a signing key managed by the key store. - New top-level option: `sq --no-key-store`: A new switch to disable the use of the key store. - New top-level option: `sq --key-store`: A new option to use an alternate key store. - New subcommand `sq key list` to list keys managed by the key store. - New subcommand `sq key import` to import a key into the key store. - When showing a user ID for a certificate, choose the one that is most authenticated. * Changes in 0.33.0 ** Notable changes - The command line interface has been restructured. Please consult the manual pages and review any code and documents using the interface. Notably: - `sq import` and `sq export` have been moved to `sq cert`. - `sq wot` has been renamed to `sq pki`. - `sq link` and `sq certify` have been moved to `sq pki`. - `sq lookup, `sq keyserver`, `sq wkd`, and `sq dane` have been moved to `sq network`. - All commands retrieving certificates from network services are now called `fetch`, e.g. `sq network fetch` and `sq network dane fetch`. The command for publishing certs on key servers is now called `sq network keyserver publish`. - `sq armor`, `sq dearmor`, and `sq packet` have been moved to `sq toolbox`. - `sq --version` is now `sq version`, and `sq output-versions` has been integrated with that command. - The manual page generation has been improved, and manual pages and shell completions are generated during the build process. To write the assets to a predictable location, set the environment variable `ASSET_OUT_DIR` to a suitable location. * Changes in 0.32.0 ** New functionality - Support for password-encrypted keys has been improved. For example, a newly generated subkey can be password protected. - When encrypting a message with a password, or creating a new password-protected key or subkey, or changing passwords on a key, sq now prompts you to repeat the password to catch typos. - Literal data metadata can now be set using `--set-metadata-filename` and `--set-metadata-time`. - sq now reads the file /etc/crypto-policies/back-ends/sequoia.config to configure its cryptographic policy. The file to load can be overridden using the SEQUOIA_CRYPTO_POLICY environment variable. For more information on the format, see: https://docs.rs/sequoia-policy-config/latest/sequoia_policy_config/#format - New subcommand: `sq dane generate`. Generates DANE records for the given domain and certificates. DANE is a way to distribute OpenPGP certificates via DNS. https://www.rfc-editor.org/rfc/rfc7929.html - When querying network resources via `sq keyserver get`, `sq wkd get`, or `sq dane get`, multiple queries can be given that are executed simultaneously. - When querying key servers via `sq keyserver get` or `sq keyserver send`, multiple servers are queried simultaneously. - There are now four default keyservers: - hkps://keys.openpgp.org - hkps://mail-api.proton.me - hkps://keys.mailvelope.com - hkps://keyserver.ubuntu.com - New subcommand: `sq lookup`. Searches for certificates using all supported network services. ** Notable changes - Padding has been disabled to increase compatibility with other implementations. The padding method we previously used relies on a compressed data packet to pad the message. However, some implementations do not gracefully process these padded encryption containers, so until we get proper padding support from the next revision of OpenPGP, we disable padding. - Message notarization has been disabled. Message notarization and their semantics are not well defined, and there is no consensus on how to do that. - When doing a userid, subkey, or third-party certificate revocation, with the cert given to --certificate-file containing secret key material, we previously emitted a revocation certificate containing secret key material. This has been fixed, and tests have been added to ensure secret key material is only emitted where we expect it to be. * Changes in 0.31.0 ** New functionality - `sq key subkey add` allows to create and add a new subkey to an existing certificate. - The functionality of `sq-keyring-linter` is now available as `sq keyring lint`. - The new subcommands `sq key revoke`, `sq key subkey revoke` and `sq key userid revoke`, allow writing to a file using the `--output` option. ** Notable changes - The `--keyring` option is now global and can be specified anywhere when calling `sq`. ** Deprecated functionality - The `--expires` and `--expires-in` options used in various subcommands are deprecated in favor of the unifying `--expiry`. - `sq key generate --export FILE` is deprecated in favor of the more generic `sq key generate --output FILE`. - The `sq revoke certificate` command has been renamed to `sq key revoke`. - The `sq revoke subkey` command has been renamed to `sq key subkey revoke`. - The `sq revoke userid` command has been renamed to `sq key userid revoke`. * Changes in 0.30.1 ** Notable changes - The `crypto-botan` feature now selects Botan's v3 interface. Use the new `crypto-botan2` feature to continue using Botan's v2 interface. ** Notable fixes - Several parser bugs were fixed in sequoia-openpgp 1.16.0 and buffered-reader 1.2.0. These are all low-severity as Rust correctly detects the out of bounds access and panics. Update Cargo.lock to make sure we use these versions. * Changes in 0.30 ** New functionality - `sq key adopt` now honors `--time`. - Add `sq key adopt --expire` to allow setting an adopted key's expiration time. - Add support for using pEp's certificate store. A pEp certificate store can be used by specifying `sq --pep-cert-store PATH` or setting the environment variable `PEP_CERT_STORE`. * Changes in 0.29 ** New functionality - `sq` now supports and implicitly uses a certificate store. By default, `sq` uses the standard OpenPGP certificate directory. This is located at `$HOME/.local/share/pgp.cert.d` on XDG compliant systems. - `sq --no-cert-store`: A new switch to disable the use of the certificate store. - `sq --cert-store`: A new option to use an alternate certificate store. Currently, only OpenPGP certificate directories are supported. - `sq import`: A new command to import certificates into the certificate store. - `sq export`: A new command to export certificates from the certificate store. - `sq encrypt --recipient-cert`: A new option to specify a recipient's certificate by fingerprint or key ID, which is then looked up in the certificate store. - `sq verify --signer-cert`: A new option to specify a signer's certificate by fingerprint or key ID, which is then looked up in the certificate store. - `sq verify` now also implicitly looks for missing certificates in the certificate store. But, unless they are explicitly named using `--signer-cert`, they are not considered authenticated and the verification will always fail. - `sq certify`: If the certificate to certify is a fingerprint or Key ID, then the corresponding certificate is looked up in the certificate store. - Add a global option, `--time`, to set the reference time. This option replaces the various subcommand's `--time` argument as well as `sq key generate` and `sq key userid add`'s `--creation-time` arguments. - Add top-level option, `--trust-root`, to allow the user to specify trust roots. - Extend `sq encrypt` to allow addressing recipients by User ID (`--recipient-userid`) or email address (`--recipient-email`). Only User IDs that can be fully authenticated are considered. - Extend `sq verify` to verify certificates looked up from the certificate store using the web of trust. If the signature includes a Signer's User ID packet, and the binding can be fully authenticated, consider the signature to be authenticated. If there is no Signer's User ID packet, consider the signature to be authenticated if any binding can fully be authenticated. - Add `sq link add`, which uses the local trust root to certify the specified bindings. - Add `sq link retract`, which retracts certifications made by the local trust root on the specified bindings. - Add `sq link list`, which lists the links. - Add a top-level option, `--keyring`, to allow the user to specify additional keyrings to search for certificates. - Import web of trust subcommands from sq-wot. Specifically, add: - `sq wot authenticate` to authenticate a binding. - `sq wot lookup` to find a certificate with a particular User ID. - `sq wot identify` to list authenticated bindings for a certificate. - `sq wot list` to list authenticated bindings. - `sq wot path` to authenticate and lint a path in a web of trust. - `sq keyserver get`, `sq wkd get`, and `sq dane get` now import any certificates into the certificate store by default instead of exporting them on stdout. It is still possible to export them using the `--output` option. - When `sq keyserver get` (for verifying key servers), `sq wkd get`, or `sq dane get` saves a certificate to the local certificate store, `sq` certifies the validated User IDs (all returned User IDs in the case of verifying key servers; User IDs that contain the looked up email address in the case of WKD and DANE) using a local service-specific proxy CA. If the proxy key doesn't exist, it is created, and certified as a minimally trusted CA (trust amount 1 of 120) by the local trust root. The proxy certificates can be managed in the usual way using `sq link add` and `sq link retract`. - Extend `sq inspect` to inspect certificates from the certificate store using the `--cert` option. ** Deprecated functionality - `sq key generate --creation-time TIME` is deprecated in favor of `sq key generate --time TIME`. - `sq key user id --creation-time TIME` is deprecated in favor of `sq user id --time TIME`. * Started the NEWS file. sequoia-sq-0.37.0/README.md000064400000000000000000000032501046102023000132610ustar 00000000000000# sq, the Sequoia-PGP command line tool [Sequoia-PGP][] is an implementation of OpenPGP in Rust. It includes a suite of library crates, which are meant to be used from applications. This crate provides the `sq` command line application. `sq` is aimed at command line users as a way to use OpenPGP conveniently from the command line. See the [sq user guide][] for instructions. The program also has built-in help, using the `--help` option and `help` subcommand: ~~~sh $ sq help ... ~~~ You can also browse the [manual pages][], look at our [acceptance criteria][], and browse the [rustdoc output][] if you want to learn about the implementation. [Sequoia-PGP]: https://sequoia-pgp.org/ [sq user guide]: https://sequoia-pgp.gitlab.io/sq-user-guide/ [manual pages]: https://sequoia-pgp.gitlab.io/sequoia-sq/man/ [acceptance criteria]: https://sequoia-pgp.gitlab.io/sequoia-sq/subplot/ [rustdoc output]: https://sequoia-pgp.gitlab.io/sequoia-sq/impl/ ## Installing The `sq` tool can be installed using cargo: ```sh cargo install sequoia-sq ``` Please see [sequoia-openpgp's README] for how to install build dependencies on your system. [sequoia-openpgp's README]: https://gitlab.com/sequoia-pgp/sequoia#requirements-and-msrv ## Building from source This crate can be built from a source checkout using the standard `cargo` toolchain: ```sh cargo build ``` The above creates the `sq` executable, the manual pages, and its shell completions. By default, the manual pages and shell completions are put into the `cargo` target directory, but the exact location is unpredictable. To write the assets to a predictable location, set the environment variable `ASSET_OUT_DIR` to a suitable location. sequoia-sq-0.37.0/build.rs000064400000000000000000000037241046102023000134550ustar 00000000000000use std::env; use std::fs; use std::path::PathBuf; use clap::ValueEnum; use clap_complete::Shell; use anyhow::Result; pub mod cli { #![allow(unused_macros)] include!("src/macros.rs"); include!("src/cli/mod.rs"); } pub mod man { include!("src/man.rs"); } fn main() { println!("cargo:rerun-if-changed=build.rs"); // Generate subplot tests. #[cfg(feature = "subplot")] subplot_build::codegen("sq.subplot") .expect("failed to generate code with Subplot"); let mut sq = cli::build(false); generate_shell_completions(&mut sq).unwrap(); generate_man_pages(&sq).unwrap(); } /// Variable name to control the asset out directory with. const ASSET_OUT_DIR: &str = "ASSET_OUT_DIR"; /// Returns the directory to write the given assets to. fn asset_out_dir(asset: &str) -> Result { println!("cargo:rerun-if-env-changed={}", ASSET_OUT_DIR); let outdir: PathBuf = env::var_os(ASSET_OUT_DIR).unwrap_or_else( || env::var_os("OUT_DIR").expect("OUT_DIR not set")).into(); if outdir.exists() && ! outdir.is_dir() { return Err( anyhow::anyhow!("{}={:?} is not a directory", ASSET_OUT_DIR, outdir)); } let path = outdir.join(asset); fs::create_dir_all(&path)?; Ok(path) } /// Generates shell completions. fn generate_shell_completions(sq: &mut clap::Command) -> Result<()> { let path = asset_out_dir("shell-completions")?; for shell in Shell::value_variants() { clap_complete::generate_to(*shell, sq, "sq", &path)?; }; println!("cargo:warning=shell completions written to {}", path.display()); Ok(()) } /// Generates man pages. fn generate_man_pages(sq: &clap::Command) -> Result<()> { let path = asset_out_dir("man-pages")?; for man in man::manpages(sq) { std::fs::write(path.join(man.filename()), man.troff_source())?; } println!("cargo:warning=man pages written to {}", path.display()); Ok(()) } sequoia-sq-0.37.0/deny.toml000064400000000000000000000021131046102023000136330ustar 00000000000000[advisories] ignore = [ "RUSTSEC-2020-0159", "RUSTSEC-2020-0071", # chrono not affected by time 0.1 issue # fehler is unmaintained. # # fehler is used by subplot and thus an indirect dependency. Remove # when a new version subplot is released without fehler. See # https://gitlab.com/subplot/subplot/-/issues/340. "RUSTSEC-2023-0067", # yaml-rust is unmaintained. # # yaml-rust is used by subplot/roadmap/serde_yaml thus an indirect # dependency. Remove when a new version of roadmap is released that # uses a newer version of serde_yaml. See # https://gitlab.com/larswirzenius/roadmap/-/issues/13 "RUSTSEC-2024-0320", ] unmaintained = "deny" yanked = "deny" [bans] multiple-versions = "allow" deny = [ # does not have responsible disclosure policy: # https://github.com/briansmith/ring#bug-reporting {name = "ring"}, ] [licenses] allow = [ "Apache-2.0", "BSD-3-Clause", "BSD-2-Clause", "BSL-1.0", "CC0-1.0", "GPL-2.0", "GPL-3.0", "ISC", "LGPL-2.0", "LGPL-3.0", "MIT", "MIT-0", "MPL-2.0", "Unicode-DFS-2016", "Unicode-3.0", ] sequoia-sq-0.37.0/openpgp-policy.toml000064400000000000000000002420651046102023000156550ustar 00000000000000version = 0 commit_goodlist = [] [authorization."Alexander Kjäll"] sign_commit = true keyring = """ -----BEGIN PGP PUBLIC KEY BLOCK----- Comment: 7E06 8070 D5EF 794B 00C8 A9D9 1D10 8E6C 07CB C406 Comment: Alexander Kjäll xjMEXkLj2xYJKwYBBAHaRw8BAQdAHUsNSgCBZ9wSRCyVciyLF/dT+mf9ezwXY0RA 9PAb3L3NLEFsZXhhbmRlciBLasOkbGwgPGFsZXhhbmRlci5ramFsbEBnbWFpbC5j b20+wpYEExYKAD4CGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQR+BoBw1e95 SwDIqdkdEI5sB8vEBgUCYgaMqwUJB4YP0AAKCRAdEI5sB8vEBh+eAP482grBHUIO ELrnswgpUbl0CUZD8j3RfEP8wI1UYYPHQQD+JK1MGOykvIPn6euJUCJJx9FNHRE2 FVR9Bd+3SzrmiAXClgQTFggAPgIbAwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgBYh BH4GgHDV73lLAMip2R0QjmwHy8QGBQJeQwFnBQkDwoSMAAoJEB0QjmwHy8QGr8gB AKBDY62Mc/SwkrMAmhSXm+ewhYjRpbwVlI5TN0rRiIOrAPwNhbTV8CKYasoZP6Ec h7GKGKTHW3FEQ6lUxLezxkuyBQ== =ptgH -----END PGP PUBLIC KEY BLOCK----- """ [authorization.dvn] sign_commit = true keyring = """ -----BEGIN PGP PUBLIC KEY BLOCK----- Comment: 0CC0 11A7 C3DC 6EB4 7567 9BC9 AC0A BA31 866A 7E76 Comment: Devan Carpenter Comment: dvn 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 /g== =nP6D -----END PGP PUBLIC KEY BLOCK----- """ [authorization.justus] sign_commit = true keyring = """ -----BEGIN PGP PUBLIC KEY BLOCK----- Comment: D2F2 C5D4 5BE9 FDE6 A4EE 0AAF 3185 5247 6038 31FD Comment: Justus Winter (Code Signing Key) Comment: Justus Winter Comment: Justus Winter Comment: Justus Winter Comment: Justus Winter Comment: Justus Winter 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 =uq6w -----END PGP PUBLIC KEY BLOCK----- """ [authorization.neal] sign_commit = true keyring = """ -----BEGIN PGP PUBLIC KEY BLOCK----- Comment: F717 3B3C 7C68 5CD9 ECC4 191B 74E4 45BA 0E15 C957 Comment: Neal H. Walfield (Code Signing Key) Comment: Neal H. Walfield Comment: Neal H. Walfield Comment: Neal H. Walfield Comment: Neal H. Walfield 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 HCL+AFMw7YtSwqT2TxbLYPc/7bU+pWAe1YT6pk0OLZhuRzyG3UuZaMVFHcp26sLP rGROgdo4R79MUUDMLYkuYKRcTrdi4bceZlmIpJeUt+SY8zcAP3m4epeEOu3vrJER 1xglFmeNDEcjD32iTJHlkGcyHw+NWhl6l8LvFov4ZVyW4pXiYjnjbOHq8ukbPIDP eafMkishG18ekELGoGuLpDqnPYG9AYXiy03D6ZwduLI770bMkG5zhKzDksIGQ8x0 JUPvtroSlgNQwe1PFlDS7c2bIs3JqwCpuJClEEqKkvg7samKXWNCO23vl9ucmOwk xMm2w4v09WooFlG28hSsH+FL+ROEU2Px1MJbUahReTbsho828NstqZ46UWmcWe9q 9YDwnHBj2sKEy47f2mZ3ZoR1wchRIxze7dcPLUTPMoEyjAFKzsoozpE+Ah/hUwIj PSEK0kfPaQx4jR9QKCwTnMrHNs16nVUM9zhXLNlwb2rdG6Y0dAyBllLvE4UHAF8x 3Gv/6O3xC/PU6LrAUitH0mViV+GHHn3jWV7oO3NmV27x+Vw1DqZO9XZMPqmgRoRz MEQXzSROZWFsIEguIFdhbGZpZWxkIDxuZWFsQHdhbGZpZWxkLm9yZz7CwWgEEwEK AD4CGwMICwkIBw0MCwoFFQoJCAsCHgECF4ACGQEWIQSPF3dxGKM92pukjmKqyzJD YwBS2QUCZCarHgUJEORDtQAKCRCqyzJDYwBS2YLaDp0fMZrwfLGqC8LJiRfI+HwV +29E7EWaJmOF6S24sewr1t//2Vz4mc41E6bDprHsHte4JEmzyCnXnXlPaobyONWU IbYcnM8723myJml0Du4EvvvJPUieMiwFWzRdmFxc/eQ+6aeTTUknNJKVhY18/qsA pvYTIkvmlePgLQVGvpnYqQ1ElgMf768KJ4+lVMmIT2+fHlLe5RyJRlZcjVryV5H9 fOy+TQqhLLoTFhxAiJBACYIUCglGgjTQejivXXRXjhvMpvlBzSxwI9iZGZUL4FE1 kjK99epoictN9iv1O5XTZYTqkdBf1PD79GicHAbG6Io8F07xR/CijZl27l6rLb55 9/33Iswi6Ma8mdnmeTJ1d+io9XbtAGhPZqKxM2XtKbVO8uJli6YCqeEpVP+/Wy2c g4RSj42b5yrplbqVvnbddx8ZYCm5SXD6Pb/ZrrUmKlayuM2UnMs9+snIGG/SMRUv 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 =MESu -----END PGP PUBLIC KEY BLOCK----- """ sequoia-sq-0.37.0/sq-subplot.md000064400000000000000000001732751046102023000144540ustar 00000000000000--- title: "Sequoia-PGP sq" subtitle: "integration tests, requirements, acceptance criteria" authors: "The Sequoia-PGP project" bindings: - subplot/sq-subplot.yaml - lib/files.yaml - lib/runcmd.yaml impls: rust: - subplot/sq-subplot.rs classes: - json ... # Introduction The [Sequoia-PGP][] project is an implementation of the [OpenPGP][] standard for encryption and digital signatures. Sequoia itself is a library for the Rust programming language, as well as the `sq` command line tool for people to use directly. This document captures the requirements and acceptance criteria for the `sq` tool and how they are verified, and at the same time acts as an integration test for the tool. [Sequoia-PGP]: https://sequoia-pgp.org/ [OpenPGP]: https://en.wikipedia.org/wiki/Pretty_Good_Privacy#OpenPGP ## Testing approach for sq This document explicitly only covers integration and acceptance testing of the `sq` command line tool. It does not try to verify that the underlying library implements OpenPGP correctly: the library has its own test suite for that. Instead, this document concentrates on making sure the `sq` command line tool behaves as it should from an end-user's point of view. We make the following simplifying assumption: we know the `sq` developers as competent developers, and assume that they don't entangle unrelated functionality. By this we mean that we feel we can assume that the code in `sq` that reads input files is separate from the code that compresses it, which in turn is independent of the code that writes output as text or binary data. Thus, we verify each such functionality independently of each other. This drastically cuts down the number of feature combinations we need to test. If this assumption turns out to be incorrect, we will rethink and revise the testing approach as needed. We also know, by inspection, that `sq` uses the well-known, well-respected Rust library `clap` for parsing the command line. Because of this we feel it's not necessary to verify that, for example, `sq` notices that a required argument is missing from the command line, or that it notices that there are extra arguments present. We will concentrate on testing that when invoked with valid arguments results in expected output. ## Using Subplot and this document The acceptance criteria and requirements are explained in prose and when they can be verified in an automated way, that is done using _test scenarios_. Both the prose and the scenarios are meant to be understood and agreed to by all stakeholders in the project. The [Subplot][] tool is used to render this document into human-readable form (HTML or PDF), and to generate a test program that executes the scenarios and checks they all pass. To achieve this, run the following commands: ~~~sh $ git clone https://gitlab.com/sequoia-pgp/sequoia-sq.git $ cd sequoia-sq $ subplot docgen sq-subplot.md -o sq-subplot.html $ subplot docgen sq-subplot.md -o sq-subplot.pdf $ cargo test ~~~ If you only care about generating and running tests, you only need to run `cargo test`. All the dependencies for that are automatically handled via `Cargo.toml`. To generate typeset documents (HTML and PDF), you need the following software installed: * [Subplot][], via cargo install or a Debian package (see its website) * Pandoc * Parts of TeX Live (for PDF) * Graphviz On a Debian system, that means the following packages: > `subplot pandoc pandoc-citeproc lmodern librsvg2-bin graphviz > texlive-latex-base texlive-latex-recommended > texlive-fonts-recommended plantuml` [Subplot]: https://subplot.liw.fi/ # Smoke test _Requirement: We must be able to invoke `sq` at all._ This scenario verifies that we can run `sq` in the simplest possible case: we ask the program for its version. If this works, then we know that the executable program exists, can be invoked, and at least some of its command line parsing code works. If this scenario doesn't work, then we can't expect anything else to work either. ~~~scenario given an installed sq when I run sq version then exit code is 0 then stderr matches regex ^sq \d+\.\d+\.\d+ ~~~ # Key management: `sq key` This chapter covers all key management functionality: the `sq key` subcommands. ## Key generation: `sq key generate` This section covers key generation with `sq`. Keys are somewhat complicated: it is possible to have keys for specify that they can only used for specific operations, or the time period when they are valid. Different cryptographic algorithms have different kinds of keys. We verify these by varying what kind keys we generate and that they look as expected, when inspected. ### Generate a key with defaults _Requirement: We must be able to generate new encryption keys and corresponding certificates._ This scenario generates a new key with `sq` using default settings and inspects it to see if it looks at least vaguely correct. Note that in this scenario we don't verify that the key works, other scenarios take care of that. Here we merely verify that the new key looks OK. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output key.pgp when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Alice" then stdout contains "Expiration time: 20" then stdout contains "Key flags: certification" then stdout contains "Key flags: signing" then stdout contains "Key flags: authentication" then stdout contains "Key flags: transport encryption, data-at-rest encryption" ~~~ ### Generate key without user identifiers _Requirement: We must be able to generate new encryption keys without any user identifiers._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp then file key.pgp contains "-----BEGIN PGP PRIVATE KEY BLOCK-----" ~~~ ### Generate key with more than one user identifier _Requirement: We must be able to generate new encryption keys with more than one user identifier._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --userid '' --output key.pgp then file key.pgp contains "Comment: Alice" then file key.pgp contains "Comment: " ~~~ ### Generate a key for certification only _Requirement: We must be able to generate a key that can only be used for certification, and can't be used for signing, encryption or authentication._ Note that `sq` always creates a key usable for certification. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp --cannot-sign --cannot-authenticate --cannot-encrypt when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Key flags: certification" then stdout doesn't contain "Key flags: signing" then stdout doesn't contain "Key flags: authentication" then stdout doesn't contain "Key flags: transport encryption, data-at-rest encryption" ~~~ ### Generate a key for encryption only _Requirement: We must be able to generate a key that can only be used for encryption, and can't be used for signing or authentication._ Note that `sq` always creates a key usable for certification. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp --cannot-sign --cannot-authenticate when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Key flags: certification" then stdout doesn't contain "Key flags: signing" then stdout doesn't contain "Key flags: authentication" then stdout contains "Key flags: transport encryption, data-at-rest encryption" ~~~ ### Generate a key for storage encryption only _Requirement: We must be able to generate a key that can only be used for at-rest (storage) encryption._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp --can-encrypt=storage when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Key flags: certification" then stdout doesn't contain "transport encryption" then stdout contains "Key flags: data-at-rest encryption" ~~~ ### Generate a key for transport encryption only _Requirement: We must be able to generate a key that can only be used for transport encryption._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp --can-encrypt=transport when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Key flags: certification" then stdout contains "Key flags: transport encryption" then stdout doesn't contain "data-at-rest encryption" ~~~ ### Generate a key for signing only _Requirement: We must be able to generate a key that can only be used for signing, and can't be used for encryption._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp --cannot-encrypt --cannot-authenticate when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Key flags: certification" then stdout contains "Key flags: signing" then stdout doesn't contain "Key flags: transport encryption, data-at-rest encryption" then stdout doesn't contain "Key flags: authentication" ~~~ ### Generate a key for authentication only _Requirement: We must be able to generate a key that can only be used for authentication, and can't be used for encryption or signing._ Note that `sq` always creates a key usable for certification. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp --can-authenticate --cannot-sign --cannot-encrypt when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Key flags: certification" then stdout contains "Key flags: authentication" then stdout doesn't contain "Key flags: signing" then stdout doesn't contain "Key flags: transport encryption, data-at-rest encryption" ~~~ ### Generate a key for encryption and authentication _Requirement: We must be able to generate a key that can only be used for encryption and authentication, and can't be used for signing._ Note that `sq` always creates a key usable for certification. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp --cannot-sign when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Key flags: certification" then stdout contains "Key flags: authentication" then stdout contains "Key flags: transport encryption, data-at-rest encryption" then stdout doesn't contain "Key flags: signing" ~~~ ### Generate a key for encryption and signing _Requirement: We must be able to generate a key that can only be used for encryption and signing, and can't be used for authentication._ Note that `sq` always creates a key usable for certification. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp --cannot-authenticate when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Key flags: certification" then stdout contains "Key flags: transport encryption, data-at-rest encryption" then stdout contains "Key flags: signing" then stdout doesn't contain "Key flags: authentication" ~~~ ### Generate a key for signing and authentication _Requirement: We must be able to generate a key that can only be used for signing and authentication, and can't be used for encryption._ Note that `sq` always creates a key usable for certification. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp --cannot-encrypt when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Key flags: certification" then stdout doesn't contain "Key flags: transport encryption, data-at-rest encryption" then stdout contains "Key flags: signing" then stdout contains "Key flags: authentication" ~~~ ### Generate a key for encryption, authentication and signing _Requirement: We must be able to generate a key that can be used for encryption, authentication and signing._ Note that `sq` always creates a key usable for certification. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Key flags: certification" then stdout contains "Key flags: authentication" then stdout contains "Key flags: transport encryption, data-at-rest encryption" then stdout contains "Key flags: signing" ~~~ ### Generate an elliptic curve key _Requirement: We must be able to generate an Curve25519 key_ This is currently the default key, but we check it separately in case the default ever changes. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp --cipher-suite=cv25519 when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Public-key algo: EdDSA" then stdout contains "Public-key size: 256 bits" ~~~ ### Generate a three kilobit RSA key _Requirement: We must be able to generate a 3072-bit RSA key._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp --cipher-suite=rsa3k when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Public-key algo: RSA" then stdout contains "Public-key size: 3072 bits" ~~~ ### Generate four kilobit RSA key _Requirement: We must be able to generate a 4096-bit RSA key._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp --cipher-suite=rsa4k when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Public-key algo: RSA" then stdout contains "Public-key size: 4096 bits" ~~~ ### Generate a key with revocation certificate _Requirement: We must be able to specify where the revocation certificate is store._ When `sq` generates a key, it also generates a revocation certificate. By default, this is written to a file next to the key file. However, we need to able to specify where it goes. This scenario tests various cases. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp then file key.pgp.rev contains "Comment: Revocation certificate for" when I run sq --no-cert-store --no-key-store key generate --no-userids --output key2.pgp --rev-cert rev.pgp then file rev.pgp contains "Comment: Revocation certificate for" ~~~ ### Generate a key with default duration _Requirement: By default, generated key expire._ We generate a key with defaults, and check the key expires. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Expiration time: 20" ~~~ The check for expiration time assumes the scenario is run the 21st century, and will need to be amended in the 2090s or by time travellers running it before about the year 2000. ### Generate a key that expires at a given moment _Requirement: We must be able to generate a key that expires._ Note that the timestamp given to `--expire` is the first second when the key is no longer valid, not the last second it's valid. The inspect output is the last second of validity. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp --expiry=2038-01-19T03:14:07+00:00 when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Expiration time: 2038-01-19 03:14" when I run sq --no-cert-store --no-key-store inspect --time 2038-01-20T00:00:00+00:00 key.pgp then stdout contains "Invalid: The primary key is not live" ~~~ ### Generate a key with a given duration _Requirement: We must be able to generate a key that expires in a given time._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp --expiry=1y when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Expiration time: 20" ~~~ ### Generate a key without password _Requirement: We must be able to generate a that doesn't have a password._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Secret key: Unencrypted" ~~~ ### Generate a key with a password _Requirement: We must be able to generate a that does have a password._ Unfortunately, the `--with-password` option causes `sq` to read the password from the terminal, and that makes it hard to do in an automated test. Thus, this scenario isn't enabled, waiting for a way to feed `sq` a password as if the user typed it from a terminal. ~~~ given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp --with-password when I run sq --no-cert-store --no-key-store inspect key.pgp then stdout contains "Secret key: Encrypted" ~~~ ### Update a key by adding User IDs _Requirement: We must be able to generate a key and add User IDs to it._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store key userid add key.pgp "Juliet" "" --output new.pgp when I run sq --no-cert-store --no-key-store inspect new.pgp then stdout contains "UserID: Juliet" then stdout contains "UserID: " ~~~ ### Update a key by removing a User ID _Requirement: We must be able to generate a key with a User ID, and then strip the User ID._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid "" --output key.pgp when I run sq --no-cert-store --no-key-store key userid strip --userid "" --output new.pgp key.pgp when I run sq --no-cert-store --no-key-store inspect new.pgp then stdout doesn't contain "UserID:" ~~~ ## Certificate extraction: `sq toolbox extract-cert` This section covers extraction of certificates from keys: the `sq toolbox extract-certificate` subcommand and its variations. ### Extract certificate to the standard output _Requirement: We must be able to extract a certificate to standard output._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert key.pgp then stdout contains "-----BEGIN PGP PUBLIC KEY BLOCK-----" then stdout contains "-----END PGP PUBLIC KEY BLOCK-----" ~~~ ### Extract certificate to a file _Requirement: We must be able to extract a certificate to a named file._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --output key.pgp --userid Alice when I run sq --no-cert-store --no-key-store toolbox extract-cert key.pgp -o cert.pgp when I run sq --no-cert-store --no-key-store inspect cert.pgp then stdout contains "OpenPGP Certificate." then stdout contains "Alice" ~~~ ### Extract binary certificate to the standard output _Requirement: We must be able to extract a binary certificate to the standard output._ This scenario actually only verifies the output doesn't look like a textual certificate. It could certainly be improved. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert key.pgp --binary then stdout doesn't contain "-----BEGIN PGP PUBLIC KEY BLOCK-----" then stdout doesn't contain "-----END PGP PUBLIC KEY BLOCK-----" ~~~ ### Extract binary certificate from the standard input _Requirement: We must be able to extract a certificate from a key read from the standard input._ Unfortunately, Subplot does not currently have a way to redirect stding from a file. This scenario is inactive and here as a placeholder until Subplot learns a new trick. ~~~ given an installed sq when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert < key.pgp then stdout contains "-----BEGIN PGP PUBLIC KEY BLOCK-----" then stdout contains "-----END PGP PUBLIC KEY BLOCK-----" ~~~ # Keyring management: `sq toolbox keyring` This chapter verifies that the various subcommands to manage keyring files work: subcommands of the `sq toolbox keyring` command. ## Joining keys into a keyring: `sq toolbox keyring merge` The scenarios in this section verify that various ways of joining keys into a keyring work. ### Join two keys into a textual keyring to stdout _Requirement: we can join two keys into a keyring, and have it written to stdout._ This is for secret keys, with the output going to stdout in text form. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store key generate --userid Bob --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox keyring merge alice.pgp bob.pgp -o ring.pgp when I run sq --no-cert-store --no-key-store toolbox keyring list ring.pgp then stdout contains "Alice" then stdout contains "Bob" ~~~ ### Join two keys into a textual keyring to a named file _Requirement: we can join two keys into a keyring, and have it written to a named file._ This is for secret keys, with the output going to a file in text form. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store key generate --userid Bob --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox keyring merge alice.pgp bob.pgp -o ring.pgp then file ring.pgp contains "-----BEGIN PGP PRIVATE KEY BLOCK-----" then file ring.pgp contains "-----END PGP PRIVATE KEY BLOCK-----" when I run sq --no-cert-store --no-key-store inspect ring.pgp then stdout contains "Transferable Secret Key." then stdout contains "Alice" then stdout contains "Bob" ~~~ ### Join two keys into a binary keyring _Requirement: we can join two keys into a keyring in binary form._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store key generate --userid Bob --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox keyring merge alice.pgp bob.pgp -o ring.pgp --binary when I try to run grep PGP ring.pgp then command fails when I run sq --no-cert-store --no-key-store inspect ring.pgp then stdout contains "Transferable Secret Key." then stdout contains "Alice" then stdout contains "Bob" ~~~ ### Join two certificates into a keyring _Requirement: we can join two certificates into a keyring._ This scenario writes the keyring to a named file. We assume the writing operation is independent of the types of items in the keyring, so we don't change writing to stdout separately. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store key generate --userid Bob --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert alice.pgp -o alice-cert.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert bob.pgp -o bob-cert.pgp when I run sq --no-cert-store --no-key-store toolbox keyring merge alice-cert.pgp bob-cert.pgp -o ring.pgp when I run cat ring.pgp then stdout contains "-----BEGIN PGP PUBLIC KEY BLOCK-----" then stdout contains "-----END PGP PUBLIC KEY BLOCK-----" when I run sq --no-cert-store --no-key-store inspect ring.pgp then stdout doesn't contain "Transferable Secret Key." then stdout contains "OpenPGP Certificate." then stdout contains "Alice" then stdout contains "Bob" ~~~ ## Filter a keyring: `sq toolbox keyring filter` The scenarios in this section verify that various ways of filtering the contents of a keyring work: the `sq toolbox keyring filter` subcommand variants. ### We can extract only certificates to named file _Requirement: we can remove private keys from a keyring, leaving only certificates._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store key generate --userid Bob --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox keyring merge alice.pgp bob.pgp -o ring.pgp when I run sq --no-cert-store --no-key-store toolbox keyring filter --to-cert ring.pgp -o filtered.pgp when I run sq --no-cert-store --no-key-store inspect filtered.pgp then stdout contains "OpenPGP Certificate." then stdout doesn't contain "Transferable Secret Key." then stdout contains "Alice" then stdout contains "Bob" ~~~ ### We can filter to stdout _Requirement: we can get filter output to stdout instead of a named file._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store key generate --userid Bob --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox keyring merge alice.pgp bob.pgp -o ring.pgp when I run sq --no-cert-store --no-key-store toolbox keyring filter --to-cert ring.pgp then stdout contains "-----BEGIN PGP PUBLIC KEY BLOCK-----" then stdout contains "-----END PGP PUBLIC KEY BLOCK-----" ~~~ ### We can filter with binary output _Requirement: we can get filter output in binary form._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store key generate --userid Bob --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox keyring merge alice.pgp bob.pgp -o ring.pgp when I run sq --no-cert-store --no-key-store toolbox keyring filter --binary --to-cert ring.pgp then stdout doesn't contain "-----BEGIN PGP PUBLIC KEY BLOCK-----" ~~~ ### We can keep only matching certificates _Requirement: we can remove certificates that don't match filter criteria._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --userid Bob --output alice.pgp when I run sq --no-cert-store --no-key-store toolbox keyring filter --prune-certs --name Alice alice.pgp -o filtered.pgp when I run sq --no-cert-store --no-key-store inspect filtered.pgp then stdout contains "Alice" then stdout doesn't contain "Bob" ~~~ ### We can filter for specific user id _Requirement: we can extract only keys and certificates with a specific user id._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store key generate --userid Bob --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox keyring merge alice.pgp bob.pgp -o ring.pgp when I run sq --no-cert-store --no-key-store toolbox keyring filter --userid Alice ring.pgp -o filtered.pgp when I run sq --no-cert-store --no-key-store inspect filtered.pgp then stdout contains "Alice" then stdout doesn't contain "Bob" ~~~ ### We can filter for any of several user ids _Requirement: we can extract only keys and certificates with any of specific user ids._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store key generate --userid Bob --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox keyring merge alice.pgp bob.pgp -o ring.pgp when I run sq --no-cert-store --no-key-store toolbox keyring filter --userid Alice --userid Bob ring.pgp -o filtered.pgp when I run sq --no-cert-store --no-key-store inspect filtered.pgp then stdout contains "Alice" then stdout contains "Bob" ~~~ ### We can filter for a name _Requirement: we can extract only keys and certificates with a name as part of a user ids._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid 'Alice ' --output alice.pgp when I run sq --no-cert-store --no-key-store key generate --userid 'Bob ' --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox keyring merge alice.pgp bob.pgp -o ring.pgp when I run sq --no-cert-store --no-key-store toolbox keyring filter --name Alice ring.pgp -o filtered.pgp when I run sq --no-cert-store --no-key-store inspect filtered.pgp then stdout contains "Alice" then stdout doesn't contain "Bob" ~~~ ### We can filter for several names _Requirement: we can extract only keys and certificates with any of several names as part of the user id._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid 'Alice ' --output alice.pgp when I run sq --no-cert-store --no-key-store key generate --userid 'Bob ' --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox keyring merge alice.pgp bob.pgp -o ring.pgp when I run sq --no-cert-store --no-key-store toolbox keyring filter --name Alice --name Bob ring.pgp -o filtered.pgp when I run sq --no-cert-store --no-key-store inspect filtered.pgp then stdout contains "Alice" then stdout contains "Bob" ~~~ ### We can filter for a domain _Requirement: we can extract only keys and certificates with a name as part of a user ids._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid 'Alice ' --output alice.pgp when I run sq --no-cert-store --no-key-store key generate --userid 'Bob ' --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox keyring merge alice.pgp bob.pgp -o ring.pgp when I run sq --no-cert-store --no-key-store toolbox keyring filter --domain example.com ring.pgp -o filtered.pgp when I run sq --no-cert-store --no-key-store inspect filtered.pgp then stdout contains "Alice" then stdout doesn't contain "Bob" ~~~ ### We can filter for several domains _Requirement: we can extract only keys and certificates with any of several names as part of the user id._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid 'Alice ' --output alice.pgp when I run sq --no-cert-store --no-key-store key generate --userid 'Bob ' --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox keyring merge alice.pgp bob.pgp -o ring.pgp when I run sq --no-cert-store --no-key-store toolbox keyring filter --domain example.com --domain sequoia-pgp.org ring.pgp -o filtered.pgp when I run sq --no-cert-store --no-key-store inspect filtered.pgp then stdout contains "Alice" then stdout contains "Bob" ~~~ ## Listing contents of a keyring: `sq toolbox keyring list` The scenarios in this section verify the contents of a keyring can be listed. ### Choose too-new output major version for keyring listing _Requirement: If we ask for an unsupported major output version, we get an error._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I try to run sq --output-version=9999 keyring list alice.pgp then command fails when I try to run env SQ_OUTPUT_VERSION=9999 sq toolbox keyring list alice.pgp then command fails ~~~ ### Choose too-new output minor version for keyring listing _Requirement: If we ask for an unsupported output minor version, we get an error._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I try to run sq --output-version=0.9999 keyring list alice.pgp then command fails ~~~ ### Choose too-new output patch version for keyring listing _Requirement: If we ask for an unsupported output patch version, we get an error._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I try to run sq --output-version=0.0.9999 keyring list alice.pgp then command fails ~~~ ### List keys in a keyring _Requirement: we can list the keys in a keyring._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store key generate --userid Bob --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox keyring merge alice.pgp bob.pgp -o ring.pgp when I run sq --no-cert-store --no-key-store toolbox keyring list ring.pgp then stdout contains "Alice" then stdout contains "Bob" ~~~ ### List, as JSON, keys in a keyring _Requirement: we can list the keys in a keyring in a JSON format._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --userid '' --output alice.pgp when I run sq --no-cert-store --no-key-store inspect alice.pgp then I remember the fingerprint as ALICE_FINGERPRINT when I run sq --no-cert-store --no-key-store toolbox keyring merge alice.pgp -o ring.pgp when I run sq --no-cert-store --no-key-store --output-format=json toolbox keyring list ring.pgp then stdout, as JSON, matches pattern keyring-list-pattern.json when I run env SQ_OUTPUT_FORMAT=json sq toolbox keyring list ring.pgp then stdout, as JSON, matches pattern keyring-list-pattern.json when I run env SQ_OUTPUT_FORMAT=human-readable sq --output-format=json toolbox keyring list ring.pgp then stdout, as JSON, matches pattern keyring-list-pattern.json ~~~ ~~~{#keyring-list-pattern.json .file .json .numberLines} { "sq_output_version": { "major": 0, "minor": 0, "patch": 0 }, "keys": [ { "fingerprint": "${ALICE_FINGERPRINT}", "primary_userid": "Alice", "userids": [""] } ] } ~~~ ### List keys in a key file _Requirement: we can list the keys in a key file._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store toolbox keyring list alice.pgp then stdout contains "Alice" then stdout doesn't contain "Bob" ~~~ ### List all user ids in a key file _Requirement: we can list all user ids._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --userid Bob --output alice.pgp when I run sq --no-cert-store --no-key-store toolbox keyring list alice.pgp --all-userids then stdout contains "Alice" then stdout contains "Bob" ~~~ ### List keys in keyring read from stdin _Requirement: we can list keys in a keyring that we read from stdin._ This isn't implemented yet, because Subplot needs to add support for redirecting stdin to come from a file first. ## Split a keyring: `sq toolbox keyring split` The scenarios in this section verify that splitting a keyring into individual files, one per key: the `sq toolbox keyring split` subcommand. Or rather, there will be such scenarios here when Subplot provides tools for dealing with randomly named files. Until then, this section is a placeholder. ~~~ given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store key generate --userid Bob --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox keyring merge alice.pgp bob.pgp -o ring.pgp when I run sq --no-cert-store --no-key-store toolbox keyring split ring.pgp then the resulting files match alice,pgp and bob.pgp ~~~ # Encryption and decryption: `sq encrypt` and `sq decrypt` This chapter has scenarios for verifying that encryption and decryption work. The overall approach is to do round trips: we encrypt, then decrypt, and is the result is identical to the input, all good. ## Encrypt to stdout as ASCII armored _Requirement: We must be able to encrypt a file using a certificate, with output going to stdout. We also verify that the encrypted output doesn't contain the message in cleartext, just in case. ~~~scenario given an installed sq given file hello.txt when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert -o cert.pgp key.pgp when I run sq --no-cert-store --no-key-store encrypt --recipient-file cert.pgp hello.txt then stdout contains "-----BEGIN PGP MESSAGE-----" then stdout doesn't contain "hello, world" ~~~ ## Encrypt to stdout as binary _Requirement: We must be able to encrypt a file using a certificate, with output going to stdout. We also verify that the encrypted output doesn't contain the message in cleartext, just in case. ~~~scenario given an installed sq given file hello.txt when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert -o cert.pgp key.pgp when I run sq --no-cert-store --no-key-store encrypt --binary --recipient-file cert.pgp hello.txt then stdout doesn't contain "-----BEGIN PGP MESSAGE-----" then stdout doesn't contain "hello, world" ~~~ ## Encrypt and decrypt using asymmetric encryption _Requirement: We must be able to encrypt a file using a certificate, and then decrypt it using the corresponding key._ This scenario creates a plain text file, generates a key, encrypts and then decrypts the file. The resulting output must be identical to the original plain text input file. This is a very simplistic scenario and does not even try to test harder cases (binary files, very large files, etc). ~~~scenario given an installed sq given file hello.txt when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert -o cert.pgp key.pgp when I run sq --no-cert-store --no-key-store encrypt -o x.pgp --recipient-file cert.pgp hello.txt when I run sq --no-cert-store --no-key-store decrypt -o output.txt --recipient-file key.pgp x.pgp then files hello.txt and output.txt match ~~~ ## Encrypt for multiple recipients _Requirement: We must be able to encrypt a message for multiple recipients at a time._ ~~~scenario given an installed sq given file hello.txt when I run sq --no-cert-store --no-key-store key generate --no-userids --output alice.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert -o alice-cert.pgp alice.pgp when I run sq --no-cert-store --no-key-store key generate --no-userids --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert -o bob-cert.pgp bob.pgp when I run sq --no-cert-store --no-key-store encrypt --recipient-file alice-cert.pgp --recipient-file bob-cert.pgp hello.txt -o x.pgp when I run sq --no-cert-store --no-key-store decrypt --recipient-file alice.pgp -o alice.txt x.pgp then files hello.txt and alice.txt match when I run sq --no-cert-store --no-key-store decrypt --recipient-file bob.pgp -o bob.txt x.pgp then files hello.txt and bob.txt match ~~~ ## Encrypt and sign at the same time _Requirement: We must be able to sign and encrypt a message at the same time._ ~~~scenario given an installed sq given file hello.txt when I run sq --no-cert-store --no-key-store key generate --no-userids --output alice.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert -o alice-cert.pgp alice.pgp when I run sq --no-cert-store --no-key-store encrypt --recipient-file alice-cert.pgp --signer-file alice.pgp hello.txt -o x.pgp when I run sq --no-cert-store --no-key-store decrypt --recipient-file alice.pgp -o alice.txt x.pgp --signer-file alice-cert.pgp then files hello.txt and alice.txt match ~~~ ## Detect bad signature when decrypting _Requirement: When decrypting a message, if a signature check fails, there should be no output._ ~~~scenario given an installed sq given file hello.txt given file empty when I run sq --no-cert-store --no-key-store key generate --no-userids --output alice.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert -o alice-cert.pgp alice.pgp when I run sq --no-cert-store --no-key-store key generate --no-userids --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert -o bob-cert.pgp bob.pgp when I run sq --no-cert-store --no-key-store encrypt --recipient-file alice-cert.pgp --signer-file alice.pgp hello.txt -o x.pgp when I try to run sq decrypt --recipient-file alice.pgp -o alice.txt x.pgp --signer-file bob-cert.pgp then exit code is 1 then files alice.txt and empty match ~~~ # Certify user identities: `sq pki certify` The scenarios in this chapter verify the certification functionality: the subcommand `sq certify` in its various variations. ## Certify an identity as ASCII armor _Requirement: We can certify a user identity on a key._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert alice.pgp -o alice-cert.pgp when I run sq --no-cert-store --no-key-store key generate --userid Bob --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert bob.pgp -o bob-cert.pgp when I run sq --no-cert-store --no-key-store inspect bob-cert.pgp then stdout doesn't contain "Certifications:" when I run sq --no-cert-store --no-key-store pki certify alice.pgp bob-cert.pgp Bob -o cert.pgp then file cert.pgp contains "-----BEGIN PGP PUBLIC KEY BLOCK-----" then file cert.pgp contains "-----END PGP PUBLIC KEY BLOCK-----" when I run sq --no-cert-store --no-key-store inspect cert.pgp then stdout contains "Certifications: 1," ~~~ ## Certify an identity as binary _Requirement: We can certify a user identity on a key._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert alice.pgp -o alice-cert.pgp when I run sq --no-cert-store --no-key-store key generate --userid Bob --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert bob.pgp -o bob-cert.pgp when I run sq --no-cert-store --no-key-store inspect bob-cert.pgp then stdout doesn't contain "Certifications:" when I run sq --no-cert-store --no-key-store pki certify alice.pgp bob-cert.pgp Bob -o cert.pgp --binary when I run cat cert.pgp then stdout doesn't contain "-----BEGIN PGP PUBLIC KEY BLOCK-----" when I run sq --no-cert-store --no-key-store inspect cert.pgp then stdout contains "Certifications: 1," ~~~ ## Certify an identity matched by email address _Requirement: We can certify a user identity on a cert identified by email address._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid "" --output alice.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert alice.pgp -o alice-cert.pgp when I run sq --no-cert-store --no-key-store key generate --userid "" --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert bob.pgp -o bob-cert.pgp when I run sq --no-cert-store --no-key-store pki certify alice.pgp bob-cert.pgp --email bob@example.org -o cert.pgp when I run sq --no-cert-store --no-key-store inspect cert.pgp then stdout contains "Certifications: 1," ~~~ ## Certify multiple identities matched by email address _Requirement: We can certify multiple user identities on a cert identified by email address._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid "" --output alice.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert alice.pgp -o alice-cert.pgp when I run sq --no-cert-store --no-key-store key generate --userid "" --userid "Bob " --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert bob.pgp -o bob-cert.pgp when I run sq --no-cert-store --no-key-store pki certify alice.pgp bob-cert.pgp --email bob@example.org -o cert.pgp when I run sq --no-cert-store --no-key-store key userid strip --userid "" -o cert.0.pgp cert.pgp when I run sq --no-cert-store --no-key-store inspect cert.0.pgp then stdout contains "Certifications: 1," when I run sq --no-cert-store --no-key-store key userid strip --userid "Bob " -o cert.1.pgp cert.pgp when I run sq --no-cert-store --no-key-store inspect cert.1.pgp then stdout contains "Certifications: 1," ~~~ ## Certify an identity that is not self-signed _Requirement: We can certify a user identity on a cert, even if that user identity doesn't exist on that cert, and consequently has no self-signature._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert alice.pgp -o alice-cert.pgp when I run sq --no-cert-store --no-key-store key generate --userid Bob --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert bob.pgp -o bob-cert.pgp when I run sq --no-cert-store --no-key-store inspect bob-cert.pgp then stdout doesn't contain "Certifications:" when I run sq --no-cert-store --no-key-store pki certify --add-userid alice.pgp bob-cert.pgp "My friend Bob" -o cert.pgp when I run sq --no-cert-store --no-key-store inspect cert.pgp then stdout contains "My friend Bob" then stdout contains "Certifications: 1," ~~~ ## Certify an email identity that is not self-signed _Requirement: We can certify an email on a cert, even if that email address doesn't exist on that cert, and consequently has no self-signature._ ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert alice.pgp -o alice-cert.pgp when I run sq --no-cert-store --no-key-store key generate --userid Bob --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert bob.pgp -o bob-cert.pgp when I run sq --no-cert-store --no-key-store pki certify --add-userid alice.pgp bob-cert.pgp --email "bob@example.org" -o cert.pgp when I run sq --no-cert-store --no-key-store inspect cert.pgp then stdout contains "" then stdout contains "Certifications: 1," ~~~ # Sign a document and verify the signature: `sq sign` and `sq verify` This chapter verifies that digital signatures work in `sq`. Like with encryption, the verification is based on round trips: we create a signature, and that it matches the signed data. We break this into a number simple cases. ## Create signature to stdout in ASCII armor _Requirement: We can create a signature and have it written to stdout in ASCII armor form._ ~~~scenario given an installed sq given file hello.txt when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store sign --signer-file key.pgp hello.txt then stdout contains "-----BEGIN PGP MESSAGE-----" then stdout contains "-----END PGP MESSAGE-----" ~~~ ## Create signature to stdout in binary _Requirement: We can create a signature and have it written to stdout in binary form._ ~~~scenario given an installed sq given file hello.txt when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store sign --signer-file key.pgp hello.txt --binary then stdout doesn't contain "-----BEGIN PGP MESSAGE-----" then stdout doesn't contain "-----END PGP MESSAGE-----" ~~~ ## Create signature to named file _Requirement: We can create a signature and have it written to a named file._ ~~~scenario given an installed sq given file hello.txt when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store sign --signer-file key.pgp hello.txt -o signed.txt then file signed.txt contains "-----BEGIN PGP MESSAGE-----" then file signed.txt contains "-----END PGP MESSAGE-----" ~~~ ## Signed file can be verified _Requirement: We can sign a file and verify the signature._ ~~~scenario given an installed sq given file hello.txt when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert key.pgp -o cert.pgp when I run sq --no-cert-store --no-key-store sign --signer-file key.pgp hello.txt -o signed.txt when I run sq --no-cert-store --no-key-store verify --signer-file cert.pgp signed.txt then stdout contains "hello, world" ~~~ ## File is signed with all required keys _Requirement: We can verify that a file is signed by all required keys._ We verify this by signing a file twice, and verifying there are two signatures. We also verify that if there is only one signature, it's not enough, when we need two. ~~~scenario given an installed sq given file hello.txt when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert alice.pgp -o alice-cert.pgp when I run sq --no-cert-store --no-key-store key generate --userid Bob --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert bob.pgp -o bob-cert.pgp when I run sq --no-cert-store --no-key-store sign --signer-file alice.pgp hello.txt -o signed1.txt when I try to run sq verify --signer-file alice-cert.pgp --signer-file bob-cert.pgp --signatures=2 signed1.txt then exit code is 1 when I run sq --no-cert-store --no-key-store sign --append --signer-file bob.pgp signed1.txt -o signed2.txt when I run sq --no-cert-store --no-key-store verify --signer-file alice-cert.pgp --signer-file bob-cert.pgp --signatures=1 signed2.txt then stdout contains "hello, world" when I run sq --no-cert-store --no-key-store verify --signer-file alice-cert.pgp --signer-file bob-cert.pgp --signatures=2 signed2.txt then stdout contains "hello, world" ~~~ ## Signed file cannot be verified if it has been modified _Requirement: We can sign a file and verifying the signature fails if the signed file has been modified._ We modify the signed file by removing the third line of it. The file starts with a line containing "-----BEGIN PGP MESSAGE-----" and then an empty line, and the third line is actual data. If we delete that, the file by definition can't be valid anymore. ~~~scenario given an installed sq given file hello.txt given file sed-in-place when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert key.pgp -o cert.pgp when I run sq --no-cert-store --no-key-store sign --signer-file key.pgp hello.txt -o signed.txt when I run bash sed-in-place 3d signed.txt when I try to run sq verify --signer-file cert.pgp signed.txt then command fails ~~~ ~~~{#sed-in-place .file .sh} #!/bin/sh set -eu tmp="$(mktemp)" trap 'rm -f "$tmp"' EXIT sed "$1" "$2" > "$tmp" cat "$tmp" > "$2" ~~~ ## Create cleartext signature _Requirement: We can create a signature such that the signed data is included in a readable form._ ~~~scenario given an installed sq given file hello.txt when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert key.pgp -o cert.pgp when I run sq --no-cert-store --no-key-store sign --cleartext-signature --signer-file key.pgp hello.txt -o signed.txt then file signed.txt contains "-----BEGIN PGP SIGNED MESSAGE-----" then file signed.txt contains "hello, world" then file signed.txt contains "-----END PGP SIGNATURE-----" when I run sq --no-cert-store --no-key-store verify --signer-file cert.pgp signed.txt then stdout contains "hello, world" ~~~ ## Cleartext signature cannot be verified if it has been modified _Requirement: If a cleartext signature is modified, it can't be verified._ ~~~scenario given an installed sq given file hello.txt given file sed-in-place when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert key.pgp -o cert.pgp when I run sq --no-cert-store --no-key-store sign --cleartext-signature --signer-file key.pgp hello.txt -o signed.txt when I run bash sed-in-place s/hello/HELLO/ signed.txt when I try to run sq verify --signer-file cert.pgp signed.txt then exit code is 1 ~~~ ## Create a detached signature _Requirement: We can create a signature that is doesn't include the data it signs._ ~~~scenario given an installed sq given file hello.txt when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert key.pgp -o cert.pgp when I run sq --no-cert-store --no-key-store sign --detached --signer-file key.pgp hello.txt -o sig.txt then file sig.txt contains "-----BEGIN PGP SIGNATURE-----" then file sig.txt contains "-----END PGP SIGNATURE-----" when I run sq --no-cert-store --no-key-store verify --detached=sig.txt --signer-file=cert.pgp hello.txt then stdout doesn't contain "hello, world" then exit code is 0 ~~~ ## Detached signature cannot be verified if the data has been modified _Requirement: If the file that is signed using a detached signature is modified, the signature can't be verified._ ~~~scenario given an installed sq given file hello.txt given file sed-in-place when I run sq --no-cert-store --no-key-store key generate --no-userids --output key.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert key.pgp -o cert.pgp when I run sq --no-cert-store --no-key-store sign --detached --signer-file key.pgp hello.txt -o sig.txt when I run bash sed-in-place s/hello/HELLO/ hello.txt when I try to run sq verify --detached=sig.txt --signer-file=cert.pgp hello.txt then exit code is 1 ~~~ ## Append signature to already signed message _Requirement: We must be able to add a signature to an already signed message._ ~~~scenario given an installed sq given file hello.txt when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert alice.pgp -o alice-cert.pgp when I run sq --no-cert-store --no-key-store key generate --userid Bob --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert bob.pgp -o bob-cert.pgp when I run sq --no-cert-store --no-key-store sign --signer-file alice.pgp hello.txt -o signed1.txt when I run sq --no-cert-store --no-key-store sign --signer-file bob.pgp --append signed1.txt -o signed2.txt when I run sq --no-cert-store --no-key-store verify signed2.txt --signer-file alice-cert.pgp --signer-file bob-cert.pgp then stdout contains "hello, world" then stderr matches regex 2.good signatures ~~~ ## Merge signed files _Requirement: We must be able to merge signatures of a file signed twice separately._ ~~~scenario given an installed sq given file hello.txt when I run sq --no-cert-store --no-key-store key generate --userid Alice --output alice.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert alice.pgp -o alice-cert.pgp when I run sq --no-cert-store --no-key-store key generate --userid Bob --output bob.pgp when I run sq --no-cert-store --no-key-store toolbox extract-cert bob.pgp -o bob-cert.pgp when I run sq --no-cert-store --no-key-store sign --signer-file alice.pgp hello.txt -o signed1.txt when I run sq --no-cert-store --no-key-store sign --signer-file bob.pgp hello.txt -o signed2.txt when I run sq --no-cert-store --no-key-store sign --merge=signed2.txt signed1.txt -o merged.txt when I run sq --no-cert-store --no-key-store verify merged.txt --signer-file alice-cert.pgp --signer-file bob-cert.pgp then stdout contains "hello, world" then stderr matches regex 2.good signatures ~~~ # ASCII Armor data representation: `sq toolbox armor` and `sq toolbox dearmor` The scenarios in this chapter verify that `sq` can convert data into the "ASCII Armor" representation and back. ## Convert data file to armored format to stdout _Requirement: We must be able to convert a file to armored format to stdout._ ~~~scenario given an installed sq given file hello.txt when I run sq --no-cert-store --no-key-store toolbox armor hello.txt then stdout contains "-----BEGIN PGP ARMORED FILE-----" then stdout contains "-----END PGP ARMORED FILE-----" ~~~ ## Convert data file to armored format to file _Requirement: We must be able to convert a file to armored format to a named file._ ~~~scenario given an installed sq given file hello.txt given file hello.asc when I run sq --no-cert-store --no-key-store toolbox armor hello.txt -o hello.out then files hello.asc and hello.out match ~~~ ## Convert data file to armored format with desired label _Requirement: We must be able to convert a file to armored format with the label we choose._ ~~~scenario given an installed sq given file hello.txt when I run sq --no-cert-store --no-key-store toolbox armor hello.txt --label auto then stdout contains "-----BEGIN PGP ARMORED FILE-----" when I run sq --no-cert-store --no-key-store toolbox armor hello.txt --label message then stdout contains "-----BEGIN PGP MESSAGE-----" when I run sq --no-cert-store --no-key-store toolbox armor hello.txt --label cert then stdout contains "-----BEGIN PGP PUBLIC KEY BLOCK-----" when I run sq --no-cert-store --no-key-store toolbox armor hello.txt --label key then stdout contains "-----BEGIN PGP PRIVATE KEY BLOCK-----" when I run sq --no-cert-store --no-key-store toolbox armor hello.txt --label sig then stdout contains "-----BEGIN PGP SIGNATURE-----" when I run sq --no-cert-store --no-key-store toolbox armor hello.txt --label file then stdout contains "-----BEGIN PGP ARMORED FILE-----" ~~~ ## Convert data file from armored format to stdout _Requirement: We must be able to convert a file from armored format to stdout._ ~~~scenario given an installed sq given file hello.asc when I run sq --no-cert-store --no-key-store toolbox dearmor hello.asc then stdout contains "hello, world" ~~~ ## Convert data file from armored format to file _Requirement: We must be able to convert a file from armored format to a named file._ ~~~scenario given an installed sq given file hello.txt given file hello.asc when I run sq --no-cert-store --no-key-store toolbox dearmor hello.asc -o hello.out then files hello.txt and hello.out match ~~~ ## Armor round trip _Requirement: We must be able to convert data to armored format and back._ ~~~scenario given an installed sq given file hello.txt when I run sq --no-cert-store --no-key-store toolbox armor hello.txt -o hello.tmp when I run sq --no-cert-store --no-key-store toolbox dearmor hello.tmp -o hello.out then files hello.txt and hello.out match ~~~ # Web key directory (WKD) support [Web Key Directory]: https://wiki.gnupg.org/WKD [Internet Draft 14 for WKD]: https://www.ietf.org/archive/id/draft-koch-openpgp-webkey-service-14.html [Web Key Directory][] (WKD) specifies how to locate a certificate for a given email address by constructing HTTPS URLs from the email address. It is specified in [Internet Draft 14 for WKD][]. The two URLs are called the "advanced" and "direct" URLs. They are the same, except the advanced one uses a subdomain, and an a subdirectory named after the domain. This allows the web server where the certificates are published to be operated separately from any other services for the parent domain. The advanced URL is the preferred URL. That is why `wkd wkd url` prints that, and the other URL is a longer command. ## Advanced WKD URL _Requirement: Output the advanced URL for an email address._ An advanced URL uses the "openpgpkey" subdomain of the domain in the email address, and a subdirectory named after the email domain. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store network wkd url me@example.com then stdout contains "https://openpgpkey.example.com/.well-known/openpgpkey/example.com/hu/s8y7oh5xrdpu9psba3i5ntk64ohouhga?l=me" when I run sq --no-cert-store --no-key-store --output-format=json network wkd url me@example.com then stdout, as JSON, matches pattern wkd.json ~~~ ~~~{#wkd.json .file .json .numberLines} { "sq_output_version": { "major": 0, "minor": 0, "patch": 0 }, "advanced_url": "https://openpgpkey.example.com/.well-known/openpgpkey/example.com/hu/s8y7oh5xrdpu9psba3i5ntk64ohouhga?l=me", "direct_url": "https://example.com/.well-known/openpgpkey/hu/s8y7oh5xrdpu9psba3i5ntk64ohouhga?l=me" } ~~~ ## Direct WKD URL _Requirement: Output the direct URL for an email address._ The direct URL lacks the subdomain and subdirectory of an advanced one. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store network wkd direct-url me@example.com then stdout contains "https://example.com/.well-known/openpgpkey/hu/s8y7oh5xrdpu9psba3i5ntk64ohouhga?l=me" when I run sq --no-cert-store --no-key-store --output-format=json network wkd url me@example.com then stdout, as JSON, matches pattern wkd.json ~~~ ## Email local part in original form in WKD URL _Requirement: The WKD URL has the local part of an email address as given in the input, just in case it matters to the server._ An advanced URL uses the "openpgpkey" subdomain of the domain in the email address, and a subdirectory named after the email domain. ~~~scenario given an installed sq when I run sq --no-cert-store --no-key-store network wkd url Joe.Doe@Example.ORG then stdout contains "https://openpgpkey.example.org/.well-known/openpgpkey/example.org/hu/iy9q119eutrkn8s1mk4r39qejnbu3n5q?l=Joe.Doe" when I run sq --no-cert-store --no-key-store network wkd direct-url Joe.Doe@Example.ORG then stdout contains "https://example.org/.well-known/openpgpkey/hu/iy9q119eutrkn8s1mk4r39qejnbu3n5q?l=Joe.Doe" ~~~ # Test data file We use this file as an input file in the tests. It is a very short file, and a text file, but this is enough for the current set of requirements and scenarios. ~~~{#hello.txt .file} hello, world ~~~ This is the same content, but in ASCII armored representation. ~~~{#hello.asc .file} -----BEGIN PGP ARMORED FILE----- aGVsbG8sIHdvcmxkCg== =FOuc -----END PGP ARMORED FILE----- ~~~ This is an empty file. ~~~{#empty .file add-newline=no} ~~~ sequoia-sq-0.37.0/sq.subplot000064400000000000000000000004311046102023000140350ustar 00000000000000title: "Sequoia-PGP sq" subtitle: "integration tests, requirements, acceptance criteria" authors: - "The Sequoia-PGP project" markdowns: - sq-subplot.md bindings: - subplot/sq-subplot.yaml - lib/files.yaml - lib/runcmd.yaml impls: rust: - subplot/sq-subplot.rs classes: - json sequoia-sq-0.37.0/src/cli/autocrypt.rs000064400000000000000000000121071046102023000157410ustar 00000000000000use std::path::PathBuf; use clap::{ValueEnum, Args, Parser, Subcommand}; use super::types::ClapData; use super::types::FileOrStdin; use super::types::FileOrStdout; use super::types::SessionKey; #[derive(Parser, Debug)] #[clap( name = "autocrypt", about = "Communicate certificates using Autocrypt", long_about = "Communicate certificates using Autocrypt Autocrypt is a standard for mail user agents to provide convenient end-to-end encryption of emails. This subcommand provides a limited way to produce and consume headers that are used by Autocrypt to communicate certificates between clients. See . ", subcommand_required = true, arg_required_else_help = true )] pub struct Command { #[clap(subcommand)] pub subcommand: Subcommands, } #[derive(Debug, Subcommand)] pub enum Subcommands { Import(ImportCommand), Decode(DecodeCommand), EncodeSender(EncodeSenderCommand), } #[derive(Debug, Args)] #[clap( about = "Import Autocrypt-encoded certificates", long_about = "Import Autocrypt-encoded certificates Given a mail containing autocrypt headers (or an key-gossip headers), this command extracts and imports the certificates encoded within it. ", after_help = "EXAMPLES: # Imports all certificates from a mail $ sq autocrypt import autocrypt.eml " )] pub struct ImportCommand { #[clap( long = "recipient-file", value_name = "KEY_FILE", help = "Decrypt the message using the key in KEY_FILE", )] pub secret_key_file: Vec, #[clap( long = "session-key", value_name = "SESSION-KEY", help = "Decrypt an encrypted message using SESSION-KEY", )] pub session_key: Vec, #[clap( default_value_t = FileOrStdin::default(), help = FileOrStdin::HELP_OPTIONAL, value_name = FileOrStdin::VALUE_NAME, )] pub input: FileOrStdin, } #[derive(Debug, Args)] #[clap( about = "Read Autocrypt-encoded certificates", long_about = "Read Autocrypt-encoded certificates Given an autocrypt header (or an key-gossip header), this command extracts the certificate encoded within it. The converse operation is `sq autocrypt encode-sender`. ", after_help = "EXAMPLES: # Extract all certificates from a mail $ sq autocrypt decode autocrypt.eml " )] pub struct DecodeCommand { #[clap( default_value_t = FileOrStdin::default(), help = FileOrStdin::HELP_OPTIONAL, value_name = FileOrStdin::VALUE_NAME, )] pub input: FileOrStdin, #[clap( default_value_t = FileOrStdout::default(), help = FileOrStdout::HELP_OPTIONAL, long, short, value_name = FileOrStdout::VALUE_NAME, )] pub output: FileOrStdout, #[clap(short = 'B', long, help = "Emit binary data")] pub binary: bool, } //#[derive(Subcommand)] #[derive(Debug, Args)] #[clap( name = "encode-sender", about = "Encode a certificate into an Autocrypt header", long_about = "Encode a certificate into an Autocrypt header A certificate can be encoded and included in a header of an email message. This command encodes the certificate, adds the senders email address (which must match the one used in the `From` header), and the senders `prefer-encrypt` state (see the Autocrypt spec for more information). The converse operation is `sq autocrypt decode`. ", after_help = "EXAMPLES: # Encodes a certificate $ sq autocrypt encode-sender juliet.pgp # Encodes a certificate with an explicit sender address $ sq autocrypt encode-sender --email juliet@example.org juliet.pgp # Encodes a certificate while indicating the willingness to encrypt $ sq autocrypt encode-sender --prefer-encrypt mutual juliet.pgp " )] pub struct EncodeSenderCommand { #[clap( default_value_t = FileOrStdin::default(), help = FileOrStdin::HELP_OPTIONAL, value_name = FileOrStdin::VALUE_NAME, )] pub input: FileOrStdin, #[clap( default_value_t = FileOrStdout::default(), help = FileOrStdout::HELP_OPTIONAL, long, short, value_name = FileOrStdout::VALUE_NAME, )] pub output: FileOrStdout, // TODO the help message looks like "primary userid" might be the default // email. clarify #[clap( long = "email", value_name = "ADDRESS", help = "Set the address [default: primary userid]" )] pub address: Option, #[clap( long = "prefer-encrypt", value_name = "PREFER-ENCRYPT", default_value_t = PreferEncryptArgs::NoPreference, help = "Set the prefer-encrypt attribute", value_enum, )] pub prefer_encrypt: PreferEncryptArgs, } #[derive(ValueEnum, Debug, Clone)] pub enum PreferEncryptArgs { #[clap(name = "nopreference")] NoPreference, Mutual, } impl std::fmt::Display for PreferEncryptArgs { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { PreferEncryptArgs::Mutual => write!(f, "mutual"), PreferEncryptArgs::NoPreference => write!(f, "nopreference"), } } } sequoia-sq-0.37.0/src/cli/cert/export.rs000064400000000000000000000115531046102023000161710ustar 00000000000000use clap::Parser; use sequoia_openpgp as openpgp; use openpgp::KeyHandle; use crate::cli::examples; use examples::Action; use examples::Actions; use examples::Example; const EXAMPLES: Actions = Actions { actions: &[ Action::Example(Example { comment: "Export all certificates.", command: &[ "sq", "cert", "export", "--all", ], }), Action::Example(Example { comment: "\ Export certificates with a matching User ID packet. The binding \ signatures are checked, but the User IDs are not authenticated. \ Note: this check is case sensitive.", command: &[ "sq", "cert", "export", "--userid", "Alice ", ], }), Action::Example(Example { comment: "\ Export certificates with a User ID containing the email address. \ The binding signatures are checked, but the User IDs are not \ authenticated. Note: this check is case insensitive.", command: &[ "sq", "cert", "export", "--email", "alice@example.org", ], }), Action::Example(Example { comment: "\ Export certificates where the certificate (i.e., the primary key) \ has the specified Key ID.", command: &[ "sq", "cert", "export", "--cert", "6F0073F60FD0CBF0", ], }), Action::Example(Example { comment: "\ Export certificates where the primary key or a subkey matches the \ specified Key ID.", command: &[ "sq", "cert", "export", "--key", "24F3955B0B8DECC8", ], }), Action::Example(Example { comment: "\ Export certificates that contain a User ID with *either* (not both!) \ email address. Note: this check is case insensitive.", command: &[ "sq", "cert", "export", "--email", "alice@example.org", "--email", "bob@example.org", ], }), ], }; test_examples!(sq_cert_export, EXAMPLES); #[derive(Parser, Debug)] #[clap( name = "export", about = "Export certificates from the local certificate store", long_about = "Export certificates from the local certificate store If multiple predicates are specified a certificate is returned if at least one of them matches. This does not check the authenticity of the certificates in anyway. Before using the certificates, be sure to validate and authenticate them. When matching on subkeys or User IDs, the component must have a valid self signature according to the policy. This is not the case when matching the certificate's key handle using `--cert` or when exporting all certificates. Fails if search criteria are specified and none of them matches any certificates. Note: this means if the certificate store is empty and no search criteria are specified, then this will return success.", after_help = EXAMPLES, )] pub struct Command { #[clap( short = 'B', long, help = "Emit binary data", )] pub binary: bool, #[clap( long, conflicts_with_all = [ "cert", "key", "userid", "grep", "email", "domain", "query", ], help = "Export all certificates", )] pub all: bool, #[clap( long = "cert", value_name = "FINGERPRINT|KEYID", help = "Return certificates that \ have the specified fingerprint or key ID", )] pub cert: Vec, #[clap( long = "key", value_name = "FINGERPRINT|KEYID", help = "Return certificates where the primary key or \ a subkey has the specified fingerprint or key ID", )] pub key: Vec, #[clap( long = "userid", value_name = "USERID", help = "Return certificates that have a User ID that \ matches exactly, including case", )] pub userid: Vec, #[clap( long = "grep", value_name = "PATTERN", help = "Return certificates that have a User ID that \ contains the string, case insensitively", )] pub grep: Vec, #[clap( long = "email", value_name = "EMAIL", help = "Return certificates that have a User ID with \ the specified email address, case insensitively", )] pub email: Vec, #[clap( long = "domain", value_name = "DOMAIN", help = "Return certificates that have a User ID with \ an email address from the specified domain", )] pub domain: Vec, #[clap( value_name = "QUERY", help = "Return certificates matching QUERY. \ This may be a subkey fingerprint or key ID, \ an email address, or an User ID fragment.", )] pub query: Vec, } sequoia-sq-0.37.0/src/cli/cert/import.rs000064400000000000000000000014211046102023000161530ustar 00000000000000use std::path::PathBuf; use clap::Parser; use crate::cli::examples; use examples::Action; use examples::Actions; use examples::Example; const EXAMPLES: Actions = Actions { actions: &[ Action::Example(Example { comment: "Import a certificate.", command: &[ "sq", "cert", "import", "juliet.pgp", ], }), ] }; test_examples!(sq_cert_import, EXAMPLES); #[derive(Parser, Debug)] #[clap( name = "import", about = "Import certificates into the local certificate store", long_about = "Import certificates into the local certificate store ", after_help = EXAMPLES, )] pub struct Command { #[clap(value_name = "FILE", help = "Read from FILE or stdin if omitted")] pub input: Vec, } sequoia-sq-0.37.0/src/cli/cert/lint.rs000064400000000000000000000100621046102023000156100ustar 00000000000000//! Command-line parser for `sq cert lint`. use clap::Args; use clap::ArgGroup; use sequoia_openpgp as openpgp; use openpgp::KeyHandle; use crate::cli::types::ClapData; use crate::cli::types::FileOrStdin; use crate::cli::types::FileOrStdout; /// Checks for and optionally repairs OpenPGP certificates that use /// SHA-1. #[derive(Debug, Args)] #[clap( about = "Check certificates for issues", long_about = "Check certificates for issues `sq cert lint` checks the supplied certificates for the following SHA-1-related issues: - Whether a certificate revocation uses SHA-1. - Whether the current self signature for a non-revoked User ID uses SHA-1. - Whether the current subkey binding signature for a non-revoked, live subkey uses SHA-1. - Whether a primary key binding signature (\"backsig\") for a non-revoked, live subkey uses SHA-1. Diagnostics are printed to stderr. At the end, some statistics are shown. This is useful when examining a keyring. If `--fix` is specified and at least one issue could be fixed, the fixed certificates are printed to stdout. This tool does not currently support smart cards. But, if only the subkeys are on a smart card, this tool may still be able to partially repair the certificate. In particular, it will be able to fix any issues with User ID self signatures and subkey binding signatures for encryption-capable subkeys, but it will not be able to generate new primary key binding signatures for any signing-capable subkeys. ", after_help = "EXIT STATUS: If `--fix` is not specified: 2 if any issues were found, 1 if not issues were found, but there were errors reading the input, 0 if there were no issues. If `--fix` is specified: 3 if any issues could not be fixed, 1 if not issues were found, but there were errors reading the input, 0 if all issues were fixed or there were no issues. EXAMPLES: # To gather statistics, simply run: $ sq cert lint keyring.pgp # To fix a key: $ gpg --export-secret-keys FPR \\ | sq cert lint --fix -p passw0rd -p password123 \\ | gpg --import # To get a list of keys with issues: $ sq cert lint --list-keys keyring.pgp \\ | while read FPR; do something; done " )] #[clap(group(ArgGroup::new("cert_input").args(&["cert_file", "cert"]).required(true)))] pub struct Command { /// Quiet; does not output any diagnostics. #[arg(short, long)] pub quiet: bool, /// Attempts to fix certificates, when possible. #[arg(short = 'F', long)] pub fix: bool, /// When fixing a certificate, the fixed certificate is exported /// without any secret key material. Using this switch causes any /// secret key material to also be exported. #[arg(short, long)] pub export_secret_keys: bool, /// If set, outputs a list of fingerprints, one per line, of /// certificates that have issues. This output is intended for /// use by scripts. /// /// This option implies `--quiet`. If you also specify `--fix`, /// errors will still be printed to stderr, and fixed certificates /// will still be emitted to stdout. #[arg(short='k', long)] pub list_keys: bool, #[clap( long, value_name = "CERT_FILE", help = "Lint the certificates in the specified file", )] pub cert_file: Vec, #[clap( long, value_name = "FINGERPRINT|KEYID", help = "Lint the specified certificate", conflicts_with = "cert_file", )] pub cert: Vec, #[clap( long, short, value_name = FileOrStdout::VALUE_NAME, help = "Write to the specified FILE. If not specified, and the \ certificate was read from the certificate store, imports the \ modified certificate into the cert store. If not specified, \ and the certificate was read from a file, writes the modified \ certificate to stdout.", )] pub output: Option, #[clap( short = 'B', long = "binary", help = "Emit binary data", )] pub binary: bool, } sequoia-sq-0.37.0/src/cli/cert.rs000064400000000000000000000015261046102023000146470ustar 00000000000000//! Command-line parser for `sq cert`. use clap::{Parser, Subcommand}; pub mod export; pub mod import; pub mod lint; #[derive(Parser, Debug)] #[clap( name = "cert", about = "Manage certificates", long_about = "Manage certificates We use the term \"certificate\", or \"cert\" for short, to refer to OpenPGP keys that do not contain secrets. This subcommand provides primitives to generate and otherwise manipulate certs. Conversely, we use the term \"key\" to refer to OpenPGP keys that do contain secrets. See `sq key` for operations on keys. ", subcommand_required = true, arg_required_else_help = true, )] pub struct Command { #[clap(subcommand)] pub subcommand: Subcommands, } #[derive(Debug, Subcommand)] pub enum Subcommands { Import(import::Command), Export(export::Command), Lint(lint::Command), } sequoia-sq-0.37.0/src/cli/decrypt.rs000064400000000000000000000076431046102023000153720ustar 00000000000000//! Command-line parser for `sq decrypt`. use std::path::PathBuf; use clap::Parser; use super::types::ClapData; use super::types::FileOrStdin; use super::types::FileOrStdout; use super::types::SessionKey; use crate::cli::examples; use examples::Action; use examples::Actions; use examples::Example; use examples::Setup; const DECRYPT_EXAMPLES: Actions = Actions { actions: &[ Action::Example(Example { comment: "\ Decrypt a file using a secret key", command: &[ "sq", "decrypt", "--recipient-file", "juliet-secret.pgp", "ciphertext.pgp", ], }), Action::Example(Example { comment: "\ Decrypt a file verifying signatures", command: &[ "sq", "decrypt", "--recipient-file", "juliet-secret.pgp", "--signer-file", "romeo.pgp", "ciphertext.pgp" ], }), Action::Setup(Setup { command: &[ "sq", "key", "import", "juliet-secret.pgp", ], }), Action::Example(Example { comment: "\ Decrypt a file using the key store", command: &[ "sq", "decrypt", "ciphertext.pgp", ], }), ] }; test_examples!(sq_decrypt, DECRYPT_EXAMPLES); #[derive(Parser, Debug)] #[clap( name = "decrypt", about = "Decrypt a message", long_about = "Decrypt a message Decrypt a message using either supplied keys, or by prompting for a password. If message tampering is detected, an error is returned. See below for details. If certificates are supplied using the `--signer-cert` option, any signatures that are found are checked using these certificates. Verification is only successful if there is no bad signature, and the number of successfully verified signatures reaches the threshold configured with the `--signatures` parameter. If the signature verification fails, or if message tampering is detected, the program terminates with an exit status indicating failure. In addition to that, the last 25 MiB of the message are withheld, i.e. if the message is smaller than 25 MiB, no output is produced, and if it is larger, then the output will be truncated. The converse operation is `sq encrypt`. ", after_help = DECRYPT_EXAMPLES, )] // TODO use usize pub struct Command { #[clap( default_value_t = FileOrStdin::default(), help = FileOrStdin::HELP_OPTIONAL, value_name = FileOrStdin::VALUE_NAME, )] pub input: FileOrStdin, #[clap( default_value_t = FileOrStdout::default(), help = FileOrStdout::HELP_OPTIONAL, long, short, value_name = FileOrStdout::VALUE_NAME, )] pub output: FileOrStdout, #[clap( short = 'n', long = "signatures", value_name = "N", help = "Set the threshold of valid signatures to N", long_help = "Set the threshold of valid signatures to N. \ The message will only be considered \ verified if this threshold is reached. \ [default: 1 if at least one signer cert file \ is given, 0 otherwise]", )] pub signatures: Option, #[clap( long = "signer-file", value_name = "CERT_FILE", help = "Verify signatures using the certificates in CERT_FILE", )] pub sender_cert_file: Vec, #[clap( long = "recipient-file", value_name = "KEY_FILE", help = "Decrypt the message using the key in KEY_FILE", )] pub secret_key_file: Vec, #[clap( long = "dump-session-key", help = "Print the session key to stderr", )] pub dump_session_key: bool, #[clap( long = "session-key", value_name = "SESSION-KEY", help = "Decrypt an encrypted message using SESSION-KEY", )] pub session_key: Vec, } sequoia-sq-0.37.0/src/cli/encrypt.rs000064400000000000000000000145701046102023000154010ustar 00000000000000//! Command-line parser for `sq encrypt`. use std::path::PathBuf; use clap::ArgAction::Count; use clap::{ValueEnum, Parser}; use sequoia_openpgp as openpgp; use openpgp::KeyHandle; use super::types::ClapData; use super::types::EncryptPurpose; use super::types::MetadataTime; use super::types::FileOrStdin; use super::types::FileOrStdout; #[derive(Parser, Debug)] #[clap( name = "encrypt", about = "Encrypt a message", long_about = "Encrypt a message Encrypt a message for any number of recipients and with any number of passwords, optionally signing the message in the process. The converse operation is `sq decrypt`. `sq encrypt` respects the reference time set by the top-level `--time` argument. It uses the reference time when selecting encryption keys, and it sets the signature's creation time to the reference time. ", after_help = "EXAMPLES: # Encrypt a file using a certificate $ sq encrypt --recipient-file romeo.pgp message.txt # Encrypt a file creating a signature in the process $ sq encrypt --recipient-file romeo.pgp --signer-file juliet.pgp \\ message.txt # Encrypt a file using a password $ sq encrypt --symmetric message.txt ", )] pub struct Command { #[clap( default_value_t = FileOrStdin::default(), help = FileOrStdin::HELP_OPTIONAL, value_name = FileOrStdin::VALUE_NAME, )] pub input: FileOrStdin, #[clap( default_value_t = FileOrStdout::default(), help = FileOrStdout::HELP_OPTIONAL, long, short, value_name = FileOrStdout::VALUE_NAME, )] pub output: FileOrStdout, #[clap( short = 'B', long, help = "Emit binary data", )] pub binary: bool, #[clap( long = "recipient-email", value_name = "EMAIL", help = "Encrypt to all certificates that can be authenticated \ for the specified email address", )] pub recipients_email: Vec, #[clap( long = "recipient-userid", value_name = "USERID", help = "Encrypt to all certificates that can be authenticated \ for the specified User ID", )] pub recipients_userid: Vec, #[clap( long = "recipient-cert", value_name = "FINGERPRINT|KEYID", help = "Encrypt to the named certificates", )] pub recipients_cert: Vec, #[clap( long = "recipient-file", value_name = "CERT_RING_FILE", help = "Encrypt to all certificates in CERT_RING_FILE", )] pub recipients_file: Vec, #[clap( help = "Set the filename of the encrypted file as metadata", long, long_help = "Set the filename of the encrypted file as metadata. \ Do note, that this metadata is not signed and as such relying on \ it - on sender or receiver side - is generally considered \ dangerous.", )] pub set_metadata_filename: bool, #[clap( default_value_t = MetadataTime::default(), help = "Set time for encrypted file as metadata", long, long_help = format!( "Set time for encrypted file as metadata. \ Allows setting TIME either as ISO 8601 formatted string or by \ providing custom keywords. \ With `{}`, the metadata is not set. \ With `{}`, the metadata is set to the file's creation \ timestamp. \ With `{}`, the metadata is set to the file's last \ modification timestamp. \ With `{}`, the metadata is set to the creation \ timestamp of the message for which the metadata is added. \ Do note, that this metadata is not signed and as such relying on \ it - on sender or receiver side - is generally considered \ dangerous.", MetadataTime::None, MetadataTime::FileCreation, MetadataTime::FileModification, MetadataTime::MessageCreation, ), value_name = "TIME", )] pub set_metadata_time: MetadataTime, #[clap( long = "signer-file", value_name = "KEY_FILE", help = "Sign the message using the key in KEY_FILE", )] pub signer_key_file: Vec, #[clap( long = "signer-key", value_name = "KEYID|FINGERPRINT", help = "Sign the message using the specified key on the key store", )] pub signer_key: Vec, #[clap( short = 's', long = "symmetric", help = "Prompt to add a password to encrypt with", long_help = "Prompt to add a password to encrypt with. \ When using this option, the user is asked to provide a password, \ which is used to encrypt the message. \ This option can be provided more than once to provide more than \ one password. \ The encrypted data can afterwards be decrypted with either one of \ the recipient's keys, or one of the provided passwords.", action = Count, )] pub symmetric: u8, #[clap( long = "encrypt-for", value_name = "PURPOSE", default_value_t = EncryptPurpose::Universal, help = "Select what kind of keys are considered for encryption.", long_help = "Select what kind of keys are considered for \ encryption. 'transport' selects subkeys marked \ as suitable for transport encryption, 'storage' \ selects those for encrypting data at rest, \ and 'universal' selects all encryption-capable \ subkeys.", value_enum, )] pub mode: EncryptPurpose, #[clap( long = "compression", value_name = "KIND", default_value_t = CompressionMode::None, help = "Select compression scheme to use", value_enum, )] pub compression: CompressionMode, #[clap( long = "use-expired-subkey", help = "Fall back to expired encryption subkeys", long_help = "If a certificate has only expired \ encryption-capable subkeys, fall back \ to using the one that expired last", )] pub use_expired_subkey: bool, } #[derive(ValueEnum, Debug, Clone)] pub enum CompressionMode { None, #[cfg(all(unix, not(unix)))] // Bottom, but: `cfg` predicate key cannot be a literal Pad, Zip, Zlib, Bzip2 } sequoia-sq-0.37.0/src/cli/examples.rs000064400000000000000000000132651046102023000155330ustar 00000000000000//! A framework to format and check examples. //! //! The help text for subcommands includes examples. That's great. //! But, it is even better when they are tested. This module defines //! data structures to describe the examples, mechanisms to format the //! examples, and infrastructure to execute the examples. use clap::builder::IntoResettable; use clap::builder::Resettable; /// A command that is executed by the integration test, but not shown /// in the manual pages. pub struct Setup<'a> { pub command: &'a [ &'a str ], } /// A command that is executed by the integration test, and shown in /// the manual pages. pub struct Example<'a> { // A human-readable comment. pub comment: &'a str, pub command: &'a [ &'a str ], } /// An action to execute. #[allow(dead_code)] pub enum Action<'a> { /// A command that is executed by the integration test, but not /// shown in the manual pages. Setup(Setup<'a>), /// A command that is executed by the integration test, and shown /// in the manual pages. Example(Example<'a>), } impl<'a> Action<'a> { /// Return the action's command, if any. #[allow(dead_code)] pub fn command(&self) -> Option<&'a [ &'a str ]> { match self { Action::Setup(Setup { command, .. }) => Some(command), Action::Example(Example { command, .. }) => Some(command), } } } /// A sequence of actions to execute. pub struct Actions<'a> { pub actions: &'a [Action<'a>], } impl<'a> IntoResettable for Actions<'a> { fn into_resettable(self) -> Resettable { // Default width when we aren't connected to a terminal. let default_width = 72; let terminal_size = terminal_size::terminal_size(); let width = if let Some((width, _height)) = terminal_size { let width = width.0 as usize; if width < 40 { // If the terminal is too narrow, then give up and use // the default. default_width } else { std::cmp::max(40, width) } } else { 72 }; let mut lines = vec![ "EXAMPLES:".to_string() ]; lines.extend(self.actions .iter() .filter_map(|action| { let example = if let Action::Example(example) = action { example } else { return None; }; let comment = textwrap::indent( &textwrap::wrap(example.comment, width).join("\n"), "# "); let command = example.command.iter() .fold(vec!["$".to_string()], |mut s, arg| { // Quote the argument, if necessary. let arg = if arg.contains(&[ '\"', ]) { format!("'{}'", arg) } else if arg.chars().any(char::is_whitespace) || arg.contains(&[ '`', '#', '$', '&', '*', '(', ')', '\\', '|', '[', ']', '{', '}', ';', '\'', '<', '>', '?', '!', ]) { format!("\"{}\"", arg) } else { arg.to_string() }; let last = s.last_mut().expect("have one"); let last_chars = last.chars().count(); let arg_chars = arg.chars().count(); // Our manpage generate complains if an // example is too long: // // warning: Command in example exceeds 64 chars: if last_chars + 1 + arg_chars <= width.min(64) { *last = format!("{} {}", last, arg); } else { *last = format!("{} \\", last); s.push(format!(" {}", arg)); } s }) .join("\n"); Some(format!("{}\n{}", comment, command)) })); let text = lines.join("\n\n").into(); Resettable::Value(text) } } macro_rules! test_examples { ($ident:ident, $actions:expr) => { #[test] fn $ident() { use std::path::PathBuf; use tempfile::TempDir; use assert_cmd::Command; let fixtures = PathBuf::from(concat!( env!("CARGO_MANIFEST_DIR"), "/tests/data/examples")); let tmp_dir = TempDir::new().unwrap(); dircpy::copy_dir(&fixtures, &tmp_dir) .expect(&format!("Copying {:?} to {:?}", fixtures, &tmp_dir)); let cert_store = tmp_dir.path().join("cert-store"); let key_store = tmp_dir.path().join("key-store"); for action in $actions.actions { let command = if let Some(command) = action.command() { command } else { continue; }; eprintln!("Executing: {:?}", command); Command::cargo_bin(command[0]).unwrap() .current_dir(&tmp_dir) .env("SQ_CERT_STORE", &cert_store) .env("SQ_KEY_STORE", &key_store) .args(&command[1..]) .assert() .success(); } } }; } sequoia-sq-0.37.0/src/cli/inspect.rs000064400000000000000000000044031046102023000153540ustar 00000000000000//! Command-line parser for `sq inspect`. use clap::Parser; use sequoia_openpgp as openpgp; use openpgp::KeyHandle; use super::types::ClapData; use super::types::FileOrStdin; use crate::cli::examples; use examples::Action; use examples::Actions; use examples::Example; const INSPECT_EXAMPLES: Actions = Actions { actions: &[ Action::Example(Example { comment: "\ Inspect a certificate.", command: &[ "sq", "inspect", "juliet.pgp", ], }), Action::Example(Example { comment: "\ Show how the certificate looked on July 21, 2013.", command: &[ "sq", "inspect", "--time", "20130721", "juliet.pgp", ], }), Action::Example(Example { comment: "\ Inspect an encrypted message.", command: &[ "sq", "inspect", "message.pgp", ], }), Action::Example(Example { comment: "\ Inspect a detachted signature.", command: &[ "sq", "inspect", "document.sig", ], }), ] }; test_examples!(sq_inspect, INSPECT_EXAMPLES); #[derive(Parser, Debug)] #[clap( name = "inspect", about = "Inspect data, like file(1)", long_about = "Inspect data, like file(1) It is often difficult to tell from cursory inspection using cat(1) or file(1) what kind of OpenPGP one is looking at. This subcommand inspects the data and provides a meaningful human-readable description of it. `sq inspect` respects the reference time set by the top-level `--time` argument. It uses the reference time when determining what binding signatures are active. ", after_help = INSPECT_EXAMPLES, )] pub struct Command { #[clap( default_value_t = FileOrStdin::default(), help = FileOrStdin::HELP_OPTIONAL, value_name = FileOrStdin::VALUE_NAME, )] pub input: FileOrStdin, #[clap( long = "cert", value_name = "FINGERPRINT|KEYID", conflicts_with = "input", help = "Read the specified certificate from the certificate store", )] pub cert: Vec, #[clap( long = "certifications", help = "Print third-party certifications", )] pub certifications: bool, } sequoia-sq-0.37.0/src/cli/key/expire.rs000064400000000000000000000053011046102023000157710ustar 00000000000000//! Command-line parser for `sq key expire`. use clap::Args; use clap::ArgGroup; use sequoia_openpgp as openpgp; use openpgp::KeyHandle; use crate::cli::types::ClapData; use crate::cli::types::Expiration; use crate::cli::types::FileOrStdin; use crate::cli::types::FileOrStdout; use crate::cli::examples::*; const EXAMPLES: Actions = Actions { actions: &[ Action::Example(Example { comment: "Make Alice's key expire in a year.", command: &[ "sq", "key", "expire", "1y", "--cert-file", "alice-secret.pgp", ], }), Action::Example(Example { comment: "Make Alice's key never expire.", command: &[ "sq", "key", "expire", "never", "--cert-file", "alice-secret.pgp", ], }), ], }; test_examples!(sq_key_expire, EXAMPLES); #[derive(Debug, Args)] #[clap( name = "expire", about = "Change expiration times", long_about = "Change expiration times Change or clear a certificate's expiration time. This subcommand changes the certificate's expiration time. To change the expiration time of an individual subkey, use the `sq key subkey expire` subcommand.", after_help = EXAMPLES, )] #[clap(group(ArgGroup::new("cert_input").args(&["cert_file", "cert"]).required(true)))] pub struct Command { #[clap( help = FileOrStdout::HELP_OPTIONAL, long, short, value_name = FileOrStdout::VALUE_NAME, )] pub output: Option, #[clap( short = 'B', long, help = "Emit binary data", )] pub binary: bool, #[clap( value_name = "EXPIRATION", help = "Define EXPIRATION for the key as ISO 8601 formatted string or \ custom duration.", long_help = "Define EXPIRATION for the key as ISO 8601 formatted string or \ custom duration. \ If an ISO 8601 formatted string is provided, the validity period \ reaches from the reference time (may be set using `--time`) to \ the provided time. \ Custom durations starting from the reference time may be set using \ `N[ymwds]`, for N years, months, weeks, days, or seconds. \ The special keyword `never` sets an unlimited expiry.", )] pub expiration: Expiration, #[clap( long, value_name = "FINGERPRINT|KEYID", help = "Change the certificate's expiration time", )] pub cert: Option, #[clap( long, value_name = "CERT_FILE", help = "Change the certificate's expiration time", )] pub cert_file: Option, } sequoia-sq-0.37.0/src/cli/key.rs000064400000000000000000001572151046102023000145110ustar 00000000000000//! Command-line parser for `sq key`. use std::path::PathBuf; use clap::{ValueEnum, ArgGroup, Args, Parser, Subcommand}; use sequoia_openpgp as openpgp; use openpgp::cert::CipherSuite as SqCipherSuite; use openpgp::KeyHandle; use openpgp::packet::UserID; use openpgp::types::ReasonForRevocation; use crate::cli::KEY_VALIDITY_DURATION; use crate::cli::KEY_VALIDITY_IN_YEARS; use crate::cli::types::ClapData; use crate::cli::types::EncryptPurpose; use crate::cli::types::Expiration; use crate::cli::types::FileOrCertStore; use crate::cli::types::FileOrStdin; use crate::cli::types::FileOrStdout; use crate::cli::types::Time; use crate::cli::examples; use examples::Action; use examples::Actions; use examples::Example; pub mod expire; /// The revocation reason for a certificate or subkey #[derive(ValueEnum, Clone, Debug)] pub enum KeyReasonForRevocation { /// The secret key material may have been compromised. Prefer /// this value if you suspect that the secret key has been leaked. Compromised, /// The owner of the certificate has a new certificate. Prefer /// `compromised` if the secret key material has been compromised /// even if the certificate is also being replaced! You should /// include the fingerprint of the new certificate in the message. Superseded, /// The certificate should not be used anymore, and there is no /// replacement. This is appropriate when someone leaves an /// organisation. Prefer `compromised` if the secret key material /// has been compromised even if the certificate is also being /// retired! You should include how to contact the owner, or who /// to contact instead in the message. Retired, /// None of the other reasons apply. OpenPGP implementations /// conservatively treat this type of revocation similar to a /// compromised key. Unspecified, } impl From for ReasonForRevocation { fn from(rr: KeyReasonForRevocation) -> Self { match rr { KeyReasonForRevocation::Compromised => ReasonForRevocation::KeyCompromised, KeyReasonForRevocation::Superseded => ReasonForRevocation::KeySuperseded, KeyReasonForRevocation::Retired => ReasonForRevocation::KeyRetired, KeyReasonForRevocation::Unspecified => ReasonForRevocation::Unspecified, } } } /// The revocation reason for a user ID #[derive(ValueEnum, Clone, Debug)] pub enum UserIDReasonForRevocation { /// The user ID is no longer valid. This is appropriate when /// someone leaves an organisation, and the organisation does not /// have their secret key material. For instance, if someone was /// part of Debian and retires, they would use this to indicate /// that a Debian-specific User ID is no longer valid. Retired, /// None of the other reasons apply. OpenPGP implementations /// conservatively treat this type of revocation similar to a /// compromised key. Unspecified } impl From for ReasonForRevocation { fn from(rr: UserIDReasonForRevocation) -> Self { match rr { UserIDReasonForRevocation::Retired => ReasonForRevocation::UIDRetired, UserIDReasonForRevocation::Unspecified => ReasonForRevocation::Unspecified, } } } #[derive(Parser, Debug)] #[clap( name = "key", about = "Manage keys", long_about = "Manage keys We use the term \"key\" to refer to OpenPGP keys that do contain \ secrets. This subcommand provides primitives to generate and \ otherwise manipulate keys. Conversely, we use the term \"certificate\", or \"cert\" for short, to refer \ to OpenPGP keys that do not contain secrets. See `sq cert` for operations on \ certificates.", subcommand_required = true, arg_required_else_help = true, )] pub struct Command { #[clap(subcommand)] pub subcommand: Subcommands, } #[derive(Debug, Subcommand)] pub enum Subcommands { List(ListCommand), Generate(GenerateCommand), Import(ImportCommand), Export(ExportCommand), Delete(DeleteCommand), Password(PasswordCommand), Expire(expire::Command), Revoke(RevokeCommand), #[clap(subcommand)] Userid(UseridCommand), #[clap(subcommand)] Subkey(SubkeyCommand), AttestCertifications(AttestCertificationsCommand), Adopt(AdoptCommand), } const LIST_EXAMPLES: Actions = Actions { actions: &[ Action::Example(Example { comment: "\ List the keys managed by the keystore server.", command: &[ "sq", "key", "list", ], }), ] }; test_examples!(sq_key_list, LIST_EXAMPLES); #[derive(Debug, Args)] #[clap( about = "List keys managed by the key store", after_help = LIST_EXAMPLES, )] pub struct ListCommand { } const GENERATE_EXAMPLES: Actions = Actions { actions: &[ Action::Example(Example { comment: "\ Generate a key, and save it on the key store.", command: &[ "sq", "key", "generate", "--userid", "Alice ", ], }), Action::Example(Example { comment: "\ Generate a key, and save it in a file instead of in the key store.", command: &[ "sq", "key", "generate", "--userid", "Alice ", "--output", "alice-priv.pgp", ], }), Action::Example(Example { comment: "\ Strip the secret key material from the new key.", command: &[ "sq", "toolbox", "extract-cert", "alice-priv.pgp", "--output", "alice.pgp", ], }), ] }; test_examples!(sq_key_generate, GENERATE_EXAMPLES); #[derive(Debug, Args)] #[clap( about = "Generate a new key", long_about = format!( "Generate a new key Generating a key is the prerequisite to receiving encrypted messages \ and creating signatures. There are a few parameters to this process, \ but we provide reasonable defaults for most users. When generating a key, we also generate an emergency revocation \ certificate. This can be used in case the key is lost or compromised. \ It is saved alongside the key. This can be changed using the \ `--rev-cert` argument. By default a key expires after {} years. This can be changed using \ the `--expiration` argument. `sq key generate` respects the reference time set by the top-level \ `--time` argument. It sets the creation time of the primary key, any \ subkeys, and the binding signatures to the reference time. ", KEY_VALIDITY_IN_YEARS, ), after_help = GENERATE_EXAMPLES, )] #[clap(group(ArgGroup::new("cap-sign").args(&["can_sign", "cannot_sign"])))] #[clap(group(ArgGroup::new("cap-authenticate").args(&["can_authenticate", "cannot_authenticate"])))] #[clap(group(ArgGroup::new("cap-encrypt").args(&["can_encrypt", "cannot_encrypt"])))] #[clap(group(ArgGroup::new("cert-userid").args(&["userid", "no_userids"]).required(true)))] pub struct GenerateCommand { #[clap( short = 'u', long = "userid", value_name = "USERID", help = "Add a user ID to the key" )] pub userid: Vec, #[clap( long = "allow-non-canonical-userids", help = "Don't reject user IDs that are not in canonical form", long_help = "\ Don't reject user IDs that are not in canonical form. Canonical user IDs are of the form `Name (Comment) \ `.", )] pub allow_non_canonical_userids: bool, #[clap( long = "no-userids", help = "Create a key without any user IDs", conflicts_with = "userid", )] pub no_userids: bool, #[clap( short = 'c', long = "cipher-suite", value_name = "CIPHER-SUITE", default_value_t = CipherSuite::Cv25519, help = "Select the cryptographic algorithms for the key", value_enum, )] pub cipher_suite: CipherSuite, #[clap( long = "with-password", help = "Protect the secret key material with a password", )] pub with_password: bool, #[clap( long = "expiration", value_name = "EXPIRATION", default_value_t = Expiration::Duration(KEY_VALIDITY_DURATION), help = "Sets the certificate's expiration time", long_help = "\ Sets the certificate's expiration time. EXPIRATION is either an ISO 8601 formatted string or a custom duration, \ which takes the form `N[ymwds]`, where the letters stand for years, \ months, weeks, days, and seconds, respectively. Alternatively, the \ keyword `never` does not set an expiration time. When using an ISO 8601 formatted string, the validity period is from \ the certificate's creation time to the specified time. When using a \ duration, the validity period is from the certificate's creation time \ for the specified duration.", )] pub expiration: Expiration, #[clap( long = "can-sign", help ="Add a signing-capable subkey (default)", )] pub can_sign: bool, #[clap( long = "cannot-sign", help = "Don't add a signing-capable subkey", )] pub cannot_sign: bool, #[clap( long = "can-authenticate", help = "Add an authentication-capable subkey (default)", )] pub can_authenticate: bool, #[clap( long = "cannot-authenticate", help = "Don't add an authentication-capable subkey", )] pub cannot_authenticate: bool, #[clap( long = "can-encrypt", value_name = "PURPOSE", help = "Add an encryption-capable subkey [default: universal]", long_help = "\ Add an encryption-capable subkey. Encryption-capable subkeys can be marked as suitable for transport \ encryption, storage encryption, or both, i.e., universal. [default: \ universal]", value_enum, )] pub can_encrypt: Option, #[clap( long = "cannot-encrypt", help = "Don't add an encryption-capable subkey", )] pub cannot_encrypt: bool, #[clap( long, short, value_name = FileOrStdout::VALUE_NAME, help = "Write the key to the specified file", long_help = "\ Write the key to the specified file. When not specified, the key is saved on the key store.", )] pub output: Option, #[clap( long = "rev-cert", value_name = "FILE", help = "Write the emergency revocation certificate to FILE", long_help = format!("\ Write the emergency revocation certificate to FILE. When the key is stored on the key store, the revocation certificate is \ stored in {} by default. When `--output` is specified, the revocation certificate is written to \ `FILE.rev` by default. If `--output` is `-`, then this option must be provided.", sequoia_directories::Home::default() .map(|home| { let p = home.data_dir(sequoia_directories::Component::Other( "revocation-certificates".into())); let p = p.display().to_string(); if let Some(home) = dirs::home_dir() { let home = home.display().to_string(); if let Some(rest) = p.strip_prefix(&home) { return format!("$HOME{}", rest); } } p }) .unwrap_or("".to_string())) )] pub rev_cert: Option } #[derive(ValueEnum, Clone, Debug)] pub enum CipherSuite { Rsa3k, Rsa4k, Cv25519 } impl CipherSuite { /// Return a matching `sequoia_openpgp::cert::CipherSuite` pub fn as_ciphersuite(&self) -> SqCipherSuite { match self { CipherSuite::Rsa3k => SqCipherSuite::RSA3k, CipherSuite::Rsa4k => SqCipherSuite::RSA4k, CipherSuite::Cv25519 => SqCipherSuite::Cv25519, } } } const IMPORT_EXAMPLES: Actions = Actions { actions: &[ Action::Example(Example { comment: "\ Import the keys into the key store.", command: &[ "sq", "key", "import", "alice-secret.pgp", ], }), ] }; test_examples!(sq_key_import, IMPORT_EXAMPLES); #[derive(Debug, Args)] #[clap( about = "Import keys into the key store", after_help = IMPORT_EXAMPLES, )] pub struct ImportCommand { #[clap( value_name = "KEY_FILE", help = "Import the keys in KEY_FILE", )] pub file: Vec, } const EXPORT_EXAMPLES: Actions = Actions { actions: &[ Action::Example(Example { comment: "\ Import a certificate.", command: &[ "sq", "key", "import", "alice-secret.pgp", ], }), Action::Example(Example { comment: "\ Export Alice's certificate with all available secret key material.", command: &[ "sq", "key", "export", "--cert", "EB28F26E2739A4870ECC47726F0073F60FD0CBF0", ], }), Action::Example(Example { comment: "\ Export Alice's signing-capable and encryption-capable subkeys, but not \ her primary key or her authentication-capable subkey.", command: &[ "sq", "key", "export", "--key", "42020B87D51877E5AF8D272124F3955B0B8DECC8", "--key", "74DCDEAF17D9B995679EB52BA6E65EA2C8497728", ], }), ] }; test_examples!(sq_key_export, EXPORT_EXAMPLES); #[derive(Debug, Args)] #[clap( about = "Export keys from the key store", after_help = EXPORT_EXAMPLES, )] #[clap(group(ArgGroup::new("export").args(&["cert", "key"])))] pub struct ExportCommand { #[clap( long, value_name = "FINGERPRINT|KEYID", help = "Export the specified certificate with its secret key material", long_help = "\ Export the specified certificate with its secret key material. Iterate over the specified certificate's primary key and subkeys and \ export any keys with secret key material. An error is returned if \ the certificate does not contain any secret key material.", )] pub cert: Vec, #[clap( long, value_name = "FINGERPRINT|KEYID", help = "\ Export the secret key material for the specified key, and its certificate", long_help = "\ Export the specified key. The entire certificate is exported, but only the specified key's \ secret key material is exported. An error is returned if the secret \ key material for the specified key is not available.", )] pub key: Vec, } const DELETE_EXAMPLES: Actions = Actions { actions: &[ Action::Example(Example { comment: "\ Import Alice's key.", command: &[ "sq", "key", "import", "alice-secret.pgp", ], }), Action::Example(Example { comment: "\ Delete any secret key associated with the certificate.", command: &[ "sq", "key", "delete", "--cert", "EB28F26E2739A4870ECC47726F0073F60FD0CBF0", ], }), ] }; test_examples!(sq_key_delete, DELETE_EXAMPLES); #[derive(Debug, Args)] #[clap( name = "delete", about = "Delete a certificate's secret key material", after_help = DELETE_EXAMPLES, )] #[clap(group(ArgGroup::new("cert_input").args(&["cert_file", "cert"]).required(true)))] pub struct DeleteCommand { #[clap( long, help = "Delete the secret key material from the specified certificate", value_name = FileOrStdin::VALUE_NAME, )] pub cert: Option, #[clap( long, value_name = "CERT_FILE", help = "Delete the secret key material from the specified certificate", long_help = "\ Delete the secret key material from the specified certificate. Read the certificate from FILE or stdin, if `-`. It is an error \ for the file to contain more than one certificate.", )] pub cert_file: Option, #[clap( long, short, value_name = FileOrStdout::VALUE_NAME, conflicts_with = "cert", help = "Write the stripped certificate to the specified file", )] pub output: Option, #[clap( short = 'B', long, help = "Emit binary data", )] pub binary: bool, } const PASSWORD_EXAMPLES: Actions = Actions { actions: &[ Action::Example(Example { comment: "\ Import a key that has no password protection.", command: &[ "sq", "key", "import", "alice-secret.pgp" ], }), Action::Example(Example { comment: "\ Change the password for all keys to password in the specified file.", command: &[ "sq", "key", "password", "--new-password-file", "password-file.txt", "--cert", "EB28F26E2739A4870ECC47726F0073F60FD0CBF0" ], }), Action::Example(Example { comment: "\ Clear the password protection.", command: &[ "sq", "key", "password", "--password-file", "password-file.txt", "--clear-password", "--cert", "EB28F26E2739A4870ECC47726F0073F60FD0CBF0" ], }), ] }; test_examples!(sq_key_password, PASSWORD_EXAMPLES); #[derive(Debug, Args)] #[clap( name = "password", about = "Change the password protecting secret key material", long_about = " Change the password protecting secret key material. Secret key material can be protected by a password. This subcommand \ changes or clears the password. To strip the password either use `--clear` or supply a zero-length \ password when prompted for the new password. If a key is password protected, and the correct password was not \ supplied using the `--password-file` argument, the user is \ prompted for the password. Likewise, if the new password isn't \ provided, the user is prompted.", after_help = PASSWORD_EXAMPLES, )] #[clap(group(ArgGroup::new("cert_input").args(&["cert_file", "cert"]).required(true)))] pub struct PasswordCommand { #[clap( long, help = "Change the password of the specified certificate's keys", value_name = FileOrStdin::VALUE_NAME, )] pub cert: Option, #[clap( long, value_name = "CERT_FILE", help = "Change the password of the specified certificate's keys", long_help = "\ Change the password of the specified certificate's keys. Read the certificate from FILE or stdin, if `-`. It is an error \ for the file to contain more than one certificate.", )] pub cert_file: Option, #[clap( long, value_name = "PASSWORD_FILE", help = "\ File containing password to encrypt the secret key material", long_help = "\ File containing password to encrypt the secret key material. Note that the entire key file will be used as the password including \ any surrounding whitespace like a trailing newline." )] pub new_password_file: Option, #[clap( long, help = "Clear the password protecting the secret key material", )] pub clear_password: bool, #[clap( help = FileOrStdout::HELP_OPTIONAL, long, short, value_name = FileOrStdout::VALUE_NAME, conflicts_with = "cert", )] pub output: Option, #[clap( short = 'B', long, help = "Emit binary data", )] pub binary: bool, } const REVOKE_EXAMPLES: Actions = Actions { actions: &[ Action::Example(Example { comment: "\ Import a key.", command: &[ "sq", "key", "import", "alice-secret.pgp" ], }), Action::Example(Example { comment: "\ Revoke the key, indicating that there is a new certificate.", command: &[ "sq", "key", "revoke", "--cert", "EB28F26E2739A4870ECC47726F0073F60FD0CBF0", "superseded", "My new cert is 31EC6A9453BC59F1239C785E4CA79EF01933A2ED", ], }), Action::Example(Example { comment: "\ Revoke the key, indicating that the secret key material was \ compromised.", command: &[ "sq", "key", "revoke", "--cert", "EB28F26E2739A4870ECC47726F0073F60FD0CBF0", "compromised", "Computer attacked, secret key material compromised", ], }), ] }; test_examples!(sq_key_revoke, REVOKE_EXAMPLES); #[derive(Debug, Args)] #[clap( about = "Revoke a certificate", long_about = "\ Revoke a certificate. Creates a revocation certificate for a certificate. If `--revoker` or `--revoker-file` is provided, then that key is used \ to create the revocation certificate. If that key is different from \ the certificate that is being revoked, this results in a third-party \ revocation. This is normally only useful if the owner of the \ certificate designated the key to be a designated revoker. `sq key revoke` respects the reference time set by the top-level \ `--time` argument. When set, it uses the specified time instead of \ the current time when determining what keys are valid, and it sets \ the revocation certificate's creation time to the reference time \ instead of the current time.", after_help = REVOKE_EXAMPLES, )] #[clap(group(ArgGroup::new("cert_input").args(&["cert_file", "cert"]).required(true)))] #[clap(group(ArgGroup::new("revoker_input").args(&["revoker_file", "revoker"])))] pub struct RevokeCommand { #[clap( long, value_name = "FINGERPRINT|KEYID", help = "The certificate to revoke", )] pub cert: Option, #[clap( long, value_name = "CERT_FILE", conflicts_with = "cert", help = "The certificate to revoke", long_help = "\ The certificate to revoke. Read the certificate to revoke from FILE or stdin, if `-`. It is \ an error for the file to contain more than one certificate.", )] pub cert_file: Option, #[clap( long, value_name = "FINGERPRINT|KEYID", help = "The certificate that issues the revocation", long_help = "\ The certificate that issues the revocation. Sign the revocation certificate using the specified key. By default, \ the certificate being revoked is used. Using this option, it is \ possible to create a third-party revocation.", )] pub revoker: Option, #[clap( long, value_name = "KEY_FILE", conflicts_with = "revoker", help = "The certificate that issues the revocation", long_help = "\ The certificate that issues the revocation. Sign the revocation certificate using the specified key. By default, \ the certificate being revoked is used. Using this option, it is \ possible to create a third-party revocation. Read the certificate from KEY_FILE or stdin, if `-`. It is an error \ for the file to contain more than one certificate.", )] pub revoker_file: Option, #[clap( value_name = "REASON", required = true, help = "The reason for the revocation", long_help = "\ The reason for the revocation. If the reason happened in the past, you should specify that using the \ `--time` argument. This allows OpenPGP implementations to more \ accurately reason about artifacts whose validity depends on the validity \ of the certificate.", value_enum, )] pub reason: KeyReasonForRevocation, #[clap( value_name = "MESSAGE", help = "A short, explanatory text", long_help = "\ A short, explanatory text. The text is shown to a viewer of the revocation certificate, and \ explains why the certificate has been revoked. For instance, if Alice \ has created a new key, she would generate a `superseded` revocation \ certificate for her old key, and might include the message `I've \ created a new certificate, $FINGERPRINT, please use that in the \ future.`", )] pub message: String, #[clap( long, value_names = &["NAME", "VALUE"], number_of_values = 2, help = "Add a notation to the certification", long_help = "\ Add a notation to the certification. A user-defined notation's name must be of the form \ `name@a.domain.you.control.org`. If the notation's name starts with a \ `!`, then the notation is marked as being critical. If a consumer of \ a signature doesn't understand a critical notation, then it will \ ignore the signature. The notation is marked as being human \ readable." )] pub notation: Vec, #[clap( long, short, value_name = FileOrStdout::VALUE_NAME, help = "Write to the specified FILE", long_help = "\ Write to the specified FILE. If not specified, and the certificate was read from the certificate \ store, imports the modified certificate into the cert store. If not \ specified, and the certificate was read from a file, writes the \ modified certificate to stdout.", )] pub output: Option, #[clap( short = 'B', long, help = "Emit binary data", )] pub binary: bool, } #[derive(Debug, Subcommand)] #[clap( name = "userid", about = "Manage User IDs", long_about = "Manage User IDs Add User IDs to a key, or revoke them. ", subcommand_required = true, arg_required_else_help = true, )] pub enum UseridCommand { Add(UseridAddCommand), Revoke(UseridRevokeCommand), Strip(UseridStripCommand), } const USERID_ADD_EXAMPLES: Actions = Actions { actions: &[ Action::Example(Example { comment: "\ Import a key.", command: &[ "sq", "key", "import", "alice-secret.pgp" ], }), Action::Example(Example { comment: "\ Add a new user ID.", command: &[ "sq", "key", "userid", "add", "--cert", "EB28F26E2739A4870ECC47726F0073F60FD0CBF0", "--userid", "Alice ", ], }), ] }; test_examples!(sq_key_userid_add, USERID_ADD_EXAMPLES); #[derive(Debug, Args)] #[clap( about = "Add a user ID", long_about = "Add a user ID. A user ID can contain a name, like `Juliet`, or an email address, like \ ``. Historically, a name and an email address were \ usually combined as a single user ID, like `Juliet `. `sq userid add` respects the reference time set by the top-level \ `--time` argument. It sets the creation time of the user ID's \ binding signature to the specified time. ", after_help = USERID_ADD_EXAMPLES, )] #[clap(group(ArgGroup::new("cert_input").args(&["cert_file", "cert"]).required(true)))] pub struct UseridAddCommand { #[clap( long, value_name = "FINGERPRINT|KEYID", help = "Add the user ID to the specified certificate", )] pub cert: Option, #[clap( long, value_name = "CERT_FILE", conflicts_with = "cert", help = "Add the user ID to the specified certificate", )] pub cert_file: Option, #[clap( long, value_name = "USERID", required = true, help = "User ID to add", )] pub userid: Vec, #[clap( long, help = "Don't reject user IDs that are not in canonical form", long_help = "\ Don't reject user IDs that are not in canonical form. Canonical user IDs are of the form `Name (Comment) \ `.", )] pub allow_non_canonical_userids: bool, #[clap( long, short, value_name = FileOrCertStore::VALUE_NAME, help = "Write to the specified FILE", long_help = "\ Write to the specified FILE. If not specified, and the certificate was read from the certificate \ store, imports the modified certificate into the cert store. If not \ specified, and the certificate was read from a file, writes the \ modified certificate to stdout.", )] pub output: Option, #[clap( short = 'B', long, help = "Emit binary data", )] pub binary: bool, } const USERID_REVOKE_EXAMPLES: Actions = Actions { actions: &[ Action::Example(Example { comment: "\ Import a key.", command: &[ "sq", "key", "import", "alice-secret.pgp" ], }), Action::Example(Example { comment: "\ Retire a user ID.", command: &[ "sq", "key", "userid", "revoke", "--cert", "EB28F26E2739A4870ECC47726F0073F60FD0CBF0", "--userid", "Alice ", "retired", "No longer at example.org.", ], }), ] }; test_examples!(sq_key_userid_revoke, USERID_REVOKE_EXAMPLES); #[derive(Debug, Args)] #[clap( about = "Revoke a user ID", long_about = "\ Revoke a user ID. Creates a revocation certificate for a user ID. If `--revoker` or `--revoker-file` is provided, then that key is used \ to create the revocation certificate. If that key is different from \ the certificate that is being revoked, this results in a third-party \ revocation. This is normally only useful if the owner of the \ certificate designated the key to be a designated revoker. `sq key userid revoke` respects the reference time set by the top-level \ `--time` argument. When set, it uses the specified time instead of \ the current time when determining what keys are valid, and it sets \ the revocation certificate's creation time to the reference time \ instead of the current time.", after_help = USERID_REVOKE_EXAMPLES, )] #[clap(group(ArgGroup::new("cert_input").args(&["cert_file", "cert"]).required(true)))] #[clap(group(ArgGroup::new("revoker_input").args(&["revoker_file", "revoker"])))] pub struct UseridRevokeCommand { #[clap( long, value_name = "FINGERPRINT|KEYID", help = "Revoke the user ID on the specified certificate", )] pub cert: Option, #[clap( long, help = FileOrStdin::HELP_OPTIONAL, value_name = "CERT_FILE", conflicts_with = "cert", help = "Revoke the user ID on the specified certificate", long_help = "\ Revoke the user ID on the specified certificate. Read the certificate whose user ID should be revoked from FILE or \ stdin, if `-`. It is an error for the file to contain more than one \ certificate.", )] pub cert_file: Option, #[clap( long, value_name = "FINGERPRINT|KEYID", help = "The certificate that issues the revocation", long_help = "\ The certificate that issues the revocation. Sign the revocation certificate using the specified key. By default, \ the certificate being revoked is used. Using this option, it is \ possible to create a third-party revocation.", )] pub revoker: Option, #[clap( long, value_name = "KEY_FILE", conflicts_with = "revoker", help = "The certificate that issues the revocation", long_help = "\ The certificate that issues the revocation. Sign the revocation certificate using the specified key. By default, \ the certificate being revoked is used. Using this option, it is \ possible to create a third-party revocation. Read the certificate from KEY_FILE or stdin, if `-`. It is an error \ for the file to contain more than one certificate.", )] pub revoker_file: Option, #[clap( long, value_name = "USERID", help = "The user ID to revoke", long_help = "\ The user ID to revoke. By default, this must exactly match a self-signed User ID. Use \ `--force` to generate a revocation certificate for a User ID that is \ not self signed." )] pub userid: String, #[clap( value_enum, value_name = "REASON", help = "The reason for the revocation", long_help = "\ The reason for the revocation. If the reason happened in the past, you should specify that using the \ `--time` argument. This allows OpenPGP implementations to more \ accurately reason about artifacts whose validity depends on the validity \ of the user ID." )] pub reason: UserIDReasonForRevocation, #[clap( value_name = "MESSAGE", help = "A short, explanatory text", long_help = "\ A short, explanatory text. The text is shown to a viewer of the revocation certificate, and \ explains why the certificate has been revoked. For instance, if Alice \ has left the organization, it might say who to contact instead.", )] pub message: String, #[clap( long, value_names = &["NAME", "VALUE"], number_of_values = 2, help = "Add a notation to the certification.", long_help = "\ Add a notation to the certification. A user-defined notation's name must be of the form \ `name@a.domain.you.control.org`. If the notation's name starts with a \ `!`, then the notation is marked as being critical. If a consumer of \ a signature doesn't understand a critical notation, then it will \ ignore the signature. The notation is marked as being human \ readable." )] pub notation: Vec, #[clap( long, short, value_name = FileOrCertStore::VALUE_NAME, help = "Write to the specified FILE", long_help = "\ Write to the specified FILE. If not specified, and the certificate was read from the certificate \ store, imports the modified certificate into the cert store. If not \ specified, and the certificate was read from a file, writes the \ modified certificate to stdout.", )] pub output: Option, #[clap( short = 'B', long, help = "Emit binary data", )] pub binary: bool, } #[derive(Debug, Args)] #[clap( about = "Strip a user ID", long_about = "Strip a user ID. Note that this operation does not reliably remove User IDs from a \ certificate that has already been disseminated! (OpenPGP software \ typically appends new information it receives about a certificate to \ its local copy of that certificate. Systems that have obtained a copy \ of your certificate with the User ID that you are trying to strip will \ not drop that User ID from their copy.) In most cases, you will want to use the 'sq key userid revoke' operation \ instead. That issues a revocation for a User ID, which can be used to mark \ the User ID as invalidated. However, this operation can be useful in very specific cases, in particular: \ to remove a mistakenly added User ID before it has been uploaded to key \ servers or otherwise shared. Stripping a User ID may change how a certificate is interpreted. This \ is because information about the certificate like algorithm preferences, \ the primary key's key flags, etc. is stored in the User ID's binding \ signature. ", after_help = "EXAMPLES: # First, generate a key: $ sq key generate --userid '' \\ --output juliet.key.pgp # Then, strip a User ID: $ sq key userid strip --userid '' \\ --output juliet-new.key.pgp juliet.key.pgp ", )] pub struct UseridStripCommand { #[clap( default_value_t = FileOrStdin::default(), help = FileOrStdin::HELP_OPTIONAL, value_name = FileOrStdin::VALUE_NAME, )] pub input: FileOrStdin, #[clap( default_value_t = FileOrStdout::default(), help = FileOrStdout::HELP_OPTIONAL, long, short, value_name = FileOrStdout::VALUE_NAME, )] pub output: FileOrStdout, #[clap( value_name = "USERID", short, long, help = "User IDs to strip", long_help = "The User IDs to strip. Values must exactly match a \ User ID." )] pub userid: Vec, #[clap( short = 'B', long, help = "Emit binary data", )] pub binary: bool, } #[derive(Debug, Subcommand)] #[clap( name = "subkey", about = "Manage subkeys", long_about = "\ Manage subkeys. Add new subkeys to an existing certificate, change their expiration, \ and revoke them.", subcommand_required = true, arg_required_else_help = true, )] #[non_exhaustive] pub enum SubkeyCommand { Add(SubkeyAddCommand), Expire(SubkeyExpireCommand), Revoke(SubkeyRevokeCommand), } const ADOPT_EXAMPLES: Actions = Actions { actions: &[ Action::Example(Example { comment: "\ Import Alice's old key and new key.", command: &[ "sq", "key", "import", "alice-secret.pgp", "alice-new-secret.pgp", ], }), Action::Example(Example { comment: "\ Have the new certificate adopt Alice's old authentication subkey.", command: &[ "sq", "key", "adopt", "--cert", "C5999E8191BF7B503653BE958B1F7910D01F86E5", "--key", "0D45C6A756A038670FDFD85CB1C82E8D27DB23A1", ], }), ] }; test_examples!(sq_key_adopt, ADOPT_EXAMPLES); #[derive(Debug, Args)] #[clap( name = "adopt", about = "Bind keys from one certificate to another", long_about = "\ Bind keys from one certificate to another. This command allows the user to attach a primary key or a subkey \ attached to one certificate to another certificate. Say you want to \ transition to a new certificate, but have an authentication subkey on \ your current certificate that you want to keep because it allows access \ a server and updating its configuration is not feasible. This command \ makes it easy to attach the subkey to the new certificate.", after_help = ADOPT_EXAMPLES, )] #[clap(group(ArgGroup::new("cert_input").args(&["cert_file", "cert"]).required(true)))] pub struct AdoptCommand { #[clap( short = 'k', long, value_name = "KEY", required(true), help = "Add the key or subkey KEY to the certificate", )] pub key: Vec, #[clap( long, value_name = "EXPIRATION", help = "Make adopted subkeys expire at the given time", )] pub expiration: Option