Update to LibSignal v0.95.0
This commit is contained in:
parent
1a4acf84fc
commit
5e81462d83
@ -5,6 +5,11 @@
|
||||
|
||||
// WARNING: this file was automatically generated
|
||||
|
||||
// swiftlint:disable superfluous_disable_command
|
||||
// swiftlint and swift-format disagree on some comma formatting
|
||||
// swiftlint:disable comma
|
||||
// swiftlint:disable large_tuple
|
||||
|
||||
import Foundation
|
||||
import SignalFfi
|
||||
|
||||
|
||||
@ -20,9 +20,12 @@ internal protocol NiceArgConverter {
|
||||
}
|
||||
|
||||
extension NiceArgConverter {
|
||||
static func convertArgBorrowed<Result>(_ arg: NiceArg, _ thunk: (FfiArg) throws -> Result) rethrows -> Result {
|
||||
static internal func genericArgBorrowed<Result>(
|
||||
_ arg: NiceArg,
|
||||
_ thunk: (FfiArg) throws -> Result
|
||||
) rethrows -> Result {
|
||||
return try withExtendedLifetime(arg) {
|
||||
let (ffi, ka) = self.convertArg(arg)
|
||||
let (ffi, ka) = convertArg(arg)
|
||||
return try withExtendedLifetime(ka) {
|
||||
return try thunk(ffi)
|
||||
}
|
||||
|
||||
@ -60,6 +60,7 @@ public class SessionRecord: ClonableHandleOwner<SignalMutPointerSessionRecord> {
|
||||
}
|
||||
}
|
||||
|
||||
/// - Throws: ``SignalError/sessionNotFound(_:)`` if there is no current session state.
|
||||
public func remoteRegistrationId() throws -> UInt32 {
|
||||
return try self.withNativeHandle { nativeHandle in
|
||||
try invokeFnReturningInteger {
|
||||
|
||||
@ -0,0 +1,286 @@
|
||||
//
|
||||
// Copyright 2026 Signal Messenger, LLC.
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SignalFfi
|
||||
|
||||
/// Client-side state for an in-flight avatar upload credential request.
|
||||
///
|
||||
/// This value is not sent over the wire; it is retained by the client between issuing a
|
||||
/// ``AvatarUploadCredentialRequest`` and receiving the corresponding
|
||||
/// ``AvatarUploadCredentialResponse``.
|
||||
public final class AvatarUploadCredentialRequestContext: ByteArray {
|
||||
public required init(contents: Data) throws {
|
||||
try super.init(contents, checkValid: signal_avatar_upload_credential_request_context_check_valid_contents)
|
||||
}
|
||||
|
||||
/// Creates a new request context for `aci`.
|
||||
///
|
||||
/// - Parameter aci: The account the credential will be issued for. The issuing server must independently
|
||||
/// authenticate this ACI.
|
||||
/// - Parameter zkCredentialKey: The account's long-term Ristretto ZK credential key pair.
|
||||
/// - Parameter rotationId: The server-chosen avatar slot rotation ID, which the client already received
|
||||
/// when it set its ZK credential key. It is folded into the commitment; the issuing server
|
||||
/// verifies the request against its own rotation ID, so this must match the server's value.
|
||||
public static func create(
|
||||
aci: Aci,
|
||||
zkCredentialKey: ZkCredentialKeyPair,
|
||||
rotationId: UInt64
|
||||
) -> AvatarUploadCredentialRequestContext {
|
||||
return failOnError {
|
||||
self.create(
|
||||
aci: aci,
|
||||
zkCredentialKey: zkCredentialKey,
|
||||
rotationId: rotationId,
|
||||
randomness: try .generate()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new request context, using a dedicated source of randomness.
|
||||
///
|
||||
/// This can be used to make tests deterministic. Prefer ``create(aci:zkCredentialKey:rotationId:)``
|
||||
/// if the source of randomness doesn't matter.
|
||||
public static func create(
|
||||
aci: Aci,
|
||||
zkCredentialKey: ZkCredentialKeyPair,
|
||||
rotationId: UInt64,
|
||||
randomness: Randomness
|
||||
) -> AvatarUploadCredentialRequestContext {
|
||||
return failOnError {
|
||||
try withAllBorrowed(aci, zkCredentialKey, randomness) { aci, key, randomness in
|
||||
try invokeFnReturningVariableLengthSerialized {
|
||||
signal_avatar_upload_credential_request_context_new($0, aci, key, rotationId, randomness)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The request to send to the issuing server.
|
||||
public func getRequest() -> AvatarUploadCredentialRequest {
|
||||
return failOnError {
|
||||
try withUnsafeBorrowedBuffer { contents in
|
||||
try invokeFnReturningVariableLengthSerialized {
|
||||
signal_avatar_upload_credential_request_context_get_request($0, contents)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Verifies the issuing server's response and produces a usable ``AvatarUploadCredential``.
|
||||
///
|
||||
/// The issuing server chooses the redemption time and embeds it in `response`. The client
|
||||
/// doesn't need to predict it; this call confirms only that the credential is usable at
|
||||
/// `now`, since the verifying server applies the same window (see
|
||||
/// ``AvatarUploadCredentialPresentation/verify(now:serverParams:)``).
|
||||
///
|
||||
/// - Parameter response: The response received from the issuing server.
|
||||
/// - Parameter now: The client's view of wall-clock time. The response's redemption time must be
|
||||
/// day-aligned and within the redemption window relative to this.
|
||||
/// - Parameter serverParams: The public params matching the secret params the issuing server used.
|
||||
/// - Throws ``SignalError/verificationFailed(_:)`` if the response is not valid for this context.
|
||||
public func receive(
|
||||
_ response: AvatarUploadCredentialResponse,
|
||||
now: Date = Date(),
|
||||
serverParams: GenericServerPublicParams
|
||||
) throws -> AvatarUploadCredential {
|
||||
return try withAllBorrowed(self, response, serverParams) { contents, response, params in
|
||||
try invokeFnReturningVariableLengthSerialized {
|
||||
signal_avatar_upload_credential_request_context_receive_response(
|
||||
$0,
|
||||
contents,
|
||||
response,
|
||||
UInt64(now.timeIntervalSince1970),
|
||||
params
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The request a client sends to the issuing server to obtain an avatar upload credential.
|
||||
public class AvatarUploadCredentialRequest: ByteArray {
|
||||
public required init(contents: Data) throws {
|
||||
try super.init(contents, checkValid: signal_avatar_upload_credential_request_check_valid_contents)
|
||||
}
|
||||
|
||||
/// Issues an avatar upload credential.
|
||||
///
|
||||
/// - Parameter aci: The account this credential is for. The server must independently authenticate the
|
||||
/// client as this ACI.
|
||||
/// - Parameter zkCredentialKey: The account's long-term Ristretto ZK credential public key from
|
||||
/// the server's authoritative store for this account. The request's well-formedness proof
|
||||
/// binds the blinded commitment to this key, so passing the wrong value will fail issuance.
|
||||
/// - Parameter rotationId: The server-chosen avatar slot rotation ID, incorporated into the commitment.
|
||||
/// The server must return this value to the client (it is carried in the response) so the
|
||||
/// client can compute the full commitment.
|
||||
/// - Parameter redemptionTime: Must be a round number of days since the Unix epoch.
|
||||
/// - Parameter serverParams: The params that will be used by the verifying server to verify this credential.
|
||||
/// - Throws ``SignalError/verificationFailed(_:)`` if the request is not well-formed for `aci` and
|
||||
/// `zkCredentialKey`.
|
||||
public func issueCredential(
|
||||
aci: Aci,
|
||||
zkCredentialKey: ZkCredentialPublicKey,
|
||||
rotationId: UInt64,
|
||||
redemptionTime: Date,
|
||||
serverParams: GenericServerSecretParams
|
||||
) throws -> AvatarUploadCredentialResponse {
|
||||
return try self.issueCredential(
|
||||
aci: aci,
|
||||
zkCredentialKey: zkCredentialKey,
|
||||
rotationId: rotationId,
|
||||
redemptionTime: redemptionTime,
|
||||
serverParams: serverParams,
|
||||
randomness: try .generate()
|
||||
)
|
||||
}
|
||||
|
||||
/// Issues an avatar upload credential, using a dedicated source of randomness.
|
||||
///
|
||||
/// This can be used to make tests deterministic. Prefer ``issueCredential(aci:zkcredentialKey:rotationId:redemptionTime:serverParams:)``
|
||||
/// if the source of randomness doesn't matter.
|
||||
public func issueCredential(
|
||||
aci: Aci,
|
||||
zkCredentialKey: ZkCredentialPublicKey,
|
||||
rotationId: UInt64,
|
||||
redemptionTime: Date,
|
||||
serverParams: GenericServerSecretParams,
|
||||
randomness: Randomness
|
||||
) throws -> AvatarUploadCredentialResponse {
|
||||
return try withAllBorrowed(self, aci, zkCredentialKey, serverParams, randomness) {
|
||||
contents,
|
||||
aci,
|
||||
key,
|
||||
params,
|
||||
randomness in
|
||||
try invokeFnReturningVariableLengthSerialized {
|
||||
signal_avatar_upload_credential_request_issue_deterministic(
|
||||
$0,
|
||||
contents,
|
||||
aci,
|
||||
key,
|
||||
rotationId,
|
||||
UInt64(redemptionTime.timeIntervalSince1970),
|
||||
params,
|
||||
randomness
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The issuing server's response to an ``AvatarUploadCredentialRequest``.
|
||||
public class AvatarUploadCredentialResponse: ByteArray {
|
||||
public required init(contents: Data) throws {
|
||||
try super.init(contents, checkValid: signal_avatar_upload_credential_response_check_valid_contents)
|
||||
}
|
||||
}
|
||||
|
||||
/// A usable avatar upload credential, held by the client after a successful issuance.
|
||||
///
|
||||
/// Call ``Self/present(serverParams:)`` to produce an ``AvatarUploadCredentialPresentation`` for a verifying
|
||||
/// server.
|
||||
public class AvatarUploadCredential: ByteArray {
|
||||
public required init(contents: Data) throws {
|
||||
try super.init(contents, checkValid: signal_avatar_upload_credential_check_valid_contents)
|
||||
}
|
||||
|
||||
/// Produces a presentation of this credential for a verifying server.
|
||||
public func present(serverParams: GenericServerPublicParams) -> AvatarUploadCredentialPresentation {
|
||||
return failOnError {
|
||||
self.present(serverParams: serverParams, randomness: try .generate())
|
||||
}
|
||||
}
|
||||
|
||||
/// Produces a presentation of this credential, using a dedicated source of randomness.
|
||||
///
|
||||
/// This can be used to make tests deterministic. Prefer ``present(serverParams:)``
|
||||
/// if the source of randomness doesn't matter.
|
||||
public func present(
|
||||
serverParams: GenericServerPublicParams,
|
||||
randomness: Randomness
|
||||
) -> AvatarUploadCredentialPresentation {
|
||||
return failOnError {
|
||||
try withAllBorrowed(self, serverParams, randomness) { contents, serverParams, randomness in
|
||||
try invokeFnReturningVariableLengthSerialized {
|
||||
signal_avatar_upload_credential_present_deterministic($0, contents, serverParams, randomness)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The 32-byte commitment `Cm` (the avatar slot identifier).
|
||||
///
|
||||
/// This is a Pedersen commitment, not a key, so it carries no type-tag prefix.
|
||||
public var commitment: Data {
|
||||
failOnError {
|
||||
try withUnsafeBorrowedBuffer { contents in
|
||||
try invokeFnReturningFixedLengthArray {
|
||||
signal_avatar_upload_credential_get_cm($0, contents)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The redemption time the issuing server chose for this credential.
|
||||
public var redemptionTime: Date {
|
||||
let secondsSinceEpoch = failOnError {
|
||||
try withUnsafeBorrowedBuffer { contents in
|
||||
try invokeFnReturningInteger {
|
||||
signal_avatar_upload_credential_get_redemption_time($0, contents)
|
||||
}
|
||||
}
|
||||
}
|
||||
return Date(timeIntervalSince1970: TimeInterval(secondsSinceEpoch))
|
||||
}
|
||||
}
|
||||
|
||||
/// A presentation of an ``AvatarUploadCredential``, sent to a verifying server.
|
||||
public class AvatarUploadCredentialPresentation: ByteArray {
|
||||
public required init(contents: Data) throws {
|
||||
try super.init(contents, checkValid: signal_avatar_upload_credential_presentation_check_valid_contents)
|
||||
}
|
||||
|
||||
/// Verifies the presentation against the (given) current time.
|
||||
///
|
||||
/// - Throws: ``SignalError/verificationFailed(_:)`` if the presentation is invalid or outside its redemption
|
||||
/// window.
|
||||
public func verify(now: Date = Date(), serverParams: GenericServerSecretParams) throws {
|
||||
try withAllBorrowed(self, serverParams) { contents, serverParams in
|
||||
try checkError(
|
||||
signal_avatar_upload_credential_presentation_verify(
|
||||
contents,
|
||||
UInt64(now.timeIntervalSince1970),
|
||||
serverParams
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// The 32-byte commitment `Cm` (the avatar slot identifier) revealed by this presentation.
|
||||
///
|
||||
/// This is a Pedersen commitment, not a key, so it carries no type-tag prefix.
|
||||
public var commitment: Data {
|
||||
failOnError {
|
||||
try withUnsafeBorrowedBuffer { contents in
|
||||
try invokeFnReturningFixedLengthArray {
|
||||
signal_avatar_upload_credential_presentation_get_cm($0, contents)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The redemption time the issuing server chose for this credential.
|
||||
public var redemptionTime: Date {
|
||||
let secondsSinceEpoch = failOnError {
|
||||
try withUnsafeBorrowedBuffer { contents in
|
||||
try invokeFnReturningInteger {
|
||||
signal_avatar_upload_credential_presentation_get_redemption_time($0, contents)
|
||||
}
|
||||
}
|
||||
}
|
||||
return Date(timeIntervalSince1970: TimeInterval(secondsSinceEpoch))
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
//
|
||||
// Copyright 2026 Signal Messenger, LLC.
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SignalFfi
|
||||
|
||||
/// A long-term Ristretto ZK credential key pair owned by an account.
|
||||
///
|
||||
/// Distinct from the account's curve25519 identity key. Used as a binding identity across ZK
|
||||
/// credentials issued to the account (currently the avatar upload credential).
|
||||
///
|
||||
/// The secret half must be persisted by the account holder and synced to linked devices. The
|
||||
/// public half is uploaded to the server.
|
||||
public class ZkCredentialKeyPair: ByteArray {
|
||||
public static func generate() -> ZkCredentialKeyPair {
|
||||
return failOnError {
|
||||
self.generate(randomness: try Randomness.generate())
|
||||
}
|
||||
}
|
||||
|
||||
public static func generate(randomness: Randomness) -> ZkCredentialKeyPair {
|
||||
return failOnError {
|
||||
try randomness.withUnsafePointerToBytes { randomness in
|
||||
try invokeFnReturningVariableLengthSerialized {
|
||||
signal_zk_credential_key_pair_generate_deterministic($0, randomness)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public required init(contents: Data) throws {
|
||||
try super.init(contents, checkValid: signal_zk_credential_key_pair_check_valid_contents)
|
||||
}
|
||||
|
||||
public var publicKey: ZkCredentialPublicKey {
|
||||
failOnError {
|
||||
try withUnsafeBorrowedBuffer { keyPairBytes in
|
||||
try invokeFnReturningVariableLengthSerialized {
|
||||
signal_zk_credential_key_pair_get_public_key($0, keyPairBytes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The public half of a ``ZkCredentialKeyPair``.
|
||||
public class ZkCredentialPublicKey: ByteArray {
|
||||
public required init(contents: Data) throws {
|
||||
try super.init(contents, checkValid: signal_zk_credential_public_key_check_valid_contents)
|
||||
}
|
||||
|
||||
}
|
||||
@ -1805,6 +1805,36 @@ SignalFfiError *signal_authenticated_chat_connection_send_raw_grpc(SignalCPromis
|
||||
|
||||
SignalFfiError *signal_authenticated_chat_connection_send_sync_message(SignalCPromisebool *promise, SignalConstPointerTokioAsyncContext async_runtime, SignalConstPointerAuthenticatedChatConnection chat, uint64_t timestamp, SignalBorrowedSliceOfu32 device_ids, SignalBorrowedSliceOfu32 registration_ids, SignalBorrowedSliceOfConstPointerCiphertextMessage contents, bool is_urgent);
|
||||
|
||||
SignalFfiError *signal_avatar_upload_credential_check_valid_contents(SignalBorrowedBuffer credential_bytes);
|
||||
|
||||
SignalFfiError *signal_avatar_upload_credential_get_cm(uint8_t (*out)[32], SignalBorrowedBuffer credential_bytes);
|
||||
|
||||
SignalFfiError *signal_avatar_upload_credential_get_redemption_time(uint64_t *out, SignalBorrowedBuffer credential_bytes);
|
||||
|
||||
SignalFfiError *signal_avatar_upload_credential_present_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer credential_bytes, SignalBorrowedBuffer server_params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]);
|
||||
|
||||
SignalFfiError *signal_avatar_upload_credential_presentation_check_valid_contents(SignalBorrowedBuffer presentation_bytes);
|
||||
|
||||
SignalFfiError *signal_avatar_upload_credential_presentation_get_cm(uint8_t (*out)[32], SignalBorrowedBuffer presentation_bytes);
|
||||
|
||||
SignalFfiError *signal_avatar_upload_credential_presentation_get_redemption_time(uint64_t *out, SignalBorrowedBuffer presentation_bytes);
|
||||
|
||||
SignalFfiError *signal_avatar_upload_credential_presentation_verify(SignalBorrowedBuffer presentation_bytes, uint64_t current_time, SignalBorrowedBuffer server_params_bytes);
|
||||
|
||||
SignalFfiError *signal_avatar_upload_credential_request_check_valid_contents(SignalBorrowedBuffer request_bytes);
|
||||
|
||||
SignalFfiError *signal_avatar_upload_credential_request_context_check_valid_contents(SignalBorrowedBuffer context_bytes);
|
||||
|
||||
SignalFfiError *signal_avatar_upload_credential_request_context_get_request(SignalOwnedBuffer *out, SignalBorrowedBuffer context_bytes);
|
||||
|
||||
SignalFfiError *signal_avatar_upload_credential_request_context_new(SignalOwnedBuffer *out, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalBorrowedBuffer zk_credential_key_pair_bytes, uint64_t rotation_id, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]);
|
||||
|
||||
SignalFfiError *signal_avatar_upload_credential_request_context_receive_response(SignalOwnedBuffer *out, SignalBorrowedBuffer context_bytes, SignalBorrowedBuffer response_bytes, uint64_t current_time, SignalBorrowedBuffer params_bytes);
|
||||
|
||||
SignalFfiError *signal_avatar_upload_credential_request_issue_deterministic(SignalOwnedBuffer *out, SignalBorrowedBuffer request_bytes, const SignalServiceIdFixedWidthBinaryBytes *aci, SignalBorrowedBuffer zk_credential_key_pub_bytes, uint64_t rotation_id, uint64_t redemption_time, SignalBorrowedBuffer params_bytes, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]);
|
||||
|
||||
SignalFfiError *signal_avatar_upload_credential_response_check_valid_contents(SignalBorrowedBuffer response_bytes);
|
||||
|
||||
SignalFfiError *signal_backup_auth_credential_check_valid_contents(SignalBorrowedBuffer params_bytes);
|
||||
|
||||
SignalFfiError *signal_backup_auth_credential_get_backup_id(uint8_t (*out)[16], SignalBorrowedBuffer credential_bytes);
|
||||
@ -2910,4 +2940,12 @@ SignalFfiError *signal_validating_mac_update(int32_t *out, SignalMutPointerValid
|
||||
|
||||
SignalFfiError *signal_webp_sanitizer_sanitize(SignalConstPointerFfiSyncInputStreamStruct input);
|
||||
|
||||
SignalFfiError *signal_zk_credential_key_pair_check_valid_contents(SignalBorrowedBuffer key_pair_bytes);
|
||||
|
||||
SignalFfiError *signal_zk_credential_key_pair_generate_deterministic(SignalOwnedBuffer *out, const uint8_t (*randomness)[SignalRANDOMNESS_LEN]);
|
||||
|
||||
SignalFfiError *signal_zk_credential_key_pair_get_public_key(SignalOwnedBuffer *out, SignalBorrowedBuffer key_pair_bytes);
|
||||
|
||||
SignalFfiError *signal_zk_credential_public_key_check_valid_contents(SignalBorrowedBuffer public_key_bytes);
|
||||
|
||||
#endif /* SIGNAL_FFI_H_ */
|
||||
|
||||
@ -240,6 +240,112 @@ typedef struct {
|
||||
SignalTestingIntBox *raw;
|
||||
} SignalMutPointerTestingIntBox;
|
||||
|
||||
typedef struct {
|
||||
int32_t _0;
|
||||
int32_t _1;
|
||||
} SignalMyTestPointFfiResult;
|
||||
|
||||
typedef struct {
|
||||
int32_t my_numeric_field;
|
||||
SignalCStringPtr my_string_field;
|
||||
} SignalMyTestStructFfiResult;
|
||||
|
||||
typedef enum {
|
||||
SignalMyTestEnumFfiResultUnit,
|
||||
SignalMyTestEnumFfiResultSingle,
|
||||
SignalMyTestEnumFfiResultSingleNamed,
|
||||
SignalMyTestEnumFfiResultDouble,
|
||||
SignalMyTestEnumFfiResultRecord,
|
||||
} SignalMyTestEnumFfiResult_Tag;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} SignalMyTestEnumFfiResultSignalUnit_Body;
|
||||
|
||||
typedef struct {
|
||||
int32_t _0;
|
||||
} SignalMyTestEnumFfiResultSignalSingle_Body;
|
||||
|
||||
typedef struct {
|
||||
int32_t x;
|
||||
} SignalMyTestEnumFfiResultSignalSingleNamed_Body;
|
||||
|
||||
typedef struct {
|
||||
int32_t _0;
|
||||
int32_t _1;
|
||||
} SignalMyTestEnumFfiResultSignalDouble_Body;
|
||||
|
||||
typedef struct {
|
||||
SignalCStringPtr person_name;
|
||||
int32_t person_age;
|
||||
SignalMyTestPointFfiResult position;
|
||||
SignalMyTestStructFfiResult fun_struct;
|
||||
} SignalMyTestEnumFfiResultSignalRecord_Body;
|
||||
|
||||
typedef struct {
|
||||
SignalMyTestEnumFfiResult_Tag tag;
|
||||
union {
|
||||
SignalMyTestEnumFfiResultSignalUnit_Body unit;
|
||||
SignalMyTestEnumFfiResultSignalSingle_Body single;
|
||||
SignalMyTestEnumFfiResultSignalSingleNamed_Body single_named;
|
||||
SignalMyTestEnumFfiResultSignalDouble_Body double_;
|
||||
SignalMyTestEnumFfiResultSignalRecord_Body record;
|
||||
};
|
||||
} SignalMyTestEnumFfiResult;
|
||||
|
||||
typedef struct {
|
||||
int32_t _0;
|
||||
int32_t _1;
|
||||
} SignalMyTestPointFfiArg;
|
||||
|
||||
typedef struct {
|
||||
int32_t my_numeric_field;
|
||||
const char *my_string_field;
|
||||
} SignalMyTestStructFfiArg;
|
||||
|
||||
typedef enum {
|
||||
SignalMyTestEnumFfiArgUnit,
|
||||
SignalMyTestEnumFfiArgSingle,
|
||||
SignalMyTestEnumFfiArgSingleNamed,
|
||||
SignalMyTestEnumFfiArgDouble,
|
||||
SignalMyTestEnumFfiArgRecord,
|
||||
} SignalMyTestEnumFfiArg_Tag;
|
||||
|
||||
typedef struct {
|
||||
|
||||
} SignalMyTestEnumFfiArgSignalUnit_Body;
|
||||
|
||||
typedef struct {
|
||||
int32_t _0;
|
||||
} SignalMyTestEnumFfiArgSignalSingle_Body;
|
||||
|
||||
typedef struct {
|
||||
int32_t x;
|
||||
} SignalMyTestEnumFfiArgSignalSingleNamed_Body;
|
||||
|
||||
typedef struct {
|
||||
int32_t _0;
|
||||
int32_t _1;
|
||||
} SignalMyTestEnumFfiArgSignalDouble_Body;
|
||||
|
||||
typedef struct {
|
||||
const char *person_name;
|
||||
int32_t person_age;
|
||||
SignalMyTestPointFfiArg position;
|
||||
SignalMyTestStructFfiArg fun_struct;
|
||||
} SignalMyTestEnumFfiArgSignalRecord_Body;
|
||||
|
||||
typedef struct {
|
||||
SignalMyTestEnumFfiArg_Tag tag;
|
||||
union {
|
||||
SignalMyTestEnumFfiArgSignalUnit_Body unit;
|
||||
SignalMyTestEnumFfiArgSignalSingle_Body single;
|
||||
SignalMyTestEnumFfiArgSignalSingleNamed_Body single_named;
|
||||
SignalMyTestEnumFfiArgSignalDouble_Body double_;
|
||||
SignalMyTestEnumFfiArgSignalRecord_Body record;
|
||||
};
|
||||
} SignalMyTestEnumFfiArg;
|
||||
|
||||
typedef struct {
|
||||
int32_t first;
|
||||
SignalCStringPtr second;
|
||||
@ -435,6 +541,18 @@ SignalFfiError *signal_testing_key_trans_non_fatal_verification_failure(void);
|
||||
|
||||
SignalFfiError *signal_testing_key_trans_stored_account_data(SignalOwnedBuffer *out);
|
||||
|
||||
SignalFfiError *signal_testing_my_test_enum_identity(SignalMyTestEnumFfiResult *out, SignalMyTestEnumFfiArg x);
|
||||
|
||||
SignalFfiError *signal_testing_my_test_enum_to_string(SignalCStringPtr *out, SignalMyTestEnumFfiArg x);
|
||||
|
||||
SignalFfiError *signal_testing_my_test_point_identity(SignalMyTestPointFfiResult *out, SignalMyTestPointFfiArg x);
|
||||
|
||||
SignalFfiError *signal_testing_my_test_point_to_string(SignalCStringPtr *out, SignalMyTestPointFfiArg x);
|
||||
|
||||
SignalFfiError *signal_testing_my_test_struct_identity(SignalMyTestStructFfiResult *out, SignalMyTestStructFfiArg x);
|
||||
|
||||
SignalFfiError *signal_testing_my_test_struct_to_string(SignalCStringPtr *out, SignalMyTestStructFfiArg x);
|
||||
|
||||
SignalFfiError *signal_testing_other_testing_handle_type_get_value(SignalCStringPtr *out, SignalConstPointerOtherTestingHandleType handle);
|
||||
|
||||
SignalFfiError *signal_testing_panic_in_body_async(const void *_input);
|
||||
|
||||
@ -0,0 +1,232 @@
|
||||
//
|
||||
// Copyright 2026 Signal Messenger, LLC.
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import LibSignalClient
|
||||
import Testing
|
||||
|
||||
private struct AvatarUploadCredentialTests {
|
||||
// Chosen randomly.
|
||||
let TEST_ACI = try! Aci.parseFrom(serviceIdString: "c0fc16e4-bae5-4343-9f0d-e7ecf4251343")
|
||||
|
||||
let ZK_CRED_KEY_RANDOM = Randomness(
|
||||
fromHexString: "4242424242424242424242424242424242424242424242424242424242424242"
|
||||
)!
|
||||
|
||||
let WRONG_ZK_CRED_KEY_RANDOM = Randomness(
|
||||
fromHexString: "9999999999999999999999999999999999999999999999999999999999999999"
|
||||
)!
|
||||
|
||||
let SERVER_SECRET_RANDOM = Randomness(
|
||||
fromHexString: "6987b92bdea075d3f8b42b39d780a5be0bc264874a18e11cac694e4fe28f6cca"
|
||||
)!
|
||||
|
||||
let CREATE_RANDOM = Randomness(
|
||||
fromHexString: "657e7a2ac9dd981b789c9b2fbcdfbbe46cb6230c7a2c67c1be3472cb006463e2"
|
||||
)!
|
||||
|
||||
let ISSUE_RANDOM = Randomness(
|
||||
fromHexString: "8e3f24cb0a7e7614c7b4ab04ba8a145f108c53c4b10a096aa4503ae1e0c9f661"
|
||||
)!
|
||||
|
||||
let PRESENT_RANDOM = Randomness(
|
||||
fromHexString: "475149b2bdcb6f9bd3a8e3a5d4c6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f8"
|
||||
)!
|
||||
|
||||
let ROTATION_ID: UInt64 = 7
|
||||
|
||||
@Test
|
||||
func testAvatarUploadCredentialIntegration() {
|
||||
// SERVER: generate keys.
|
||||
let serverSecretParams = GenericServerSecretParams.generate(randomness: SERVER_SECRET_RANDOM)
|
||||
let serverPublicParams = serverSecretParams.getPublicParams()
|
||||
|
||||
// CLIENT: generate its long-term ZK credential key pair and (out of band) register the public
|
||||
// half with the server.
|
||||
let zkCredentialKeyPair = ZkCredentialKeyPair.generate(randomness: ZK_CRED_KEY_RANDOM)
|
||||
let zkCredentialKeyPublic = zkCredentialKeyPair.publicKey
|
||||
|
||||
// CLIENT: build a request.
|
||||
let context = AvatarUploadCredentialRequestContext.create(
|
||||
aci: TEST_ACI,
|
||||
zkCredentialKey: zkCredentialKeyPair,
|
||||
rotationId: ROTATION_ID,
|
||||
randomness: CREATE_RANDOM
|
||||
)
|
||||
let request = context.getRequest()
|
||||
|
||||
// Round-tripping the request through serialize() must preserve it.
|
||||
#expect(request.serialize() == (try! AvatarUploadCredentialRequest(contents: request.serialize()).serialize()))
|
||||
|
||||
// SERVER: authenticate the ACI, look up its ZK credential key, and issue.
|
||||
let now = Date()
|
||||
let nowInSeconds = UInt64(now.timeIntervalSince1970)
|
||||
let startOfDayInSeconds = nowInSeconds - (nowInSeconds % SECONDS_PER_DAY)
|
||||
let startOfDay = Date(timeIntervalSince1970: TimeInterval(startOfDayInSeconds))
|
||||
let response = try! request.issueCredential(
|
||||
aci: TEST_ACI,
|
||||
zkCredentialKey: zkCredentialKeyPublic,
|
||||
rotationId: ROTATION_ID,
|
||||
redemptionTime: startOfDay,
|
||||
serverParams: serverSecretParams,
|
||||
randomness: ISSUE_RANDOM
|
||||
)
|
||||
|
||||
// CLIENT: verify and unblind the credential. The client passes its current wall-clock time;
|
||||
// libsignal checks that the credential's redemption_time (chosen by the server, carried in
|
||||
// `response`) is day-aligned and inside the redemption window relative to `now`.
|
||||
let credential = try! context.receive(response, now: now, serverParams: serverPublicParams)
|
||||
|
||||
// The client can read back the redemption time the issuing server chose.
|
||||
#expect(startOfDay == credential.redemptionTime)
|
||||
|
||||
let credentialDefaultTime = try! context.receive(response, serverParams: serverPublicParams)
|
||||
#expect(credential.serialize() == credentialDefaultTime.serialize())
|
||||
|
||||
// CLIENT: present the credential.
|
||||
let presentation = credential.present(serverParams: serverPublicParams, randomness: PRESENT_RANDOM)
|
||||
|
||||
// The revealed commitment Cm must match between the credential and its presentation.
|
||||
#expect(credential.commitment == presentation.commitment)
|
||||
#expect(credential.redemptionTime == presentation.redemptionTime)
|
||||
|
||||
// SERVER: verify the presentation across the redemption window.
|
||||
try! presentation.verify(now: startOfDay, serverParams: serverSecretParams)
|
||||
try! presentation.verify(now: startOfDay + TimeInterval(SECONDS_PER_DAY), serverParams: serverSecretParams)
|
||||
|
||||
#expect("Credential should be expired more than 2 days after redemption time") {
|
||||
try presentation.verify(
|
||||
now: startOfDay + 2 * TimeInterval(SECONDS_PER_DAY + 1),
|
||||
serverParams: serverSecretParams
|
||||
)
|
||||
} throws: {
|
||||
if case SignalError.verificationFailed(_:) = $0 { true } else { false }
|
||||
}
|
||||
|
||||
#expect("Credential should be invalid before its redemption time") {
|
||||
try presentation.verify(
|
||||
now: startOfDay - TimeInterval(SECONDS_PER_DAY + 1),
|
||||
serverParams: serverSecretParams
|
||||
)
|
||||
} throws: {
|
||||
if case SignalError.verificationFailed(_:) = $0 { true } else { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
func testIssuanceRejectsWrongAci() {
|
||||
let serverSecretParams = GenericServerSecretParams.generate(randomness: SERVER_SECRET_RANDOM)
|
||||
|
||||
let zkCredentialKeyPair = ZkCredentialKeyPair.generate(randomness: ZK_CRED_KEY_RANDOM)
|
||||
let zkCredentialKeyPublic = zkCredentialKeyPair.publicKey
|
||||
|
||||
let context = AvatarUploadCredentialRequestContext.create(
|
||||
aci: TEST_ACI,
|
||||
zkCredentialKey: zkCredentialKeyPair,
|
||||
rotationId: ROTATION_ID,
|
||||
randomness: CREATE_RANDOM
|
||||
)
|
||||
let request = context.getRequest()
|
||||
|
||||
let wrongAci = try! Aci.parseFrom(serviceIdString: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee")
|
||||
|
||||
let now = Date()
|
||||
let nowInSeconds = UInt64(now.timeIntervalSince1970)
|
||||
let startOfDayInSeconds = nowInSeconds - (nowInSeconds % SECONDS_PER_DAY)
|
||||
let startOfDay = Date(timeIntervalSince1970: TimeInterval(startOfDayInSeconds))
|
||||
|
||||
#expect("Issuance should fail when the server checks against a different ACI") {
|
||||
try request.issueCredential(
|
||||
aci: wrongAci,
|
||||
zkCredentialKey: zkCredentialKeyPublic,
|
||||
rotationId: ROTATION_ID,
|
||||
redemptionTime: startOfDay,
|
||||
serverParams: serverSecretParams,
|
||||
randomness: ISSUE_RANDOM
|
||||
)
|
||||
} throws: {
|
||||
if case SignalError.verificationFailed(_:) = $0 { true } else { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
func testIssuanceRejectsWrongZkCredentialKey() {
|
||||
let serverSecretParams = GenericServerSecretParams.generate(randomness: SERVER_SECRET_RANDOM)
|
||||
|
||||
let zkCredentialKeyPair = ZkCredentialKeyPair.generate(randomness: ZK_CRED_KEY_RANDOM)
|
||||
|
||||
let context = AvatarUploadCredentialRequestContext.create(
|
||||
aci: TEST_ACI,
|
||||
zkCredentialKey: zkCredentialKeyPair,
|
||||
rotationId: ROTATION_ID,
|
||||
randomness: CREATE_RANDOM
|
||||
)
|
||||
let request = context.getRequest()
|
||||
|
||||
// Server has a different ZK credential public key on file for this account.
|
||||
let wrongZkCredentialKeyPublic = ZkCredentialKeyPair.generate(randomness: WRONG_ZK_CRED_KEY_RANDOM).publicKey
|
||||
|
||||
let now = Date()
|
||||
let nowInSeconds = UInt64(now.timeIntervalSince1970)
|
||||
let startOfDayInSeconds = nowInSeconds - (nowInSeconds % SECONDS_PER_DAY)
|
||||
let startOfDay = Date(timeIntervalSince1970: TimeInterval(startOfDayInSeconds))
|
||||
|
||||
#expect("Issuance should fail when the server uses a different ZK credential public key") {
|
||||
try request.issueCredential(
|
||||
aci: TEST_ACI,
|
||||
zkCredentialKey: wrongZkCredentialKeyPublic,
|
||||
rotationId: ROTATION_ID,
|
||||
redemptionTime: startOfDay,
|
||||
serverParams: serverSecretParams,
|
||||
randomness: ISSUE_RANDOM
|
||||
)
|
||||
} throws: {
|
||||
if case SignalError.verificationFailed(_:) = $0 { true } else { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
func testIssuanceRejectsWrongRotationId() {
|
||||
let serverSecretParams = GenericServerSecretParams.generate(randomness: SERVER_SECRET_RANDOM)
|
||||
|
||||
let zkCredentialKeyPair = ZkCredentialKeyPair.generate(randomness: ZK_CRED_KEY_RANDOM)
|
||||
let zkCredentialKeyPublic = zkCredentialKeyPair.publicKey
|
||||
|
||||
// Client commits to one rotation ID...
|
||||
let context = AvatarUploadCredentialRequestContext.create(
|
||||
aci: TEST_ACI,
|
||||
zkCredentialKey: zkCredentialKeyPair,
|
||||
rotationId: ROTATION_ID,
|
||||
randomness: CREATE_RANDOM
|
||||
)
|
||||
let request = context.getRequest()
|
||||
|
||||
let now = Date()
|
||||
let nowInSeconds = UInt64(now.timeIntervalSince1970)
|
||||
let startOfDayInSeconds = nowInSeconds - (nowInSeconds % SECONDS_PER_DAY)
|
||||
let startOfDay = Date(timeIntervalSince1970: TimeInterval(startOfDayInSeconds))
|
||||
|
||||
#expect("Issuance should fail when the server uses a different rotation ID") {
|
||||
try request.issueCredential(
|
||||
aci: TEST_ACI,
|
||||
zkCredentialKey: zkCredentialKeyPublic,
|
||||
rotationId: ROTATION_ID + 1,
|
||||
redemptionTime: startOfDay,
|
||||
serverParams: serverSecretParams,
|
||||
randomness: ISSUE_RANDOM
|
||||
)
|
||||
} throws: {
|
||||
if case SignalError.verificationFailed(_:) = $0 { true } else { false }
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
func testPublicKeyDerivationIsDeterministic() {
|
||||
let a = ZkCredentialKeyPair.generate(randomness: ZK_CRED_KEY_RANDOM)
|
||||
let b = ZkCredentialKeyPair.generate(randomness: ZK_CRED_KEY_RANDOM)
|
||||
#expect(a.serialize() == b.serialize())
|
||||
#expect(a.publicKey.serialize() == b.publicKey.serialize())
|
||||
}
|
||||
}
|
||||
@ -5,13 +5,622 @@
|
||||
|
||||
// WARNING: this file was automatically generated
|
||||
|
||||
// swiftlint:disable superfluous_disable_command
|
||||
// swiftlint and swift-format disagree on some comma formatting
|
||||
// swiftlint:disable comma
|
||||
// swiftlint:disable large_tuple
|
||||
|
||||
#if !os(iOS) || targetEnvironment(simulator)
|
||||
|
||||
import Foundation
|
||||
import SignalFfi
|
||||
@testable import LibSignalClient
|
||||
|
||||
internal enum MyTestEnum {
|
||||
case unit
|
||||
case single(Int32)
|
||||
case singleNamed(x: Int32)
|
||||
case double(Int32, Int32)
|
||||
case record(personName: String, personAge: Int32, position: MyTestPoint, funStruct: MyTestStruct)
|
||||
}
|
||||
|
||||
internal struct MyTestPoint {
|
||||
var _0: Int32
|
||||
var _1: Int32
|
||||
|
||||
init(_ _0: Int32, _ _1: Int32, ) {
|
||||
self._0 = _0
|
||||
self._1 = _1
|
||||
|
||||
}
|
||||
init(_0: Int32, _1: Int32, ) {
|
||||
self._0 = _0
|
||||
self._1 = _1
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal struct MyTestStruct {
|
||||
var myNumericField: Int32
|
||||
var myStringField: String
|
||||
|
||||
}
|
||||
|
||||
internal enum DerivedReturnConverterMyTestEnum: NiceReturnConverter {
|
||||
typealias NiceReturn = MyTestEnum
|
||||
typealias FfiReturn = SignalMyTestEnumFfiResult
|
||||
static func emptyFfiReturn() -> FfiReturn {
|
||||
SignalMyTestEnumFfiResult()
|
||||
}
|
||||
static func convertReturn(consuming ffiValue: FfiReturn) throws -> NiceReturn {
|
||||
switch ffiValue.tag {
|
||||
case SignalMyTestEnumFfiResultUnit:
|
||||
return MyTestEnum.unit
|
||||
case SignalMyTestEnumFfiResultSingle:
|
||||
let _0 = Result {
|
||||
try IdentityConverter<Int32>.convertReturn(
|
||||
consuming: ffiValue.single._0
|
||||
)
|
||||
}
|
||||
return MyTestEnum.single(try _0.get())
|
||||
case SignalMyTestEnumFfiResultSingleNamed:
|
||||
let x = Result {
|
||||
try IdentityConverter<Int32>.convertReturn(
|
||||
consuming: ffiValue.single_named.x
|
||||
)
|
||||
}
|
||||
return MyTestEnum.singleNamed(x: try x.get())
|
||||
case SignalMyTestEnumFfiResultDouble:
|
||||
let _0 = Result {
|
||||
try IdentityConverter<Int32>.convertReturn(
|
||||
consuming: ffiValue.double_._0
|
||||
)
|
||||
}
|
||||
let _1 = Result {
|
||||
try IdentityConverter<Int32>.convertReturn(
|
||||
consuming: ffiValue.double_._1
|
||||
)
|
||||
}
|
||||
return MyTestEnum.double(try _0.get(), try _1.get())
|
||||
case SignalMyTestEnumFfiResultRecord:
|
||||
let person_name = Result {
|
||||
try StringConverter.convertReturn(
|
||||
consuming: ffiValue.record.person_name
|
||||
)
|
||||
}
|
||||
let person_age = Result {
|
||||
try IdentityConverter<Int32>.convertReturn(
|
||||
consuming: ffiValue.record.person_age
|
||||
)
|
||||
}
|
||||
let position = Result {
|
||||
try DerivedReturnConverterMyTestPoint.convertReturn(
|
||||
consuming: ffiValue.record.position
|
||||
)
|
||||
}
|
||||
let fun_struct = Result {
|
||||
try DerivedReturnConverterMyTestStruct.convertReturn(
|
||||
consuming: ffiValue.record.fun_struct
|
||||
)
|
||||
}
|
||||
return MyTestEnum.record(
|
||||
personName: try person_name.get(),
|
||||
personAge: try person_age.get(),
|
||||
position: try position.get(),
|
||||
funStruct: try fun_struct.get()
|
||||
)
|
||||
default:
|
||||
throw SignalError.internalError("Unexpected enum tag for MyTestEnum: \(ffiValue.tag)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal enum DerivedReturnConverterMyTestPoint: NiceReturnConverter {
|
||||
typealias NiceReturn = MyTestPoint
|
||||
typealias FfiReturn = SignalMyTestPointFfiResult
|
||||
static func emptyFfiReturn() -> FfiReturn {
|
||||
SignalMyTestPointFfiResult()
|
||||
}
|
||||
static func convertReturn(consuming ffiValue: FfiReturn) throws -> NiceReturn {
|
||||
|
||||
let _0 = Result { try IdentityConverter<Int32>.convertReturn(consuming: ffiValue._0) }
|
||||
let _1 = Result { try IdentityConverter<Int32>.convertReturn(consuming: ffiValue._1) }
|
||||
|
||||
return MyTestPoint(_0: try _0.get(), _1: try _1.get())
|
||||
}
|
||||
}
|
||||
|
||||
internal enum DerivedReturnConverterMyTestStruct: NiceReturnConverter {
|
||||
typealias NiceReturn = MyTestStruct
|
||||
typealias FfiReturn = SignalMyTestStructFfiResult
|
||||
static func emptyFfiReturn() -> FfiReturn {
|
||||
SignalMyTestStructFfiResult()
|
||||
}
|
||||
static func convertReturn(consuming ffiValue: FfiReturn) throws -> NiceReturn {
|
||||
|
||||
let my_numeric_field = Result {
|
||||
try IdentityConverter<Int32>.convertReturn(consuming: ffiValue.my_numeric_field)
|
||||
}
|
||||
let my_string_field = Result { try StringConverter.convertReturn(consuming: ffiValue.my_string_field) }
|
||||
|
||||
return MyTestStruct(myNumericField: try my_numeric_field.get(), myStringField: try my_string_field.get())
|
||||
}
|
||||
}
|
||||
|
||||
internal enum MyTestEnumArgConverterKeepAlive {
|
||||
case unit(())
|
||||
case single((IdentityConverter<Int32>.KeepAlive?))
|
||||
case singleNamed((IdentityConverter<Int32>.KeepAlive?))
|
||||
case double((IdentityConverter<Int32>.KeepAlive?, IdentityConverter<Int32>.KeepAlive?))
|
||||
case record(
|
||||
(
|
||||
StringConverter.KeepAlive?, IdentityConverter<Int32>.KeepAlive?, DerivedArgConverterMyTestPoint.KeepAlive?,
|
||||
DerivedArgConverterMyTestStruct.KeepAlive?
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
internal enum DerivedArgConverterMyTestEnum: NiceArgConverter {
|
||||
typealias NiceArg = MyTestEnum
|
||||
typealias FfiArg = SignalMyTestEnumFfiArg
|
||||
typealias KeepAlive = MyTestEnumArgConverterKeepAlive
|
||||
static func convertArg(_ niceArg: NiceArg) -> (FfiArg, KeepAlive?) {
|
||||
switch niceArg {
|
||||
case .unit:
|
||||
|
||||
let ffiStructArg = SignalMyTestEnumFfiArgSignalUnit_Body()
|
||||
let ffiStructKeepAlive: ()? =
|
||||
(false) ? () : nil
|
||||
|
||||
return (
|
||||
SignalMyTestEnumFfiArg.init(
|
||||
tag: SignalMyTestEnumFfiArgUnit,
|
||||
.init(unit: ffiStructArg),
|
||||
),
|
||||
ffiStructKeepAlive.map { .unit($0) },
|
||||
)
|
||||
case .single(
|
||||
let _0,
|
||||
):
|
||||
|
||||
let (_0_ffi, _0_keepalive):
|
||||
(
|
||||
IdentityConverter<Int32>.FfiArg,
|
||||
IdentityConverter<Int32>.KeepAlive?,
|
||||
) = IdentityConverter<Int32>.convertArg(_0)
|
||||
|
||||
let ffiStructArg = SignalMyTestEnumFfiArgSignalSingle_Body(_0: _0_ffi, )
|
||||
let ffiStructKeepAlive: (IdentityConverter<Int32>.KeepAlive?, )? =
|
||||
(_0_keepalive != nil || false) ? (_0_keepalive,) : nil
|
||||
|
||||
return (
|
||||
SignalMyTestEnumFfiArg.init(
|
||||
tag: SignalMyTestEnumFfiArgSingle,
|
||||
.init(single: ffiStructArg),
|
||||
),
|
||||
ffiStructKeepAlive.map { .single($0) },
|
||||
)
|
||||
case .singleNamed(
|
||||
let x,
|
||||
):
|
||||
|
||||
let (x_ffi, x_keepalive):
|
||||
(
|
||||
IdentityConverter<Int32>.FfiArg,
|
||||
IdentityConverter<Int32>.KeepAlive?,
|
||||
) = IdentityConverter<Int32>.convertArg(x)
|
||||
|
||||
let ffiStructArg = SignalMyTestEnumFfiArgSignalSingleNamed_Body(x: x_ffi, )
|
||||
let ffiStructKeepAlive: (IdentityConverter<Int32>.KeepAlive?, )? =
|
||||
(x_keepalive != nil || false) ? (x_keepalive,) : nil
|
||||
|
||||
return (
|
||||
SignalMyTestEnumFfiArg.init(
|
||||
tag: SignalMyTestEnumFfiArgSingleNamed,
|
||||
.init(single_named: ffiStructArg),
|
||||
),
|
||||
ffiStructKeepAlive.map { .singleNamed($0) },
|
||||
)
|
||||
case .double(
|
||||
let _0,
|
||||
let _1,
|
||||
):
|
||||
|
||||
let (_0_ffi, _0_keepalive):
|
||||
(
|
||||
IdentityConverter<Int32>.FfiArg,
|
||||
IdentityConverter<Int32>.KeepAlive?,
|
||||
) = IdentityConverter<Int32>.convertArg(_0)
|
||||
let (_1_ffi, _1_keepalive):
|
||||
(
|
||||
IdentityConverter<Int32>.FfiArg,
|
||||
IdentityConverter<Int32>.KeepAlive?,
|
||||
) = IdentityConverter<Int32>.convertArg(_1)
|
||||
|
||||
let ffiStructArg = SignalMyTestEnumFfiArgSignalDouble_Body(_0: _0_ffi, _1: _1_ffi, )
|
||||
let ffiStructKeepAlive: (IdentityConverter<Int32>.KeepAlive?, IdentityConverter<Int32>.KeepAlive?, )? =
|
||||
(_0_keepalive != nil || _1_keepalive != nil || false) ? (_0_keepalive, _1_keepalive,) : nil
|
||||
|
||||
return (
|
||||
SignalMyTestEnumFfiArg.init(
|
||||
tag: SignalMyTestEnumFfiArgDouble,
|
||||
.init(double_: ffiStructArg),
|
||||
),
|
||||
ffiStructKeepAlive.map { .double($0) },
|
||||
)
|
||||
case .record(
|
||||
personName: let person_name,
|
||||
personAge: let person_age,
|
||||
let position,
|
||||
funStruct: let fun_struct,
|
||||
):
|
||||
|
||||
let (person_name_ffi, person_name_keepalive):
|
||||
(
|
||||
StringConverter.FfiArg,
|
||||
StringConverter.KeepAlive?,
|
||||
) = StringConverter.convertArg(person_name)
|
||||
let (person_age_ffi, person_age_keepalive):
|
||||
(
|
||||
IdentityConverter<Int32>.FfiArg,
|
||||
IdentityConverter<Int32>.KeepAlive?,
|
||||
) = IdentityConverter<Int32>.convertArg(person_age)
|
||||
let (position_ffi, position_keepalive):
|
||||
(
|
||||
DerivedArgConverterMyTestPoint.FfiArg,
|
||||
DerivedArgConverterMyTestPoint.KeepAlive?,
|
||||
) = DerivedArgConverterMyTestPoint.convertArg(position)
|
||||
let (fun_struct_ffi, fun_struct_keepalive):
|
||||
(
|
||||
DerivedArgConverterMyTestStruct.FfiArg,
|
||||
DerivedArgConverterMyTestStruct.KeepAlive?,
|
||||
) = DerivedArgConverterMyTestStruct.convertArg(fun_struct)
|
||||
|
||||
let ffiStructArg = SignalMyTestEnumFfiArgSignalRecord_Body(
|
||||
person_name: person_name_ffi,
|
||||
person_age: person_age_ffi,
|
||||
position: position_ffi,
|
||||
fun_struct: fun_struct_ffi,
|
||||
)
|
||||
let ffiStructKeepAlive:
|
||||
(
|
||||
StringConverter.KeepAlive?, IdentityConverter<Int32>.KeepAlive?,
|
||||
DerivedArgConverterMyTestPoint.KeepAlive?, DerivedArgConverterMyTestStruct.KeepAlive?,
|
||||
)? =
|
||||
(person_name_keepalive != nil || person_age_keepalive != nil || position_keepalive != nil
|
||||
|| fun_struct_keepalive != nil || false)
|
||||
? (person_name_keepalive, person_age_keepalive, position_keepalive, fun_struct_keepalive,) : nil
|
||||
|
||||
return (
|
||||
SignalMyTestEnumFfiArg.init(
|
||||
tag: SignalMyTestEnumFfiArgRecord,
|
||||
.init(record: ffiStructArg),
|
||||
),
|
||||
ffiStructKeepAlive.map { .record($0) },
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
static func convertArgBorrowed<Result>(
|
||||
_ niceArg: NiceArg,
|
||||
_ niceThunk: (FfiArg) throws -> Result,
|
||||
) rethrows -> Result {
|
||||
switch niceArg {
|
||||
case .unit:
|
||||
|
||||
return try niceThunk(
|
||||
SignalMyTestEnumFfiArg.init(
|
||||
tag: SignalMyTestEnumFfiArgUnit,
|
||||
.init(
|
||||
unit:
|
||||
SignalMyTestEnumFfiArgSignalUnit_Body()
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
case .single(
|
||||
let _0,
|
||||
):
|
||||
|
||||
return try IdentityConverter<Int32>.convertArgBorrowed(_0) {
|
||||
ffi__0 in
|
||||
|
||||
return try niceThunk(
|
||||
SignalMyTestEnumFfiArg.init(
|
||||
tag: SignalMyTestEnumFfiArgSingle,
|
||||
.init(
|
||||
single:
|
||||
SignalMyTestEnumFfiArgSignalSingle_Body(
|
||||
_0: ffi__0,
|
||||
)
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
case .singleNamed(
|
||||
let x,
|
||||
):
|
||||
|
||||
return try IdentityConverter<Int32>.convertArgBorrowed(x) {
|
||||
ffi_x in
|
||||
|
||||
return try niceThunk(
|
||||
SignalMyTestEnumFfiArg.init(
|
||||
tag: SignalMyTestEnumFfiArgSingleNamed,
|
||||
.init(
|
||||
single_named:
|
||||
SignalMyTestEnumFfiArgSignalSingleNamed_Body(
|
||||
x: ffi_x,
|
||||
)
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
case .double(
|
||||
let _0,
|
||||
let _1,
|
||||
):
|
||||
|
||||
return try IdentityConverter<Int32>.convertArgBorrowed(_0) {
|
||||
ffi__0 in
|
||||
return try IdentityConverter<Int32>.convertArgBorrowed(_1) {
|
||||
ffi__1 in
|
||||
|
||||
return try niceThunk(
|
||||
SignalMyTestEnumFfiArg.init(
|
||||
tag: SignalMyTestEnumFfiArgDouble,
|
||||
.init(
|
||||
double_:
|
||||
SignalMyTestEnumFfiArgSignalDouble_Body(
|
||||
_0: ffi__0,
|
||||
_1: ffi__1,
|
||||
)
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
case .record(
|
||||
personName: let person_name,
|
||||
personAge: let person_age,
|
||||
let position,
|
||||
funStruct: let fun_struct,
|
||||
):
|
||||
|
||||
return try StringConverter.convertArgBorrowed(person_name) {
|
||||
ffi_person_name in
|
||||
return try IdentityConverter<Int32>.convertArgBorrowed(person_age) {
|
||||
ffi_person_age in
|
||||
return try DerivedArgConverterMyTestPoint.convertArgBorrowed(position) {
|
||||
ffi_position in
|
||||
return try DerivedArgConverterMyTestStruct.convertArgBorrowed(fun_struct) {
|
||||
ffi_fun_struct in
|
||||
|
||||
return try niceThunk(
|
||||
SignalMyTestEnumFfiArg.init(
|
||||
tag: SignalMyTestEnumFfiArgRecord,
|
||||
.init(
|
||||
record:
|
||||
SignalMyTestEnumFfiArgSignalRecord_Body(
|
||||
person_name: ffi_person_name,
|
||||
person_age: ffi_person_age,
|
||||
position: ffi_position,
|
||||
fun_struct: ffi_fun_struct,
|
||||
)
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal enum DerivedArgConverterMyTestPoint: NiceArgConverter {
|
||||
typealias NiceArg = MyTestPoint
|
||||
typealias FfiArg = SignalMyTestPointFfiArg
|
||||
|
||||
typealias KeepAlive = (IdentityConverter<Int32>.KeepAlive?, IdentityConverter<Int32>.KeepAlive?, )
|
||||
static func convertArg(_ niceArg: NiceArg) -> (FfiArg, KeepAlive?) {
|
||||
let _0 = niceArg._0
|
||||
let _1 = niceArg._1
|
||||
|
||||
let (_0_ffi, _0_keepalive):
|
||||
(
|
||||
IdentityConverter<Int32>.FfiArg,
|
||||
IdentityConverter<Int32>.KeepAlive?,
|
||||
) = IdentityConverter<Int32>.convertArg(_0)
|
||||
let (_1_ffi, _1_keepalive):
|
||||
(
|
||||
IdentityConverter<Int32>.FfiArg,
|
||||
IdentityConverter<Int32>.KeepAlive?,
|
||||
) = IdentityConverter<Int32>.convertArg(_1)
|
||||
|
||||
let ffiStructArg = FfiArg(_0: _0_ffi, _1: _1_ffi, )
|
||||
let ffiStructKeepAlive: (IdentityConverter<Int32>.KeepAlive?, IdentityConverter<Int32>.KeepAlive?, )? =
|
||||
(_0_keepalive != nil || _1_keepalive != nil || false) ? (_0_keepalive, _1_keepalive,) : nil
|
||||
|
||||
return (ffiStructArg, ffiStructKeepAlive)
|
||||
}
|
||||
static func convertArgBorrowed<Result>(
|
||||
_ niceArg: NiceArg,
|
||||
_ niceThunk: (FfiArg) throws -> Result,
|
||||
) rethrows -> Result {
|
||||
let _0 = niceArg._0
|
||||
let _1 = niceArg._1
|
||||
|
||||
return try IdentityConverter<Int32>.convertArgBorrowed(_0) {
|
||||
ffi__0 in
|
||||
return try IdentityConverter<Int32>.convertArgBorrowed(_1) {
|
||||
ffi__1 in
|
||||
|
||||
return try niceThunk(
|
||||
FfiArg(
|
||||
_0: ffi__0,
|
||||
_1: ffi__1,
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
internal enum DerivedArgConverterMyTestStruct: NiceArgConverter {
|
||||
typealias NiceArg = MyTestStruct
|
||||
typealias FfiArg = SignalMyTestStructFfiArg
|
||||
|
||||
typealias KeepAlive = (IdentityConverter<Int32>.KeepAlive?, StringConverter.KeepAlive?, )
|
||||
static func convertArg(_ niceArg: NiceArg) -> (FfiArg, KeepAlive?) {
|
||||
let my_numeric_field = niceArg.myNumericField
|
||||
let my_string_field = niceArg.myStringField
|
||||
|
||||
let (my_numeric_field_ffi, my_numeric_field_keepalive):
|
||||
(
|
||||
IdentityConverter<Int32>.FfiArg,
|
||||
IdentityConverter<Int32>.KeepAlive?,
|
||||
) = IdentityConverter<Int32>.convertArg(my_numeric_field)
|
||||
let (my_string_field_ffi, my_string_field_keepalive):
|
||||
(
|
||||
StringConverter.FfiArg,
|
||||
StringConverter.KeepAlive?,
|
||||
) = StringConverter.convertArg(my_string_field)
|
||||
|
||||
let ffiStructArg = FfiArg(my_numeric_field: my_numeric_field_ffi, my_string_field: my_string_field_ffi, )
|
||||
let ffiStructKeepAlive: (IdentityConverter<Int32>.KeepAlive?, StringConverter.KeepAlive?, )? =
|
||||
(my_numeric_field_keepalive != nil || my_string_field_keepalive != nil || false)
|
||||
? (my_numeric_field_keepalive, my_string_field_keepalive,) : nil
|
||||
|
||||
return (ffiStructArg, ffiStructKeepAlive)
|
||||
}
|
||||
static func convertArgBorrowed<Result>(
|
||||
_ niceArg: NiceArg,
|
||||
_ niceThunk: (FfiArg) throws -> Result,
|
||||
) rethrows -> Result {
|
||||
let my_numeric_field = niceArg.myNumericField
|
||||
let my_string_field = niceArg.myStringField
|
||||
|
||||
return try IdentityConverter<Int32>.convertArgBorrowed(my_numeric_field) {
|
||||
ffi_my_numeric_field in
|
||||
return try StringConverter.convertArgBorrowed(my_string_field) {
|
||||
ffi_my_string_field in
|
||||
|
||||
return try niceThunk(
|
||||
FfiArg(
|
||||
my_numeric_field: ffi_my_numeric_field,
|
||||
my_string_field: ffi_my_string_field,
|
||||
)
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
internal enum NativeTestingNice {
|
||||
internal static func TESTING_MyTestEnum_identity(
|
||||
x: MyTestEnum,
|
||||
) throws -> MyTestEnum {
|
||||
try DerivedArgConverterMyTestEnum.convertArgBorrowed(x) { xFfi in
|
||||
var rawOutput = DerivedReturnConverterMyTestEnum.emptyFfiReturn()
|
||||
try checkError(
|
||||
SignalFfi.signal_testing_my_test_enum_identity(
|
||||
&rawOutput,
|
||||
xFfi,
|
||||
)
|
||||
)
|
||||
return try DerivedReturnConverterMyTestEnum.convertReturn(consuming: rawOutput)
|
||||
}
|
||||
|
||||
}
|
||||
internal static func TESTING_MyTestEnum_to_string(
|
||||
x: MyTestEnum,
|
||||
) throws -> String {
|
||||
try DerivedArgConverterMyTestEnum.convertArgBorrowed(x) { xFfi in
|
||||
var rawOutput = StringConverter.emptyFfiReturn()
|
||||
try checkError(
|
||||
SignalFfi.signal_testing_my_test_enum_to_string(
|
||||
&rawOutput,
|
||||
xFfi,
|
||||
)
|
||||
)
|
||||
return try StringConverter.convertReturn(consuming: rawOutput)
|
||||
}
|
||||
|
||||
}
|
||||
internal static func TESTING_MyTestPoint_identity(
|
||||
x: MyTestPoint,
|
||||
) throws -> MyTestPoint {
|
||||
try DerivedArgConverterMyTestPoint.convertArgBorrowed(x) { xFfi in
|
||||
var rawOutput = DerivedReturnConverterMyTestPoint.emptyFfiReturn()
|
||||
try checkError(
|
||||
SignalFfi.signal_testing_my_test_point_identity(
|
||||
&rawOutput,
|
||||
xFfi,
|
||||
)
|
||||
)
|
||||
return try DerivedReturnConverterMyTestPoint.convertReturn(consuming: rawOutput)
|
||||
}
|
||||
|
||||
}
|
||||
internal static func TESTING_MyTestPoint_to_string(
|
||||
x: MyTestPoint,
|
||||
) throws -> String {
|
||||
try DerivedArgConverterMyTestPoint.convertArgBorrowed(x) { xFfi in
|
||||
var rawOutput = StringConverter.emptyFfiReturn()
|
||||
try checkError(
|
||||
SignalFfi.signal_testing_my_test_point_to_string(
|
||||
&rawOutput,
|
||||
xFfi,
|
||||
)
|
||||
)
|
||||
return try StringConverter.convertReturn(consuming: rawOutput)
|
||||
}
|
||||
|
||||
}
|
||||
internal static func TESTING_MyTestStruct_identity(
|
||||
x: MyTestStruct,
|
||||
) throws -> MyTestStruct {
|
||||
try DerivedArgConverterMyTestStruct.convertArgBorrowed(x) { xFfi in
|
||||
var rawOutput = DerivedReturnConverterMyTestStruct.emptyFfiReturn()
|
||||
try checkError(
|
||||
SignalFfi.signal_testing_my_test_struct_identity(
|
||||
&rawOutput,
|
||||
xFfi,
|
||||
)
|
||||
)
|
||||
return try DerivedReturnConverterMyTestStruct.convertReturn(consuming: rawOutput)
|
||||
}
|
||||
|
||||
}
|
||||
internal static func TESTING_MyTestStruct_to_string(
|
||||
x: MyTestStruct,
|
||||
) throws -> String {
|
||||
try DerivedArgConverterMyTestStruct.convertArgBorrowed(x) { xFfi in
|
||||
var rawOutput = StringConverter.emptyFfiReturn()
|
||||
try checkError(
|
||||
SignalFfi.signal_testing_my_test_struct_to_string(
|
||||
&rawOutput,
|
||||
xFfi,
|
||||
)
|
||||
)
|
||||
return try StringConverter.convertReturn(consuming: rawOutput)
|
||||
}
|
||||
|
||||
}
|
||||
internal static func TESTING_TestingIntBox_Get(
|
||||
myIntBox my_int_box: TestingIntBox,
|
||||
) throws -> Int32 {
|
||||
|
||||
@ -11,29 +11,58 @@ import Foundation
|
||||
import SignalFfi
|
||||
import Testing
|
||||
|
||||
struct NativeTestingNiceTests {
|
||||
private func testConversion<Item: Equatable>(
|
||||
items: any Sequence<Item>,
|
||||
toString: (Item) throws -> String,
|
||||
nativeToString: (Item) throws -> String,
|
||||
nativeIdentity: (Item) throws -> Item,
|
||||
extension NiceArgConverter {
|
||||
fileprivate static func testConversion(
|
||||
items: any Sequence<NiceArg>,
|
||||
toString: (NiceArg) throws -> String,
|
||||
nativeToString: (NiceArg) throws -> String,
|
||||
rawNativeToString: (UnsafeMutablePointer<UnsafePointer<CChar>?>?, FfiArg) -> SignalFfiErrorRef?,
|
||||
nativeIdentity: (NiceArg) throws -> NiceArg,
|
||||
) throws {
|
||||
for item in items {
|
||||
let swiftString = try toString(item)
|
||||
let nativeString = try nativeToString(item)
|
||||
#expect(swiftString == nativeString)
|
||||
let actualIdentity = try nativeIdentity(item)
|
||||
#expect(item == actualIdentity)
|
||||
let actualIdentityString = try toString(actualIdentity)
|
||||
#expect(actualIdentityString == nativeString)
|
||||
// Manually check both the borrowed and keep alive forms
|
||||
let rawBorrowedNativeString = try self.convertArgBorrowed(item) { itemFfi in
|
||||
var rawOutput = StringConverter.emptyFfiReturn()
|
||||
try checkError(
|
||||
rawNativeToString(
|
||||
&rawOutput,
|
||||
itemFfi,
|
||||
)
|
||||
)
|
||||
return try StringConverter.convertReturn(consuming: rawOutput)
|
||||
}
|
||||
#expect(swiftString == rawBorrowedNativeString)
|
||||
let rawKeepAliveNativeString = try self.genericArgBorrowed(item) { itemFfi in
|
||||
var rawOutput = StringConverter.emptyFfiReturn()
|
||||
try checkError(
|
||||
rawNativeToString(
|
||||
&rawOutput,
|
||||
itemFfi,
|
||||
)
|
||||
)
|
||||
return try StringConverter.convertReturn(consuming: rawOutput)
|
||||
}
|
||||
#expect(swiftString == rawKeepAliveNativeString)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct NativeTestingNiceTests {
|
||||
@Test
|
||||
func testString() throws {
|
||||
try testConversion(
|
||||
try StringConverter.testConversion(
|
||||
items: ["", "abc", "îüéè"],
|
||||
toString: { $0 },
|
||||
nativeToString: {
|
||||
try NativeTestingNice.TESTING_conversion_string_identity(x: $0)
|
||||
},
|
||||
rawNativeToString: SignalFfi.signal_testing_conversion_string_identity,
|
||||
nativeIdentity: {
|
||||
try NativeTestingNice.TESTING_conversion_string_identity(x: $0)
|
||||
},
|
||||
@ -41,43 +70,47 @@ struct NativeTestingNiceTests {
|
||||
}
|
||||
@Test
|
||||
func testBool() throws {
|
||||
try testConversion(
|
||||
try IdentityConverter<Bool>.testConversion(
|
||||
items: [true, false],
|
||||
toString: { "\($0)" },
|
||||
nativeToString: { try NativeTestingNice.TESTING_conversion_bool_to_string(x: $0) },
|
||||
rawNativeToString: SignalFfi.signal_testing_conversion_bool_to_string,
|
||||
nativeIdentity: { try NativeTestingNice.TESTING_conversion_bool_identity(x: $0) }
|
||||
)
|
||||
}
|
||||
@Test
|
||||
func testU8() throws {
|
||||
try testConversion(
|
||||
try IdentityConverter<UInt8>.testConversion(
|
||||
items: UInt8.min...UInt8.max,
|
||||
toString: { "\($0)" },
|
||||
nativeToString: { try NativeTestingNice.TESTING_conversion_u8_to_string(x: $0) },
|
||||
rawNativeToString: SignalFfi.signal_testing_conversion_u8_to_string,
|
||||
nativeIdentity: { try NativeTestingNice.TESTING_conversion_u8_identity(x: $0) }
|
||||
)
|
||||
}
|
||||
@Test
|
||||
func testU16() throws {
|
||||
try testConversion(
|
||||
try IdentityConverter<UInt16>.testConversion(
|
||||
items: UInt16.min...UInt16.max,
|
||||
toString: { "\($0)" },
|
||||
nativeToString: { try NativeTestingNice.TESTING_conversion_u16_to_string(x: $0) },
|
||||
rawNativeToString: SignalFfi.signal_testing_conversion_u16_to_string,
|
||||
nativeIdentity: { try NativeTestingNice.TESTING_conversion_u16_identity(x: $0) }
|
||||
)
|
||||
}
|
||||
@Test
|
||||
func testI32() throws {
|
||||
try testConversion(
|
||||
try IdentityConverter<Int32>.testConversion(
|
||||
items: -1024...1024,
|
||||
toString: { "\($0)" },
|
||||
nativeToString: { try NativeTestingNice.TESTING_conversion_i32_to_string(x: $0) },
|
||||
rawNativeToString: SignalFfi.signal_testing_conversion_i32_to_string,
|
||||
nativeIdentity: { try NativeTestingNice.TESTING_conversion_i32_identity(x: $0) }
|
||||
)
|
||||
}
|
||||
@Test
|
||||
func testServiceId() throws {
|
||||
try testConversion(
|
||||
try ServiceIdConverter.testConversion(
|
||||
items: [
|
||||
Aci(fromUUID: UUID()),
|
||||
Pni(fromUUID: UUID()),
|
||||
@ -86,19 +119,74 @@ struct NativeTestingNiceTests {
|
||||
],
|
||||
toString: { $0.serviceIdString },
|
||||
nativeToString: { try NativeTestingNice.TESTING_conversion_ServiceId_to_string(x: $0) },
|
||||
rawNativeToString: SignalFfi.signal_testing_conversion_service_id_to_string,
|
||||
nativeIdentity: { try NativeTestingNice.TESTING_conversion_ServiceId_identity(x: $0) }
|
||||
)
|
||||
}
|
||||
@Test
|
||||
func testData() throws {
|
||||
try testConversion(
|
||||
try DataConverter.testConversion(
|
||||
items: (0..<10).lazy.map { count in Data((0..<(1 << count)).map { _ in UInt8.random(in: 0...255) }) },
|
||||
toString: { $0.base64EncodedString() },
|
||||
nativeToString: { try NativeTestingNice.TESTING_conversion_Data_to_string(x: $0) },
|
||||
rawNativeToString: SignalFfi.signal_testing_conversion_data_to_string,
|
||||
nativeIdentity: { try NativeTestingNice.TESTING_conversion_Data_identity(x: $0) }
|
||||
)
|
||||
}
|
||||
@Test
|
||||
func testMyTestPoint() throws {
|
||||
try DerivedArgConverterMyTestPoint.testConversion(
|
||||
items: [MyTestPoint(1, 2)],
|
||||
toString: { "[\($0._0),\($0._1)]" },
|
||||
nativeToString: { try NativeTestingNice.TESTING_MyTestPoint_to_string(x: $0) },
|
||||
rawNativeToString: SignalFfi.signal_testing_my_test_point_to_string,
|
||||
nativeIdentity: { try NativeTestingNice.TESTING_MyTestPoint_identity(x: $0) },
|
||||
)
|
||||
}
|
||||
@Test
|
||||
func testMyTestStruct() throws {
|
||||
try DerivedArgConverterMyTestStruct.testConversion(
|
||||
items: [MyTestStruct(myNumericField: 123, myStringField: "string!")],
|
||||
toString: { "{\"myNumericField\":\($0.myNumericField),\"myStringField\":\"\($0.myStringField)\"}" },
|
||||
nativeToString: { try NativeTestingNice.TESTING_MyTestStruct_to_string(x: $0) },
|
||||
rawNativeToString: SignalFfi.signal_testing_my_test_struct_to_string,
|
||||
nativeIdentity: { try NativeTestingNice.TESTING_MyTestStruct_identity(x: $0) },
|
||||
)
|
||||
}
|
||||
@Test
|
||||
func testMyTestEnum() throws {
|
||||
try DerivedArgConverterMyTestEnum.testConversion(
|
||||
items: [
|
||||
.unit,
|
||||
.single(73),
|
||||
.record(
|
||||
personName: "Person!",
|
||||
personAge: 101,
|
||||
position: MyTestPoint(3, 4),
|
||||
funStruct: MyTestStruct(myNumericField: 847, myStringField: "string!")
|
||||
),
|
||||
.singleNamed(x: 847),
|
||||
.double(8, 9),
|
||||
],
|
||||
toString: { value in
|
||||
return switch value {
|
||||
case .double(let x, let y): #"{"double":[\#(x),\#(y)]}"#
|
||||
case .record(let personName, let personAge, let position, let funStruct):
|
||||
#"{"record":{"personName":"\#(personName)","personAge":\#(personAge),"#
|
||||
+ #""position":[\#(position._0),\#(position._1)],"#
|
||||
+ #""funStruct":{"myNumericField":\#(funStruct.myNumericField),"#
|
||||
+ #""myStringField":"\#(funStruct.myStringField)"}}}"#
|
||||
case .single(let x): #"{"single":\#(x)}"#
|
||||
case .singleNamed(let x): #"{"singleNamed":{"x":\#(x)}}"#
|
||||
case .unit: #""unit""#
|
||||
}
|
||||
},
|
||||
nativeToString: { try NativeTestingNice.TESTING_MyTestEnum_to_string(x: $0) },
|
||||
rawNativeToString: SignalFfi.signal_testing_my_test_enum_to_string,
|
||||
nativeIdentity: { try NativeTestingNice.TESTING_MyTestEnum_identity(x: $0) },
|
||||
)
|
||||
}
|
||||
@Test
|
||||
func asyncTest() async throws {
|
||||
let ctx = TokioAsyncContext()
|
||||
for c in [0, 1, 2, 4, 8, 16, 32, 64, 128, 256] {
|
||||
|
||||
@ -3,10 +3,13 @@
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
//
|
||||
|
||||
import SignalFfi
|
||||
import XCTest
|
||||
|
||||
@testable import LibSignalClient
|
||||
|
||||
let SECONDS_PER_DAY: UInt64 = 24 * 60 * 60
|
||||
|
||||
class BadStore: InMemorySignalProtocolStore {
|
||||
enum Error: Swift.Error {
|
||||
case badness
|
||||
@ -61,6 +64,24 @@ extension RangeReplaceableCollection where Element == UInt8 {
|
||||
}
|
||||
}
|
||||
|
||||
extension Randomness {
|
||||
internal init?(fromHexString hex: String) {
|
||||
guard let array = [UInt8](fromHexString: hex) else {
|
||||
return nil
|
||||
}
|
||||
var bytes: SignalRandomnessBytes = (
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
)
|
||||
if array.count != MemoryLayout.size(ofValue: bytes) {
|
||||
return nil
|
||||
}
|
||||
withUnsafeMutableBytes(of: &bytes) {
|
||||
$0.copyBytes(from: array)
|
||||
}
|
||||
self.init(bytes)
|
||||
}
|
||||
}
|
||||
|
||||
// Helper for async error assertions until XCTest supports async autoclosures
|
||||
// Adapted from https://arturgruchala.com/testing-async-await-exceptions/
|
||||
func assertThrowsErrorAsync<T>(
|
||||
|
||||
@ -7,8 +7,6 @@ import Foundation
|
||||
import LibSignalClient
|
||||
import Testing
|
||||
|
||||
private let SECONDS_PER_DAY: UInt64 = 24 * 60 * 60
|
||||
|
||||
class ZKGroupTests {
|
||||
let TEST_ARRAY_16: UUID = .init(
|
||||
uuid: (0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F)
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
{
|
||||
"name": "LibSignalClient",
|
||||
"version": "0.94.4",
|
||||
"version": "0.95.0",
|
||||
"summary": "A Swift wrapper library for communicating with the Signal messaging service.",
|
||||
"homepage": "https://github.com/signalapp/libsignal",
|
||||
"license": "AGPL-3.0-only",
|
||||
"authors": "Signal Messenger LLC",
|
||||
"source": {
|
||||
"git": "https://github.com/signalapp/libsignal.git",
|
||||
"tag": "v0.94.4"
|
||||
"tag": "v0.95.0"
|
||||
},
|
||||
"swift_versions": "5",
|
||||
"platforms": {
|
||||
@ -30,8 +30,8 @@
|
||||
"LIBSIGNAL_FFI_TEMP_DIR": "$(PROJECT_TEMP_DIR)/libsignal_ffi",
|
||||
"LIBSIGNAL_FFI_LIB_TO_LINK": "$(LIBSIGNAL_FFI_TEMP_DIR)/$(LIBSIGNAL_FFI_BUILD_PATH)/libsignal_ffi.a",
|
||||
"OTHER_LDFLAGS": "$(LIBSIGNAL_FFI_LIB_TO_LINK)",
|
||||
"LIBSIGNAL_FFI_PREBUILD_ARCHIVE": "libsignal-client-ios-build-v0.94.4.tar.gz",
|
||||
"LIBSIGNAL_FFI_PREBUILD_CHECKSUM": "273236d44fdd2eb76f18de0d4229dd82d73ac1edb2e52e71885c6f98843a9c0d",
|
||||
"LIBSIGNAL_FFI_PREBUILD_ARCHIVE": "libsignal-client-ios-build-v0.95.0.tar.gz",
|
||||
"LIBSIGNAL_FFI_PREBUILD_CHECKSUM": "79f53932ff82f792b70e30bad3b38801da0b882137adaf65ad54d907a94f3d29",
|
||||
"CARGO_BUILD_TARGET[sdk=iphonesimulator*][arch=arm64]": "aarch64-apple-ios-sim",
|
||||
"CARGO_BUILD_TARGET[sdk=iphonesimulator*][arch=*]": "x86_64-apple-ios",
|
||||
"CARGO_BUILD_TARGET[sdk=iphoneos*][arch=arm64e]": "arm64e-apple-ios",
|
||||
|
||||
@ -9,8 +9,8 @@ PODS:
|
||||
- LibMobileCoin/CoreHTTP (6.0.2):
|
||||
- SwiftProtobuf (~> 1.5)
|
||||
- libPhoneNumber-iOS (1.2.0)
|
||||
- LibSignalClient (0.94.4)
|
||||
- LibSignalClient/Tests (0.94.4)
|
||||
- LibSignalClient (0.95.0)
|
||||
- LibSignalClient/Tests (0.95.0)
|
||||
- libwebp (1.5.0):
|
||||
- libwebp/demux (= 1.5.0)
|
||||
- libwebp/mux (= 1.5.0)
|
||||
@ -52,8 +52,8 @@ DEPENDENCIES:
|
||||
- GRDB.swift/SQLCipher
|
||||
- LibMobileCoin/CoreHTTP (from `https://github.com/signalapp/libmobilecoin-ios-artifacts`, tag `signal/6.0.2`)
|
||||
- libPhoneNumber-iOS (from `https://github.com/signalapp/libPhoneNumber-iOS`, branch `signal-master`)
|
||||
- LibSignalClient (from `https://github.com/signalapp/libsignal.git`, tag `v0.94.4`)
|
||||
- LibSignalClient/Tests (from `https://github.com/signalapp/libsignal.git`, tag `v0.94.4`)
|
||||
- LibSignalClient (from `https://github.com/signalapp/libsignal.git`, tag `v0.95.0`)
|
||||
- LibSignalClient/Tests (from `https://github.com/signalapp/libsignal.git`, tag `v0.95.0`)
|
||||
- libwebp
|
||||
- lottie-ios
|
||||
- MobileCoin/CoreHTTP (from `https://github.com/mobilecoinofficial/MobileCoin-Swift`, tag `v6.0.3`)
|
||||
@ -89,7 +89,7 @@ EXTERNAL SOURCES:
|
||||
:git: https://github.com/signalapp/libPhoneNumber-iOS
|
||||
LibSignalClient:
|
||||
:git: https://github.com/signalapp/libsignal.git
|
||||
:tag: v0.94.4
|
||||
:tag: v0.95.0
|
||||
MobileCoin:
|
||||
:git: https://github.com/mobilecoinofficial/MobileCoin-Swift
|
||||
:tag: v6.0.3
|
||||
@ -113,7 +113,7 @@ CHECKOUT OPTIONS:
|
||||
:git: https://github.com/signalapp/libPhoneNumber-iOS
|
||||
LibSignalClient:
|
||||
:git: https://github.com/signalapp/libsignal.git
|
||||
:tag: v0.94.4
|
||||
:tag: v0.95.0
|
||||
MobileCoin:
|
||||
:git: https://github.com/mobilecoinofficial/MobileCoin-Swift
|
||||
:tag: v6.0.3
|
||||
@ -131,7 +131,7 @@ SPEC CHECKSUMS:
|
||||
GRDB.swift: 1395cb3556df6b16ed69dfc74c3886abc75d2825
|
||||
LibMobileCoin: 8503f567fa32184a5be7bc038fbd727747dd9991
|
||||
libPhoneNumber-iOS: 1a34106b49dc6e12a7f37eb9aee7c64011509547
|
||||
LibSignalClient: 08d66ae1b4e9c93f9e6930cc0260df27c14ecd03
|
||||
LibSignalClient: a98db1d538243e43ecac040005204bd274cbd8c7
|
||||
libwebp: 02b23773aedb6ff1fd38cec7a77b81414c6842a8
|
||||
Logging: beeb016c9c80cf77042d62e83495816847ef108b
|
||||
lottie-ios: fcb5e73e17ba4c983140b7d21095c834b3087418
|
||||
@ -143,6 +143,6 @@ SPEC CHECKSUMS:
|
||||
SQLCipher: ff2f045b20d675a73a70f7329395ddd4a2580063
|
||||
SwiftProtobuf: 9e106a71456f4d3f6a3b0c8fd87ef0be085efc38
|
||||
|
||||
PODFILE CHECKSUM: e3d9c2375b2f8bb1af334adb83effea5eedff4fb
|
||||
PODFILE CHECKSUM: ee98007764e1569e9dbe4f25053510725b19fc88
|
||||
|
||||
COCOAPODS: 1.15.2
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -15,7 +15,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>FMWK</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.94.4</string>
|
||||
<string>0.95.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
|
||||
@ -18,8 +18,8 @@ HEADER_SEARCH_PATHS = $(inherited) $(PODS_TARGET_SRCROOT)/swift/Sources/SignalFf
|
||||
LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
|
||||
LIBSIGNAL_FFI_BUILD_PATH = target/$(CARGO_BUILD_TARGET)/release
|
||||
LIBSIGNAL_FFI_LIB_TO_LINK = $(LIBSIGNAL_FFI_TEMP_DIR)/$(LIBSIGNAL_FFI_BUILD_PATH)/libsignal_ffi.a
|
||||
LIBSIGNAL_FFI_PREBUILD_ARCHIVE = libsignal-client-ios-build-v0.94.4.tar.gz
|
||||
LIBSIGNAL_FFI_PREBUILD_CHECKSUM = 273236d44fdd2eb76f18de0d4229dd82d73ac1edb2e52e71885c6f98843a9c0d
|
||||
LIBSIGNAL_FFI_PREBUILD_ARCHIVE = libsignal-client-ios-build-v0.95.0.tar.gz
|
||||
LIBSIGNAL_FFI_PREBUILD_CHECKSUM = 79f53932ff82f792b70e30bad3b38801da0b882137adaf65ad54d907a94f3d29
|
||||
LIBSIGNAL_FFI_TEMP_DIR = $(PROJECT_TEMP_DIR)/libsignal_ffi
|
||||
OTHER_LDFLAGS = $(LIBSIGNAL_FFI_LIB_TO_LINK) $(inherited)
|
||||
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
|
||||
|
||||
@ -18,8 +18,8 @@ HEADER_SEARCH_PATHS = $(inherited) $(PODS_TARGET_SRCROOT)/swift/Sources/SignalFf
|
||||
LIBRARY_SEARCH_PATHS = $(inherited) "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
|
||||
LIBSIGNAL_FFI_BUILD_PATH = target/$(CARGO_BUILD_TARGET)/release
|
||||
LIBSIGNAL_FFI_LIB_TO_LINK = $(LIBSIGNAL_FFI_TEMP_DIR)/$(LIBSIGNAL_FFI_BUILD_PATH)/libsignal_ffi.a
|
||||
LIBSIGNAL_FFI_PREBUILD_ARCHIVE = libsignal-client-ios-build-v0.94.4.tar.gz
|
||||
LIBSIGNAL_FFI_PREBUILD_CHECKSUM = 273236d44fdd2eb76f18de0d4229dd82d73ac1edb2e52e71885c6f98843a9c0d
|
||||
LIBSIGNAL_FFI_PREBUILD_ARCHIVE = libsignal-client-ios-build-v0.95.0.tar.gz
|
||||
LIBSIGNAL_FFI_PREBUILD_CHECKSUM = 79f53932ff82f792b70e30bad3b38801da0b882137adaf65ad54d907a94f3d29
|
||||
LIBSIGNAL_FFI_TEMP_DIR = $(PROJECT_TEMP_DIR)/libsignal_ffi
|
||||
OTHER_LDFLAGS = $(LIBSIGNAL_FFI_LIB_TO_LINK) $(inherited)
|
||||
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
|
||||
|
||||
@ -19,8 +19,8 @@ LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift "$(PLATFORM_DIR)/Developer
|
||||
LIBRARY_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
|
||||
LIBSIGNAL_FFI_BUILD_PATH = target/$(CARGO_BUILD_TARGET)/release
|
||||
LIBSIGNAL_FFI_LIB_TO_LINK =
|
||||
LIBSIGNAL_FFI_PREBUILD_ARCHIVE = libsignal-client-ios-build-v0.94.4.tar.gz
|
||||
LIBSIGNAL_FFI_PREBUILD_CHECKSUM = 273236d44fdd2eb76f18de0d4229dd82d73ac1edb2e52e71885c6f98843a9c0d
|
||||
LIBSIGNAL_FFI_PREBUILD_ARCHIVE = libsignal-client-ios-build-v0.95.0.tar.gz
|
||||
LIBSIGNAL_FFI_PREBUILD_CHECKSUM = 79f53932ff82f792b70e30bad3b38801da0b882137adaf65ad54d907a94f3d29
|
||||
LIBSIGNAL_FFI_TEMP_DIR = $(PROJECT_TEMP_DIR)/libsignal_ffi
|
||||
OTHER_LDFLAGS = $(LIBSIGNAL_FFI_LIB_TO_LINK) $(inherited) -ObjC -framework "LibSignalClient"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
|
||||
|
||||
@ -19,8 +19,8 @@ LD_RUNPATH_SEARCH_PATHS = $(inherited) /usr/lib/swift "$(PLATFORM_DIR)/Developer
|
||||
LIBRARY_SEARCH_PATHS = $(inherited) "$(PLATFORM_DIR)/Developer/Library/Frameworks" "${TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" /usr/lib/swift
|
||||
LIBSIGNAL_FFI_BUILD_PATH = target/$(CARGO_BUILD_TARGET)/release
|
||||
LIBSIGNAL_FFI_LIB_TO_LINK =
|
||||
LIBSIGNAL_FFI_PREBUILD_ARCHIVE = libsignal-client-ios-build-v0.94.4.tar.gz
|
||||
LIBSIGNAL_FFI_PREBUILD_CHECKSUM = 273236d44fdd2eb76f18de0d4229dd82d73ac1edb2e52e71885c6f98843a9c0d
|
||||
LIBSIGNAL_FFI_PREBUILD_ARCHIVE = libsignal-client-ios-build-v0.95.0.tar.gz
|
||||
LIBSIGNAL_FFI_PREBUILD_CHECKSUM = 79f53932ff82f792b70e30bad3b38801da0b882137adaf65ad54d907a94f3d29
|
||||
LIBSIGNAL_FFI_TEMP_DIR = $(PROJECT_TEMP_DIR)/libsignal_ffi
|
||||
OTHER_LDFLAGS = $(LIBSIGNAL_FFI_LIB_TO_LINK) $(inherited) -ObjC -framework "LibSignalClient"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS
|
||||
|
||||
Loading…
Reference in New Issue
Block a user