Additionally, never look up a session by e164 when decrypting
sealed-sender messages.
This is an API-breaking change for both Java and Swift clients;
certain fields and arguments are no longer Optional. On top of that,
some tests may need to be updated to provide UUIDs instead of just
phone numbers.
If a session has just been reset (archiveCurrentState()), then there
won't be an active state in the session and sends will fail until a
new session is properly established by the client.
This simplifies SignalProtocolError at the cost of an extra heap
allocation for other errors. On its own, that probably isn't worth it,
but this lays groundwork for propagating exceptions / errors back up
in the native environment.
There were two discrepancies between the logic here and the original
logic of libsignal-protocol-java.
First, if the session record had an uninitialized active session, in
Java this would still attempt decryption with the old session states,
but Rust would stop immediately without trying the old states. [I am
not sure if this ever happens but it could possibly occur due to use
of archiveCurrentState]
Secondly, we returned the wrong error condition. We treated lack of a
sender chain as an invalid state (effectively an internal error) but
Java treats it as an invalid message, which makes sense in so far as
it is a message which we are unable to process with the information we
have available. This wrong error type led to an unexpected exception
being thrown in Android.
In libsignal-protocol-java, SessionRecord holds a SesssionState struct which is
the "active" session plus a list of old states. If the record is freshly
created, there is still a SessionState, but it is an uninitialized/new protobuf
structure which causes all fields to be empty/zero/false.
So in the original Java logic you can call for example hasSenderChain, and on
an empty/fresh record it will return false. However in Rust, in this case the
Option is empty and we return an error instead.
For hasSenderChain, it seems reasonable to return false if there is no active
session, since if there is no session there is certainly no chain.
Android also expects the session version to be == 0 on such sessions, but this
makes less sense, so have this logic only in the Java binding and not in the
Rust library proper.
These are here just to copy the Java SessionCipher API but if you
need this just load the session record from your store.
[The Java library does exactly this, without bothering to call the
Rust version]
Previously ChainKey etc were used by JNI during some intermediate
steps in converting the Java library to use Rust. But no longer,
so don't export them.
These still need to be exposed for the Java tests but they only
need to see the SessionRecord not the SessionState.
The internal functions still need to return a SessionState due to how
these functions are used within the crate.
Remove some functions which were not used within the crate or the bindings.
Also fix some type errors in the JNI binding - SessionState was being
used instead of SessionRecord, and this happened to work because the
first element of a SessionRecord is an Option<SessionState>
Both the Android and iOS clients currently allow customizing this
validatation logic for testing purposes, and iOS additionally wants to
log the information about the unwrapped message even if there are
problems with it.
iOS does also currently log information about the unwrapped message
even if the static key being used is wrong, but in order to fix that
we'd have to have a secondary return value (either the expected static
key, computed during decrypt-to-USMC, or a flag saying whether the
comparison failed).