mirror of
https://github.com/logos-messaging/libchat.git
synced 2026-03-31 08:33:11 +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,
|
convo_handle: ConvoHandle,
|
||||||
content: c_slice::Ref<'_, u8>,
|
content: c_slice::Ref<'_, u8>,
|
||||||
) -> PayloadResult {
|
) -> 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
|
let ffi_payloads: Vec<Payload> = payloads
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
use std::{collections::HashMap, rc::Rc, sync::Arc};
|
use std::{collections::HashMap, rc::Rc, sync::Arc};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
conversation::{ConversationId, ConversationStore, Convo, Id},
|
conversation::{ConversationStore, Convo, Id},
|
||||||
errors::ChatError,
|
errors::ChatError,
|
||||||
identity::Identity,
|
identity::Identity,
|
||||||
inbox::Inbox,
|
inbox::Inbox,
|
||||||
types::{ContentData, PayloadData},
|
types::{AddressedEnvelope, ContentData},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use crate::inbox::Introduction;
|
pub use crate::inbox::Introduction;
|
||||||
@ -53,22 +53,37 @@ impl Context {
|
|||||||
&mut self,
|
&mut self,
|
||||||
remote_bundle: &Introduction,
|
remote_bundle: &Introduction,
|
||||||
content: String,
|
content: String,
|
||||||
) -> (ConvoHandle, Vec<PayloadData>) {
|
) -> (ConvoHandle, Vec<AddressedEnvelope>) {
|
||||||
let (convo, payloads) = self
|
let (convo, payloads) = self
|
||||||
.inbox
|
.inbox
|
||||||
.invite_to_private_convo(remote_bundle, content)
|
.invite_to_private_convo(remote_bundle, content)
|
||||||
.unwrap_or_else(|_| todo!("Log/Surface Error"));
|
.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);
|
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> {
|
pub fn send_content(
|
||||||
// !TODO Replace Mock
|
&mut self,
|
||||||
vec![PayloadData {
|
convo_handle: ConvoHandle,
|
||||||
delivery_address: format!("addr-for-{convo_id}"),
|
content: &[u8],
|
||||||
data: vec![40, 30, 20, 10],
|
) -> 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> {
|
pub fn handle_payload(&mut self, _payload: &[u8]) -> Option<ContentData> {
|
||||||
@ -92,6 +107,19 @@ impl Context {
|
|||||||
|
|
||||||
handle
|
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)]
|
#[cfg(test)]
|
||||||
|
|||||||
@ -3,7 +3,7 @@ use std::fmt::Debug;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub use crate::errors::ChatError;
|
pub use crate::errors::ChatError;
|
||||||
use crate::types::ContentData;
|
use crate::types::{AddressedEncryptedPayload, ContentData};
|
||||||
|
|
||||||
pub type ConversationId<'a> = &'a str;
|
pub type ConversationId<'a> = &'a str;
|
||||||
pub type ConversationIdOwned = Arc<str>;
|
pub type ConversationIdOwned = Arc<str>;
|
||||||
@ -20,7 +20,10 @@ pub trait ConvoFactory: Id + Debug {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub trait Convo: 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 {
|
pub struct ConversationStore {
|
||||||
@ -76,6 +79,5 @@ impl ConversationStore {
|
|||||||
mod group_test;
|
mod group_test;
|
||||||
mod privatev1;
|
mod privatev1;
|
||||||
|
|
||||||
use crate::proto::EncryptedPayload;
|
|
||||||
pub use group_test::GroupTestConvo;
|
pub use group_test::GroupTestConvo;
|
||||||
pub use privatev1::PrivateV1Convo;
|
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)]
|
#[derive(Debug)]
|
||||||
pub struct GroupTestConvo {}
|
pub struct GroupTestConvo {}
|
||||||
@ -19,7 +20,14 @@ impl Id for GroupTestConvo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Convo 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![])
|
Ok(vec![])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn remote_id(&self) -> String {
|
||||||
|
self.id().to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ use prost::{Message, bytes::Bytes};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
conversation::{ChatError, ConversationId, Convo, Id},
|
conversation::{ChatError, ConversationId, Convo, Id},
|
||||||
|
types::AddressedEncryptedPayload,
|
||||||
utils::timestamp_millis,
|
utils::timestamp_millis,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -41,7 +42,10 @@ impl Id for PrivateV1Convo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Convo 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 {
|
let frame = PrivateV1Frame {
|
||||||
conversation_id: self.id().into(),
|
conversation_id: self.id().into(),
|
||||||
sender: "delete".into(),
|
sender: "delete".into(),
|
||||||
@ -49,8 +53,16 @@ impl Convo for PrivateV1Convo {
|
|||||||
frame_type: Some(FrameType::Content(content.to_vec().into())),
|
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,
|
InvalidKeyLength,
|
||||||
#[error("bytes provided to {0} failed")]
|
#[error("bytes provided to {0} failed")]
|
||||||
BadParsing(&'static str),
|
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 hex;
|
||||||
use prost::Message;
|
use prost::Message;
|
||||||
use prost::bytes::Bytes;
|
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::crypto::{Blake2b128, CopyBytes, Digest, PublicKey, StaticSecret};
|
||||||
use crate::identity::Identity;
|
use crate::identity::Identity;
|
||||||
use crate::inbox::handshake::InboxHandshake;
|
use crate::inbox::handshake::InboxHandshake;
|
||||||
use crate::proto::{self};
|
use crate::proto;
|
||||||
use crate::types::{ContentData, PayloadData};
|
use crate::types::{AddressedEncryptedPayload, ContentData};
|
||||||
|
|
||||||
/// Compute the deterministic Delivery_address for an installation
|
/// Compute the deterministic Delivery_address for an installation
|
||||||
fn delivery_address_for_installation(_: PublicKey) -> String {
|
fn delivery_address_for_installation(_: PublicKey) -> String {
|
||||||
@ -75,7 +74,7 @@ impl Inbox {
|
|||||||
&self,
|
&self,
|
||||||
remote_bundle: &Introduction,
|
remote_bundle: &Introduction,
|
||||||
initial_message: String,
|
initial_message: String,
|
||||||
) -> Result<(PrivateV1Convo, Vec<PayloadData>), ChatError> {
|
) -> Result<(PrivateV1Convo, Vec<AddressedEncryptedPayload>), ChatError> {
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
|
|
||||||
// TODO: Include signature in introduction bundle. Manaully fill for now
|
// 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 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
|
// Wrap First payload in Invite
|
||||||
if let Some(first_message) = initial_payloads.get_mut(0) {
|
if let Some(first_message) = payloads.get_mut(0) {
|
||||||
let old = first_message.clone();
|
// Take the the value of .data - it's being replaced at the end of this block
|
||||||
let frame = Self::wrap_in_invite(old);
|
let frame = Self::wrap_in_invite(std::mem::take(&mut first_message.data));
|
||||||
|
|
||||||
// TODO: Encrypt frame
|
// TODO: Encrypt frame
|
||||||
let ciphertext = frame.encode_to_vec();
|
let ciphertext = frame.encode_to_vec();
|
||||||
@ -113,21 +112,16 @@ impl Inbox {
|
|||||||
payload: Bytes::from_owner(ciphertext),
|
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)),
|
encryption: Some(proto::Encryption::InboxHandshake(handshake)),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert Encrypted Payloads to PayloadData
|
Ok((convo, payloads))
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wrap_in_invite(payload: proto::EncryptedPayload) -> proto::InboxV1Frame {
|
fn wrap_in_invite(payload: proto::EncryptedPayload) -> proto::InboxV1Frame {
|
||||||
@ -174,7 +168,7 @@ impl Inbox {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// TODO: Decrypt Content
|
// TODO: Decrypt Content
|
||||||
let frame = InboxV1Frame::decode(handshake.payload)?;
|
let frame = proto::InboxV1Frame::decode(handshake.payload)?;
|
||||||
Ok((seed_key, frame))
|
Ok((seed_key, frame))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
pub use chat_proto::logoschat::encryption::encrypted_payload::Encryption;
|
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::inbox_handshake_v1::InboxHeaderV1;
|
||||||
pub use chat_proto::logoschat::encryption::{EncryptedPayload, InboxHandshakeV1};
|
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::inbox::InboxV1Frame;
|
||||||
pub use chat_proto::logoschat::invite::InvitePrivateV1;
|
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.
|
// This struct represents Outbound data.
|
||||||
// It wraps an encoded payload with a delivery address, so it can be handled by the delivery service.
|
// 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 delivery_address: String,
|
||||||
pub data: Vec<u8>,
|
pub data: Vec<u8>,
|
||||||
}
|
}
|
||||||
@ -11,3 +15,28 @@ pub struct ContentData {
|
|||||||
pub conversation_id: String,
|
pub conversation_id: String,
|
||||||
pub data: Vec<u8>,
|
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