use serde::{Deserialize, Serialize};
use signer_core::{SignerCrypted, SignerSigned, SignerUser};
use crate::{
HttpClient, HttpClientConfig, JsonTextResponse, OApiEnvelope,
OApiSignerSignedOApiEnvelopeInner, PostEnvelopesRequest, SignerDaemon,
model::viewobject::MessageVO,
};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Envelope {
pub data: SignerSigned<SignerCrypted<EnvelopeInner>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[cfg_attr(feature = "poem-openapi", derive(poem_openapi::Object))]
pub struct EnvelopeInner {
pub destinations: Vec<String>,
pub message: MessageVO,
}
impl Envelope {
pub async fn create(
daemon: &SignerDaemon,
message: &MessageVO,
destinations: Vec<String>,
) -> crate::DaemonResult<Self> {
let user = daemon.state.user.clone();
let inner = EnvelopeInner {
destinations,
message: message.clone(),
};
let inner = SignerCrypted::create(
&user,
&inner.message.chat.chat_key(&daemon.core).await?,
inner.clone(),
)?;
let inner = SignerSigned::from_value(&user, &inner)?;
Ok(Self { data: inner })
}
pub fn open(&self, user: &SignerUser) -> crate::DaemonResult<EnvelopeInner> {
let inner = self.data.verify_to_value()?;
let inner = inner.decrypt(user)?;
Ok(inner)
}
pub async fn send(&self, user: &SignerUser) -> crate::DaemonResult<()> {
let inner = self.data.verify_to_value()?.decrypt(user)?;
for destination in inner.destinations {
let envelope = self.clone();
let config = HttpClientConfig::new(user.clone(), destination);
let client = HttpClient::new(config);
let _response: JsonTextResponse = client
.post(
"/api/envelopes",
&PostEnvelopesRequest {
data: vec![OApiEnvelope {
data: Box::new(OApiSignerSignedOApiEnvelopeInner {
sig: envelope.data.sig,
msg: envelope.data.msg,
pubkey: envelope.data.pubkey,
}),
}],
},
)
.await?;
}
Ok(())
}
pub fn sender(&self) -> crate::DaemonResult<String> {
Ok(self.data.verify_to_value()?.sender_pub_key)
}
pub fn receiver(&self) -> crate::DaemonResult<String> {
Ok(self.data.verify_to_value()?.receiver_pub_key)
}
}
#[cfg(test)]
mod test {
use crate::{model::viewobject::PrivateChatVO, signer_remote::SignerRemote};
#[tokio::test]
async fn test_envelope() -> crate::DaemonResult<()> {
use signer_core::SignerUser;
use crate::{
SignerDaemon,
model::viewobject::{ChatVO, Envelope, MessageContent, MessageVO},
};
let alice = SignerUser::generete("alice")?;
let bob = SignerUser::generete("bob")?;
let alice_peer = uuid::Uuid::new_v4().to_string();
let bob_peer = uuid::Uuid::new_v4().to_string();
let alice_daemon = SignerDaemon::from_memory(&alice, &alice_peer).await?;
let bob_daemon = SignerDaemon::from_memory(&bob, &bob_peer).await?;
let message = MessageContent::Text(format!("Hello Bob!"));
let message_id = uuid::Uuid::new_v4().to_string();
let message = MessageVO {
chat: ChatVO::Private(PrivateChatVO {
peers: vec![bob.public.pub_key.clone(), alice.public.pub_key.clone()],
}),
id: message_id.clone(),
parent_id: None,
parent_user_key: None,
user_key: alice.public.pub_key.clone(),
create_time: chrono::Utc::now().timestamp_millis(),
receiver_keys: vec![bob.public.pub_key.clone()],
content: message,
};
let addr = format!("http://localhost:8080");
let remote = SignerRemote::new(&addr);
remote.ping(&alice).await?;
remote.ping(&bob).await?;
let envelope =
Envelope::create(&*alice_daemon.read().await, &message, vec![addr.clone()]).await?;
envelope.send(&alice).await?;
remote.pull_message(&mut *bob_daemon.write().await).await?;
let msgs = bob_daemon.read().await.store.message.list().await?;
assert!(msgs.len() == 1);
Ok(())
}
#[tokio::test]
async fn test_envelope_send_to_client() -> crate::DaemonResult<()> {
use signer_core::SignerUser;
use crate::{
SignerDaemon,
model::viewobject::{ChatVO, Envelope, MessageContent, MessageVO},
};
let alice = SignerUser::generete("alice")?;
let alice_daemon =
SignerDaemon::from_memory(&alice, &uuid::Uuid::new_v4().to_string()).await?;
let message = MessageContent::Text(format!("Hello Bob!"));
let message_id = uuid::Uuid::new_v4().to_string();
let message = MessageVO {
chat: ChatVO::Private(PrivateChatVO {
peers: vec![
"flNGOqa6fbJ67M8EKunes6P88zB09gcr6nRFFs-lJDs=".to_string(),
alice.public.pub_key.clone(),
],
}),
id: message_id.clone(),
parent_id: None,
parent_user_key: None,
user_key: alice.public.pub_key.clone(),
create_time: chrono::Utc::now().timestamp_millis(),
receiver_keys: vec!["flNGOqa6fbJ67M8EKunes6P88zB09gcr6nRFFs-lJDs=".to_string()],
content: message,
};
let envelope = Envelope::create(
&*alice_daemon.read().await,
&message,
vec!["http://localhost:8080".to_string()],
)
.await?;
envelope.send(&alice).await?;
Ok(())
}
}