mirror of
https://github.com/logos-messaging/libchat.git
synced 2026-04-01 09:04:03 +00:00
pr feedback and test fix
This commit is contained in:
parent
ecd1be3b9e
commit
14a403399e
@ -47,11 +47,13 @@ pub struct ContextHandle(pub(crate) Context);
|
||||
/// Creates a new libchat Ctx
|
||||
///
|
||||
/// # Returns
|
||||
/// Opaque handle to the store. Must be freed with destroy_context()
|
||||
/// Opaque handle to the store. Must be freed with destroy_context().
|
||||
/// Uses lossy UTF-8 conversion: invalid bytes are replaced with U+FFFD
|
||||
/// so the caller always gets a deterministic name reflecting their input.
|
||||
#[ffi_export]
|
||||
pub fn create_context(name: c_slice::Ref<'_, u8>) -> repr_c::Box<ContextHandle> {
|
||||
let name_str = std::str::from_utf8(name.as_slice()).unwrap_or("default");
|
||||
Box::new(ContextHandle(Context::new_with_name(name_str))).into()
|
||||
let name_str = std::string::String::from_utf8_lossy(name.as_slice());
|
||||
Box::new(ContextHandle(Context::new_with_name(&name_str))).into()
|
||||
}
|
||||
|
||||
/// Returns the friendly name of the contexts installation.
|
||||
@ -193,7 +195,16 @@ pub fn send_content(
|
||||
content: c_slice::Ref<'_, u8>,
|
||||
out: &mut SendContentResult,
|
||||
) {
|
||||
let convo_id_str = std::str::from_utf8(convo_id.as_slice()).unwrap_or("");
|
||||
let convo_id_str = match std::str::from_utf8(convo_id.as_slice()) {
|
||||
Ok(s) => s,
|
||||
Err(_) => {
|
||||
*out = SendContentResult {
|
||||
error_code: ErrorCode::BadConvoId as i32,
|
||||
payloads: safer_ffi::Vec::EMPTY,
|
||||
};
|
||||
return;
|
||||
}
|
||||
};
|
||||
let payloads = match ctx.0.send_content(convo_id_str, &content) {
|
||||
Ok(p) => p,
|
||||
Err(_) => {
|
||||
|
||||
@ -60,7 +60,11 @@ pub struct PrivateV1Convo {
|
||||
}
|
||||
|
||||
impl PrivateV1Convo {
|
||||
pub fn new_initiator(seed_key: SymmetricKey32, remote: PublicKey, remote_delivery_address: String) -> Self {
|
||||
pub fn new_initiator(
|
||||
seed_key: SymmetricKey32,
|
||||
remote: PublicKey,
|
||||
remote_delivery_address: String,
|
||||
) -> Self {
|
||||
let base_convo_id = BaseConvoId::new(&seed_key);
|
||||
let local_convo_id = base_convo_id.id_for_participant(Role::Initiator);
|
||||
let remote_convo_id = base_convo_id.id_for_participant(Role::Responder);
|
||||
@ -79,7 +83,11 @@ impl PrivateV1Convo {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_responder(seed_key: SymmetricKey32, dh_self: &PrivateKey, remote_delivery_address: String) -> Self {
|
||||
pub fn new_responder(
|
||||
seed_key: SymmetricKey32,
|
||||
dh_self: &PrivateKey,
|
||||
remote_delivery_address: String,
|
||||
) -> Self {
|
||||
let base_convo_id = BaseConvoId::new(&seed_key);
|
||||
let local_convo_id = base_convo_id.id_for_participant(Role::Responder);
|
||||
let remote_convo_id = base_convo_id.id_for_participant(Role::Initiator);
|
||||
@ -239,7 +247,8 @@ mod tests {
|
||||
let seed_key_saro = SymmetricKey32::from(seed_key);
|
||||
let seed_key_raya = SymmetricKey32::from(seed_key);
|
||||
let send_content_bytes = vec![0, 2, 4, 6, 8];
|
||||
let mut sr_convo = PrivateV1Convo::new_initiator(seed_key_saro, pub_raya, "test_addr".into());
|
||||
let mut sr_convo =
|
||||
PrivateV1Convo::new_initiator(seed_key_saro, pub_raya, "test_addr".into());
|
||||
let mut rs_convo = PrivateV1Convo::new_responder(seed_key_raya, &raya, "test_addr".into());
|
||||
|
||||
let send_frame = PrivateV1Frame {
|
||||
|
||||
@ -72,8 +72,13 @@ impl Inbox {
|
||||
let (seed_key, ephemeral_pub) =
|
||||
InboxHandshake::perform_as_initiator(self.ident.secret(), &pkb, &mut rng);
|
||||
|
||||
let remote_delivery_addr = Inbox::inbox_identifier_for_key(*remote_bundle.installation_key());
|
||||
let mut convo = PrivateV1Convo::new_initiator(seed_key, *remote_bundle.ephemeral_key(), remote_delivery_addr.clone());
|
||||
let remote_delivery_addr =
|
||||
Inbox::inbox_identifier_for_key(*remote_bundle.installation_key());
|
||||
let mut convo = PrivateV1Convo::new_initiator(
|
||||
seed_key,
|
||||
*remote_bundle.ephemeral_key(),
|
||||
remote_delivery_addr.clone(),
|
||||
);
|
||||
|
||||
let mut payloads = convo.send_message(initial_message)?;
|
||||
|
||||
@ -119,17 +124,21 @@ impl Inbox {
|
||||
let ephemeral_key = self.lookup_ephemeral_key(&key_index)?;
|
||||
|
||||
// Extract initiator's identity key for delivery address before header is consumed
|
||||
let initiator_static_bytes: [u8; 32] = header.initiator_static.as_ref()
|
||||
let initiator_static_bytes: [u8; 32] = header
|
||||
.initiator_static
|
||||
.as_ref()
|
||||
.try_into()
|
||||
.map_err(|_| ChatError::BadBundleValue("wrong size - initiator static".into()))?;
|
||||
let remote_delivery_addr = Inbox::inbox_identifier_for_key(PublicKey::from(initiator_static_bytes));
|
||||
let remote_delivery_addr =
|
||||
Inbox::inbox_identifier_for_key(PublicKey::from(initiator_static_bytes));
|
||||
|
||||
// Perform handshake and decrypt frame
|
||||
let (seed_key, frame) = self.perform_handshake(ephemeral_key, header, handshake.payload)?;
|
||||
|
||||
match frame.frame_type.unwrap() {
|
||||
proto::inbox_v1_frame::FrameType::InvitePrivateV1(_invite_private_v1) => {
|
||||
let mut convo = PrivateV1Convo::new_responder(seed_key, ephemeral_key, remote_delivery_addr);
|
||||
let mut convo =
|
||||
PrivateV1Convo::new_responder(seed_key, ephemeral_key, remote_delivery_addr);
|
||||
|
||||
let Some(enc_payload) = _invite_private_v1.initial_message else {
|
||||
return Err(ChatError::Protocol("missing initial encpayload".into()));
|
||||
|
||||
10
flake.nix
10
flake.nix
@ -51,18 +51,24 @@
|
||||
doCheck = false; # tests require network access unavailable in nix sandbox
|
||||
|
||||
postBuild = ''
|
||||
cargo run --release --bin generate-libchat-headers --features headers
|
||||
cargo run --frozen --release --bin generate-libchat-headers --features headers
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
runHook preInstall
|
||||
mkdir -p $out/lib $out/include
|
||||
|
||||
# Copy shared library
|
||||
# Copy shared library (platform-dependent extension)
|
||||
cp target/release/liblibchat.so $out/lib/ 2>/dev/null || true
|
||||
cp target/release/liblibchat.dylib $out/lib/ 2>/dev/null || true
|
||||
cp target/release/liblibchat.a $out/lib/ 2>/dev/null || true
|
||||
|
||||
# Fail if no library was produced
|
||||
if [ -z "$(ls $out/lib/liblibchat.* 2>/dev/null)" ]; then
|
||||
echo "ERROR: No library artifact found in target/release/"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Copy generated header
|
||||
cp libchat.h $out/include/
|
||||
|
||||
|
||||
@ -85,7 +85,7 @@ type
|
||||
|
||||
## Creates a new libchat Context
|
||||
## Returns: Opaque handle to the context. Must be freed with destroy_context()
|
||||
proc create_context*(name: ReprCString): ContextHandle {.importc.}
|
||||
proc create_context*(name: SliceUint8): ContextHandle {.importc.}
|
||||
|
||||
## Returns the friendly name of the context's identity
|
||||
## The result must be freed by the caller (repr_c::String ownership transfers)
|
||||
@ -129,7 +129,7 @@ proc list_conversations*(
|
||||
## The result must be freed with destroy_send_content_result()
|
||||
proc send_content*(
|
||||
ctx: ContextHandle,
|
||||
convo_id: ReprCString,
|
||||
convo_id: SliceUint8,
|
||||
content: SliceUint8,
|
||||
): SendContentResult {.importc.}
|
||||
|
||||
|
||||
@ -72,7 +72,7 @@ proc testHelperProcs() =
|
||||
proc testContextLifecycle() =
|
||||
echo "\n--- testContextLifecycle ---"
|
||||
|
||||
let ctx = create_context(toReprCString("lifecycle-test"))
|
||||
let ctx = create_context(toSlice("lifecycle-test"))
|
||||
check(ctx != nil, "create_context: returns non-nil handle")
|
||||
|
||||
let iname = installation_name(ctx)
|
||||
@ -94,10 +94,10 @@ proc testContextLifecycle() =
|
||||
proc testFullConversationFlow() =
|
||||
echo "\n--- testFullConversationFlow ---"
|
||||
|
||||
let aliceCtx = create_context(toReprCString("alice"))
|
||||
let aliceCtx = create_context(toSlice("alice"))
|
||||
check(aliceCtx != nil, "Alice: create_context non-nil")
|
||||
|
||||
let bobCtx = create_context(toReprCString("bob"))
|
||||
let bobCtx = create_context(toSlice("bob"))
|
||||
check(bobCtx != nil, "Bob: create_context non-nil")
|
||||
|
||||
# --- create_intro_bundle ---
|
||||
@ -177,7 +177,7 @@ proc testFullConversationFlow() =
|
||||
# --- send_content ---
|
||||
var sendRes = send_content(
|
||||
aliceCtx,
|
||||
toReprCString(aliceConvoId),
|
||||
toSlice(aliceConvoId),
|
||||
toSlice("How are you, Bob?")
|
||||
)
|
||||
check(sendRes.error_code == ErrNone,
|
||||
@ -213,13 +213,13 @@ proc testFullConversationFlow() =
|
||||
proc testErrorCases() =
|
||||
echo "\n--- testErrorCases ---"
|
||||
|
||||
let ctx = create_context(toReprCString("error-tester"))
|
||||
let ctx = create_context(toSlice("error-tester"))
|
||||
check(ctx != nil, "error-tester: create_context non-nil")
|
||||
|
||||
# send_content with a nonexistent convo_id must fail
|
||||
var badSend = send_content(
|
||||
ctx,
|
||||
toReprCString("00000000-0000-0000-0000-nonexistent"),
|
||||
toSlice("00000000-0000-0000-0000-nonexistent"),
|
||||
toSlice("payload")
|
||||
)
|
||||
check(badSend.error_code != ErrNone,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user