use cryptovec::CryptoVec;
use std::sync::Arc;
use thrussh_keys::encoding;
use thrussh_keys::key;
use tokio::io::{AsyncRead, AsyncWrite};
bitflags! {
pub struct MethodSet: u32 {
const NONE = 1;
const PASSWORD = 2;
const PUBLICKEY = 4;
const HOSTBASED = 8;
const KEYBOARD_INTERACTIVE = 16;
}
}
macro_rules! iter {
( $y:expr, $x:expr ) => {{
if $y.contains($x) {
$y.remove($x);
return Some($x);
}
}};
}
impl Iterator for MethodSet {
type Item = MethodSet;
fn next(&mut self) -> Option<MethodSet> {
iter!(self, MethodSet::NONE);
iter!(self, MethodSet::PASSWORD);
iter!(self, MethodSet::PUBLICKEY);
iter!(self, MethodSet::HOSTBASED);
iter!(self, MethodSet::KEYBOARD_INTERACTIVE);
None
}
}
pub trait Signer: Sized {
type Error: From<crate::SendError>;
type Future: futures::Future<Output = (Self, Result<CryptoVec, Self::Error>)> + Send;
fn auth_publickey_sign(self, key: &key::PublicKey, to_sign: CryptoVec) -> Self::Future;
}
#[derive(Debug, Error)]
pub enum AgentAuthError {
#[error(transparent)]
Send(#[from] crate::SendError),
#[error(transparent)]
Key(#[from] thrussh_keys::Error),
}
impl<R: AsyncRead + AsyncWrite + Unpin + Send + 'static> Signer
for thrussh_keys::agent::client::AgentClient<R>
{
type Error = AgentAuthError;
type Future = std::pin::Pin<
Box<dyn futures::Future<Output = (Self, Result<CryptoVec, Self::Error>)> + Send>,
>;
fn auth_publickey_sign(self, key: &key::PublicKey, to_sign: CryptoVec) -> Self::Future {
let fut = self.sign_request(key, to_sign);
futures::FutureExt::boxed(async move {
let (a, b) = fut.await;
(a, b.map_err(AgentAuthError::Key))
})
}
}
#[derive(Debug)]
pub enum Method {
Password { password: String },
PublicKey { key: Arc<key::KeyPair> },
FuturePublicKey { key: key::PublicKey },
}
impl encoding::Bytes for MethodSet {
fn bytes(&self) -> &'static [u8] {
match *self {
MethodSet::NONE => b"none",
MethodSet::PASSWORD => b"password",
MethodSet::PUBLICKEY => b"publickey",
MethodSet::HOSTBASED => b"hostbased",
MethodSet::KEYBOARD_INTERACTIVE => b"keyboard-interactive",
_ => b"",
}
}
}
impl MethodSet {
pub(crate) fn from_bytes(b: &[u8]) -> Option<MethodSet> {
match b {
b"none" => Some(MethodSet::NONE),
b"password" => Some(MethodSet::PASSWORD),
b"publickey" => Some(MethodSet::PUBLICKEY),
b"hostbased" => Some(MethodSet::HOSTBASED),
b"keyboard-interactive" => Some(MethodSet::KEYBOARD_INTERACTIVE),
_ => None,
}
}
}
#[doc(hidden)]
#[derive(Debug)]
pub struct AuthRequest {
pub methods: MethodSet,
pub partial_success: bool,
pub current: Option<CurrentRequest>,
pub rejection_count: usize,
}
#[doc(hidden)]
#[derive(Debug)]
pub enum CurrentRequest {
PublicKey {
key: CryptoVec,
algo: CryptoVec,
sent_pk_ok: bool,
},
KeyboardInteractive {
submethods: String,
},
}