use super::{constants::SN_AUTHD_CONNECTION_IDLE_TIMEOUT, Error, Result};
use log::info;
use qjsonrpc::ClientEndpoint;
use serde::de::DeserializeOwned;
use tokio::runtime;
pub mod auth_types {
use crate::api::ipc::req::IpcReq;
use serde::{Deserialize, Serialize};
pub type SafeAuthReq = IpcReq;
pub type SafeAuthReqId = u32;
#[derive(Debug, Serialize, Deserialize)]
pub struct AuthedApp {
pub id: String,
pub name: String,
pub vendor: String,
}
pub type AuthedAppsList = Vec<AuthedApp>;
}
pub fn parse_hex(hex_str: &str) -> Vec<u8> {
let mut hex_bytes = hex_str
.as_bytes()
.iter()
.filter_map(|b| match b {
b'0'..=b'9' => Some(b - b'0'),
b'a'..=b'f' => Some(b - b'a' + 10),
b'A'..=b'F' => Some(b - b'A' + 10),
_ => None,
})
.fuse();
let mut bytes = Vec::new();
while let (Some(h), Some(l)) = (hex_bytes.next(), hex_bytes.next()) {
bytes.push(h << 4 | l)
}
bytes
}
#[allow(unused)]
pub fn bls_sk_from_hex(hex_str: &str) -> Result<threshold_crypto::SecretKey> {
let sk_bytes = parse_hex(&hex_str);
bincode::deserialize(&sk_bytes).map_err(|_| {
Error::InvalidInput("Failed to deserialize provided BLS secret key".to_string())
})
}
pub fn ed_sk_from_hex(hex_str: &str) -> Result<ed25519_dalek::SecretKey> {
let sk_bytes = parse_hex(&hex_str);
ed25519_dalek::SecretKey::from_bytes(&sk_bytes).map_err(|_| {
Error::InvalidInput("Failed to deserialize provided Ed25519 secret key".to_string())
})
}
pub fn sk_to_hex(sk: sn_data_types::SecretKey) -> String {
match sk {
sn_data_types::SecretKey::Ed25519(sk) => {
sk.to_bytes().iter().map(|b| format!("{:02x}", b)).collect()
}
sn_data_types::SecretKey::BlsShare(sk) => sk.inner().reveal(), }
}
pub async fn send_authd_request<T>(
dest_endpoint: &str,
method: &str,
params: serde_json::Value,
) -> Result<T>
where
T: DeserializeOwned,
{
info!(
"Sending '{}' request to SAFE Authenticator on {} ...",
method, dest_endpoint
);
match dirs_next::home_dir() {
None => Err(Error::AuthdClientError(
"Failed to obtain local project directory where to read certificate from".to_string(),
)),
Some(mut paths) => {
paths.push(".safe");
paths.push("authd");
let cert_base_path = paths.display().to_string();
let qjsonrpc_client = ClientEndpoint::new(
&cert_base_path,
Some(SN_AUTHD_CONNECTION_IDLE_TIMEOUT),
false,
)
.map_err(|err| {
Error::AuthdClientError(format!("Failed to create client endpoint: {}", err))
})?;
let runtime = match runtime::Handle::try_current() {
Ok(r) => r,
Err(_) => runtime::Runtime::new()
.map_err(|err| {
Error::AuthdClientError(format!("Failed to create runtime: {}", err))
})?
.handle()
.clone(),
};
let mut outgoing_conn = {
runtime.enter(|| qjsonrpc_client.bind()).map_err(|err| {
Error::AuthdClientError(format!("Failed to bind endpoint: {}", err))
})?
};
outgoing_conn
.connect(dest_endpoint, None)
.await
.map_err(|err| {
Error::AuthdClientError(format!(
"Failed to establish connection with authd: {}",
err
))
})?
.send(method, params)
.await
.map_err(|err| match err {
qjsonrpc::Error::RemoteEndpointError(msg) => Error::AuthdError(msg),
other => Error::AuthdClientError(other.to_string()),
})
}
}
}