mirror of
https://github.com/logos-messaging/libchat.git
synced 2026-02-09 16:33:10 +00:00
Implement Content::send_content (#31)
* Implement Content::send_content * rename stamp fn
This commit is contained in:
parent
10940321ff
commit
5a98258ff1
@ -112,7 +112,15 @@ pub fn send_content(
|
||||
convo_handle: ConvoHandle,
|
||||
content: c_slice::Ref<'_, u8>,
|
||||
) -> PayloadResult {
|
||||
let payloads = ctx.0.send_content(convo_handle, &content);
|
||||
let payloads = match ctx.0.send_content(convo_handle, &content) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
return PayloadResult {
|
||||
error_code: ErrorCode::UnknownError as i32,
|
||||
payloads: safer_ffi::Vec::EMPTY,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
let ffi_payloads: Vec<Payload> = payloads
|
||||
.into_iter()
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
use std::{collections::HashMap, rc::Rc, sync::Arc};
|
||||
|
||||
use crate::{
|
||||
conversation::{ConversationId, ConversationStore, Convo, Id},
|
||||
conversation::{ConversationStore, Convo, Id},
|
||||
errors::ChatError,
|
||||
identity::Identity,
|
||||
inbox::Inbox,
|
||||
types::{ContentData, PayloadData},
|
||||
types::{AddressedEnvelope, ContentData},
|
||||
};
|
||||
|
||||
pub use crate::inbox::Introduction;
|
||||
@ -53,22 +53,37 @@ impl Context {
|
||||
&mut self,
|
||||
remote_bundle: &Introduction,
|
||||
content: String,
|
||||
) -> (ConvoHandle, Vec<PayloadData>) {
|
||||
) -> (ConvoHandle, Vec<AddressedEnvelope>) {
|
||||
let (convo, payloads) = self
|
||||
.inbox
|
||||
.invite_to_private_convo(remote_bundle, content)
|
||||
.unwrap_or_else(|_| todo!("Log/Surface Error"));
|
||||
|
||||
let payload_bytes = payloads
|
||||
.into_iter()
|
||||
.map(|p| p.to_envelope(convo.id().to_string()))
|
||||
.collect();
|
||||
|
||||
let convo_handle = self.add_convo(convo);
|
||||
(convo_handle, payloads)
|
||||
(convo_handle, payload_bytes)
|
||||
}
|
||||
|
||||
pub fn send_content(&mut self, convo_id: ConvoHandle, _content: &[u8]) -> Vec<PayloadData> {
|
||||
// !TODO Replace Mock
|
||||
vec![PayloadData {
|
||||
delivery_address: format!("addr-for-{convo_id}"),
|
||||
data: vec![40, 30, 20, 10],
|
||||
}]
|
||||
pub fn send_content(
|
||||
&mut self,
|
||||
convo_handle: ConvoHandle,
|
||||
content: &[u8],
|
||||
) -> Result<Vec<AddressedEnvelope>, ChatError> {
|
||||
// Lookup convo from handle
|
||||
let convo = self.get_convo_mut(convo_handle)?;
|
||||
|
||||
// Generate encrypted payloads
|
||||
let payloads = convo.send_message(content)?;
|
||||
|
||||
// Attach conversation_ids to Envelopes
|
||||
Ok(payloads
|
||||
.into_iter()
|
||||
.map(|p| p.to_envelope(convo.remote_id()))
|
||||
.collect())
|
||||
}
|
||||
|
||||
pub fn handle_payload(&mut self, _payload: &[u8]) -> Option<ContentData> {
|
||||
@ -92,6 +107,19 @@ impl Context {
|
||||
|
||||
handle
|
||||
}
|
||||
|
||||
// Returns a mutable reference to a Convo for a given ConvoHandle
|
||||
fn get_convo_mut(&mut self, handle: ConvoHandle) -> Result<&mut dyn Convo, ChatError> {
|
||||
let convo_id = self
|
||||
.convo_handle_map
|
||||
.get(&handle)
|
||||
.ok_or_else(|| ChatError::NoConvo(handle))?
|
||||
.clone();
|
||||
|
||||
self.store
|
||||
.get_mut(&convo_id)
|
||||
.ok_or_else(|| ChatError::NoConvo(handle))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@ -3,7 +3,7 @@ use std::fmt::Debug;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub use crate::errors::ChatError;
|
||||
use crate::types::ContentData;
|
||||
use crate::types::{AddressedEncryptedPayload, ContentData};
|
||||
|
||||
pub type ConversationId<'a> = &'a str;
|
||||
pub type ConversationIdOwned = Arc<str>;
|
||||
@ -20,7 +20,10 @@ pub trait ConvoFactory: Id + Debug {
|
||||
}
|
||||
|
||||
pub trait Convo: Id + Debug {
|
||||
fn send_message(&mut self, content: &[u8]) -> Result<Vec<EncryptedPayload>, ChatError>;
|
||||
fn send_message(&mut self, content: &[u8])
|
||||
-> Result<Vec<AddressedEncryptedPayload>, ChatError>;
|
||||
|
||||
fn remote_id(&self) -> String;
|
||||
}
|
||||
|
||||
pub struct ConversationStore {
|
||||
@ -76,6 +79,5 @@ impl ConversationStore {
|
||||
mod group_test;
|
||||
mod privatev1;
|
||||
|
||||
use crate::proto::EncryptedPayload;
|
||||
pub use group_test::GroupTestConvo;
|
||||
pub use privatev1::PrivateV1Convo;
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use chat_proto::logoschat::encryption::EncryptedPayload;
|
||||
|
||||
use crate::conversation::{ChatError, ConversationId, Convo, Id};
|
||||
use crate::{
|
||||
conversation::{ChatError, ConversationId, Convo, Id},
|
||||
types::AddressedEncryptedPayload,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GroupTestConvo {}
|
||||
@ -19,7 +20,14 @@ impl Id for GroupTestConvo {
|
||||
}
|
||||
|
||||
impl Convo for GroupTestConvo {
|
||||
fn send_message(&mut self, _content: &[u8]) -> Result<Vec<EncryptedPayload>, ChatError> {
|
||||
fn send_message(
|
||||
&mut self,
|
||||
_content: &[u8],
|
||||
) -> Result<Vec<AddressedEncryptedPayload>, ChatError> {
|
||||
Ok(vec![])
|
||||
}
|
||||
|
||||
fn remote_id(&self) -> String {
|
||||
self.id().to_string()
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ use prost::{Message, bytes::Bytes};
|
||||
|
||||
use crate::{
|
||||
conversation::{ChatError, ConversationId, Convo, Id},
|
||||
types::AddressedEncryptedPayload,
|
||||
utils::timestamp_millis,
|
||||
};
|
||||
|
||||
@ -41,7 +42,10 @@ impl Id for PrivateV1Convo {
|
||||
}
|
||||
|
||||
impl Convo for PrivateV1Convo {
|
||||
fn send_message(&mut self, content: &[u8]) -> Result<Vec<EncryptedPayload>, ChatError> {
|
||||
fn send_message(
|
||||
&mut self,
|
||||
content: &[u8],
|
||||
) -> Result<Vec<AddressedEncryptedPayload>, ChatError> {
|
||||
let frame = PrivateV1Frame {
|
||||
conversation_id: self.id().into(),
|
||||
sender: "delete".into(),
|
||||
@ -49,8 +53,16 @@ impl Convo for PrivateV1Convo {
|
||||
frame_type: Some(FrameType::Content(content.to_vec().into())),
|
||||
};
|
||||
|
||||
let ef = self.encrypt(frame);
|
||||
let data = self.encrypt(frame);
|
||||
|
||||
Ok(vec![ef])
|
||||
Ok(vec![AddressedEncryptedPayload {
|
||||
delivery_address: "delivery_address".into(),
|
||||
data,
|
||||
}])
|
||||
}
|
||||
|
||||
fn remote_id(&self) -> String {
|
||||
//TODO: Implement as per spec
|
||||
self.id().into()
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,4 +18,6 @@ pub enum ChatError {
|
||||
InvalidKeyLength,
|
||||
#[error("bytes provided to {0} failed")]
|
||||
BadParsing(&'static str),
|
||||
#[error("convo with handle: {0} was not found")]
|
||||
NoConvo(u32),
|
||||
}
|
||||
|
||||
@ -1,4 +1,3 @@
|
||||
use chat_proto::logoschat::inbox::InboxV1Frame;
|
||||
use hex;
|
||||
use prost::Message;
|
||||
use prost::bytes::Bytes;
|
||||
@ -13,8 +12,8 @@ use crate::conversation::{ChatError, ConversationId, Convo, ConvoFactory, Id, Pr
|
||||
use crate::crypto::{Blake2b128, CopyBytes, Digest, PublicKey, StaticSecret};
|
||||
use crate::identity::Identity;
|
||||
use crate::inbox::handshake::InboxHandshake;
|
||||
use crate::proto::{self};
|
||||
use crate::types::{ContentData, PayloadData};
|
||||
use crate::proto;
|
||||
use crate::types::{AddressedEncryptedPayload, ContentData};
|
||||
|
||||
/// Compute the deterministic Delivery_address for an installation
|
||||
fn delivery_address_for_installation(_: PublicKey) -> String {
|
||||
@ -75,7 +74,7 @@ impl Inbox {
|
||||
&self,
|
||||
remote_bundle: &Introduction,
|
||||
initial_message: String,
|
||||
) -> Result<(PrivateV1Convo, Vec<PayloadData>), ChatError> {
|
||||
) -> Result<(PrivateV1Convo, Vec<AddressedEncryptedPayload>), ChatError> {
|
||||
let mut rng = OsRng;
|
||||
|
||||
// TODO: Include signature in introduction bundle. Manaully fill for now
|
||||
@ -91,12 +90,12 @@ impl Inbox {
|
||||
|
||||
let mut convo = PrivateV1Convo::new(seed_key);
|
||||
|
||||
let mut initial_payloads = convo.send_message(initial_message.as_bytes())?;
|
||||
let mut payloads = convo.send_message(initial_message.as_bytes())?;
|
||||
|
||||
// Wrap First payload in Invite
|
||||
if let Some(first_message) = initial_payloads.get_mut(0) {
|
||||
let old = first_message.clone();
|
||||
let frame = Self::wrap_in_invite(old);
|
||||
if let Some(first_message) = payloads.get_mut(0) {
|
||||
// Take the the value of .data - it's being replaced at the end of this block
|
||||
let frame = Self::wrap_in_invite(std::mem::take(&mut first_message.data));
|
||||
|
||||
// TODO: Encrypt frame
|
||||
let ciphertext = frame.encode_to_vec();
|
||||
@ -113,21 +112,16 @@ impl Inbox {
|
||||
payload: Bytes::from_owner(ciphertext),
|
||||
};
|
||||
|
||||
*first_message = proto::EncryptedPayload {
|
||||
// Update the address field with the Inbox delivery_Address
|
||||
first_message.delivery_address =
|
||||
delivery_address_for_installation(remote_bundle.installation_key);
|
||||
// Update the data field with new Payload
|
||||
first_message.data = proto::EncryptedPayload {
|
||||
encryption: Some(proto::Encryption::InboxHandshake(handshake)),
|
||||
};
|
||||
}
|
||||
|
||||
// Convert Encrypted Payloads to PayloadData
|
||||
let payload_data = initial_payloads
|
||||
.iter()
|
||||
.map(|p| PayloadData {
|
||||
delivery_address: delivery_address_for_installation(remote_bundle.installation_key),
|
||||
data: p.encode_to_vec(),
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok((convo, payload_data))
|
||||
Ok((convo, payloads))
|
||||
}
|
||||
|
||||
fn wrap_in_invite(payload: proto::EncryptedPayload) -> proto::InboxV1Frame {
|
||||
@ -174,7 +168,7 @@ impl Inbox {
|
||||
);
|
||||
|
||||
// TODO: Decrypt Content
|
||||
let frame = InboxV1Frame::decode(handshake.payload)?;
|
||||
let frame = proto::InboxV1Frame::decode(handshake.payload)?;
|
||||
Ok((seed_key, frame))
|
||||
}
|
||||
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
pub use chat_proto::logoschat::encryption::encrypted_payload::Encryption;
|
||||
pub use chat_proto::logoschat::encryption::inbox_handshake_v1::InboxHeaderV1;
|
||||
pub use chat_proto::logoschat::encryption::{EncryptedPayload, InboxHandshakeV1};
|
||||
pub use chat_proto::logoschat::envelope::EnvelopeV1;
|
||||
pub use chat_proto::logoschat::inbox::InboxV1Frame;
|
||||
pub use chat_proto::logoschat::invite::InvitePrivateV1;
|
||||
|
||||
pub use prost::Message;
|
||||
pub use prost::bytes::Bytes;
|
||||
|
||||
@ -1,6 +1,10 @@
|
||||
use crate::proto::{self, Message};
|
||||
|
||||
// FFI Type definitions
|
||||
|
||||
// This struct represents Outbound data.
|
||||
// It wraps an encoded payload with a delivery address, so it can be handled by the delivery service.
|
||||
pub struct PayloadData {
|
||||
pub struct AddressedEnvelope {
|
||||
pub delivery_address: String,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
@ -11,3 +15,28 @@ pub struct ContentData {
|
||||
pub conversation_id: String,
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
// Internal type Definitions
|
||||
|
||||
// Used by Conversations to attach addresses to outbound encrypted payloads
|
||||
pub(crate) struct AddressedEncryptedPayload {
|
||||
pub delivery_address: String,
|
||||
pub data: proto::EncryptedPayload,
|
||||
}
|
||||
|
||||
impl AddressedEncryptedPayload {
|
||||
// Wrap in an envelope and prepare for transmission
|
||||
pub fn to_envelope(self, convo_id: String) -> AddressedEnvelope {
|
||||
let envelope = proto::EnvelopeV1 {
|
||||
// TODO: conversation_id should be obscured
|
||||
conversation_hint: convo_id,
|
||||
salt: 0,
|
||||
payload: proto::Bytes::copy_from_slice(self.data.encode_to_vec().as_slice()),
|
||||
};
|
||||
|
||||
AddressedEnvelope {
|
||||
delivery_address: self.delivery_address,
|
||||
data: envelope.encode_to_vec(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user