use crate::*;
use holochain_zome_types::Signature;
use kitsune_p2p_types::dependencies::lair_keystore_api;
use lair_keystore_api::prelude::*;
use lair_keystore_api_0_0::actor::Cert as LegacyCert;
use lair_keystore_api_0_0::actor::CertDigest as LegacyCertDigest;
use lair_keystore_api_0_0::actor::CertPrivKey as LegacyCertPrivKey;
use lair_keystore_api_0_0::actor::LairClientApiSender;
use std::future::Future;
use std::sync::Arc;
pub use kitsune_p2p_types::dependencies::lair_keystore_api::LairResult;
#[derive(Clone)]
pub enum MetaLairClient {
Legacy(KeystoreSender),
NewLair(LairClient),
}
impl MetaLairClient {
pub fn shutdown(&self) -> impl Future<Output = LairResult<()>> + 'static + Send {
let this = self.clone();
async move {
match this {
Self::Legacy(client) => {
use ghost_actor::GhostControlSender;
client
.ghost_actor_shutdown_immediate()
.await
.map_err(one_err::OneErr::new)
}
Self::NewLair(client) => client.shutdown().await,
}
}
}
pub fn new_sign_keypair_random(
&self,
) -> impl Future<Output = LairResult<holo_hash::AgentPubKey>> + 'static + Send {
let this = self.clone();
async move {
match this {
Self::Legacy(client) => {
let (_, pk) = client
.sign_ed25519_new_from_entropy()
.await
.map_err(one_err::OneErr::new)?;
Ok(holo_hash::AgentPubKey::from_raw_32(pk.to_vec()))
}
Self::NewLair(client) => {
let tag = nanoid::nanoid!();
let info = client.new_seed(tag.into(), None).await?;
let pub_key =
holo_hash::AgentPubKey::from_raw_32(info.ed25519_pub_key.0.to_vec());
Ok(pub_key)
}
}
}
}
pub fn sign(
&self,
pub_key: holo_hash::AgentPubKey,
data: Arc<[u8]>,
) -> impl Future<Output = LairResult<Signature>> + 'static + Send {
let this = self.clone();
async move {
tokio::time::timeout(std::time::Duration::from_secs(30), async move {
match this {
Self::Legacy(client) => {
let pk = pub_key.get_raw_32();
let sig = client
.sign_ed25519_sign_by_pub_key(pk.to_vec().into(), data.to_vec().into())
.await
.map_err(one_err::OneErr::new)?;
let sig = Signature::try_from(sig.to_vec().as_ref())
.map_err(one_err::OneErr::new)?;
Ok(sig)
}
Self::NewLair(client) => {
let mut pub_key_2 = [0; 32];
pub_key_2.copy_from_slice(pub_key.get_raw_32());
let sig = client.sign_by_pub_key(pub_key_2.into(), None, data).await?;
Ok(Signature(*sig.0))
}
}
})
.await
.map_err(one_err::OneErr::new)?
}
}
pub fn new_x25519_keypair_random(
&self,
) -> impl Future<Output = LairResult<X25519PubKey>> + 'static + Send {
let this = self.clone();
async move {
match this {
Self::Legacy(client) => {
let (_, pk) = client
.x25519_new_from_entropy()
.await
.map_err(one_err::OneErr::new)?;
Ok(pk.to_bytes().into())
}
Self::NewLair(client) => {
let tag = nanoid::nanoid!();
let info = client.new_seed(tag.into(), None).await?;
let pub_key = info.x25519_pub_key;
Ok(pub_key)
}
}
}
}
pub fn crypto_box_xsalsa(
&self,
sender_pub_key: X25519PubKey,
recipient_pub_key: X25519PubKey,
data: Arc<[u8]>,
) -> impl Future<Output = LairResult<([u8; 24], Arc<[u8]>)>> + 'static + Send {
let this = self.clone();
async move {
match this {
Self::Legacy(client) => {
let res = client
.crypto_box_by_pub_key(
(*sender_pub_key).into(),
(*recipient_pub_key).into(),
lair_keystore_api_0_0::internal::crypto_box::CryptoBoxData {
data: data.to_vec().into(),
}
.into(),
)
.await
.map_err(one_err::OneErr::new)?;
Ok((*res.nonce.as_ref(), res.encrypted_data.to_vec().into()))
}
Self::NewLair(client) => {
client
.crypto_box_xsalsa_by_pub_key(sender_pub_key, recipient_pub_key, None, data)
.await
}
}
}
}
pub fn crypto_box_xsalsa_open(
&self,
sender_pub_key: X25519PubKey,
recipient_pub_key: X25519PubKey,
nonce: [u8; 24],
data: Arc<[u8]>,
) -> impl Future<Output = LairResult<Arc<[u8]>>> + 'static + Send {
let this = self.clone();
async move {
match this {
Self::Legacy(client) => {
let res = client
.crypto_box_open_by_pub_key(
(*sender_pub_key).into(),
(*recipient_pub_key).into(),
lair_keystore_api_0_0::internal::crypto_box::CryptoBoxEncryptedData {
nonce: nonce.into(),
encrypted_data: data.to_vec().into(),
}
.into(),
)
.await
.map_err(one_err::OneErr::new)?;
let res = res.ok_or_else(|| {
one_err::OneErr::new(
"None returned from crypto_box_open--why is that an Option??",
)
})?;
Ok(res.data.to_vec().into())
}
Self::NewLair(client) => {
client
.crypto_box_xsalsa_open_by_pub_key(
sender_pub_key,
recipient_pub_key,
None,
nonce,
data,
)
.await
}
}
}
}
pub fn get_or_create_first_tls_cert(
&self,
) -> impl Future<Output = LairResult<(LegacyCertDigest, LegacyCert, LegacyCertPrivKey)>>
+ 'static
+ Send {
let this = self.clone();
async move {
match this {
Self::Legacy(client) => client
.get_or_create_first_tls_cert()
.await
.map_err(one_err::OneErr::new),
Self::NewLair(client) => {
const ONE_CERT: &str = "SingleHcTlsWkaCert";
let info = match client.get_entry(ONE_CERT.into()).await {
Ok(info) => match info {
LairEntryInfo::WkaTlsCert { cert_info, .. } => cert_info,
oth => {
return Err(format!(
"invalid entry type, expecting wka tls cert: {:?}",
oth
)
.into())
}
},
Err(_) => client.new_wka_tls_cert(ONE_CERT.into()).await?,
};
let pk = client.get_wka_tls_cert_priv_key(ONE_CERT.into()).await?;
let digest: LegacyCertDigest = info.digest.to_vec().into();
let cert: LegacyCert = info.cert.to_vec().into();
let pk: LegacyCertPrivKey = pk.read_lock().to_vec().into();
Ok((digest, cert, pk))
}
}
}
}
}