-
Notifications
You must be signed in to change notification settings - Fork 23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Encrypt and Decrypt support #39
Conversation
@neekolas I don't think vodozemac/olm support decryption of your own encrypted message. I tried it briefly and came to the conclusion that the way they set up their ratchet chains etc, the onus is on the library consumer to record outgoing plaintexts separately. I could be wrong here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM - I think we're about evenly matched already in Rust so I found nothing to be harsh about
bindings/wasm/crate/src/lib.rs
Outdated
|
||
let result = instance.encrypt_message_serialized(session_id, message); | ||
// Do we actually need to do this? | ||
instances.get(sending_handle).unwrap().set(instance); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't have to do this here. Instead of using take()
you should be able to use get_mut()
on the cell (so .get(sending_handle).ok_or(...)?.get_mut()
approximately.
This pattern comes from my own lack of Rust borrow-checker knowledge when implementing the inbound/outbound
session functions. I couldn't take mutable references of two INSTANCE_MAP values in the same scope so ended up doing it via Cell
in a weird way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact, now that we're using .public_account
, I think we can do away with this pattern in those existing functions too. I might tackle that in a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type checker doesn't seem to like that, but it recommends that I replace the cell with a RefCell
. RefCell then has a method borrow_mut
. If I use that, everything is happy and I don't have to manually set the cell to updated values.
Does have some scary language about concurrent usage leading to a panic, but I think that's fine for now given that all our code is synchronous.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've committed that change here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good, anything works for now as long as borrow/type checker likes it. We can take a holistic look at the map/cell strategy in a subsequent PR.
Actually, on second look: RefCell seems much better than the take/set strategy. Nice!
|
||
// Alice can't decrypt her own message. Does work for Bob though | ||
// const decrypted = await alice.decryptMessage(sessionId, encrypted); | ||
const decrypted = await bob.decryptMessage(sessionId, encrypted); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
beautiful
@@ -29,7 +29,7 @@ pub fn create_outbound_session( | |||
sending_handle: &str, | |||
receiving_handle: &str, | |||
message: &str, | |||
) -> Result<String, JsValue> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I follow the need for the Box here.
My understanding was that JsValues through WASM_BINDGEN get copied between the memory space?
Heap Allocating here seems unnecessary at a high level.
Ok((session_id, ciphertext_json)) => Ok(vec![ | ||
JsValue::from_str(&session_id), | ||
JsValue::from_str(&ciphertext_json), | ||
] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using the Vec here changes the memory structure. Given the size cannot be known at compile time.
Imagine using a tuple would be easier to use and would avoid the need for boxing of the values.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, wasm-bindgen
doesn't appear to support tuples as return values. rustwasm/wasm-bindgen#122
match result { | ||
Ok(ciphertext_json) => Ok(ciphertext_json), | ||
Err(e) => Err(JsValue::from_str(&e.to_string())), | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems fine to me, however there are more idomatic ways to use a Match statement.
- Pretty sure that RHS
Ok()
is not needed. Values are implicitlyOk
- result is an 'Result' which you are trying to map the error. You can use
result.map_error(|e| JsValue::from_str(&e.to_string()))
sending_handle: &str, | ||
session_id: &str, | ||
message: &str, | ||
) -> Result<String, JsValue> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These types look both to be Strings, only the error gets converted to a wasmbind:JsValue. Shouldn't they be the same type?
let instances = INSTANCE_MAP.lock().unwrap(); | ||
let mut instance = instances | ||
.get(sending_handle) | ||
.ok_or("sending_handle not found")? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this conversion from an Option to Result.
You could have used a match, but this is much cleaner
@@ -20,7 +20,7 @@ lazy_static! { | |||
pub fn new_voodoo_instance() -> String { | |||
let mut instances = INSTANCE_MAP.lock().unwrap(); | |||
let handle = (instances.len() as u64).to_string(); | |||
instances.insert(handle.clone(), Cell::new(VoodooInstance::new())); | |||
instances.insert(handle.clone(), RefCell::new(VoodooInstance::new())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RefCell seems odd here: Though WASM is odd so it might be the best way. Naively I would have thought we could handle borrows at compile time.
Summary
Trying to teach myself some Rust here. Attempted to add Encrypt and Decrypt support. This also required me to change the output type from
createInboundSession
andcreateOutboundSession
to include thesessionId
in the payload. I went for theBox<JsValue>
type and am returning the two values as a tuple for simplicity, but I'm not sure what the best pattern is here.Notes
Bad MAC
.