use serde::{Deserialize, Serialize};
use signer_core::{SignerCrypted, SignerSigned, SignerUser};
use crate::{SignerDaemon, reqwest_auth::ReqwestAuth};
use super::MessageVO;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Envelope(pub SignerSigned<SignerCrypted<EnvelopeInner>>);
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnvelopeInner {
pub destinations: Vec<String>,
pub message: MessageVO,
}
impl Envelope {
pub async fn create(
daemon: &SignerDaemon,
message: &MessageVO,
destinations: Vec<String>,
) -> anyhow::Result<Self> {
let user = daemon.user.lock().await.clone();
let inner = EnvelopeInner {
destinations,
message: message.clone(),
};
let inner = SignerCrypted::create(
&user,
&inner.message.chat.chat_key(daemon).await?,
inner.clone(),
)?;
let inner = SignerSigned::from_value(&user, &inner)?;
Ok(Self(inner))
}
pub fn open(&self, user: &SignerUser) -> anyhow::Result<EnvelopeInner> {
let inner = self.0.verify_to_value()?;
let inner = inner.decrypt(user)?;
Ok(inner)
}
pub async fn send(&self, user: &SignerUser) -> anyhow::Result<()> {
let inner = self.0.verify_to_value()?.decrypt(user)?;
let client = reqwest::Client::new();
for destination in inner.destinations {
client
.post(&format!("{}/envelopes", &destination))
.with_signer_auth(&user)
.json(&serde_json::json!({
"data": vec![self.clone()],
}))
.send()
.await?
.error_for_status()?;
}
Ok(())
}
pub fn sender(&self) -> anyhow::Result<String> {
Ok(self.0.verify_to_value()?.sender_pub_key)
}
pub fn receiver(&self) -> anyhow::Result<String> {
Ok(self.0.verify_to_value()?.receiver_pub_key)
}
}
#[cfg(test)]
mod test {
#[tokio::test]
async fn test_envelope() -> anyhow::Result<()> {
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 {
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/api/signer");
alice_daemon.ping_server(&addr).await?;
bob_daemon.ping_server(&addr).await?;
let envelope =
Envelope::create(&alice_daemon, &message, vec![addr.clone()]).await?;
envelope.send(&alice).await?;
bob_daemon.remote_pull_message(&addr).await?;
let msgs = bob_daemon.list_message().await?;
assert!(msgs.len() == 1);
Ok(())
}
#[tokio::test]
async fn test_envelope_send_to_client() -> anyhow::Result<()> {
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 {
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,
&message,
vec!["http://localhost:8080/api/signer".to_string()],
)
.await?;
envelope.send(&alice).await?;
Ok(())
}
}