QZ5HE3YCM4QPKQDF2XUHI7IASJ5PYGMKTF4JVWM3TLRIWGEIM5QQC // Copyright © 2023 Kim Altintop <kim@eagain.io>// SPDX-License-Identifier: GPL-2.0-onlyuse core::fmt;use std::collections::{HashMap,HashSet,};pub use ssh_key as ssh;pub mod gpg {pub use pgp::{composed::signed_key::SignedPublicKey,types::KeyTrait,Deserializable,};pub type Fingerprint = Vec<u8>;}mod github;use github::Github;mod gitlab;use gitlab::Gitlab;mod resolver;use resolver::Resolver as _;#[cfg(test)]mod tests;#[derive(Clone, Copy, Debug)]pub enum Platform {Github,Gitlab,}pub struct Identity {pub platform: Platform,pub username: String,pub ssh: HashSet<ssh::PublicKey>,pub gpg: HashMap<gpg::Fingerprint, gpg::SignedPublicKey>,}impl fmt::Debug for Identity {fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {f.debug_struct("Identity").field("platform", &self.platform).field("username", &self.username).field("ssh",&self.ssh.iter().map(|key| key.to_openssh().unwrap()).collect::<Vec<_>>(),).field("gpg",&self.gpg.keys().map(hex::encode_upper).collect::<Vec<_>>(),).finish()}}impl Identity {pub async fn resolve<S>(platform: Platform, username: S) -> anyhow::Result<Self>whereS: AsRef<str> + Into<String>,{let client = reqwest::Client::builder().user_agent("nestje").build()?;let resolver::Keys { ssh, gpg } = match platform {Platform::Github => Github::new(username.as_ref(), client).resolve().await?,Platform::Gitlab => Gitlab::new(username.as_ref(), client).resolve().await?,};Ok(Self {platform,username: username.into(),ssh,gpg,})}}
// Copyright © 2023 Kim Altintop <kim@eagain.io>// SPDX-License-Identifier: GPL-2.0-onlyuse test_log::test;use tracing::info;use super::*;#[test]fn smoke() {let (gh, gl) = tokio::runtime::Builder::new_current_thread().enable_all().build().unwrap().block_on(async {tokio::try_join!(Identity::resolve(Platform::Github, "kim"),Identity::resolve(Platform::Gitlab, "kalt"))}).unwrap();info!("{gh:#?}");info!("{gl:#?}");}
// Copyright © 2023 Kim Altintop <kim@eagain.io>// SPDX-License-Identifier: GPL-2.0-onlyuse std::collections::{HashMap,HashSet,};use anyhow::bail;use async_trait::async_trait;use reqwest::Response;use tracing::debug;use super::{gpg,ssh,};pub struct Keys {pub ssh: HashSet<ssh::PublicKey>,pub gpg: HashMap<gpg::Fingerprint, gpg::SignedPublicKey>,}#[async_trait]pub trait Resolver {type Error: Send + Sync;async fn resolve(&self) -> Result<Keys, Self::Error> {tokio::try_join!(self.resolve_ssh(), self.resolve_gpg()).map(|(ssh, gpg)| Keys { ssh, gpg })}async fn resolve_ssh(&self) -> Result<HashSet<ssh::PublicKey>, Self::Error>;async fn resolve_gpg(&self,) -> Result<HashMap<gpg::Fingerprint, gpg::SignedPublicKey>, Self::Error>;}#[async_trait]pub trait ResponseExt: Sized {async fn succeed(self) -> anyhow::Result<Self>;}#[async_trait]impl ResponseExt for Response {async fn succeed(self) -> anyhow::Result<Self> {debug!("{}", self.status());if !self.status().is_success() {debug!("{:#?}", self.headers());let body = self.text().await?;bail!(body)}Ok(self)}}
// Copyright © 2023 Kim Altintop <kim@eagain.io>// SPDX-License-Identifier: GPL-2.0-onlyuse std::collections::{HashMap,HashSet,};use anyhow::{anyhow,Context as _,};use async_trait::async_trait;use tracing::debug;use url::Url;use super::{gpg::{self,Deserializable as _,KeyTrait as _,},resolver::{Resolver,ResponseExt as _,},ssh,};pub struct Gitlab<'a> {username: &'a str,client: reqwest::Client,}impl<'a> Gitlab<'a> {pub const fn new(username: &'a str, client: reqwest::Client) -> Self {Self { username, client }}}#[async_trait]impl<'a> Resolver for Gitlab<'a> {type Error = anyhow::Error;#[tracing::instrument(skip_all, fields(platform = "gitlab"))]async fn resolve_ssh(&self) -> Result<HashSet<ssh::PublicKey>, Self::Error> {let url = format!("https://gitlab.com/{}.keys", self.username);debug!("fetch: {url}");let keys = self.client.get(url).send().await?.succeed().await?.text().await?.lines().map(ssh::PublicKey::from_openssh).collect::<Result<_, _>>()?;Ok(keys)}#[tracing::instrument(skip_all, fields(platform = "gitlab"))]async fn resolve_gpg(&self,) -> Result<HashMap<gpg::Fingerprint, gpg::SignedPublicKey>, Self::Error> {let mut url = Url::parse("https://gitlab.com/api/v4/users").unwrap();#[derive(serde::Deserialize)]struct User {id: u64,}url.query_pairs_mut().append_pair("username", self.username);debug!("resolve user: {url}");let user = {let mut user = self.client.get(url.as_str()).send().await?.succeed().await?.json::<Vec<User>>().await?;user.pop().ok_or_else(|| anyhow!("username `{}` not found at gitlab", self.username))?};#[derive(serde::Deserialize)]struct Key {key: String,}url.set_query(None);url.path_segments_mut().expect("cannot be base cannot be").push(&user.id.to_string()).push("gpg_keys");debug!("fetch: {url}");let keys = self.client.get(url).send().await?.succeed().await?.json::<Vec<Key>>().await?.iter().map(|Key { key }| {let (key, _) = gpg::SignedPublicKey::from_string(key.as_str())?;let fp = key.fingerprint();key.verify().with_context(|| format!("key {} failed to verify", hex::encode_upper(&fp)))?;Ok((fp, key))}).collect::<Result<HashMap<_, _>, anyhow::Error>>()?;Ok(keys)}}
// Copyright © 2023 Kim Altintop <kim@eagain.io>// SPDX-License-Identifier: GPL-2.0-onlyuse std::collections::{HashMap,HashSet,};use anyhow::Context as _;use async_trait::async_trait;use tracing::debug;use super::{gpg::{self,Deserializable as _,KeyTrait as _,},resolver::{Resolver,ResponseExt as _,},ssh,};pub struct Github<'a> {username: &'a str,client: reqwest::Client,}impl<'a> Github<'a> {pub const fn new(username: &'a str, client: reqwest::Client) -> Self {Self { username, client }}}#[async_trait]impl<'a> Resolver for Github<'a> {type Error = anyhow::Error;#[tracing::instrument(skip_all, fields(platform = "github"))]async fn resolve_ssh(&self) -> Result<HashSet<ssh::PublicKey>, Self::Error> {let url = format!("https://github.com/{}.keys", self.username);debug!("fetch: {url}");let keys = self.client.get(url).send().await?.succeed().await?.text().await?.lines().map(ssh::PublicKey::from_openssh).collect::<Result<_, _>>()?;Ok(keys)}#[tracing::instrument(skip_all, fields(platform = "gitlab"))]async fn resolve_gpg(&self,) -> Result<HashMap<gpg::Fingerprint, gpg::SignedPublicKey>, Self::Error> {let url = format!("https://api.github.com/users/{}/gpg_keys", self.username);debug!("fetch: {url}");#[derive(serde::Deserialize)]struct Key {raw_key: String,}let keys = self.client.get(url).send().await?.succeed().await?.json::<Vec<Key>>().await?.iter().map(|Key { raw_key }| {let (key, _) = gpg::SignedPublicKey::from_string(raw_key.as_str())?;let fp = key.fingerprint();key.verify().with_context(|| format!("key {} failed to verify", hex::encode_upper(&fp)))?;Ok((fp, key))}).collect::<Result<HashMap<_, _>, anyhow::Error>>()?;Ok(keys)}}
tracing = { version = "0.1", features = ["log"] }url = "2.4.1"
[[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.4"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"[[package]]name = "base64ct"version = "1.6.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
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 0.4.4",][[package]]
name = "curve25519-dalek"version = "4.1.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "e89b8c6a2e4b1f45971ad09761aafb85514a84744b67a95e32c3cc1352d1f65c"dependencies = ["cfg-if","cpufeatures","curve25519-dalek-derive","digest 0.10.7","fiat-crypto","platforms","rustc_version","subtle","zeroize",][[package]]name = "curve25519-dalek-derive"version = "0.1.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b"dependencies = ["proc-macro2","quote","syn 2.0.31",][[package]]name = "darling"version = "0.14.4"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850"dependencies = ["darling_core","darling_macro",][[package]]name = "darling_core"version = "0.14.4"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0"dependencies = ["fnv","ident_case","proc-macro2","quote","strsim","syn 1.0.109",][[package]]name = "darling_macro"version = "0.14.4"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e"dependencies = ["darling_core","quote","syn 1.0.109",][[package]]
[[package]]name = "der"version = "0.7.8"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c"dependencies = ["const-oid","pem-rfc7468","zeroize",][[package]]name = "derive_builder"version = "0.12.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "8d67778784b508018359cbc8696edb3db78160bab2c2a28ba7f56ef6932997f8"dependencies = ["derive_builder_macro",]
name = "derive_builder_core"version = "0.12.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "c11bdc11a0c47bc7d37d582b5285da6849c96681023680b906673c5707af7b0f"dependencies = ["darling","proc-macro2","quote","syn 1.0.109",][[package]]name = "derive_builder_macro"version = "0.12.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "ebcda35c7a396850a55ffeac740804b40ffec779b98fffbb1738f4033f0ee79e"dependencies = ["derive_builder_core","syn 1.0.109",][[package]]name = "des"version = "0.8.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e"dependencies = ["cipher 0.4.4",][[package]]
"signature",
"signature 1.6.4",][[package]]name = "ed25519"version = "2.2.2"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "60f6d271ca33075c88028be6f04d502853d63a5ece419d269c15315d4fc1cf1d"dependencies = ["pkcs8","signature 2.1.0",
name = "ed25519-dalek"version = "2.0.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "7277392b266383ef8396db7fdeb1e77b6c52fed775f5df15bb24f35b72156980"dependencies = ["curve25519-dalek 4.1.1","ed25519 2.2.2","serde","sha2 0.10.7","zeroize",][[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.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"dependencies = ["percent-encoding",][[package]]
][[package]]name = "futures-channel"version = "0.3.28"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"dependencies = ["futures-core",][[package]]name = "futures-core"version = "0.3.28"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"[[package]]name = "futures-sink"version = "0.3.28"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"[[package]]name = "futures-task"version = "0.3.28"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"[[package]]name = "futures-util"version = "0.3.28"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"dependencies = ["futures-core","futures-task","pin-project-lite","pin-utils",
name = "group"version = "0.13.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63"dependencies = ["ff","rand_core 0.6.4","subtle",][[package]]name = "h2"version = "0.3.21"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833"dependencies = ["bytes","fnv","futures-core","futures-sink","futures-util","http","indexmap 1.9.3","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 = "humantime"version = "2.1.0"
name = "hmac"version = "0.12.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"dependencies = ["digest 0.10.7",][[package]]name = "http"version = "0.2.9"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"dependencies = ["bytes","fnv","itoa",][[package]]name = "http-body"version = "0.4.5"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"dependencies = ["bytes","http","pin-project-lite",][[package]]name = "httparse"version = "1.8.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"[[package]]name = "httpdate"version = "1.0.3"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"[[package]]name = "hyper"version = "0.14.27"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"dependencies = ["bytes","futures-channel","futures-core","futures-util","h2","http","http-body","httparse","httpdate","itoa","pin-project-lite","socket2 0.4.9","tokio","tower-service","tracing","want",]
][[package]]name = "idea"version = "0.5.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "075557004419d7f2031b8bb7f44bb43e55a83ca7b63076a8fb8fe75753836477"dependencies = ["cipher 0.4.4",][[package]]name = "ident_case"version = "1.0.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"[[package]]name = "idna"version = "0.4.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"dependencies = ["unicode-bidi","unicode-normalization",
checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b"dependencies = ["hermit-abi","rustix","windows-sys",]
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
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 0.10.7",][[package]]
name = "mio"version = "0.8.8"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"dependencies = ["libc","wasi 0.11.0+wasi-snapshot-preview1","windows-sys",][[package]]name = "native-tls"version = "0.2.11"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"dependencies = ["lazy_static","libc","log","openssl","openssl-probe","openssl-sys","schannel","security-framework","security-framework-sys","tempfile",][[package]]
][[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 0.8.5","serde","smallvec","zeroize",][[package]]name = "num-derive"version = "0.4.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e"dependencies = ["proc-macro2","quote","syn 2.0.31",][[package]]name = "num-integer"version = "0.1.45"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"dependencies = ["autocfg","num-traits",][[package]]name = "num-iter"version = "0.1.43"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"dependencies = ["autocfg","num-integer","num-traits",
[[package]]name = "openssl"version = "0.10.57"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c"dependencies = ["bitflags 2.4.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.31",][[package]]name = "openssl-probe"version = "0.1.5"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[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 0.10.7",]
"parking_lot_core",
"parking_lot_core 0.8.6",][[package]]name = "parking_lot"version = "0.12.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"dependencies = ["lock_api","parking_lot_core 0.9.8",
][[package]]name = "parking_lot_core"version = "0.9.8"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"dependencies = ["cfg-if","libc","redox_syscall 0.3.5","smallvec","windows-targets",
name = "pgp"version = "0.10.2"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "27e1f8e085bfa9b85763fe3ddaacbe90a09cd847b3833129153a6cb063bbe132"dependencies = ["aes 0.8.3","base64","bitfield","block-padding","blowfish","bstr","buffer-redux","byteorder","camellia","cast5","cfb-mode","chrono","cipher 0.4.4","crc24","curve25519-dalek 4.1.1","derive_builder","des","digest 0.10.7","ed25519-dalek 2.0.0","elliptic-curve","flate2","generic-array","hex","idea","log","md-5","nom","num-bigint-dig","num-derive","num-traits","p256","p384","rand 0.8.5","ripemd","rsa","sha1","sha2 0.10.7","sha3","signature 2.1.0","smallvec","thiserror","twofish","x25519-dalek","zeroize",][[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]]
"regex-automata","regex-syntax",
"regex-automata 0.3.8","regex-syntax 0.7.5",][[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",
name = "reqwest"version = "0.11.22"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b"dependencies = ["base64","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","serde","serde_json","serde_urlencoded","system-configuration","tokio","tokio-native-tls","tower-service","url","wasm-bindgen","wasm-bindgen-futures","web-sys","winreg",][[package]]name = "rfc6979"version = "0.4.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2"dependencies = ["hmac 0.12.1","subtle",][[package]]name = "ripemd"version = "0.1.3"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f"dependencies = ["digest 0.10.7",][[package]]name = "rsa"version = "0.9.2"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "6ab43bb47d23c1a631b4b680199a45255dce26fa9ab2fa902581f624ff13e6a8"dependencies = ["byteorder","const-oid","digest 0.10.7","num-bigint-dig","num-integer","num-iter","num-traits","pkcs1","pkcs8","rand_core 0.6.4","sha2 0.10.7","signature 2.1.0","spki","subtle","zeroize",][[package]]
name = "security-framework"version = "2.9.2"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"dependencies = ["bitflags 1.3.2","core-foundation","core-foundation-sys","libc","security-framework-sys",][[package]]name = "security-framework-sys"version = "2.9.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"dependencies = ["core-foundation-sys","libc",][[package]]name = "semver"version = "1.0.19"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0"[[package]]
name = "socket2"version = "0.5.4"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e"dependencies = ["libc","windows-sys",][[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.2"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a"dependencies = ["base64ct","der",][[package]]name = "ssh-cipher"version = "0.2.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "caac132742f0d33c3af65bfcde7f6aa8f62f0e991d80db99149eb9d44708784f"dependencies = ["cipher 0.4.4","ssh-encoding",][[package]]name = "ssh-encoding"version = "0.2.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "eb9242b9ef4108a78e8cd1a2c98e193ef372437f8c22be363075233321dd4a15"dependencies = ["base64ct","pem-rfc7468","sha2 0.10.7",][[package]]name = "ssh-key"version = "0.6.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "728fdf5286c394f12d83eaad51190af629aade5494813ce6b57f7425f1ca51b7"dependencies = ["p256","p384","rand_core 0.6.4","rsa","sec1","sha2 0.10.7","signature 2.1.0","ssh-cipher","ssh-encoding","subtle","zeroize",][[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]]
"bytes","libc","mio","num_cpus","parking_lot 0.12.1","pin-project-lite","signal-hook-registry","socket2 0.5.4","tokio-macros","windows-sys",][[package]]name = "tokio-macros"version = "2.1.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"dependencies = ["proc-macro2","quote","syn 2.0.31",][[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.9"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "1d68074620f57a0b21594d9735eb2e98ab38b17f80d3fcb189fca266771ca60d"dependencies = [
name = "tracing-subscriber"version = "0.3.17"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77"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.4"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"[[package]]name = "twofish"version = "0.7.1"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "a78e83a30223c757c3947cd144a31014ff04298d8719ae10d03c31c0448c8013"dependencies = ["cipher 0.4.4",][[package]]
name = "winreg"version = "0.50.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"dependencies = ["cfg-if","windows-sys",][[package]]name = "x25519-dalek"version = "2.0.0"source = "registry+https://github.com/rust-lang/crates.io-index"checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96"dependencies = ["curve25519-dalek 4.1.1","rand_core 0.6.4","serde","zeroize",][[package]]