mirror of
https://github.com/signalapp/libsignal.git
synced 2026-04-25 17:25:18 +02:00
swift: Make FingerprintMismatch error more useful
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -2494,6 +2494,7 @@ dependencies = [
|
||||
"libsignal-protocol",
|
||||
"log",
|
||||
"log-panics",
|
||||
"paste",
|
||||
"signal-media",
|
||||
"zerocopy",
|
||||
]
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
v0.76.1
|
||||
|
||||
- Making a chat connection now accepts a locale (Java) or a list of language codes (Swift, TypeScript), which will set the default language to be used for any requests on that connection if provided.
|
||||
|
||||
- swift: Fingerpint mismatch error now contains both versions
|
||||
|
||||
@@ -34,6 +34,7 @@ signal-media = { workspace = true }
|
||||
hex = { workspace = true }
|
||||
log = { workspace = true }
|
||||
log-panics = { workspace = true, features = ["with-backtrace"] }
|
||||
paste = { workspace = true }
|
||||
zerocopy = { workspace = true }
|
||||
|
||||
[target.aarch64-apple-ios.dependencies]
|
||||
|
||||
@@ -15,6 +15,7 @@ use libsignal_bridge::ffi::*;
|
||||
use libsignal_bridge_testing::*;
|
||||
use libsignal_core::try_scoped;
|
||||
use libsignal_protocol::*;
|
||||
use paste::paste;
|
||||
|
||||
pub mod logging;
|
||||
|
||||
@@ -149,40 +150,6 @@ pub unsafe extern "C" fn signal_error_get_invalid_protocol_address(
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn signal_error_get_retry_after_seconds(
|
||||
err: *const SignalFfiError,
|
||||
out: *mut u32,
|
||||
) -> *mut SignalFfiError {
|
||||
let err = AssertUnwindSafe(err);
|
||||
run_ffi_safe(|| {
|
||||
let err = err.as_ref().ok_or(NullPointerError)?;
|
||||
let value = err.provide_retry_after_seconds().map_err(|_| {
|
||||
SignalProtocolError::InvalidArgument(format!(
|
||||
"cannot get retry_after_seconds from error ({err})"
|
||||
))
|
||||
})?;
|
||||
write_result_to(out, value)
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn signal_error_get_tries_remaining(
|
||||
err: *const SignalFfiError,
|
||||
out: *mut u32,
|
||||
) -> *mut SignalFfiError {
|
||||
let err = AssertUnwindSafe(err);
|
||||
run_ffi_safe(|| {
|
||||
let err = err.as_ref().ok_or(NullPointerError)?;
|
||||
let value = err.provide_tries_remaining().map_err(|_| {
|
||||
SignalProtocolError::InvalidArgument(format!(
|
||||
"cannot get tries_remaining from error ({err})"
|
||||
))
|
||||
})?;
|
||||
write_result_to(out, value)
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn signal_error_get_unknown_fields(
|
||||
err: *const SignalFfiError,
|
||||
@@ -258,6 +225,57 @@ pub unsafe extern "C" fn signal_error_get_registration_lock(
|
||||
})
|
||||
}
|
||||
|
||||
macro_rules! get_named_u32_from_err_impl {
|
||||
($name:ident) => {
|
||||
paste! {
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn [< signal_error_get_ $name >](
|
||||
err: *const SignalFfiError,
|
||||
out: *mut u32,
|
||||
) -> *mut SignalFfiError {
|
||||
let err = AssertUnwindSafe(err);
|
||||
run_ffi_safe(|| {
|
||||
let err = err.as_ref().ok_or(NullPointerError)?;
|
||||
let value = err.[< provide_ $name >]().map_err(|_| {
|
||||
SignalProtocolError::InvalidArgument(format!(
|
||||
"cannot get $name from error ({err})"
|
||||
))
|
||||
})?;
|
||||
write_result_to(out, value)
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
// Similar to the above, only adds an extra .map(...) step to extract the final u32
|
||||
($name:ident, $field:ident, $c_name:ident) => {
|
||||
paste! {
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn [< signal_error_get_ $c_name >](
|
||||
err: *const SignalFfiError,
|
||||
out: *mut u32,
|
||||
) -> *mut SignalFfiError {
|
||||
let err = AssertUnwindSafe(err);
|
||||
run_ffi_safe(|| {
|
||||
let err = err.as_ref().ok_or(NullPointerError)?;
|
||||
let value = err.[< provide_ $name >]()
|
||||
.map(|x| x.$field)
|
||||
.map_err(|_| {
|
||||
SignalProtocolError::InvalidArgument(format!(
|
||||
"cannot get $name from error ({err})"
|
||||
))}
|
||||
)?;
|
||||
write_result_to(out, value)
|
||||
})
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
get_named_u32_from_err_impl!(fingerprint_versions, ours, our_fingerprint_version);
|
||||
get_named_u32_from_err_impl!(fingerprint_versions, theirs, their_fingerprint_version);
|
||||
get_named_u32_from_err_impl!(retry_after_seconds);
|
||||
get_named_u32_from_err_impl!(tries_remaining);
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn signal_error_get_rate_limit_challenge(
|
||||
err: *const SignalFfiError,
|
||||
|
||||
@@ -328,3 +328,13 @@ async fn TESTING_InputStreamReadIntoZeroLengthSlice(
|
||||
|
||||
first.into_iter().chain(remainder).collect()
|
||||
}
|
||||
|
||||
#[bridge_fn(jni = false, node = false)]
|
||||
fn TESTING_FingerprintVersionMismatchError(
|
||||
theirs: u32,
|
||||
ours: u32,
|
||||
) -> Result<(), SignalProtocolError> {
|
||||
Err(SignalProtocolError::FingerprintVersionMismatch(
|
||||
theirs, ours,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -138,6 +138,11 @@ impl<T: std::any::Any> UpcastAsAny for T {
|
||||
/// Error returned when asking for an attribute of an error that doesn't support that attribute.
|
||||
pub struct WrongErrorKind;
|
||||
|
||||
pub struct FingerprintVersions {
|
||||
pub theirs: u32,
|
||||
pub ours: u32,
|
||||
}
|
||||
|
||||
pub trait FfiError: UpcastAsAny + fmt::Debug + Send + 'static {
|
||||
fn describe(&self) -> String;
|
||||
fn code(&self) -> SignalErrorCode;
|
||||
@@ -171,6 +176,9 @@ pub trait FfiError: UpcastAsAny + fmt::Debug + Send + 'static {
|
||||
fn provide_rate_limit_challenge(&self) -> Result<&RateLimitChallenge, WrongErrorKind> {
|
||||
Err(WrongErrorKind)
|
||||
}
|
||||
fn provide_fingerprint_versions(&self) -> Result<FingerprintVersions, WrongErrorKind> {
|
||||
Err(WrongErrorKind)
|
||||
}
|
||||
}
|
||||
|
||||
/// The top-level error type (opaquely) returned to C clients when something goes wrong.
|
||||
@@ -306,6 +314,16 @@ impl FfiError for SignalProtocolError {
|
||||
_ => Err(WrongErrorKind),
|
||||
}
|
||||
}
|
||||
|
||||
fn provide_fingerprint_versions(&self) -> Result<FingerprintVersions, WrongErrorKind> {
|
||||
match self {
|
||||
Self::FingerprintVersionMismatch(theirs, ours) => Ok(FingerprintVersions {
|
||||
theirs: *theirs,
|
||||
ours: *ours,
|
||||
}),
|
||||
_ => Err(WrongErrorKind),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FfiError for DeviceTransferError {
|
||||
|
||||
@@ -21,7 +21,7 @@ public enum SignalError: Error {
|
||||
case invalidKey(String)
|
||||
case invalidSignature(String)
|
||||
case invalidAttestationData(String)
|
||||
case fingerprintVersionMismatch(String)
|
||||
case fingerprintVersionMismatch(theirs: UInt32, ours: UInt32)
|
||||
case fingerprintParsingError(String)
|
||||
case sealedSenderSelfSend(String)
|
||||
case untrustedIdentity(String)
|
||||
@@ -135,7 +135,13 @@ internal func checkError(_ error: SignalFfiErrorRef?) throws {
|
||||
case SignalErrorCodeInvalidAttestationData:
|
||||
throw SignalError.invalidAttestationData(errStr)
|
||||
case SignalErrorCodeFingerprintVersionMismatch:
|
||||
throw SignalError.fingerprintVersionMismatch(errStr)
|
||||
let theirs = try invokeFnReturningInteger {
|
||||
signal_error_get_their_fingerprint_version(error, $0)
|
||||
}
|
||||
let ours = try invokeFnReturningInteger {
|
||||
signal_error_get_our_fingerprint_version(error, $0)
|
||||
}
|
||||
throw SignalError.fingerprintVersionMismatch(theirs: theirs, ours: ours)
|
||||
case SignalErrorCodeUntrustedIdentity:
|
||||
throw SignalError.untrustedIdentity(errStr)
|
||||
case SignalErrorCodeInvalidKeyIdentifier:
|
||||
|
||||
@@ -1594,6 +1594,8 @@ SignalFfiError *signal_error_get_invalid_protocol_address(const SignalFfiError *
|
||||
|
||||
SignalFfiError *signal_error_get_message(const SignalFfiError *err, const char **out);
|
||||
|
||||
SignalFfiError *signal_error_get_our_fingerprint_version(const SignalFfiError *err, uint32_t *out);
|
||||
|
||||
SignalFfiError *signal_error_get_rate_limit_challenge(const SignalFfiError *err, const char **out_token, SignalOwnedBuffer *out_options);
|
||||
|
||||
SignalFfiError *signal_error_get_registration_error_not_deliverable(const SignalFfiError *err, const char **out_reason, bool *out_permanent);
|
||||
@@ -1602,6 +1604,8 @@ SignalFfiError *signal_error_get_registration_lock(const SignalFfiError *err, ui
|
||||
|
||||
SignalFfiError *signal_error_get_retry_after_seconds(const SignalFfiError *err, uint32_t *out);
|
||||
|
||||
SignalFfiError *signal_error_get_their_fingerprint_version(const SignalFfiError *err, uint32_t *out);
|
||||
|
||||
SignalFfiError *signal_error_get_tries_remaining(const SignalFfiError *err, uint32_t *out);
|
||||
|
||||
uint32_t signal_error_get_type(const SignalFfiError *err);
|
||||
|
||||
@@ -319,6 +319,8 @@ SignalFfiError *signal_testing_fake_chat_server_get_next_remote(SignalCPromiseMu
|
||||
|
||||
SignalFfiError *signal_testing_fake_registration_session_create_session(SignalCPromiseMutPointerRegistrationService *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalFfiRegistrationCreateSessionRequest create_session, SignalConstPointerFakeChatServer chat);
|
||||
|
||||
SignalFfiError *signal_testing_fingerprint_version_mismatch_error(uint32_t theirs, uint32_t ours);
|
||||
|
||||
SignalFfiError *signal_testing_future_cancellation_counter_create(SignalMutPointerTestingFutureCancellationCounter *out, uint8_t initial_value);
|
||||
|
||||
SignalFfiError *signal_testing_future_cancellation_counter_destroy(SignalMutPointerTestingFutureCancellationCounter p);
|
||||
|
||||
@@ -253,6 +253,18 @@ final class BridgingTests: XCTestCase {
|
||||
}
|
||||
XCTAssertEqual(UUID(uuidString: "abababab-1212-8989-baba-565656565656"), shouldBePresent)
|
||||
}
|
||||
|
||||
func testFingerprintVersionMismatchError() throws {
|
||||
let theirs = UInt32(11)
|
||||
let ours = UInt32(22)
|
||||
do {
|
||||
try checkError(signal_testing_fingerprint_version_mismatch_error(theirs, ours))
|
||||
XCTFail("should have thrown")
|
||||
} catch SignalError.fingerprintVersionMismatch(let actualTheirs, let actualOurs) {
|
||||
XCTAssertEqual(theirs, actualTheirs)
|
||||
XCTAssertEqual(ours, actualOurs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user