mirror of
https://github.com/signalapp/libsignal.git
synced 2024-09-20 03:52:17 +02:00
bridge: Be more explicit about bridging u64 timestamps
u64 can't be represented as a primitive in Java or TypeScript (and for the latter, Neon doesn't support bigint yet). However, for timestamps represented as milliseconds, the integer-safe range of float64 still covers more than 285,000 years, so it's reasonably safe to use TypeScript's 'number' or Java's 'long' to represent these ostensibly-64-bit values. Indicate this with a new Timestamp wrapper type in the bridge layer. In theory we could push this new Timestamp type down to the libsignal-protocol crate. However, the protocol itself doesn't impose any restrictions on the timestamp fields, so I figured it was best to put it at the bridge layer, to indicate that it's about how Signal specifically uses these fields. This commit paves the way for being stricter about *other* u64 values that might want to use the full 64-bit space.
This commit is contained in:
parent
0f27f82890
commit
2544f3d827
17
node/Native.d.ts
vendored
17
node/Native.d.ts
vendored
@ -6,6 +6,7 @@
|
||||
// WARNING: this file was automatically generated
|
||||
|
||||
type Uuid = Buffer;
|
||||
type Timestamp = number;
|
||||
|
||||
export abstract class IdentityKeyStore {
|
||||
_getIdentityKey(): Promise<PrivateKey>;
|
||||
@ -51,10 +52,10 @@ export function CiphertextMessage_Serialize(obj: Wrapper<CiphertextMessage>): Bu
|
||||
export function CiphertextMessage_Type(msg: Wrapper<CiphertextMessage>): number;
|
||||
export function DecryptionErrorMessage_Deserialize(data: Buffer): DecryptionErrorMessage;
|
||||
export function DecryptionErrorMessage_ExtractFromSerializedContent(bytes: Buffer): DecryptionErrorMessage;
|
||||
export function DecryptionErrorMessage_ForOriginalMessage(originalBytes: Buffer, originalType: number, originalTimestamp: number, originalSenderDeviceId: number): DecryptionErrorMessage;
|
||||
export function DecryptionErrorMessage_ForOriginalMessage(originalBytes: Buffer, originalType: number, originalTimestamp: Timestamp, originalSenderDeviceId: number): DecryptionErrorMessage;
|
||||
export function DecryptionErrorMessage_GetDeviceId(obj: Wrapper<DecryptionErrorMessage>): number;
|
||||
export function DecryptionErrorMessage_GetRatchetKey(m: Wrapper<DecryptionErrorMessage>): PublicKey | null;
|
||||
export function DecryptionErrorMessage_GetTimestamp(obj: Wrapper<DecryptionErrorMessage>): number;
|
||||
export function DecryptionErrorMessage_GetTimestamp(obj: Wrapper<DecryptionErrorMessage>): Timestamp;
|
||||
export function DecryptionErrorMessage_Serialize(obj: Wrapper<DecryptionErrorMessage>): Buffer;
|
||||
export function Fingerprint_DisplayString(obj: Wrapper<Fingerprint>): string;
|
||||
export function Fingerprint_New(iterations: number, version: number, localIdentifier: Buffer, localKey: Wrapper<PublicKey>, remoteIdentifier: Buffer, remoteKey: Wrapper<PublicKey>): Fingerprint;
|
||||
@ -113,7 +114,7 @@ export function SealedSenderDecryptionResult_GetDeviceId(obj: Wrapper<SealedSend
|
||||
export function SealedSenderDecryptionResult_GetSenderE164(obj: Wrapper<SealedSenderDecryptionResult>): string | null;
|
||||
export function SealedSenderDecryptionResult_GetSenderUuid(obj: Wrapper<SealedSenderDecryptionResult>): string;
|
||||
export function SealedSenderDecryptionResult_Message(obj: Wrapper<SealedSenderDecryptionResult>): Buffer;
|
||||
export function SealedSender_DecryptMessage(message: Buffer, trustRoot: Wrapper<PublicKey>, timestamp: number, localE164: string | null, localUuid: string, localDeviceId: number, sessionStore: SessionStore, identityStore: IdentityKeyStore, prekeyStore: PreKeyStore, signedPrekeyStore: SignedPreKeyStore): Promise<SealedSenderDecryptionResult>;
|
||||
export function SealedSender_DecryptMessage(message: Buffer, trustRoot: Wrapper<PublicKey>, timestamp: Timestamp, localE164: string | null, localUuid: string, localDeviceId: number, sessionStore: SessionStore, identityStore: IdentityKeyStore, prekeyStore: PreKeyStore, signedPrekeyStore: SignedPreKeyStore): Promise<SealedSenderDecryptionResult>;
|
||||
export function SealedSender_DecryptToUsmc(ctext: Buffer, identityStore: IdentityKeyStore, ctx: null): Promise<UnidentifiedSenderMessageContent>;
|
||||
export function SealedSender_Encrypt(destination: Wrapper<ProtocolAddress>, content: Wrapper<UnidentifiedSenderMessageContent>, identityKeyStore: IdentityKeyStore, ctx: null): Promise<Buffer>;
|
||||
export function SealedSender_MultiRecipientEncrypt(recipients: Wrapper<ProtocolAddress>[], recipientSessions: Wrapper<SessionRecord>[], content: Wrapper<UnidentifiedSenderMessageContent>, identityKeyStore: IdentityKeyStore, ctx: null): Promise<Buffer>;
|
||||
@ -121,15 +122,15 @@ export function SealedSender_MultiRecipientMessageForSingleRecipient(encodedMult
|
||||
export function SenderCertificate_Deserialize(data: Buffer): SenderCertificate;
|
||||
export function SenderCertificate_GetCertificate(obj: Wrapper<SenderCertificate>): Buffer;
|
||||
export function SenderCertificate_GetDeviceId(obj: Wrapper<SenderCertificate>): number;
|
||||
export function SenderCertificate_GetExpiration(obj: Wrapper<SenderCertificate>): number;
|
||||
export function SenderCertificate_GetExpiration(obj: Wrapper<SenderCertificate>): Timestamp;
|
||||
export function SenderCertificate_GetKey(obj: Wrapper<SenderCertificate>): PublicKey;
|
||||
export function SenderCertificate_GetSenderE164(obj: Wrapper<SenderCertificate>): string | null;
|
||||
export function SenderCertificate_GetSenderUuid(obj: Wrapper<SenderCertificate>): string;
|
||||
export function SenderCertificate_GetSerialized(obj: Wrapper<SenderCertificate>): Buffer;
|
||||
export function SenderCertificate_GetServerCertificate(cert: Wrapper<SenderCertificate>): ServerCertificate;
|
||||
export function SenderCertificate_GetSignature(obj: Wrapper<SenderCertificate>): Buffer;
|
||||
export function SenderCertificate_New(senderUuid: string, senderE164: string | null, senderDeviceId: number, senderKey: Wrapper<PublicKey>, expiration: number, signerCert: Wrapper<ServerCertificate>, signerKey: Wrapper<PrivateKey>): SenderCertificate;
|
||||
export function SenderCertificate_Validate(cert: Wrapper<SenderCertificate>, key: Wrapper<PublicKey>, time: number): boolean;
|
||||
export function SenderCertificate_New(senderUuid: string, senderE164: string | null, senderDeviceId: number, senderKey: Wrapper<PublicKey>, expiration: Timestamp, signerCert: Wrapper<ServerCertificate>, signerKey: Wrapper<PrivateKey>): SenderCertificate;
|
||||
export function SenderCertificate_Validate(cert: Wrapper<SenderCertificate>, key: Wrapper<PublicKey>, time: Timestamp): boolean;
|
||||
export function SenderKeyDistributionMessage_Create(sender: Wrapper<ProtocolAddress>, distributionId: Uuid, store: SenderKeyStore, ctx: null): Promise<SenderKeyDistributionMessage>;
|
||||
export function SenderKeyDistributionMessage_Deserialize(data: Buffer): SenderKeyDistributionMessage;
|
||||
export function SenderKeyDistributionMessage_GetChainId(obj: Wrapper<SenderKeyDistributionMessage>): number;
|
||||
@ -180,8 +181,8 @@ export function SignedPreKeyRecord_GetId(obj: Wrapper<SignedPreKeyRecord>): numb
|
||||
export function SignedPreKeyRecord_GetPrivateKey(obj: Wrapper<SignedPreKeyRecord>): PrivateKey;
|
||||
export function SignedPreKeyRecord_GetPublicKey(obj: Wrapper<SignedPreKeyRecord>): PublicKey;
|
||||
export function SignedPreKeyRecord_GetSignature(obj: Wrapper<SignedPreKeyRecord>): Buffer;
|
||||
export function SignedPreKeyRecord_GetTimestamp(obj: Wrapper<SignedPreKeyRecord>): number;
|
||||
export function SignedPreKeyRecord_New(id: number, timestamp: number, pubKey: Wrapper<PublicKey>, privKey: Wrapper<PrivateKey>, signature: Buffer): SignedPreKeyRecord;
|
||||
export function SignedPreKeyRecord_GetTimestamp(obj: Wrapper<SignedPreKeyRecord>): Timestamp;
|
||||
export function SignedPreKeyRecord_New(id: number, timestamp: Timestamp, pubKey: Wrapper<PublicKey>, privKey: Wrapper<PrivateKey>, signature: Buffer): SignedPreKeyRecord;
|
||||
export function SignedPreKeyRecord_Serialize(obj: Wrapper<SignedPreKeyRecord>): Buffer;
|
||||
export function UnidentifiedSenderMessageContent_Deserialize(data: Buffer): UnidentifiedSenderMessageContent;
|
||||
export function UnidentifiedSenderMessageContent_GetContentHint(m: Wrapper<UnidentifiedSenderMessageContent>): number;
|
||||
|
@ -6,6 +6,7 @@
|
||||
// WARNING: this file was automatically generated
|
||||
|
||||
type Uuid = Buffer;
|
||||
type Timestamp = number;
|
||||
|
||||
export abstract class IdentityKeyStore {
|
||||
_getIdentityKey(): Promise<PrivateKey>;
|
||||
|
@ -350,6 +350,20 @@ impl ResultTypeInfo for Option<u32> {
|
||||
}
|
||||
}
|
||||
|
||||
impl SimpleArgTypeInfo for crate::protocol::Timestamp {
|
||||
type ArgType = u64;
|
||||
fn convert_from(foreign: Self::ArgType) -> SignalFfiResult<Self> {
|
||||
Ok(Self::from_millis(foreign))
|
||||
}
|
||||
}
|
||||
|
||||
impl ResultTypeInfo for crate::protocol::Timestamp {
|
||||
type ResultType = u64;
|
||||
fn convert_into(self) -> SignalFfiResult<Self::ResultType> {
|
||||
Ok(self.as_millis())
|
||||
}
|
||||
}
|
||||
|
||||
/// A marker for Rust objects exposed as opaque pointers.
|
||||
///
|
||||
/// When we do this, we hand the lifetime over to the app. Since we don't know how long the object
|
||||
@ -503,6 +517,7 @@ macro_rules! ffi_arg_type {
|
||||
(Option<String>) => (*const libc::c_char);
|
||||
(Option<&str>) => (*const libc::c_char);
|
||||
(Context) => (*mut libc::c_void);
|
||||
(Timestamp) => (u64);
|
||||
(Uuid) => (*const [u8; 16]);
|
||||
(&[& $typ:ty]) => (*const *const $typ);
|
||||
(&mut dyn $typ:ty) => (*const paste!(ffi::[<Ffi $typ Struct>]));
|
||||
@ -537,6 +552,7 @@ macro_rules! ffi_result_type {
|
||||
(Option<String>) => (*const libc::c_char);
|
||||
(Option<&str>) => (*const libc::c_char);
|
||||
(Option<$typ:ty>) => (*mut $typ);
|
||||
(Timestamp) => (u64);
|
||||
(Uuid) => ([u8; 16]);
|
||||
( $typ:ty ) => (*mut $typ);
|
||||
}
|
||||
|
@ -166,16 +166,16 @@ impl<'a> SimpleArgTypeInfo<'a> for Option<u32> {
|
||||
///
|
||||
/// Negative `long` values are *not* reinterpreted as large `u64` values.
|
||||
/// Note that this is different from the implementation of [`ResultTypeInfo`] for `u64`.
|
||||
impl<'a> SimpleArgTypeInfo<'a> for u64 {
|
||||
impl<'a> SimpleArgTypeInfo<'a> for crate::protocol::Timestamp {
|
||||
type ArgType = jlong;
|
||||
fn convert_from(_env: &JNIEnv, foreign: jlong) -> SignalJniResult<Self> {
|
||||
if foreign < 0 {
|
||||
return Err(SignalJniError::IntegerOverflow(format!(
|
||||
"{} to u64",
|
||||
"{} to Timestamp (u64)",
|
||||
foreign
|
||||
)));
|
||||
}
|
||||
Ok(foreign as u64)
|
||||
Ok(Self::from_millis(foreign as u64))
|
||||
}
|
||||
}
|
||||
|
||||
@ -436,14 +436,14 @@ impl ResultTypeInfo for Option<u32> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Reinterprets the bits of the `u64` as a Java `long`.
|
||||
/// Reinterprets the bits of the timestamp's `u64` as a Java `long`.
|
||||
///
|
||||
/// Note that this is different from the implementation of [`ArgTypeInfo`] for `u64`.
|
||||
impl ResultTypeInfo for u64 {
|
||||
/// Note that this is different from the implementation of [`ArgTypeInfo`] for `Timestamp`.
|
||||
impl ResultTypeInfo for crate::protocol::Timestamp {
|
||||
type ResultType = jlong;
|
||||
fn convert_into(self, _env: &JNIEnv) -> SignalJniResult<Self::ResultType> {
|
||||
// Note that we don't check bounds here.
|
||||
Ok(self as jlong)
|
||||
Ok(self.as_millis() as jlong)
|
||||
}
|
||||
fn convert_into_jobject(_signal_jni_result: &SignalJniResult<Self::ResultType>) -> JObject {
|
||||
JObject::null()
|
||||
@ -849,9 +849,6 @@ macro_rules! jni_arg_type {
|
||||
(Option<u32>) => {
|
||||
jni::jint
|
||||
};
|
||||
(u64) => {
|
||||
jni::jlong
|
||||
};
|
||||
(String) => {
|
||||
jni::JString
|
||||
};
|
||||
@ -870,6 +867,9 @@ macro_rules! jni_arg_type {
|
||||
(Context) => {
|
||||
jni::JObject
|
||||
};
|
||||
(Timestamp) => {
|
||||
jni::jlong
|
||||
};
|
||||
(Uuid) => {
|
||||
jni::JavaUUID
|
||||
};
|
||||
@ -932,9 +932,6 @@ macro_rules! jni_result_type {
|
||||
(u32) => {
|
||||
jni::jint
|
||||
};
|
||||
(u64) => {
|
||||
jni::jlong
|
||||
};
|
||||
(Option<u32>) => {
|
||||
jni::jint
|
||||
};
|
||||
@ -947,6 +944,9 @@ macro_rules! jni_result_type {
|
||||
(Uuid) => {
|
||||
jni::JavaReturnUUID
|
||||
};
|
||||
(Timestamp) => {
|
||||
jni::jlong
|
||||
};
|
||||
(&[u8]) => {
|
||||
jni::jbyteArray
|
||||
};
|
||||
|
@ -250,14 +250,14 @@ const MAX_SAFE_JS_INTEGER: f64 = 9007199254740991.0;
|
||||
/// Converts non-negative numbers up to [`Number.MAX_SAFE_INTEGER`][].
|
||||
///
|
||||
/// [`Number.MAX_SAFE_INTEGER`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
|
||||
impl SimpleArgTypeInfo for u64 {
|
||||
impl SimpleArgTypeInfo for crate::protocol::Timestamp {
|
||||
type ArgType = JsNumber;
|
||||
fn convert_from(cx: &mut FunctionContext, foreign: Handle<Self::ArgType>) -> NeonResult<Self> {
|
||||
let value = foreign.value(cx);
|
||||
if !can_convert_js_number_to_int(value, 0.0..=MAX_SAFE_JS_INTEGER) {
|
||||
return cx.throw_range_error(format!("cannot convert {} to u64", value));
|
||||
return cx.throw_range_error(format!("cannot convert {} to Timestamp (u64)", value));
|
||||
}
|
||||
Ok(value as u64)
|
||||
Ok(Self::from_millis(value as u64))
|
||||
}
|
||||
}
|
||||
|
||||
@ -527,17 +527,17 @@ impl<'a> ResultTypeInfo<'a> for bool {
|
||||
/// Converts non-negative values up to [`Number.MAX_SAFE_INTEGER`][].
|
||||
///
|
||||
/// [`Number.MAX_SAFE_INTEGER`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER
|
||||
impl<'a> ResultTypeInfo<'a> for u64 {
|
||||
impl<'a> ResultTypeInfo<'a> for crate::protocol::Timestamp {
|
||||
type ResultType = JsNumber;
|
||||
fn convert_into(self, cx: &mut impl Context<'a>) -> NeonResult<Handle<'a, Self::ResultType>> {
|
||||
let result = self as f64;
|
||||
let result = self.as_millis() as f64;
|
||||
if result > MAX_SAFE_JS_INTEGER {
|
||||
cx.throw_range_error(format!(
|
||||
"precision loss during conversion of {} to f64",
|
||||
self
|
||||
self.as_millis()
|
||||
))?;
|
||||
}
|
||||
Ok(cx.number(self as f64))
|
||||
Ok(cx.number(result))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,25 @@ bridge_handle!(SignedPreKeyRecord);
|
||||
bridge_handle!(UnidentifiedSenderMessageContent, clone = false);
|
||||
bridge_handle!(SealedSenderDecryptionResult, ffi = false, jni = false);
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub(crate) struct Timestamp(u64);
|
||||
|
||||
impl Timestamp {
|
||||
pub(crate) fn from_millis(millis: u64) -> Self {
|
||||
Self(millis)
|
||||
}
|
||||
|
||||
pub(crate) fn as_millis(self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for Timestamp {
|
||||
fn from(value: u64) -> Self {
|
||||
Self::from_millis(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[bridge_fn_buffer(ffi = false)]
|
||||
fn HKDF_DeriveSecrets(
|
||||
output_length: u32,
|
||||
@ -417,7 +436,7 @@ fn SenderKeyDistributionMessage_GetSignatureKey(
|
||||
}
|
||||
|
||||
bridge_deserialize!(DecryptionErrorMessage::try_from);
|
||||
bridge_get!(DecryptionErrorMessage::timestamp -> u64);
|
||||
bridge_get!(DecryptionErrorMessage::timestamp -> Timestamp);
|
||||
bridge_get!(DecryptionErrorMessage::device_id -> u32);
|
||||
bridge_get_buffer!(
|
||||
DecryptionErrorMessage::serialized as Serialize -> &[u8],
|
||||
@ -433,7 +452,7 @@ fn DecryptionErrorMessage_GetRatchetKey(m: &DecryptionErrorMessage) -> Option<Pu
|
||||
fn DecryptionErrorMessage_ForOriginalMessage(
|
||||
original_bytes: &[u8],
|
||||
original_type: u8,
|
||||
original_timestamp: u64,
|
||||
original_timestamp: Timestamp,
|
||||
original_sender_device_id: u32,
|
||||
) -> Result<DecryptionErrorMessage> {
|
||||
let original_type = CiphertextMessageType::try_from(original_type).map_err(|_| {
|
||||
@ -442,7 +461,7 @@ fn DecryptionErrorMessage_ForOriginalMessage(
|
||||
DecryptionErrorMessage::for_original(
|
||||
original_bytes,
|
||||
original_type,
|
||||
original_timestamp,
|
||||
original_timestamp.as_millis(),
|
||||
original_sender_device_id,
|
||||
)
|
||||
}
|
||||
@ -528,20 +547,20 @@ bridge_get_buffer!(
|
||||
jni = "SignedPreKeyRecord_1GetSerialized"
|
||||
);
|
||||
bridge_get!(SignedPreKeyRecord::id -> u32);
|
||||
bridge_get!(SignedPreKeyRecord::timestamp -> u64);
|
||||
bridge_get!(SignedPreKeyRecord::timestamp -> Timestamp);
|
||||
bridge_get!(SignedPreKeyRecord::public_key -> PublicKey);
|
||||
bridge_get!(SignedPreKeyRecord::private_key -> PrivateKey);
|
||||
|
||||
#[bridge_fn]
|
||||
fn SignedPreKeyRecord_New(
|
||||
id: u32,
|
||||
timestamp: u64,
|
||||
timestamp: Timestamp,
|
||||
pub_key: &PublicKey,
|
||||
priv_key: &PrivateKey,
|
||||
signature: &[u8],
|
||||
) -> SignedPreKeyRecord {
|
||||
let keypair = KeyPair::new(*pub_key, *priv_key);
|
||||
SignedPreKeyRecord::new(id, timestamp, &keypair, signature)
|
||||
SignedPreKeyRecord::new(id, timestamp.as_millis(), &keypair, signature)
|
||||
}
|
||||
|
||||
bridge_deserialize!(PreKeyRecord::deserialize);
|
||||
@ -593,7 +612,7 @@ bridge_get_buffer!(SenderCertificate::certificate -> &[u8]);
|
||||
bridge_get_buffer!(SenderCertificate::signature -> &[u8]);
|
||||
bridge_get!(SenderCertificate::sender_uuid -> &str);
|
||||
bridge_get!(SenderCertificate::sender_e164 -> Option<&str>);
|
||||
bridge_get!(SenderCertificate::expiration -> u64);
|
||||
bridge_get!(SenderCertificate::expiration -> Timestamp);
|
||||
bridge_get!(SenderCertificate::sender_device_id as GetDeviceId -> u32);
|
||||
bridge_get!(SenderCertificate::key -> PublicKey);
|
||||
|
||||
@ -601,9 +620,9 @@ bridge_get!(SenderCertificate::key -> PublicKey);
|
||||
fn SenderCertificate_Validate(
|
||||
cert: &SenderCertificate,
|
||||
key: &PublicKey,
|
||||
time: u64,
|
||||
time: Timestamp,
|
||||
) -> Result<bool> {
|
||||
cert.validate(key, time)
|
||||
cert.validate(key, time.as_millis())
|
||||
}
|
||||
|
||||
#[bridge_fn]
|
||||
@ -617,7 +636,7 @@ fn SenderCertificate_New(
|
||||
sender_e164: Option<String>,
|
||||
sender_device_id: u32,
|
||||
sender_key: &PublicKey,
|
||||
expiration: u64,
|
||||
expiration: Timestamp,
|
||||
signer_cert: &ServerCertificate,
|
||||
signer_key: &PrivateKey,
|
||||
) -> Result<SenderCertificate> {
|
||||
@ -628,7 +647,7 @@ fn SenderCertificate_New(
|
||||
sender_e164,
|
||||
*sender_key,
|
||||
sender_device_id,
|
||||
expiration,
|
||||
expiration.as_millis(),
|
||||
signer_cert.clone(),
|
||||
signer_key,
|
||||
&mut rng,
|
||||
@ -1080,7 +1099,7 @@ async fn SealedSessionCipher_DecryptToUsmc(
|
||||
async fn SealedSender_DecryptMessage(
|
||||
message: &[u8],
|
||||
trust_root: &PublicKey,
|
||||
timestamp: u64,
|
||||
timestamp: Timestamp,
|
||||
local_e164: Option<String>,
|
||||
local_uuid: String,
|
||||
local_device_id: u32,
|
||||
@ -1092,7 +1111,7 @@ async fn SealedSender_DecryptMessage(
|
||||
sealed_sender_decrypt(
|
||||
message,
|
||||
trust_root,
|
||||
timestamp,
|
||||
timestamp.as_millis(),
|
||||
local_e164,
|
||||
local_uuid,
|
||||
local_device_id,
|
||||
|
Loading…
Reference in New Issue
Block a user