Merge pull request 'update to lcg1.7 including new APIs, new structs (ACL) and testing using bindings as helper functions with wrappers to rust-ify results and api' (#11) from lcg1.7 into main

Reviewed-on: #11
This commit is contained in:
Sarah Jamie Lewis 2022-04-11 21:48:31 +00:00
commit 14e6010574
6 changed files with 161 additions and 22 deletions

View File

@ -15,9 +15,9 @@ fn main() {
println!("cargo:rerun-if-changed=libCwtch.h");
let lib_cwtch_path = Path::new(&out_dir).join("libCwtch.so");
// https://git.openprivacy.ca/cwtch.im/libcwtch-go/releases v1.5.4
// https://git.openprivacy.ca/cwtch.im/libcwtch-go/releases v1.7.0
Command::new("wget")
.arg("https://git.openprivacy.ca/attachments/dd3c6b41-98e4-4e7b-81af-d21893bfe389")
.arg("https://git.openprivacy.ca/attachments/390d383b-ab02-489b-b5c9-e62267d8b3fd")
.arg("-O")
.arg(lib_cwtch_path)
.output()
@ -29,5 +29,5 @@ fn main() {
io::copy(&mut file, &mut hasher).expect("failed to copy file into hasher");
let hash_bytes = hasher.finalize();
assert_eq!(hash_bytes[..], hex!("776a26076dfad3370d1b2edec9ad954187584f54483ec201163be0dc356c10b0fe74168e8e95f2116f458e5676e1fb07fbd0357cab1e4389ac762fe03bd5ef67")[..]);
assert_eq!(hash_bytes[..], hex!("271c281bad59696fc4ea5e559b5d3fe5c1949384c26dd891dde91b0af0a012e30bdbc3b16781ec5de795d2945e2f42415a8985451b49394b3c85c412ab4769d3")[..]);
}

View File

@ -61,6 +61,7 @@ extern "C" {
#endif
extern int c_StartCwtch(char* dir_c, int len, char* tor_c, int torLen);
extern int c_Started();
extern void c_ReconnectCwtchForeground();
// A generic method for Rebroadcasting App Events from a UI
@ -86,11 +87,14 @@ extern char* c_GetMessageByID(char* profile_ptr, int profile_len, int conversati
// the pointer returned from this function **must** be freed by calling c_Free
extern char* c_GetMessagesByContentHash(char* profile_ptr, int profile_len, int conversation_id, char* contenthash_ptr, int contenthash_len);
// the pointer returned from this function **must** be Freed by c_Free
extern char* c_GetMessages(char* profile_ptr, int profile_len, int conversation_id, int message_index, int count);
// Dangerous function. Should only be used as documented in `MEMORY.md`
extern void c_FreePointer(char* ptr);
extern void c_SendMessage(char* profile_ptr, int profile_len, int conversation_id, char* msg_ptr, int msg_len);
extern void c_SendInvitation(char* profile_ptr, int profile_len, int conversation_id, int target_id);
extern void c_ShareFile(char* profile_ptr, int profile_len, int conversation_id, char* filepath_ptr, int filepath_len);
extern char* c_SendMessage(char* profile_ptr, int profile_len, int conversation_id, char* msg_ptr, int msg_len);
extern char* c_SendInvitation(char* profile_ptr, int profile_len, int conversation_id, int target_id);
extern char* c_ShareFile(char* profile_ptr, int profile_len, int conversation_id, char* filepath_ptr, int filepath_len);
extern void c_DownloadFile(char* profile_ptr, int profile_len, int conversation_id, char* filepath_ptr, int filepath_len, char* manifestpath_ptr, int manifestpath_len, char* filekey_ptr, int filekey_len);
extern void c_CheckDownloadStatus(char* profilePtr, int profileLen, char* fileKeyPtr, int fileKeyLen);
extern void c_VerifyOrResumeDownload(char* profile_ptr, int profile_len, int conversation_id, char* filekey_ptr, int filekey_len);
@ -101,9 +105,13 @@ extern void c_ArchiveConversation(char* profile_ptr, int profile_len, int conver
extern void c_DeleteContact(char* profile_ptr, int profile_len, int conversation_id);
extern void c_ImportBundle(char* profile_ptr, int profile_len, char* bundle_ptr, int bundle_len);
extern void c_SetProfileAttribute(char* profile_ptr, int profile_len, char* key_ptr, int key_len, char* val_ptr, int val_len);
extern char* c_GetProfileAttribute(char* profile_ptr, int profile_len, char* key_ptr, int key_len);
extern void c_SetConversationAttribute(char* profile_ptr, int profile_len, int conversation_id, char* key_ptr, int key_len, char* val_ptr, int val_len);
extern char* c_GetConversationAttribute(char* profile_ptr, int profile_len, int conversation_id, char* key_ptr, int key_len);
extern void c_SetMessageAttribute(char* profile_ptr, int profile_len, int conversation_id, int channel_id, int message_id, char* key_ptr, int key_len, char* val_ptr, int val_len);
extern void c_ChangePassword(char* profile_ptr, int profile_len, char* oldpassword_ptr, int oldpassword_len, char* newpassword_ptr, int newpassword_len, char* newpassword_again_ptr, int newpassword_again_len);
extern void c_ExportProfile(char* profile_ptr, int profile_len, char* file_ptr, int file_len);
extern char* c_ImportProfile(char* file_ptr, int file_len, char* passwordPtr, int passwordLen);
extern void c_ShutdownCwtch();
extern void c_LoadServers(char* passwordPtr, int passwordLen);
extern void c_CreateServer(char* passwordPtr, int passwordLen, char* descPtr, int descLen, char autostart);

View File

@ -8,6 +8,7 @@ use std::ffi::CString;
use super::CwtchLib;
use crate::cwtchlib_go::bindings;
use crate::{CwtchError, structs::*};
struct c_str_wrap {
raw: *mut i8,
@ -80,8 +81,16 @@ macro_rules! c_bind {
pub struct CwtchLibGo {}
// Some bindings are going to be wrapped so we can handle their returns and give most rust idiomatic returns (esp for json returning apis)
// so we pre define the real binding here as a _helper function and in the impl for CwtchLib define the wrapper
impl CwtchLibGo {
c_bind!(_get_profile_attribute(profile: &str, key: &str;;) c_GetProfileAttribute -> String);
c_bind!(_get_conversation_attribute(profile: &str; conversation_id: i32; key: &str) c_GetConversationAttribute -> String);
}
impl CwtchLib for CwtchLibGo {
c_bind!(start_cwtch(app_dir: &str, tor_path: &str;;) c_StartCwtch -> i32);
c_bind!(started(;;) c_Started -> i32);
c_bind!(send_app_event(event_json: &str;;) c_SendAppEvent);
c_bind!(send_profile_event(profile: &str, event_jason: &str;;) c_SendProfileEvent);
c_bind!(get_appbus_event(;;) c_GetAppBusEvent -> String);
@ -90,12 +99,13 @@ impl CwtchLib for CwtchLibGo {
c_bind!(accept_conversation(profile: &str ; conversation_id: i32 ;) c_AcceptConversation);
c_bind!(block_contact(profile: &str ; conversation_id: i32; ) c_BlockContact);
c_bind!(unblock_contact(profile: &str ; conversation_id: i32; ) c_UnblockContact);
c_bind!(get_message(profile: &str; conversation_id: i32, message_index: i32 ;) c_GetMessage -> String);
c_bind!(get_message(profile: &str; conversation_id: i32, message_index: i32 ;) c_GetMessage -> String);
c_bind!(get_message_by_id(profile: &str ; conversation_id: i32, message_id: i32 ;) c_GetMessageByID -> String);
c_bind!(get_message_by_content_hash(profile: &str ; conversation_id: i32 ; hash: &str) c_GetMessagesByContentHash -> String);
c_bind!(send_message(profile: &str; conversation_id: i32; msg: &str) c_SendMessage);
c_bind!(send_invitation(profile: &str; conversation_id: i32, target_id: i32;) c_SendInvitation);
c_bind!(share_file(profile: &str; conversation_id: i32; file_path: &str) c_ShareFile);
c_bind!(get_messages(profile: &str; conversation_id: i32, message_index: i32, count: i32 ;) c_GetMessages -> String);
c_bind!(send_message(profile: &str; conversation_id: i32; msg: &str) c_SendMessage -> String);
c_bind!(send_invitation(profile: &str; conversation_id: i32, target_id: i32;) c_SendInvitation -> String);
c_bind!(share_file(profile: &str; conversation_id: i32; file_path: &str) c_ShareFile -> String);
c_bind!(download_file(profile: &str; conversation_id: i32; file_path: &str, manifest_path: &str, file_key: &str) c_DownloadFile);
c_bind!(check_download_status(profile: &str, file_key: &str;;) c_CheckDownloadStatus);
c_bind!(verify_or_resume_download(profile: &str; conversation_id: i32; file_key: &str) c_VerifyOrResumeDownload);
@ -110,9 +120,33 @@ impl CwtchLib for CwtchLibGo {
c_bind!(delete_contact(profile: &str; conversation_id: i32;) c_DeleteContact);
c_bind!(import_bundle(profile: &str, bundle: &str;;) c_ImportBundle);
c_bind!(set_profile_attribute(profile: &str, key: &str, val: &str;;) c_SetProfileAttribute);
fn get_profile_attribute(&self, profile: &str, key: &str) -> Result<Option<String>, CwtchError> {
let resp = self._get_profile_attribute(profile, key);
let attr: Attribute = match serde_json::from_str(&resp) {
Ok(attr) => attr,
Err(e) => return Err(e.to_string()),
};
match attr.exists {
true => Ok(Some(attr.value)),
false => Ok(None),
}
}
c_bind!(set_conversation_attribute(profile: &str; conversation_id: i32; key: &str, val: &str) c_SetConversationAttribute);
fn get_conversation_attribute(&self, profile: &str, conversation_id: i32, key: &str) -> Result<Option<String>, CwtchError> {
let resp = self._get_conversation_attribute(profile, conversation_id, key);
let attr: Attribute = match serde_json::from_str(&resp) {
Ok(attr) => attr,
Err(e) => return Err(e.to_string()),
};
match attr.exists {
true => Ok(Some(attr.value)),
false => Ok(None),
}
}
c_bind!(set_message_attribute(profile: &str; conversation_id: i32, channel_id: i32, message_id: i32; key: &str, val: &str) c_SetMessageAttribute);
c_bind!(change_password(profile: &str, old_pass: &str, new_pass: &str, new_pass_again: &str;;) c_ChangePassword);
c_bind!(export_profile(profile: &str, filename: &str;;) c_ExportProfile);
c_bind!(import_profile(filename: &str, password: &str;;) c_ImportProfile -> String);
fn shutdown_cwtch(&self) {
unsafe {

View File

@ -208,6 +208,9 @@ extern "C" {
torLen: ::std::os::raw::c_int,
) -> ::std::os::raw::c_int;
}
extern "C" {
pub fn c_Started() -> ::std::os::raw::c_int;
}
extern "C" {
pub fn c_ReconnectCwtchForeground();
}
@ -285,6 +288,15 @@ extern "C" {
contenthash_len: ::std::os::raw::c_int,
) -> *mut ::std::os::raw::c_char;
}
extern "C" {
pub fn c_GetMessages(
profile_ptr: *mut ::std::os::raw::c_char,
profile_len: ::std::os::raw::c_int,
conversation_id: ::std::os::raw::c_int,
message_index: ::std::os::raw::c_int,
count: ::std::os::raw::c_int,
) -> *mut ::std::os::raw::c_char;
}
extern "C" {
pub fn c_FreePointer(ptr: *mut ::std::os::raw::c_char);
}
@ -295,7 +307,7 @@ extern "C" {
conversation_id: ::std::os::raw::c_int,
msg_ptr: *mut ::std::os::raw::c_char,
msg_len: ::std::os::raw::c_int,
);
) -> *mut ::std::os::raw::c_char;
}
extern "C" {
pub fn c_SendInvitation(
@ -303,7 +315,7 @@ extern "C" {
profile_len: ::std::os::raw::c_int,
conversation_id: ::std::os::raw::c_int,
target_id: ::std::os::raw::c_int,
);
) -> *mut ::std::os::raw::c_char;
}
extern "C" {
pub fn c_ShareFile(
@ -312,7 +324,7 @@ extern "C" {
conversation_id: ::std::os::raw::c_int,
filepath_ptr: *mut ::std::os::raw::c_char,
filepath_len: ::std::os::raw::c_int,
);
) -> *mut ::std::os::raw::c_char;
}
extern "C" {
pub fn c_DownloadFile(
@ -397,6 +409,14 @@ extern "C" {
val_len: ::std::os::raw::c_int,
);
}
extern "C" {
pub fn c_GetProfileAttribute(
profile_ptr: *mut ::std::os::raw::c_char,
profile_len: ::std::os::raw::c_int,
key_ptr: *mut ::std::os::raw::c_char,
key_len: ::std::os::raw::c_int,
) -> *mut ::std::os::raw::c_char;
}
extern "C" {
pub fn c_SetConversationAttribute(
profile_ptr: *mut ::std::os::raw::c_char,
@ -408,6 +428,15 @@ extern "C" {
val_len: ::std::os::raw::c_int,
);
}
extern "C" {
pub fn c_GetConversationAttribute(
profile_ptr: *mut ::std::os::raw::c_char,
profile_len: ::std::os::raw::c_int,
conversation_id: ::std::os::raw::c_int,
key_ptr: *mut ::std::os::raw::c_char,
key_len: ::std::os::raw::c_int,
) -> *mut ::std::os::raw::c_char;
}
extern "C" {
pub fn c_SetMessageAttribute(
profile_ptr: *mut ::std::os::raw::c_char,
@ -433,6 +462,22 @@ extern "C" {
newpassword_again_len: ::std::os::raw::c_int,
);
}
extern "C" {
pub fn c_ExportProfile(
profile_ptr: *mut ::std::os::raw::c_char,
profile_len: ::std::os::raw::c_int,
file_ptr: *mut ::std::os::raw::c_char,
file_len: ::std::os::raw::c_int,
);
}
extern "C" {
pub fn c_ImportProfile(
file_ptr: *mut ::std::os::raw::c_char,
file_len: ::std::os::raw::c_int,
passwordPtr: *mut ::std::os::raw::c_char,
passwordLen: ::std::os::raw::c_int,
) -> *mut ::std::os::raw::c_char;
}
extern "C" {
pub fn c_ShutdownCwtch();
}

View File

@ -9,11 +9,17 @@ mod cwtchlib_go;
/// Basic structs using data from Cwtch and for deserializing JSON and serializing to JSON to communicate with Cwtch
pub mod structs;
/// Error type for Cwtch lib related errors, intended for use with Result
pub type CwtchError = String;
/// Interface to a Cwtch app with API matching libcwtch
pub trait CwtchLib {
/// Start a cwtch application using app_dir to store all user profile data and looking to tor_path to find tor to run
fn start_cwtch(&self, app_dir: &str, tor_path: &str) -> i32;
/// Return 1 if cwtch has been started and 0 if not
fn started(&self) -> i32;
/// Send json of a structs::CwtchEvent to the cwtch app bus
fn send_app_event(&self, event_json: &str);
@ -52,14 +58,17 @@ pub trait CwtchLib {
hash: &str,
) -> String;
/// Send json of a structs::Message from profile to contact
fn send_message(&self, profile: &str, conversation_id: i32, msg: &str);
/// Bulk get messages starting at message index and of count amoung
fn get_messages(&self, profile: &str, conversation_id: i32, message_index: i32, count: i32) -> String;
/// Send profile's contact an invite for/to target
fn send_invitation(&self, profile: &str, conversation_id: i32, target_id: i32);
/// Send json of a structs::Message from profile to contact. Returns computed sent message (including index and hash values)
fn send_message(&self, profile: &str, conversation_id: i32, msg: &str) -> String;
/// share a file file_path with a conersation
fn share_file(&self, profile: &str, conversation_id: i32, file_path: &str);
/// Send profile's contact an invite for/to target. Returns computed sent message (including index and hash values)
fn send_invitation(&self, profile: &str, conversation_id: i32, target_id: i32) -> String;
/// share a file file_path with a conersation. Returns computed sent message (including index and hash values)
fn share_file(&self, profile: &str, conversation_id: i32, file_path: &str) -> String;
/// download a file from a conversation to the file_path
fn download_file(
@ -98,6 +107,9 @@ pub trait CwtchLib {
/// Set a profile attribute key to val
fn set_profile_attribute(&self, profile: &str, key: &str, val: &str);
/// Get a profile attribute
fn get_profile_attribute(&self, profile: &str, key: &str) -> Result<Option<String>, CwtchError>;
/// Set a profile's contact's attribute of key to val
fn set_conversation_attribute(&self, profile: &str, conversation_id: i32, key: &str, val: &str);
@ -112,9 +124,18 @@ pub trait CwtchLib {
attribute_value: &str,
);
/// Get an attribute for a conversation
fn get_conversation_attribute(&self, profile: &str, conversation_id: i32, key: &str) -> Result<Option<String>, CwtchError>;
/// Change a profile's password to new_pass if old_pass is correct
fn change_password(&self, profile: &str, old_pass: &str, new_pass: &str, new_pass_again: &str);
/// Export a profile to filename
fn export_profile(&self, profile: &str, filename: &str);
/// Import a profile from a file with supplied password. Json of a profile struct returned on success
fn import_profile(&self, filename: &str, password: &str) -> String;
/// Shutdown the cwtch app and associated ACN
fn shutdown_cwtch(&self);

View File

@ -57,6 +57,17 @@ pub enum ContactAuthorization {
Blocked,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
#[allow(non_snake_case)]
/// Struct to deserialize the results of Get*Attribute requests into
pub struct Attribute {
/// Was the attribute value found in storage
pub exists: bool,
/// The value of the requested attribute
pub value: String,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
#[allow(non_snake_case)]
@ -70,6 +81,22 @@ pub struct CwtchEvent {
pub data: HashMap<String, String>,
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "PascalCase")]
#[allow(non_snake_case)]
/// AccessControl is a type determining client assigned authorization to a peer
pub struct AccessControl {
/// Any attempts from this handle to connect are blocked
pub blocked: bool,
/// Allows a handle to access the conversation
pub read: bool,
/// Allows a handle to append new messages to the conversation
pub append: bool,
}
/// represents an access control list for a conversation. Mapping handles to conversation functions
pub type ACL = HashMap<String, AccessControl>;
#[serde_as]
#[derive(Serialize, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
@ -88,6 +115,8 @@ pub struct Conversation {
pub status: ConnectionState,
/// has the conversation been manually accpted
pub accepted: bool,
///represents an access control list for a conversation. Mapping handles to conversation functions
pub access_control_list: ACL,
/// has the conversation been manually blocked
pub blocked: bool,
/// is this conversation a group? if so "onion" will be a group ID
@ -105,11 +134,13 @@ pub struct Server {
pub status: ConnectionState,
}
#[derive(Debug)]
#[serde_as]
#[derive(Debug, Serialize, Deserialize)]
/// Struct to serialize/deserialize profiles coming from libcwtch-go
pub struct Profile {
/// onion address / ID of the profile
pub onion: String,
#[serde(alias = "onion")]
pub handle: String,
/// nick name of the onion as supplied by libcwtch-go based on "name" attribute
pub nick: String,
/// path to a profile image, controled by "picture" attribute
@ -249,7 +280,7 @@ impl Profile {
Err(e) => return Err(e),
};
Ok(Profile {
onion: identity.to_string(),
handle: identity.to_string(),
nick: name.to_string(),
image_path: picture.to_string(),
attr: Default::default(),