Switch to swift-format for formatting instead of swiftformat

swift-format is owned by the Swift project and is generally less
opinionated than swiftformat (but better at formatting to a limited
line length).
This commit is contained in:
Jordan Rose
2025-06-25 11:24:57 -07:00
committed by GitHub
parent 442a507168
commit 9e13263581
115 changed files with 3244 additions and 1455 deletions

View File

@@ -415,8 +415,15 @@ jobs:
- run: brew install protobuf swiftlint
- name: Check formatting
run: swiftformat --swiftversion 5 --reporter github-actions-log --lint .
run: swift format --in-place --parallel --recursive . && git diff --exit-code .
working-directory: swift
env:
# This is only here because we're on a macOS 15 runner, which defaults to Xcode 16.0,
# which contains a swift-format that fails on some of our Swift 6.0 code.
# Once we're on a later runner, this should be removed.
# We should know that immediately if this stays at 16.2,
# because the new runners usually only keep one previous Xcode major version.
DEVELOPER_DIR: /Applications/Xcode_16.2.app
- name: Run lint
run: swiftlint lint --strict --reporter github-actions-logging

9
.swift-format Normal file
View File

@@ -0,0 +1,9 @@
{
"version": 1,
"lineLength": 120,
"indentation": { "spaces": 4 },
"indentConditionalCompilationBlocks": false,
"lineBreakBeforeEachArgument": true,
"lineBreakBetweenDeclarationAttributes": true,
"prioritizeKeepingFunctionOutputTogether": true
}

View File

@@ -1,25 +0,0 @@
#--header "\nCopyright {created.year} Signal Messenger, LLC.\nSPDX-License-Identifier: AGPL-3.0-only\n"
--disable hoistPatternLet
# Explicit self is better than implicit self.
--self insert
# Some arguments that it considers unused are used in doc comments, and replacing them with '_' is an error.
--stripunusedargs unnamed-only
--wraparguments before-first
--wrapcollections before-first
# Libsignal is a collection of many languages, remembering specific of each one is hard. Make it explicit.
--disable redundantinternal
# Ranges look better without spaces
--ranges no-space
# Pragmas should start at the begining of line.
--ifdef outdent
--indent 4
# Patters are not redundant, they show the shape of thing, they show the shape of things.
--disable redundantPattern
# Leave try in the innermost position.
--disable hoistTry
# Explicit ACL even in extensions.
--extensionacl "on-declarations"
# Explicit is better than implicit.
--disable redundantNilInit
# Indentation for multi-line string literals.
--indentstrings true

View File

@@ -18,7 +18,6 @@ brew "rocksdb"
brew "ruby"
brew "rustup"
brew "shellcheck"
brew "swiftformat"
brew "swiftlint"
brew "taplo"
brew "terraform"

View File

@@ -29,7 +29,7 @@ format-jni:
(cd java && ./gradlew spotlessApply)
format-ffi:
(cd swift && swiftformat --swiftversion 5 .)
(cd swift && swift format --in-place --parallel --recursive .)
format-node:
(cd node && npm run format)
@@ -47,7 +47,7 @@ format-all: format-jni format-ffi format-node
check-format-all:
cargo fmt --all -- --check
taplo fmt --check
(cd swift && swiftformat --swiftversion 5 . --lint)
@echo 'warning: `swift format` does not have a check mode'
(cd node && npm run format-check)
(cd java && ./gradlew spotlessCheck)

View File

@@ -1,4 +1,5 @@
disabled_rules:
- closure_parameter_position # swift-format takes precedence here
- cyclomatic_complexity
- empty_enum_arguments
- force_try
@@ -6,6 +7,7 @@ disabled_rules:
- function_parameter_count
- identifier_name
- line_length
- opening_brace # swift-format takes precedence here
- redundant_optional_initialization
- trailing_comma
- type_body_length
@@ -28,3 +30,4 @@ nesting:
type_level: 2
excluded:
- .build/**
- Benchmarks/.build/**

View File

@@ -16,7 +16,7 @@ let package = Package(
.macOS(.v10_15), .iOS(.v13),
],
products: [
.executable(name: "Benchmarks", targets: ["Benchmarks"]),
.executable(name: "Benchmarks", targets: ["Benchmarks"])
],
dependencies: [
.package(url: "https://github.com/google/swift-benchmark", from: "0.1.0"),
@@ -27,12 +27,12 @@ let package = Package(
name: "Benchmarks",
dependencies: [
.product(name: "Benchmark", package: "swift-benchmark"),
.product(name: "LibSignalClient", package: "swift" /* the folder name, sigh */ ),
.product(name: "LibSignalClient", package: "swift" /* the folder name, sigh */),
],
linkerSettings: [
.unsafeFlags(["-L\(rustReleaseBuildDir)"], .when(configuration: .release)),
.unsafeFlags(["-L\(rustDebugBuildDir)"], .when(configuration: .debug)),
]
),
)
]
)

View File

@@ -15,7 +15,9 @@ let groupSendEndorsementsSuite = BenchmarkSuite(name: "GroupSendEndorsements") {
let groupParams = try! GroupSecretParams.generate()
let now = UInt64(Date().timeIntervalSince1970)
let startOfDay = now - now % SECONDS_PER_DAY
let expiration = Date(timeIntervalSince1970: TimeInterval(startOfDay)).addingTimeInterval(TimeInterval(2 * SECONDS_PER_DAY))
let expiration = Date(timeIntervalSince1970: TimeInterval(startOfDay)).addingTimeInterval(
TimeInterval(2 * SECONDS_PER_DAY)
)
for groupSize in [10, 100, 1000] {
let members = (0..<groupSize).map { _ in Aci(fromUUID: UUID()) }
@@ -26,13 +28,31 @@ let groupSendEndorsementsSuite = BenchmarkSuite(name: "GroupSendEndorsements") {
let response = GroupSendEndorsementsResponse.issue(groupMembers: encryptedMembers, keyPair: keyPair)
suite.benchmark("receiveWithServiceIds/\(groupSize)") {
blackHole(try! response.receive(groupMembers: members, localUser: members[0], groupParams: groupParams, serverParams: serverPublicParams))
blackHole(
try! response.receive(
groupMembers: members,
localUser: members[0],
groupParams: groupParams,
serverParams: serverPublicParams
)
)
}
suite.benchmark("receiveWithCiphertexts/\(groupSize)") {
blackHole(try! response.receive(groupMembers: encryptedMembers, localUser: encryptedMembers[0], serverParams: serverPublicParams))
blackHole(
try! response.receive(
groupMembers: encryptedMembers,
localUser: encryptedMembers[0],
serverParams: serverPublicParams
)
)
}
let endorsements = try! response.receive(groupMembers: members, localUser: members[0], groupParams: groupParams, serverParams: serverPublicParams)
let endorsements = try! response.receive(
groupMembers: members,
localUser: members[0],
groupParams: groupParams,
serverParams: serverPublicParams
)
suite.benchmark("toToken/\(groupSize)") {
blackHole(endorsements.endorsements.map { $0.toToken(groupParams: groupParams) })

View File

@@ -18,10 +18,10 @@ let package = Package(
.library(
name: "LibSignalClient",
targets: ["LibSignalClient"]
),
)
],
dependencies: [
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.4.3"),
.package(url: "https://github.com/apple/swift-docc-plugin", from: "1.4.3")
],
targets: [
.systemLibrary(name: "SignalFfi"),

View File

@@ -36,7 +36,8 @@ public func hashLocalPin<Bytes: ContiguousBytes>(_ pin: Bytes) throws -> String
/// - parameter encodedHash: An encoded string of the hash, as returned by `localHash`
/// - returns: true if the pin matches the hash, false otherwise
///
public func verifyLocalPin<Bytes: ContiguousBytes>(_ pin: Bytes, againstEncodedHash encodedHash: String) throws -> Bool {
public func verifyLocalPin<Bytes: ContiguousBytes>(_ pin: Bytes, againstEncodedHash encodedHash: String) throws -> Bool
{
try encodedHash.withCString { hashPtr in
try pin.withUnsafeBorrowedBuffer { buffer in
try invokeFnReturningBool {
@@ -104,11 +105,15 @@ public class PinHash: NativeHandleOwner<SignalMutPointerPinHash>, @unchecked Sen
/// - parameter normalizedPin: A normalized, UTF-8 encoded byte representation of the pin to verify
/// - parameter salt: A 32 byte salt
/// - returns: A `PinHash`
public convenience init<PinBytes: ContiguousBytes, SaltBytes: ContiguousBytes>(normalizedPin: PinBytes, salt: SaltBytes) throws {
public convenience init<PinBytes: ContiguousBytes, SaltBytes: ContiguousBytes>(
normalizedPin: PinBytes,
salt: SaltBytes
) throws {
var result = SignalMutPointerPinHash()
try normalizedPin.withUnsafeBorrowedBuffer { pinBytes in
try salt.withUnsafeBytes { saltBytes in
try ByteArray(newContents: Data(saltBytes), expectedLength: 32).withUnsafePointerToSerialized { saltTuple in
try ByteArray(newContents: Data(saltBytes), expectedLength: 32).withUnsafePointerToSerialized {
saltTuple in
try checkError(signal_pin_hash_from_salt(&result, pinBytes, saltTuple))
}
}
@@ -124,12 +129,18 @@ public class PinHash: NativeHandleOwner<SignalMutPointerPinHash>, @unchecked Sen
/// - parameter username: The Basic Auth username used to authenticate with SVR2
/// - parameter mrenclave: The mrenclave where the hashed pin will be stored
/// - returns: A `PinHash`
public convenience init<PinBytes: ContiguousBytes, MrenclaveBytes: ContiguousBytes>(normalizedPin: PinBytes, username: String, mrenclave: MrenclaveBytes) throws {
public convenience init<PinBytes: ContiguousBytes, MrenclaveBytes: ContiguousBytes>(
normalizedPin: PinBytes,
username: String,
mrenclave: MrenclaveBytes
) throws {
var result = SignalMutPointerPinHash()
try normalizedPin.withUnsafeBorrowedBuffer { pinBytes in
try mrenclave.withUnsafeBorrowedBuffer { mrenclaveBytes in
try username.withCString { userBytes in
try checkError(signal_pin_hash_from_username_mrenclave(&result, pinBytes, userBytes, mrenclaveBytes))
try checkError(
signal_pin_hash_from_username_mrenclave(&result, pinBytes, userBytes, mrenclaveBytes)
)
}
}
}

View File

@@ -14,11 +14,13 @@ public class ProtocolAddress: ClonableHandleOwner<SignalMutPointerProtocolAddres
/// - Throws: ``SignalError#invalidProtocolAddress(name:deviceId:message:)`` if the address is not valid.
public convenience init(name: String, deviceId: UInt32) throws {
var handle = SignalMutPointerProtocolAddress()
try checkError(signal_address_new(
&handle,
name,
deviceId
))
try checkError(
signal_address_new(
&handle,
name,
deviceId
)
)
self.init(owned: NonNull(handle)!)
}
@@ -38,11 +40,16 @@ public class ProtocolAddress: ClonableHandleOwner<SignalMutPointerProtocolAddres
}
}
override internal class func cloneNativeHandle(_ newHandle: inout SignalMutPointerProtocolAddress, currentHandle: SignalConstPointerProtocolAddress) -> SignalFfiErrorRef? {
override internal class func cloneNativeHandle(
_ newHandle: inout SignalMutPointerProtocolAddress,
currentHandle: SignalConstPointerProtocolAddress
) -> SignalFfiErrorRef? {
return signal_address_clone(&newHandle, currentHandle)
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerProtocolAddress>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerProtocolAddress>
) -> SignalFfiErrorRef? {
return signal_address_destroy(handle.pointer)
}

View File

@@ -17,8 +17,12 @@ public class Aes256Ctr32: NativeHandleOwner<SignalMutPointerAes256Ctr32> {
let handle = try key.withUnsafeBorrowedBuffer { keyBuffer in
try nonce.withUnsafeBytes { nonceBytes in
guard nonceBytes.count == Self.nonceLength else {
throw SignalError.invalidArgument("nonce must be \(Self.nonceLength) bytes (got \(nonceBytes.count))")
throw SignalError.invalidArgument(
"nonce must be \(Self.nonceLength) bytes (got \(nonceBytes.count))"
)
}
// swift-format-ignore
// (vertical alignment is clearer)
let initialCounter =
(UInt32(nonceBytes[12]) << 24) |
(UInt32(nonceBytes[13]) << 16) |
@@ -27,31 +31,37 @@ public class Aes256Ctr32: NativeHandleOwner<SignalMutPointerAes256Ctr32> {
var nonceBufferWithoutCounter = SignalBorrowedBuffer(nonceBytes)
nonceBufferWithoutCounter.length -= 4
var result = SignalMutPointerAes256Ctr32()
try checkError(signal_aes256_ctr32_new(
&result,
keyBuffer,
nonceBufferWithoutCounter,
initialCounter
))
try checkError(
signal_aes256_ctr32_new(
&result,
keyBuffer,
nonceBufferWithoutCounter,
initialCounter
)
)
return result
}
}
self.init(owned: NonNull(handle)!)
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerAes256Ctr32>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerAes256Ctr32>
) -> SignalFfiErrorRef? {
return signal_aes256_ctr32_destroy(handle.pointer)
}
public func process(_ message: inout Data) throws {
try withNativeHandle { nativeHandle in
try message.withUnsafeMutableBytes { messageBytes in
try checkError(signal_aes256_ctr32_process(
nativeHandle,
SignalBorrowedMutableBuffer(messageBytes),
0,
UInt32(messageBytes.count)
))
try checkError(
signal_aes256_ctr32_process(
nativeHandle,
SignalBorrowedMutableBuffer(messageBytes),
0,
UInt32(messageBytes.count)
)
)
}
}
}

View File

@@ -92,12 +92,14 @@ public class Aes256GcmEncryption: NativeHandleOwner<SignalMutPointerAes256GcmEnc
try nonce.withUnsafeBorrowedBuffer { nonceBuffer in
try associatedData.withUnsafeBorrowedBuffer { adBuffer in
var result = SignalMutPointerAes256GcmEncryption()
try checkError(signal_aes256_gcm_encryption_new(
&result,
keyBuffer,
nonceBuffer,
adBuffer
))
try checkError(
signal_aes256_gcm_encryption_new(
&result,
keyBuffer,
nonceBuffer,
adBuffer
)
)
return result
}
}
@@ -105,19 +107,23 @@ public class Aes256GcmEncryption: NativeHandleOwner<SignalMutPointerAes256GcmEnc
self.init(owned: NonNull(handle)!)
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerAes256GcmEncryption>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerAes256GcmEncryption>
) -> SignalFfiErrorRef? {
return signal_aes256_gcm_encryption_destroy(handle.pointer)
}
public func encrypt(_ message: inout Data) throws {
try withNativeHandle { nativeHandle in
try message.withUnsafeMutableBytes { messageBytes in
try checkError(signal_aes256_gcm_encryption_update(
nativeHandle,
SignalBorrowedMutableBuffer(messageBytes),
0,
UInt32(messageBytes.count)
))
try checkError(
signal_aes256_gcm_encryption_update(
nativeHandle,
SignalBorrowedMutableBuffer(messageBytes),
0,
UInt32(messageBytes.count)
)
)
}
}
}
@@ -158,12 +164,14 @@ public class Aes256GcmDecryption: NativeHandleOwner<SignalMutPointerAes256GcmDec
try nonce.withUnsafeBorrowedBuffer { nonceBuffer in
try associatedData.withUnsafeBorrowedBuffer { adBuffer in
var result = SignalMutPointerAes256GcmDecryption()
try checkError(signal_aes256_gcm_decryption_new(
&result,
keyBuffer,
nonceBuffer,
adBuffer
))
try checkError(
signal_aes256_gcm_decryption_new(
&result,
keyBuffer,
nonceBuffer,
adBuffer
)
)
return result
}
}
@@ -171,19 +179,23 @@ public class Aes256GcmDecryption: NativeHandleOwner<SignalMutPointerAes256GcmDec
self.init(owned: NonNull(handle)!)
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerAes256GcmDecryption>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerAes256GcmDecryption>
) -> SignalFfiErrorRef? {
return signal_aes256_gcm_decryption_destroy(handle.pointer)
}
public func decrypt(_ message: inout Data) throws {
try withNativeHandle { nativeHandle in
try message.withUnsafeMutableBytes { messageBytes in
try checkError(signal_aes256_gcm_decryption_update(
nativeHandle,
SignalBorrowedMutableBuffer(messageBytes),
0,
UInt32(messageBytes.count)
))
try checkError(
signal_aes256_gcm_decryption_update(
nativeHandle,
SignalBorrowedMutableBuffer(messageBytes),
0,
UInt32(messageBytes.count)
)
)
}
}
}
@@ -192,11 +204,13 @@ public class Aes256GcmDecryption: NativeHandleOwner<SignalMutPointerAes256GcmDec
return try withNativeHandle { nativeHandle in
try tag.withUnsafeBorrowedBuffer { tagBuffer in
var result = false
try checkError(signal_aes256_gcm_decryption_verify_tag(
&result,
nativeHandle,
tagBuffer
))
try checkError(
signal_aes256_gcm_decryption_verify_tag(
&result,
nativeHandle,
tagBuffer
)
)
return result
}
}

View File

@@ -16,7 +16,9 @@ public class Aes256GcmSiv: NativeHandleOwner<SignalMutPointerAes256GcmSiv> {
self.init(owned: NonNull(handle)!)
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerAes256GcmSiv>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerAes256GcmSiv>
) -> SignalFfiErrorRef? {
return signal_aes256_gcm_siv_destroy(handle.pointer)
}

View File

@@ -120,7 +120,9 @@ private class Completer<Promise: PromiseStruct>: CompleterBase {
/// You must ensure that either the callback is called, or the result is passed to
/// ``cleanUpUncompletedPromiseStruct(_:)``.
func makePromiseStruct() -> Promise {
typealias RawPromiseCallback = @convention(c) (_ error: SignalFfiErrorRef?, _ value: sending UnsafeRawPointer?, _ context: UnsafeRawPointer?) -> Void
typealias RawPromiseCallback = @convention(c) (
_ error: SignalFfiErrorRef?, _ value: sending UnsafeRawPointer?, _ context: UnsafeRawPointer?
) -> Void
let completeOpaque: RawPromiseCallback = { error, value, context in
let completer: CompleterBase = Unmanaged.fromOpaque(context!).takeRetainedValue()
completer.completeUnsafe(error, value)
@@ -134,8 +136,14 @@ private class Completer<Promise: PromiseStruct>: CompleterBase {
// we know that Rust is already enforcing that the `bridge_fn` result is allowed to hop threads (Send),
// and that it won't use or escape the C representation of that result besides passing it to the callback.
// So first we build a promise struct---it doesn't matter which one---by reinterpreting the callback...
typealias RawPointerPromiseCallback = @convention(c) (_ error: SignalFfiErrorRef?, _ value: UnsafePointer<UnsafeRawPointer?>?, _ context: UnsafeRawPointer?) -> Void
let rawPromiseStruct = SignalCPromiseRawPointer(complete: unsafeBitCast(completeOpaque, to: RawPointerPromiseCallback.self), context: Unmanaged.passRetained(self).toOpaque(), cancellation_id: 0)
typealias RawPointerPromiseCallback = @convention(c) (
_ error: SignalFfiErrorRef?, _ value: UnsafePointer<UnsafeRawPointer?>?, _ context: UnsafeRawPointer?
) -> Void
let rawPromiseStruct = SignalCPromiseRawPointer(
complete: unsafeBitCast(completeOpaque, to: RawPointerPromiseCallback.self),
context: Unmanaged.passRetained(self).toOpaque(),
cancellation_id: 0
)
// ...And then we reinterpret the entire struct, because all promise structs *also* have the same layout.
// (Which we at least check a little bit here.)

View File

@@ -193,7 +193,8 @@ internal struct FixedLengthWrapper<FixedLengthRepr>: BorrowForFfi {
}
extension BorrowForFfi {
static func fixed<FixedLengthRepr>(_ serialized: ByteArray) -> Self where Self == FixedLengthWrapper<FixedLengthRepr> {
static func fixed<FixedLengthRepr>(_ serialized: ByteArray) -> Self
where Self == FixedLengthWrapper<FixedLengthRepr> {
.init(inner: serialized)
}
}
@@ -229,7 +230,8 @@ internal struct ElementsWrapper<FfiType: FfiBorrowedSlice>: BorrowForFfi {
}
extension BorrowForFfi {
static func slice<FfiType: FfiBorrowedSlice>(_ input: [FfiType.Element]) -> Self where Self == ElementsWrapper<FfiType> {
static func slice<FfiType: FfiBorrowedSlice>(_ input: [FfiType.Element]) -> Self
where Self == ElementsWrapper<FfiType> {
.init(inner: input)
}
}

View File

@@ -19,12 +19,14 @@ public class Cds2Client: SgxClient {
let handle = try attestationMessage.withUnsafeBorrowedBuffer { attestationMessageBuffer in
try mrenclave.withUnsafeBorrowedBuffer { mrenclaveBuffer in
var result = SignalMutPointerSgxClientState()
try checkError(signal_cds2_client_state_new(
&result,
mrenclaveBuffer,
attestationMessageBuffer,
UInt64(currentDate.timeIntervalSince1970 * 1000)
))
try checkError(
signal_cds2_client_state_new(
&result,
mrenclaveBuffer,
attestationMessageBuffer,
UInt64(currentDate.timeIntervalSince1970 * 1000)
)
)
return result
}
}

View File

@@ -68,7 +68,9 @@ public class CdsiLookupRequest: NativeHandleOwner<SignalMutPointerLookupRequest>
}
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerLookupRequest>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerLookupRequest>
) -> SignalFfiErrorRef? {
signal_lookup_request_destroy(handle.pointer)
}
}
@@ -100,7 +102,9 @@ extension SignalConstPointerLookupRequest: SignalConstPointer {
/// Returned by ``Net/cdsiLookup(auth:request:)`` when a request is successfully initiated.
public class CdsiLookup {
class NativeCdsiLookup: NativeHandleOwner<SignalMutPointerCdsiLookup> {
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerCdsiLookup>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerCdsiLookup>
) -> SignalFfiErrorRef? {
signal_cdsi_lookup_destroy(handle.pointer)
}
}
@@ -139,13 +143,18 @@ public class CdsiLookup {
/// `SignalError.networkError` for a network-level connectivity issue,
/// `SignalError.networkProtocolError` for a CDSI or attested connection protocol issue.
public func complete() async throws -> CdsiLookupResponse {
let response: SignalFfiCdsiLookupResponse = try await self.asyncContext.invokeAsyncFunction { promise, asyncContext in
let response: SignalFfiCdsiLookupResponse = try await self.asyncContext.invokeAsyncFunction {
promise,
asyncContext in
self.native.withNativeHandle { handle in
signal_cdsi_lookup_complete(promise, asyncContext.const(), handle.const())
}
}
return CdsiLookupResponse(entries: LookupResponseEntryList(owned: response.entries), debugPermitsUsed: response.debug_permits_used)
return CdsiLookupResponse(
entries: LookupResponseEntryList(owned: response.entries),
debugPermitsUsed: response.debug_permits_used
)
}
}
@@ -194,7 +203,9 @@ public class LookupResponseEntryList: Collection {
}
deinit {
signal_free_lookup_response_entry_list(SignalOwnedBufferOfFfiCdsiLookupResponseEntry(base: self.owned.baseAddress, length: self.owned.count))
signal_free_lookup_response_entry_list(
SignalOwnedBufferOfFfiCdsiLookupResponseEntry(base: self.owned.baseAddress, length: self.owned.count)
)
}
public typealias Index = UnsafeMutableBufferPointer<CdsiLookupResponseEntry>.Index

View File

@@ -11,12 +11,15 @@ import SignalFfi
extension AuthenticatedChatConnection {
internal static func fakeConnect(
tokioAsyncContext: TokioAsyncContext, listener: any ChatConnectionListener,
tokioAsyncContext: TokioAsyncContext,
listener: any ChatConnectionListener,
alerts: [String] = []
) -> (AuthenticatedChatConnection, FakeChatRemote) {
let (fakeChatConnection, listenerBridge) = failOnError {
try FakeChatConnection.create(
tokioAsyncContext: tokioAsyncContext, listener: listener, alerts: alerts
tokioAsyncContext: tokioAsyncContext,
listener: listener,
alerts: alerts
)
}
@@ -25,11 +28,14 @@ extension AuthenticatedChatConnection {
try fakeChatConnection.withNativeHandle {
try checkError(
signal_testing_fake_chat_connection_take_authenticated_chat(
&chatHandle, $0.const()
))
&chatHandle,
$0.const()
)
)
}
let chat = AuthenticatedChatConnection(
fakeHandle: NonNull(chatHandle)!, tokioAsyncContext: tokioAsyncContext
fakeHandle: NonNull(chatHandle)!,
tokioAsyncContext: tokioAsyncContext
)
listenerBridge.setConnection(chatConnection: chat)
@@ -37,12 +43,15 @@ extension AuthenticatedChatConnection {
try fakeChatConnection.withNativeHandle {
try checkError(
signal_testing_fake_chat_connection_take_remote(
&fakeRemoteHandle, $0.const()
))
&fakeRemoteHandle,
$0.const()
)
)
}
let fakeRemote = FakeChatRemote(
handle: NonNull(fakeRemoteHandle)!, tokioAsyncContext: tokioAsyncContext
handle: NonNull(fakeRemoteHandle)!,
tokioAsyncContext: tokioAsyncContext
)
return (chat, fakeRemote)
}
@@ -56,7 +65,9 @@ extension UnauthenticatedChatConnection {
) -> (UnauthenticatedChatConnection, FakeChatRemote) {
let (fakeChatConnection, listenerBridge) = failOnError {
try FakeChatConnection.create(
tokioAsyncContext: tokioAsyncContext, listener: listener, alerts: []
tokioAsyncContext: tokioAsyncContext,
listener: listener,
alerts: []
)
}
@@ -65,11 +76,15 @@ extension UnauthenticatedChatConnection {
try fakeChatConnection.withNativeHandle {
try checkError(
signal_testing_fake_chat_connection_take_authenticated_chat(
&chatHandle, $0.const()
))
&chatHandle,
$0.const()
)
)
}
let chat = UnauthenticatedChatConnection(
fakeHandle: NonNull(chatHandle)!, tokioAsyncContext: tokioAsyncContext, environment: .staging
fakeHandle: NonNull(chatHandle)!,
tokioAsyncContext: tokioAsyncContext,
environment: .staging
)
listenerBridge.setConnection(chatConnection: chat)
@@ -77,12 +92,15 @@ extension UnauthenticatedChatConnection {
try fakeChatConnection.withNativeHandle {
try checkError(
signal_testing_fake_chat_connection_take_remote(
&fakeRemoteHandle, $0.const()
))
&fakeRemoteHandle,
$0.const()
)
)
}
let fakeRemote = FakeChatRemote(
handle: NonNull(fakeRemoteHandle)!, tokioAsyncContext: tokioAsyncContext
handle: NonNull(fakeRemoteHandle)!,
tokioAsyncContext: tokioAsyncContext
)
return (chat, fakeRemote)
}
@@ -118,7 +136,9 @@ private class SetChatLaterListenerBridge: ChatListenerBridge {
}
private class SetChatLaterUnauthListenerBridge: UnauthConnectionEventsListenerBridge {
override init(chatConnectionEventsListenerForTesting chatListener: any ConnectionEventsListener<UnauthenticatedChatConnection>) {
override init(
chatConnectionEventsListenerForTesting chatListener: any ConnectionEventsListener<UnauthenticatedChatConnection>
) {
super.init(chatConnectionEventsListenerForTesting: chatListener)
}
@@ -135,7 +155,8 @@ internal class FakeChatRemote: NativeHandleOwner<SignalMutPointerFakeChatRemoteE
}
init(
handle: NonNull<SignalMutPointerFakeChatRemoteEnd>, tokioAsyncContext: TokioAsyncContext
handle: NonNull<SignalMutPointerFakeChatRemoteEnd>,
tokioAsyncContext: TokioAsyncContext
) {
self.tokioAsyncContext = tokioAsyncContext
super.init(owned: handle)
@@ -150,8 +171,10 @@ internal class FakeChatRemote: NativeHandleOwner<SignalMutPointerFakeChatRemoteE
requestBytes.withUnsafeBorrowedBuffer { requestBytes in
failOnError(
signal_testing_fake_chat_remote_end_send_raw_server_request(
handle.const(), requestBytes
))
handle.const(),
requestBytes
)
)
}
}
}
@@ -160,7 +183,9 @@ internal class FakeChatRemote: NativeHandleOwner<SignalMutPointerFakeChatRemoteE
let request = try await self.tokioAsyncContext.invokeAsyncFunction { promise, asyncContext in
withNativeHandle { handle in
signal_testing_fake_chat_remote_end_receive_incoming_request(
promise, asyncContext.const(), handle.const()
promise,
asyncContext.const(),
handle.const()
)
}
}
@@ -181,7 +206,9 @@ internal class FakeChatRemote: NativeHandleOwner<SignalMutPointerFakeChatRemoteE
let fakeResponse = FakeChatResponse(requestId: requestId, response)
try self.withNativeHandle { nativeHandle in
try fakeResponse.withNativeHandle { response in
try checkError(signal_testing_fake_chat_remote_end_send_server_response(nativeHandle.const(), response.const()))
try checkError(
signal_testing_fake_chat_remote_end_send_server_response(nativeHandle.const(), response.const())
)
}
}
}
@@ -195,8 +222,10 @@ internal class FakeChatRemote: NativeHandleOwner<SignalMutPointerFakeChatRemoteE
responseBytes.withUnsafeBorrowedBuffer { responseBytes in
failOnError(
signal_testing_fake_chat_remote_end_send_raw_server_response(
handle.const(), responseBytes
))
handle.const(),
responseBytes
)
)
}
}
}
@@ -205,7 +234,9 @@ internal class FakeChatRemote: NativeHandleOwner<SignalMutPointerFakeChatRemoteE
withNativeHandle { handle in
failOnError(
signal_testing_fake_chat_remote_end_inject_connection_interrupted(
handle.const()))
handle.const()
)
)
}
}
@@ -230,7 +261,9 @@ internal class FakeChatServer: NativeHandleOwner<SignalMutPointerFakeChatServer>
fatalError("cannot be invoked directly")
}
override class func destroyNativeHandle(_ nativeHandle: NonNull<SignalMutPointerFakeChatServer>) -> SignalFfiErrorRef? {
override class func destroyNativeHandle(
_ nativeHandle: NonNull<SignalMutPointerFakeChatServer>
) -> SignalFfiErrorRef? {
signal_fake_chat_server_destroy(nativeHandle.pointer)
}
@@ -253,7 +286,16 @@ internal class FakeChatResponse: NativeHandleOwner<SignalMutPointerFakeChatRespo
}.withUnsafeBorrowedBytestringArray { headers in
try response.body.withUnsafeBorrowedBuffer { body in
var nativeHandle = SignalMutPointerFakeChatResponse()
try checkError(signal_testing_fake_chat_response_create(&nativeHandle, requestId, response.status, message, headers, SignalOptionalBorrowedSliceOfc_uchar(present: true, value: body)))
try checkError(
signal_testing_fake_chat_response_create(
&nativeHandle,
requestId,
response.status,
message,
headers,
SignalOptionalBorrowedSliceOfc_uchar(present: true, value: body)
)
)
return nativeHandle
}
}
@@ -266,35 +308,45 @@ internal class FakeChatResponse: NativeHandleOwner<SignalMutPointerFakeChatRespo
fatalError("cannot be invoked directly")
}
override class func destroyNativeHandle(_ nativeHandle: NonNull<SignalMutPointerFakeChatResponse>) -> SignalFfiErrorRef? {
override class func destroyNativeHandle(
_ nativeHandle: NonNull<SignalMutPointerFakeChatResponse>
) -> SignalFfiErrorRef? {
signal_fake_chat_response_destroy(nativeHandle.pointer)
}
}
private class FakeChatConnection: NativeHandleOwner<SignalMutPointerFakeChatConnection> {
static func create(
tokioAsyncContext: TokioAsyncContext, listener: any ChatConnectionListener,
tokioAsyncContext: TokioAsyncContext,
listener: any ChatConnectionListener,
alerts: [String]
) throws -> (FakeChatConnection, SetChatLaterListenerBridge) {
let listenerBridge = SetChatLaterListenerBridge(
chatConnectionListenerForTesting: listener)
chatConnectionListenerForTesting: listener
)
var listenerStruct = listenerBridge.makeListenerStruct()
let chat = try FakeChatConnection.internalCreate(tokioAsyncContext, &listenerStruct, alerts)
return (chat, listenerBridge)
}
static func create(
tokioAsyncContext: TokioAsyncContext, listener: any ConnectionEventsListener<UnauthenticatedChatConnection>,
tokioAsyncContext: TokioAsyncContext,
listener: any ConnectionEventsListener<UnauthenticatedChatConnection>,
alerts: [String]
) throws -> (FakeChatConnection, SetChatLaterUnauthListenerBridge) {
let listenerBridge = SetChatLaterUnauthListenerBridge(
chatConnectionEventsListenerForTesting: listener)
chatConnectionEventsListenerForTesting: listener
)
var listenerStruct = listenerBridge.makeListenerStruct()
let chat = try FakeChatConnection.internalCreate(tokioAsyncContext, &listenerStruct, alerts)
return (chat, listenerBridge)
}
private static func internalCreate(_ tokioAsyncContext: TokioAsyncContext, _ listenerStruct: inout SignalFfiChatListenerStruct, _ alerts: [String]) throws -> FakeChatConnection {
private static func internalCreate(
_ tokioAsyncContext: TokioAsyncContext,
_ listenerStruct: inout SignalFfiChatListenerStruct,
_ alerts: [String]
) throws -> FakeChatConnection {
let connection: FakeChatConnection = try withUnsafePointer(to: &listenerStruct) { listener in
try tokioAsyncContext.withNativeHandle { asyncContext in
try invokeFnReturningNativeHandle {

View File

@@ -22,7 +22,8 @@ public protocol ChatConnection: AnyObject {
}
public class ConnectionInfo: NativeHandleOwner<SignalMutPointerChatConnectionInfo>, CustomStringConvertible {
override class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerChatConnectionInfo>) -> SignalFfiErrorRef? {
override class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerChatConnectionInfo>) -> SignalFfiErrorRef?
{
// ChatConnectionInfo is an alias for ConnectionInfo, but Swift doesn't know that.
return signal_connection_info_destroy(SignalMutPointerConnectionInfo(raw: handle.opaque))
}
@@ -95,21 +96,29 @@ extension ChatConnection {
/// Before an obtained instance can be used, it must be started by calling ``AuthenticatedChatConnection/start(listener:)``.
public class AuthenticatedChatConnection: NativeHandleOwner<
SignalMutPointerAuthenticatedChatConnection
>, ChatConnection, @unchecked Sendable {
>, ChatConnection, @unchecked Sendable
{
internal let tokioAsyncContext: TokioAsyncContext
/// Initiates establishing of the underlying unauthenticated connection to the Chat Service. Once
/// the connection is established, the returned object can be used to send and receive messages
/// after ``AuthenticatedChatConnection/start(listener:)`` is called.
internal init(
tokioAsyncContext: TokioAsyncContext, connectionManager: ConnectionManager,
username: String, password: String, receiveStories: Bool
tokioAsyncContext: TokioAsyncContext,
connectionManager: ConnectionManager,
username: String,
password: String,
receiveStories: Bool
) async throws {
let nativeHandle = try await tokioAsyncContext.invokeAsyncFunction { promise, tokioAsyncContext in
connectionManager.withNativeHandle { connectionManager in
signal_authenticated_chat_connection_connect(
promise, tokioAsyncContext.const(), connectionManager.const(), username,
password, receiveStories
promise,
tokioAsyncContext.const(),
connectionManager.const(),
username,
password,
receiveStories
)
}
}
@@ -127,7 +136,10 @@ public class AuthenticatedChatConnection: NativeHandleOwner<
fatalError("should not be called directly for a ChatConnection")
}
internal init(fakeHandle handle: NonNull<SignalMutPointerAuthenticatedChatConnection>, tokioAsyncContext: TokioAsyncContext) {
internal init(
fakeHandle handle: NonNull<SignalMutPointerAuthenticatedChatConnection>,
tokioAsyncContext: TokioAsyncContext
) {
self.tokioAsyncContext = tokioAsyncContext
super.init(owned: handle)
}
@@ -144,8 +156,10 @@ public class AuthenticatedChatConnection: NativeHandleOwner<
withUnsafePointer(to: &listenerStruct) {
failOnError(
signal_authenticated_chat_connection_init_listener(
chatConnection.const(), SignalConstPointerFfiChatListenerStruct(raw: $0)
))
chatConnection.const(),
SignalConstPointerFfiChatListenerStruct(raw: $0)
)
)
}
}
}
@@ -157,7 +171,9 @@ public class AuthenticatedChatConnection: NativeHandleOwner<
_ = try await self.tokioAsyncContext.invokeAsyncFunction { promise, tokioAsyncContext in
withNativeHandle { chatConnection in
signal_authenticated_chat_connection_disconnect(
promise, tokioAsyncContext.const(), chatConnection.const()
promise,
tokioAsyncContext.const(),
chatConnection.const()
)
}
}
@@ -175,8 +191,11 @@ public class AuthenticatedChatConnection: NativeHandleOwner<
withNativeHandle { chatService in
internalRequest.withNativeHandle { request in
signal_authenticated_chat_connection_send(
promise, tokioAsyncContext.const(), chatService.const(),
request.const(), timeoutMillis
promise,
tokioAsyncContext.const(),
chatService.const(),
request.const(),
timeoutMillis
)
}
}
@@ -224,7 +243,8 @@ extension SignalConstPointerAuthenticatedChatConnection: SignalConstPointer {
/// Before an obtained instance can be used, it must be started by calling ``UnauthenticatedChatConnection/start(listener:)``.
public class UnauthenticatedChatConnection: NativeHandleOwner<
SignalMutPointerUnauthenticatedChatConnection
>, ChatConnection, @unchecked Sendable {
>, ChatConnection, @unchecked Sendable
{
internal let tokioAsyncContext: TokioAsyncContext
internal let environment: Net.Environment
@@ -240,7 +260,9 @@ public class UnauthenticatedChatConnection: NativeHandleOwner<
let nativeHandle = try await tokioAsyncContext.invokeAsyncFunction { promise, tokioAsyncContext in
connectionManager.withNativeHandle { connectionManager in
signal_unauthenticated_chat_connection_connect(
promise, tokioAsyncContext.const(), connectionManager.const()
promise,
tokioAsyncContext.const(),
connectionManager.const()
)
}
}
@@ -277,13 +299,16 @@ public class UnauthenticatedChatConnection: NativeHandleOwner<
public func start(listener: any ConnectionEventsListener<UnauthenticatedChatConnection>) {
withNativeHandle { chatConnection in
var listenerStruct = UnauthConnectionEventsListenerBridge(
chatConnection: self, listener: listener
chatConnection: self,
listener: listener
).makeListenerStruct()
withUnsafePointer(to: &listenerStruct) {
failOnError(
signal_unauthenticated_chat_connection_init_listener(
chatConnection.const(), SignalConstPointerFfiChatListenerStruct(raw: $0)
))
chatConnection.const(),
SignalConstPointerFfiChatListenerStruct(raw: $0)
)
)
}
}
}
@@ -295,7 +320,9 @@ public class UnauthenticatedChatConnection: NativeHandleOwner<
_ = try await self.tokioAsyncContext.invokeAsyncFunction { promise, tokioAsyncContext in
withNativeHandle { chatConnection in
signal_unauthenticated_chat_connection_disconnect(
promise, tokioAsyncContext.const(), chatConnection.const()
promise,
tokioAsyncContext.const(),
chatConnection.const()
)
}
}
@@ -313,8 +340,11 @@ public class UnauthenticatedChatConnection: NativeHandleOwner<
withNativeHandle { chatService in
internalRequest.withNativeHandle { request in
signal_unauthenticated_chat_connection_send(
promise, tokioAsyncContext.const(), chatService.const(),
request.const(), timeoutMillis
promise,
tokioAsyncContext.const(),
chatService.const(),
request.const(),
timeoutMillis
)
}
}

View File

@@ -22,7 +22,12 @@ public protocol ChatConnectionListener: ConnectionEventsListener<AuthenticatedCh
///
/// If `sendAck` is not called, the server will leave this message in the message queue and
/// attempt to deliver it again in the future.
func chatConnection(_ chat: AuthenticatedChatConnection, didReceiveIncomingMessage envelope: Data, serverDeliveryTimestamp: UInt64, sendAck: @escaping () throws -> Void)
func chatConnection(
_ chat: AuthenticatedChatConnection,
didReceiveIncomingMessage envelope: Data,
serverDeliveryTimestamp: UInt64,
sendAck: @escaping () throws -> Void
)
/// Called when the server indicates that there are no further messages in the message queue.
///
@@ -53,7 +58,9 @@ extension AuthenticatedChatConnection: ChatListenerConnection {}
internal class ChatListenerBridge {
private class AckHandleOwner: NativeHandleOwner<SignalMutPointerServerMessageAck> {
override class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerServerMessageAck>) -> SignalFfiErrorRef? {
override class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerServerMessageAck>
) -> SignalFfiErrorRef? {
signal_server_message_ack_destroy(handle.pointer)
}
}
@@ -100,7 +107,8 @@ internal class ChatListenerBridge {
let envelopeData = Data(bytes: envelope.base, count: envelope.length)
bridge.chatListener.chatConnection(
chatConnection, didReceiveIncomingMessage: envelopeData,
chatConnection,
didReceiveIncomingMessage: envelopeData,
serverDeliveryTimestamp: timestamp
) { _ = ackHandleOwner.withNativeHandle { ackHandle in signal_server_message_ack_send(ackHandle.const()) } }
}
@@ -195,16 +203,31 @@ internal class UnauthConnectionEventsListenerBridge {
func makeListenerStruct() -> SignalFfiChatListenerStruct {
let receivedIncomingMessage: SignalReceivedIncomingMessage = { _, _, _, _ in
// Not used in the unauth chat listener
LoggerBridge.shared?.logger.log(level: .error, file: #fileID, line: #line, message: "unauth socket received an incoming request")
LoggerBridge.shared?.logger.log(
level: .error,
file: #fileID,
line: #line,
message: "unauth socket received an incoming request"
)
}
let receivedQueueEmpty: SignalReceivedQueueEmpty = { _ in
// Not used in the unauth chat listener
LoggerBridge.shared?.logger.log(level: .error, file: #fileID, line: #line, message: "unauth socket received a \"queue empty\" notification")
LoggerBridge.shared?.logger.log(
level: .error,
file: #fileID,
line: #line,
message: "unauth socket received a \"queue empty\" notification"
)
}
let receivedAlerts: SignalReceivedAlerts = { _, alerts in
// Not used in the unauth chat listener
if alerts.lengths.length != 0 {
LoggerBridge.shared?.logger.log(level: .error, file: #fileID, line: #line, message: "unauth socket received \(alerts.lengths.length) alerts")
LoggerBridge.shared?.logger.log(
level: .error,
file: #fileID,
line: #line,
message: "unauth socket received \(alerts.lengths.length) alerts"
)
}
}
let connectionInterrupted: SignalConnectionInterrupted = { rawCtx, maybeError in

View File

@@ -18,7 +18,13 @@ public struct ChatRequest: Equatable, Sendable {
public var body: Data?
public var timeout: TimeInterval
public init(method: String, pathAndQuery: String, headers: [String: String] = [:], body: Data? = nil, timeout: TimeInterval) {
public init(
method: String,
pathAndQuery: String,
headers: [String: String] = [:],
body: Data? = nil,
timeout: TimeInterval
) {
self.method = method
self.pathAndQuery = pathAndQuery
self.headers = headers
@@ -44,7 +50,9 @@ public struct ChatRequest: Equatable, Sendable {
var handle = SignalMutPointerHttpRequest(untyped: nil)
if let body = request.body {
try body.withUnsafeBorrowedBuffer { body in
try checkError(signal_http_request_new_with_body(&handle, request.method, request.pathAndQuery, body))
try checkError(
signal_http_request_new_with_body(&handle, request.method, request.pathAndQuery, body)
)
}
} else {
try checkError(signal_http_request_new_without_body(&handle, request.method, request.pathAndQuery))
@@ -61,8 +69,8 @@ public struct ChatRequest: Equatable, Sendable {
return signal_http_request_destroy(handle.pointer)
}
// These testing endpoints aren't generated in device builds, to save on code size.
#if !os(iOS) || targetEnvironment(simulator)
// These testing endpoints aren't generated in device builds, to save on code size.
#if !os(iOS) || targetEnvironment(simulator)
internal var method: String {
failOnError {
try withNativeHandle { request in
@@ -109,7 +117,7 @@ public struct ChatRequest: Equatable, Sendable {
}
}
}
#endif
#endif
}
}
@@ -154,28 +162,40 @@ public struct ChatResponse: Equatable, Sendable {
self.status = rawResponse.status
self.message = String(cString: rawResponse.message)
self.headers = Dictionary(uniqueKeysWithValues: rawResponse.rawHeadersAsBuffer.lazy.map { (rawHeader: UnsafePointer<CChar>?) -> (String, String) in
guard let rawHeader else {
fatalError("null in headers list")
self.headers = Dictionary(
uniqueKeysWithValues: rawResponse.rawHeadersAsBuffer.lazy.map {
(rawHeader: UnsafePointer<CChar>?) -> (String, String) in
guard let rawHeader else {
fatalError("null in headers list")
}
let asciiColon = Int32(Character(":").asciiValue!)
guard let colonPtr = strchr(rawHeader, asciiColon) else {
fatalError("header returned without colon")
}
let nameCount = UnsafePointer(colonPtr) - rawHeader
guard
let name = UnsafeBufferPointer(start: rawHeader, count: nameCount).withMemoryRebound(
to: UInt8.self,
{
String(bytes: $0, encoding: .utf8)
}
)
else {
fatalError("non-UTF-8 header name not rejected by Rust")
}
let value = String(cString: colonPtr + 1)
return (name, value)
}
let asciiColon = Int32(Character(":").asciiValue!)
guard let colonPtr = strchr(rawHeader, asciiColon) else {
fatalError("header returned without colon")
}
let nameCount = UnsafePointer(colonPtr) - rawHeader
guard let name = UnsafeBufferPointer(start: rawHeader, count: nameCount).withMemoryRebound(to: UInt8.self, {
String(bytes: $0, encoding: .utf8)
}) else {
fatalError("non-UTF-8 header name not rejected by Rust")
}
let value = String(cString: colonPtr + 1)
return (name, value)
})
)
// Avoid copying the body when possible!
self.body = Data(bytesNoCopy: rawResponse.body.base, count: rawResponse.body.length, deallocator: .custom { base, length in
signal_free_buffer(base, length)
})
self.body = Data(
bytesNoCopy: rawResponse.body.base,
count: rawResponse.body.length,
deallocator: .custom { base, length in
signal_free_buffer(base, length)
}
)
// Clear it out so it doesn't get freed eagerly.
rawResponse.body = .init()

View File

@@ -73,7 +73,9 @@ public class ComparableBackup: NativeHandleOwner<SignalMutPointerComparableBacku
}
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerComparableBackup>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerComparableBackup>
) -> SignalFfiErrorRef? {
signal_comparable_backup_destroy(handle.pointer)
}
}

View File

@@ -15,7 +15,9 @@ private struct SenderKeyName: Hashable {
var distributionId: UUID
}
open class InMemorySignalProtocolStore: IdentityKeyStore, PreKeyStore, SignedPreKeyStore, KyberPreKeyStore, SessionStore, SenderKeyStore {
open class InMemorySignalProtocolStore: IdentityKeyStore, PreKeyStore, SignedPreKeyStore, KyberPreKeyStore,
SessionStore, SenderKeyStore
{
private var publicKeys: [ProtocolAddress: IdentityKey] = [:]
private var privateKey: IdentityKeyPair
private var registrationId: UInt32
@@ -44,7 +46,11 @@ open class InMemorySignalProtocolStore: IdentityKeyStore, PreKeyStore, SignedPre
return self.registrationId
}
open func saveIdentity(_ identity: IdentityKey, for address: ProtocolAddress, context: StoreContext) throws -> IdentityChange {
open func saveIdentity(
_ identity: IdentityKey,
for address: ProtocolAddress,
context: StoreContext
) throws -> IdentityChange {
let oldIdentity = self.publicKeys.updateValue(identity, forKey: address)
if oldIdentity == nil || oldIdentity == identity {
return .newOrUnchanged
@@ -53,11 +59,16 @@ open class InMemorySignalProtocolStore: IdentityKeyStore, PreKeyStore, SignedPre
}
}
open func isTrustedIdentity(_ identity: IdentityKey, for address: ProtocolAddress, direction: Direction, context: StoreContext) throws -> Bool {
open func isTrustedIdentity(
_ identity: IdentityKey,
for address: ProtocolAddress,
direction: Direction,
context: StoreContext
) throws -> Bool {
if let pk = publicKeys[address] {
return pk == identity
} else {
return true // tofu
return true // tofu
}
}
@@ -126,11 +137,20 @@ open class InMemorySignalProtocolStore: IdentityKeyStore, PreKeyStore, SignedPre
self.sessionMap[address] = record
}
open func storeSenderKey(from sender: ProtocolAddress, distributionId: UUID, record: SenderKeyRecord, context: StoreContext) throws {
open func storeSenderKey(
from sender: ProtocolAddress,
distributionId: UUID,
record: SenderKeyRecord,
context: StoreContext
) throws {
self.senderKeyMap[SenderKeyName(sender: sender, distributionId: distributionId)] = record
}
open func loadSenderKey(from sender: ProtocolAddress, distributionId: UUID, context: StoreContext) throws -> SenderKeyRecord? {
open func loadSenderKey(
from sender: ProtocolAddress,
distributionId: UUID,
context: StoreContext
) throws -> SenderKeyRecord? {
return self.senderKeyMap[SenderKeyName(sender: sender, distributionId: distributionId)]
}
}

View File

@@ -24,8 +24,17 @@ public protocol StoreContext {}
public protocol IdentityKeyStore: AnyObject {
func identityKeyPair(context: StoreContext) throws -> IdentityKeyPair
func localRegistrationId(context: StoreContext) throws -> UInt32
func saveIdentity(_ identity: IdentityKey, for address: ProtocolAddress, context: StoreContext) throws -> IdentityChange
func isTrustedIdentity(_ identity: IdentityKey, for address: ProtocolAddress, direction: Direction, context: StoreContext) throws -> Bool
func saveIdentity(
_ identity: IdentityKey,
for address: ProtocolAddress,
context: StoreContext
) throws -> IdentityChange
func isTrustedIdentity(
_ identity: IdentityKey,
for address: ProtocolAddress,
direction: Direction,
context: StoreContext
) throws -> Bool
func identity(for address: ProtocolAddress, context: StoreContext) throws -> IdentityKey?
}
@@ -53,6 +62,15 @@ public protocol SessionStore: AnyObject {
}
public protocol SenderKeyStore: AnyObject {
func storeSenderKey(from sender: ProtocolAddress, distributionId: UUID, record: SenderKeyRecord, context: StoreContext) throws
func loadSenderKey(from sender: ProtocolAddress, distributionId: UUID, context: StoreContext) throws -> SenderKeyRecord?
func storeSenderKey(
from sender: ProtocolAddress,
distributionId: UUID,
record: SenderKeyRecord,
context: StoreContext
) throws
func loadSenderKey(
from sender: ProtocolAddress,
distributionId: UUID,
context: StoreContext
) throws -> SenderKeyRecord?
}

View File

@@ -6,12 +6,18 @@
import Foundation
import SignalFfi
internal func withIdentityKeyStore<Result>(_ store: IdentityKeyStore, _ context: StoreContext, _ body: (SignalConstPointerFfiIdentityKeyStoreStruct) throws -> Result) throws -> Result {
internal func withIdentityKeyStore<Result>(
_ store: IdentityKeyStore,
_ context: StoreContext,
_ body: (SignalConstPointerFfiIdentityKeyStoreStruct) throws -> Result
) throws -> Result {
func ffiShimGetIdentityKeyPair(
storeCtx: UnsafeMutableRawPointer?,
keyp: UnsafeMutablePointer<SignalMutPointerPrivateKey>?
) -> Int32 {
let storeContext = storeCtx!.assumingMemoryBound(to: ErrorHandlingContext<(IdentityKeyStore, StoreContext)>.self)
let storeContext = storeCtx!.assumingMemoryBound(
to: ErrorHandlingContext<(IdentityKeyStore, StoreContext)>.self
)
return storeContext.pointee.catchCallbackErrors { store, context in
var privateKey = try store.identityKeyPair(context: context).privateKey
keyp!.pointee = try cloneOrTakeHandle(from: &privateKey)
@@ -23,7 +29,9 @@ internal func withIdentityKeyStore<Result>(_ store: IdentityKeyStore, _ context:
storeCtx: UnsafeMutableRawPointer?,
idp: UnsafeMutablePointer<UInt32>?
) -> Int32 {
let storeContext = storeCtx!.assumingMemoryBound(to: ErrorHandlingContext<(IdentityKeyStore, StoreContext)>.self)
let storeContext = storeCtx!.assumingMemoryBound(
to: ErrorHandlingContext<(IdentityKeyStore, StoreContext)>.self
)
return storeContext.pointee.catchCallbackErrors { store, context in
let id = try store.localRegistrationId(context: context)
idp!.pointee = id
@@ -36,7 +44,9 @@ internal func withIdentityKeyStore<Result>(_ store: IdentityKeyStore, _ context:
address: SignalConstPointerProtocolAddress,
public_key: SignalConstPointerPublicKey
) -> Int32 {
let storeContext = storeCtx!.assumingMemoryBound(to: ErrorHandlingContext<(IdentityKeyStore, StoreContext)>.self)
let storeContext = storeCtx!.assumingMemoryBound(
to: ErrorHandlingContext<(IdentityKeyStore, StoreContext)>.self
)
return storeContext.pointee.catchCallbackErrors { store, context in
var address = ProtocolAddress(borrowing: address)
defer { cloneOrForgetAsNeeded(&address) }
@@ -55,7 +65,9 @@ internal func withIdentityKeyStore<Result>(_ store: IdentityKeyStore, _ context:
public_key: UnsafeMutablePointer<SignalMutPointerPublicKey>?,
address: SignalConstPointerProtocolAddress
) -> Int32 {
let storeContext = storeCtx!.assumingMemoryBound(to: ErrorHandlingContext<(IdentityKeyStore, StoreContext)>.self)
let storeContext = storeCtx!.assumingMemoryBound(
to: ErrorHandlingContext<(IdentityKeyStore, StoreContext)>.self
)
return storeContext.pointee.catchCallbackErrors { store, context in
var address = ProtocolAddress(borrowing: address)
defer { cloneOrForgetAsNeeded(&address) }
@@ -75,7 +87,9 @@ internal func withIdentityKeyStore<Result>(_ store: IdentityKeyStore, _ context:
public_key: SignalConstPointerPublicKey,
raw_direction: UInt32
) -> Int32 {
let storeContext = storeCtx!.assumingMemoryBound(to: ErrorHandlingContext<(IdentityKeyStore, StoreContext)>.self)
let storeContext = storeCtx!.assumingMemoryBound(
to: ErrorHandlingContext<(IdentityKeyStore, StoreContext)>.self
)
return storeContext.pointee.catchCallbackErrors { store, context in
var address = ProtocolAddress(borrowing: address)
defer { cloneOrForgetAsNeeded(&address) }
@@ -112,7 +126,11 @@ internal func withIdentityKeyStore<Result>(_ store: IdentityKeyStore, _ context:
}
}
internal func withPreKeyStore<Result>(_ store: PreKeyStore, _ context: StoreContext, _ body: (SignalConstPointerFfiPreKeyStoreStruct) throws -> Result) throws -> Result {
internal func withPreKeyStore<Result>(
_ store: PreKeyStore,
_ context: StoreContext,
_ body: (SignalConstPointerFfiPreKeyStoreStruct) throws -> Result
) throws -> Result {
func ffiShimStorePreKey(
storeCtx: UnsafeMutableRawPointer?,
id: UInt32,
@@ -164,13 +182,19 @@ internal func withPreKeyStore<Result>(_ store: PreKeyStore, _ context: StoreCont
}
}
internal func withSignedPreKeyStore<Result>(_ store: SignedPreKeyStore, _ context: StoreContext, _ body: (SignalConstPointerFfiSignedPreKeyStoreStruct) throws -> Result) throws -> Result {
internal func withSignedPreKeyStore<Result>(
_ store: SignedPreKeyStore,
_ context: StoreContext,
_ body: (SignalConstPointerFfiSignedPreKeyStoreStruct) throws -> Result
) throws -> Result {
func ffiShimStoreSignedPreKey(
storeCtx: UnsafeMutableRawPointer?,
id: UInt32,
record: SignalConstPointerSignedPreKeyRecord
) -> Int32 {
let storeContext = storeCtx!.assumingMemoryBound(to: ErrorHandlingContext<(SignedPreKeyStore, StoreContext)>.self)
let storeContext = storeCtx!.assumingMemoryBound(
to: ErrorHandlingContext<(SignedPreKeyStore, StoreContext)>.self
)
return storeContext.pointee.catchCallbackErrors { store, context in
var record = SignedPreKeyRecord(borrowing: record)
defer { cloneOrForgetAsNeeded(&record) }
@@ -184,7 +208,9 @@ internal func withSignedPreKeyStore<Result>(_ store: SignedPreKeyStore, _ contex
recordp: UnsafeMutablePointer<SignalMutPointerSignedPreKeyRecord>?,
id: UInt32
) -> Int32 {
let storeContext = storeCtx!.assumingMemoryBound(to: ErrorHandlingContext<(SignedPreKeyStore, StoreContext)>.self)
let storeContext = storeCtx!.assumingMemoryBound(
to: ErrorHandlingContext<(SignedPreKeyStore, StoreContext)>.self
)
return storeContext.pointee.catchCallbackErrors { store, context in
var record = try store.loadSignedPreKey(id: id, context: context)
recordp!.pointee = try cloneOrTakeHandle(from: &record)
@@ -204,13 +230,19 @@ internal func withSignedPreKeyStore<Result>(_ store: SignedPreKeyStore, _ contex
}
}
internal func withKyberPreKeyStore<Result>(_ store: KyberPreKeyStore, _ context: StoreContext, _ body: (SignalConstPointerFfiKyberPreKeyStoreStruct) throws -> Result) throws -> Result {
internal func withKyberPreKeyStore<Result>(
_ store: KyberPreKeyStore,
_ context: StoreContext,
_ body: (SignalConstPointerFfiKyberPreKeyStoreStruct) throws -> Result
) throws -> Result {
func ffiShimStoreKyberPreKey(
storeCtx: UnsafeMutableRawPointer?,
id: UInt32,
record: SignalConstPointerKyberPreKeyRecord
) -> Int32 {
let storeContext = storeCtx!.assumingMemoryBound(to: ErrorHandlingContext<(KyberPreKeyStore, StoreContext)>.self)
let storeContext = storeCtx!.assumingMemoryBound(
to: ErrorHandlingContext<(KyberPreKeyStore, StoreContext)>.self
)
return storeContext.pointee.catchCallbackErrors { store, context in
var record = KyberPreKeyRecord(borrowing: record)
defer { cloneOrForgetAsNeeded(&record) }
@@ -224,7 +256,9 @@ internal func withKyberPreKeyStore<Result>(_ store: KyberPreKeyStore, _ context:
recordp: UnsafeMutablePointer<SignalMutPointerKyberPreKeyRecord>?,
id: UInt32
) -> Int32 {
let storeContext = storeCtx!.assumingMemoryBound(to: ErrorHandlingContext<(KyberPreKeyStore, StoreContext)>.self)
let storeContext = storeCtx!.assumingMemoryBound(
to: ErrorHandlingContext<(KyberPreKeyStore, StoreContext)>.self
)
return storeContext.pointee.catchCallbackErrors { store, context in
var record = try store.loadKyberPreKey(id: id, context: context)
recordp!.pointee = try cloneOrTakeHandle(from: &record)
@@ -236,7 +270,9 @@ internal func withKyberPreKeyStore<Result>(_ store: KyberPreKeyStore, _ context:
storeCtx: UnsafeMutableRawPointer?,
id: UInt32
) -> Int32 {
let storeContext = storeCtx!.assumingMemoryBound(to: ErrorHandlingContext<(KyberPreKeyStore, StoreContext)>.self)
let storeContext = storeCtx!.assumingMemoryBound(
to: ErrorHandlingContext<(KyberPreKeyStore, StoreContext)>.self
)
return storeContext.pointee.catchCallbackErrors { store, context in
try store.markKyberPreKeyUsed(id: id, context: context)
return 0
@@ -256,7 +292,11 @@ internal func withKyberPreKeyStore<Result>(_ store: KyberPreKeyStore, _ context:
}
}
internal func withSessionStore<Result>(_ store: SessionStore, _ context: StoreContext, _ body: (SignalConstPointerFfiSessionStoreStruct) throws -> Result) throws -> Result {
internal func withSessionStore<Result>(
_ store: SessionStore,
_ context: StoreContext,
_ body: (SignalConstPointerFfiSessionStoreStruct) throws -> Result
) throws -> Result {
func ffiShimStoreSession(
storeCtx: UnsafeMutableRawPointer?,
address: SignalConstPointerProtocolAddress,
@@ -303,7 +343,11 @@ internal func withSessionStore<Result>(_ store: SessionStore, _ context: StoreCo
}
}
internal func withSenderKeyStore<Result>(_ store: SenderKeyStore, _ context: StoreContext, _ body: (SignalConstPointerFfiSenderKeyStoreStruct) throws -> Result) rethrows -> Result {
internal func withSenderKeyStore<Result>(
_ store: SenderKeyStore,
_ context: StoreContext,
_ body: (SignalConstPointerFfiSenderKeyStoreStruct) throws -> Result
) rethrows -> Result {
func ffiShimStoreSenderKey(
storeCtx: UnsafeMutableRawPointer?,
sender: SignalConstPointerProtocolAddress,

View File

@@ -294,7 +294,11 @@ internal func checkError(_ error: SignalFfiErrorRef?) throws {
return err
}
throw RegistrationError.registrationLock(timeRemaining: TimeInterval(timeRemaining), svr2Username: svr2Username, svr2Password: svr2Password)
throw RegistrationError.registrationLock(
timeRemaining: TimeInterval(timeRemaining),
svr2Username: svr2Username,
svr2Password: svr2Password
)
case SignalErrorCodeKeyTransparencyError:
throw SignalError.keyTransparencyError(errStr)
case SignalErrorCodeKeyTransparencyVerificationFailed:
@@ -308,7 +312,8 @@ internal func failOnError(_ error: SignalFfiErrorRef?) {
failOnError { try checkError(error) }
}
internal func failOnError<Result>(_ fn: () throws -> Result, file: StaticString = #file, line: UInt32 = #line) -> Result {
internal func failOnError<Result>(_ fn: () throws -> Result, file: StaticString = #file, line: UInt32 = #line) -> Result
{
do {
return try fn()
} catch {

View File

@@ -59,15 +59,17 @@ public struct NumericFingerprintGenerator: Sendable {
.bytes(localIdentifier),
.bytes(remoteIdentifier)
) { localKeyHandle, remoteKeyHandle, localBuffer, remoteBuffer in
try checkError(signal_fingerprint_new(
&obj,
UInt32(self.iterations),
UInt32(version),
localBuffer,
localKeyHandle.const(),
remoteBuffer,
remoteKeyHandle.const()
))
try checkError(
signal_fingerprint_new(
&obj,
UInt32(self.iterations),
UInt32(version),
localBuffer,
localKeyHandle.const(),
remoteBuffer,
remoteKeyHandle.const()
)
)
}
let fprintStr = try invokeFnReturningString {

View File

@@ -54,11 +54,13 @@ public class HsmEnclaveClient: NativeHandleOwner<SignalMutPointerHsmEnclaveClien
let handle = try publicKey.withUnsafeBorrowedBuffer { publicKeyBuffer in
try codeHashBytes.withUnsafeBorrowedBuffer { codeHashBuffer in
var result = SignalMutPointerHsmEnclaveClient()
try checkError(signal_hsm_enclave_client_new(
&result,
publicKeyBuffer,
codeHashBuffer
))
try checkError(
signal_hsm_enclave_client_new(
&result,
publicKeyBuffer,
codeHashBuffer
)
)
return result
}
}
@@ -66,7 +68,9 @@ public class HsmEnclaveClient: NativeHandleOwner<SignalMutPointerHsmEnclaveClien
self.init(owned: NonNull(handle)!)
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerHsmEnclaveClient>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerHsmEnclaveClient>
) -> SignalFfiErrorRef? {
return signal_hsm_enclave_client_destroy(handle.pointer)
}

View File

@@ -24,7 +24,14 @@ public struct IdentityKey: Equatable, Sendable {
public func verifyAlternateIdentity<Bytes: ContiguousBytes>(_ other: IdentityKey, signature: Bytes) throws -> Bool {
var result = false
try withAllBorrowed(publicKey, other.publicKey, .bytes(signature)) { selfHandle, otherHandle, signatureBuffer in
try checkError(signal_identitykey_verify_alternate_identity(&result, selfHandle.const(), otherHandle.const(), signatureBuffer))
try checkError(
signal_identitykey_verify_alternate_identity(
&result,
selfHandle.const(),
otherHandle.const(),
signatureBuffer
)
)
}
return result
}
@@ -74,7 +81,12 @@ public struct IdentityKeyPair: Sendable {
return failOnError {
try withAllBorrowed(self.publicKey, self.privateKey, other.publicKey) { publicKey, privateKey, other in
try invokeFnReturningData {
signal_identitykeypair_sign_alternate_identity($0, publicKey.const(), privateKey.const(), other.const())
signal_identitykeypair_sign_alternate_identity(
$0,
publicKey.const(),
privateKey.const(),
other.const()
)
}
}
}

View File

@@ -38,7 +38,9 @@ public class IncrementalMacContext: NativeHandleOwner<SignalMutPointerIncrementa
self.chunkSizeInBytes = chunkSize
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerIncrementalMac>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerIncrementalMac>
) -> SignalFfiErrorRef? {
return signal_incremental_mac_destroy(handle.pointer)
}
@@ -97,7 +99,9 @@ public class ValidatingMacContext: NativeHandleOwner<SignalMutPointerValidatingM
self.init(owned: NonNull(handle)!)
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerValidatingMac>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerValidatingMac>
) -> SignalFfiErrorRef? {
return signal_validating_mac_destroy(handle.pointer)
}

View File

@@ -6,7 +6,10 @@
import Foundation
import SignalFfi
internal func withInputStream<Result>(_ stream: SignalInputStream, _ body: (SignalConstPointerFfiInputStreamStruct) throws -> Result) throws -> Result {
internal func withInputStream<Result>(
_ stream: SignalInputStream,
_ body: (SignalConstPointerFfiInputStreamStruct) throws -> Result
) throws -> Result {
func ffiShimRead(
stream_ctx: UnsafeMutableRawPointer?,
pBuf: UnsafeMutablePointer<UInt8>?,

View File

@@ -18,12 +18,14 @@ public func hkdf(
try inputKeyMaterial.withUnsafeBorrowedBuffer { inputBuffer in
try salt.withUnsafeBorrowedBuffer { saltBuffer in
try info.withUnsafeBorrowedBuffer { infoBuffer in
try checkError(signal_hkdf_derive(
.init(outputBuffer),
inputBuffer,
infoBuffer,
saltBuffer
))
try checkError(
signal_hkdf_derive(
.init(outputBuffer),
inputBuffer,
infoBuffer,
saltBuffer
)
)
}
}
}

View File

@@ -15,11 +15,16 @@ public class KEMKeyPair: ClonableHandleOwner<SignalMutPointerKyberKeyPair>, @unc
}
}
override internal class func cloneNativeHandle(_ newHandle: inout SignalMutPointerKyberKeyPair, currentHandle: SignalConstPointerKyberKeyPair) -> SignalFfiErrorRef? {
override internal class func cloneNativeHandle(
_ newHandle: inout SignalMutPointerKyberKeyPair,
currentHandle: SignalConstPointerKyberKeyPair
) -> SignalFfiErrorRef? {
return signal_kyber_key_pair_clone(&newHandle, currentHandle)
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerKyberKeyPair>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerKyberKeyPair>
) -> SignalFfiErrorRef? {
return signal_kyber_key_pair_destroy(handle.pointer)
}
@@ -76,11 +81,16 @@ public class KEMPublicKey: ClonableHandleOwner<SignalMutPointerKyberPublicKey>,
self.init(owned: NonNull(handle)!)
}
override internal class func cloneNativeHandle(_ newHandle: inout SignalMutPointerKyberPublicKey, currentHandle: SignalConstPointerKyberPublicKey) -> SignalFfiErrorRef? {
override internal class func cloneNativeHandle(
_ newHandle: inout SignalMutPointerKyberPublicKey,
currentHandle: SignalConstPointerKyberPublicKey
) -> SignalFfiErrorRef? {
return signal_kyber_public_key_clone(&newHandle, currentHandle)
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerKyberPublicKey>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerKyberPublicKey>
) -> SignalFfiErrorRef? {
return signal_kyber_public_key_destroy(handle.pointer)
}
@@ -139,11 +149,16 @@ public class KEMSecretKey: ClonableHandleOwner<SignalMutPointerKyberSecretKey>,
self.init(owned: NonNull(handle)!)
}
override internal class func cloneNativeHandle(_ newHandle: inout SignalMutPointerKyberSecretKey, currentHandle: SignalConstPointerKyberSecretKey) -> SignalFfiErrorRef? {
override internal class func cloneNativeHandle(
_ newHandle: inout SignalMutPointerKyberSecretKey,
currentHandle: SignalConstPointerKyberSecretKey
) -> SignalFfiErrorRef? {
return signal_kyber_secret_key_clone(&newHandle, currentHandle)
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerKyberSecretKey>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerKyberSecretKey>
) -> SignalFfiErrorRef? {
return signal_kyber_secret_key_destroy(handle.pointer)
}

View File

@@ -66,21 +66,24 @@ extension LibsignalLogger {
public func setUpLibsignalLogging(level: LibsignalLogLevel) {
let bridge = LoggerBridge(logger: self)
let opaqueBridge = Unmanaged.passRetained(bridge)
let success = signal_init_logger(level.asFFI, SignalFfiLogger(
ctx: opaqueBridge.toOpaque(),
log: { ctx, ffiLevel, file, line, message in
let bridge: LoggerBridge = Unmanaged.fromOpaque(ctx!).takeUnretainedValue()
// Unknown log levels might have personal info in them, so map them to something low.
let level = LibsignalLogLevel(ffiLevel) ?? .debug
"".withCString { emptyStringPtr in
bridge.logger.log(level: level, file: file, line: line, message: message ?? emptyStringPtr)
let success = signal_init_logger(
level.asFFI,
SignalFfiLogger(
ctx: opaqueBridge.toOpaque(),
log: { ctx, ffiLevel, file, line, message in
let bridge: LoggerBridge = Unmanaged.fromOpaque(ctx!).takeUnretainedValue()
// Unknown log levels might have personal info in them, so map them to something low.
let level = LibsignalLogLevel(ffiLevel) ?? .debug
"".withCString { emptyStringPtr in
bridge.logger.log(level: level, file: file, line: line, message: message ?? emptyStringPtr)
}
},
flush: { ctx in
let bridge: LoggerBridge = Unmanaged.fromOpaque(ctx!).takeUnretainedValue()
bridge.logger.flush()
}
},
flush: { ctx in
let bridge: LoggerBridge = Unmanaged.fromOpaque(ctx!).takeUnretainedValue()
bridge.logger.flush()
}
))
)
)
if success {
// We save this for use within the Swift code as well,
// but only if it was registered as the Rust logger successfully.

View File

@@ -69,7 +69,10 @@ public func sanitizeWebp(input: SignalInputStream) throws {
}
public class SanitizedMetadata: ClonableHandleOwner<OpaquePointer?> {
override internal class func cloneNativeHandle(_ newHandle: inout OpaquePointer?, currentHandle: OpaquePointer?) -> SignalFfiErrorRef? {
override internal class func cloneNativeHandle(
_ newHandle: inout OpaquePointer?,
currentHandle: OpaquePointer?
) -> SignalFfiErrorRef? {
return signal_sanitized_metadata_clone(&newHandle, currentHandle)
}

View File

@@ -34,7 +34,9 @@ public class MessageBackupKey: NativeHandleOwner<SignalMutPointerMessageBackupKe
let handle = try backupKey.withUnsafePointerToSerialized { backupKey in
try backupId.withUnsafePointerToSerialized { backupId in
var outputHandle = SignalMutPointerMessageBackupKey()
try checkError(signal_message_backup_key_from_backup_key_and_backup_id(&outputHandle, backupKey, backupId))
try checkError(
signal_message_backup_key_from_backup_key_and_backup_id(&outputHandle, backupKey, backupId)
)
return outputHandle
}
}
@@ -45,7 +47,9 @@ public class MessageBackupKey: NativeHandleOwner<SignalMutPointerMessageBackupKe
super.init(owned: handle)
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerMessageBackupKey>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerMessageBackupKey>
) -> SignalFfiErrorRef? {
signal_message_backup_key_destroy(handle.pointer)
}
@@ -96,7 +100,8 @@ extension SignalConstPointerMessageBackupKey: SignalConstPointer {
public enum MessageBackupPurpose: UInt8, Sendable {
// This needs to be kept in sync with the Rust version of the enum.
case deviceTransfer = 0, remoteBackup = 1
case deviceTransfer = 0
case remoteBackup = 1
}
/// Validates a message backup file.
@@ -115,13 +120,23 @@ public enum MessageBackupPurpose: UInt8, Sendable {
///
/// - SeeAlso: ``OnlineBackupValidator``
public func validateMessageBackup(
key: MessageBackupKey, purpose: MessageBackupPurpose, length: UInt64, makeStream: () throws -> SignalInputStream
key: MessageBackupKey,
purpose: MessageBackupPurpose,
length: UInt64,
makeStream: () throws -> SignalInputStream
) throws -> MessageBackupUnknownFields {
let outcome: ValidationOutcome = try withInputStream(try makeStream()) { firstInput in
try withInputStream(try makeStream()) { secondInput in
try key.withNativeHandle { key in
try invokeFnReturningNativeHandle {
signal_message_backup_validator_validate($0, key.const(), firstInput, secondInput, length, purpose.rawValue)
signal_message_backup_validator_validate(
$0,
key.const(),
firstInput,
secondInput,
length,
purpose.rawValue
)
}
}
}
@@ -170,7 +185,9 @@ public class OnlineBackupValidator: NativeHandleOwner<SignalMutPointerOnlineBack
super.init(owned: handle)
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerOnlineBackupValidator>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerOnlineBackupValidator>
) -> SignalFfiErrorRef? {
signal_online_backup_validator_destroy(handle.pointer)
}
@@ -248,7 +265,9 @@ private class ValidationOutcome: NativeHandleOwner<SignalMutPointerMessageBackup
}
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerMessageBackupValidationOutcome>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerMessageBackupValidationOutcome>
) -> SignalFfiErrorRef? {
signal_message_backup_validation_outcome_destroy(handle.pointer)
}
}

View File

@@ -152,7 +152,10 @@ public class ClonableHandleOwner<PointerType: SignalMutPointer>: NativeHandleOwn
handle = nil
}
internal class func cloneNativeHandle(_: inout PointerType, currentHandle: PointerType.ConstPointer) -> SignalFfiErrorRef? {
internal class func cloneNativeHandle(
_: inout PointerType,
currentHandle: PointerType.ConstPointer
) -> SignalFfiErrorRef? {
fatalError("must be implemented by subclasses")
}
}
@@ -173,7 +176,9 @@ internal func cloneOrForgetAsNeeded<Owner: ClonableHandleOwner<PointerType>, Poi
///
/// As an optimization, steals the handle if `handleOwner` has no other references.
/// Checking this requires using `inout`; the reference itself won't be modified.
internal func cloneOrTakeHandle<Owner: ClonableHandleOwner<PointerType>, PointerType>(from handleOwner: inout Owner) throws -> PointerType {
internal func cloneOrTakeHandle<Owner: ClonableHandleOwner<PointerType>, PointerType>(
from handleOwner: inout Owner
) throws -> PointerType {
if isKnownUniquelyReferenced(&handleOwner) {
return handleOwner.takeNativeHandle()
}

View File

@@ -46,8 +46,20 @@ public class Net {
///
/// - Throws: if the scheme is unsupported or if the provided parameters are invalid for that scheme
/// (e.g. Signal TLS proxies don't support authentication)
public func setProxy(scheme: String, host: String, port: UInt16? = nil, username: String? = nil, password: String? = nil) throws {
try self.connectionManager.setProxy(scheme: scheme, host: host, port: port, username: username, password: password)
public func setProxy(
scheme: String,
host: String,
port: UInt16? = nil,
username: String? = nil,
password: String? = nil
) throws {
try self.connectionManager.setProxy(
scheme: scheme,
host: host,
port: port,
username: username,
password: password
)
}
/// Sets the Signal TLS proxy host to be used for all new connections (until overridden).
@@ -64,13 +76,20 @@ public class Net {
// Support <username>@<host> syntax to allow UNENCRYPTED_FOR_TESTING as a marker user.
// This is not a stable feature of the API and may go away in the future;
// the Rust layer will reject any other users anyway. But it's convenient for us.
let (username, host): (String?, String) = if let atSign = host.firstIndex(of: "@") {
(String(host[..<atSign]), String(host[atSign...].dropFirst()))
} else {
(nil, host)
}
let (username, host): (String?, String) =
if let atSign = host.firstIndex(of: "@") {
(String(host[..<atSign]), String(host[atSign...].dropFirst()))
} else {
(nil, host)
}
try self.connectionManager.setProxy(scheme: Net.signalTlsProxyScheme, host: host, port: port, username: username, password: nil)
try self.connectionManager.setProxy(
scheme: Net.signalTlsProxyScheme,
host: host,
port: port,
username: username,
password: nil
)
}
/// Refuses to make any new connections until a new proxy configuration is set or
@@ -139,7 +158,12 @@ public class Net {
acisAndAccessKeys: [AciAndAccessKey],
token: Data?
) async throws -> CdsiLookup {
let request = try CdsiLookupRequest(e164s: e164s, prevE164s: prevE164s, acisAndAccessKeys: acisAndAccessKeys, token: token)
let request = try CdsiLookupRequest(
e164s: e164s,
prevE164s: prevE164s,
acisAndAccessKeys: acisAndAccessKeys,
token: token
)
return try await self.cdsiLookup(auth: auth, request: request)
}
@@ -191,7 +215,14 @@ public class Net {
let handle = try await self.asyncContext.invokeAsyncFunction { promise, asyncContext in
self.connectionManager.withNativeHandle { connectionManager in
request.withNativeHandle { request in
signal_cdsi_lookup_new(promise, asyncContext.const(), connectionManager.const(), auth.username, auth.password, request.const())
signal_cdsi_lookup_new(
promise,
asyncContext.const(),
connectionManager.const(),
auth.username,
auth.password,
request.const()
)
}
}
}
@@ -240,8 +271,18 @@ public class Net {
///
/// - Returns:
/// An object representing the established, but not yet active, connection.
public func connectAuthenticatedChat(username: String, password: String, receiveStories: Bool) async throws -> AuthenticatedChatConnection {
return try await AuthenticatedChatConnection(tokioAsyncContext: self.asyncContext, connectionManager: self.connectionManager, username: username, password: password, receiveStories: receiveStories)
public func connectAuthenticatedChat(
username: String,
password: String,
receiveStories: Bool
) async throws -> AuthenticatedChatConnection {
return try await AuthenticatedChatConnection(
tokioAsyncContext: self.asyncContext,
connectionManager: self.connectionManager,
username: username,
password: password,
receiveStories: receiveStories
)
}
/// Asynchronously establishes an unauthenticated connection to the remote
@@ -265,7 +306,7 @@ public class Net {
return try await UnauthenticatedChatConnection(
tokioAsyncContext: self.asyncContext,
connectionManager:
self.connectionManager,
self.connectionManager,
environment: self.environment
)
}
@@ -299,7 +340,9 @@ extension Auth {
internal class ConnectionManager: NativeHandleOwner<SignalMutPointerConnectionManager> {
private class ProxyConfig: NativeHandleOwner<SignalMutPointerConnectionProxyConfig> {
override class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerConnectionProxyConfig>) -> SignalFfiErrorRef? {
override class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerConnectionProxyConfig>
) -> SignalFfiErrorRef? {
signal_connection_proxy_config_destroy(handle.pointer)
}
}
@@ -363,7 +406,9 @@ internal class ConnectionManager: NativeHandleOwner<SignalMutPointerConnectionMa
}
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerConnectionManager>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerConnectionManager>
) -> SignalFfiErrorRef? {
signal_connection_manager_destroy(handle.pointer)
}
}

View File

@@ -24,11 +24,16 @@ public class PrivateKey: ClonableHandleOwner<SignalMutPointerPrivateKey>, @unche
}
}
override internal class func cloneNativeHandle(_ newHandle: inout SignalMutPointerPrivateKey, currentHandle: SignalConstPointerPrivateKey) -> SignalFfiErrorRef? {
override internal class func cloneNativeHandle(
_ newHandle: inout SignalMutPointerPrivateKey,
currentHandle: SignalConstPointerPrivateKey
) -> SignalFfiErrorRef? {
return signal_privatekey_clone(&newHandle, currentHandle)
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerPrivateKey>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerPrivateKey>
) -> SignalFfiErrorRef? {
return signal_privatekey_destroy(handle.pointer)
}

View File

@@ -18,7 +18,14 @@ public func signalEncrypt<Bytes: ContiguousBytes>(
try withSessionStore(sessionStore, context) { ffiSessionStore in
try withIdentityKeyStore(identityStore, context) { ffiIdentityStore in
try invokeFnReturningNativeHandle {
signal_encrypt_message($0, messageBuffer, addressHandle.const(), ffiSessionStore, ffiIdentityStore, UInt64(now.timeIntervalSince1970 * 1000))
signal_encrypt_message(
$0,
messageBuffer,
addressHandle.const(),
ffiSessionStore,
ffiIdentityStore,
UInt64(now.timeIntervalSince1970 * 1000)
)
}
}
}
@@ -36,7 +43,13 @@ public func signalDecrypt(
try withSessionStore(sessionStore, context) { ffiSessionStore in
try withIdentityKeyStore(identityStore, context) { ffiIdentityStore in
try invokeFnReturningData {
signal_decrypt_message($0, messageHandle.const(), addressHandle.const(), ffiSessionStore, ffiIdentityStore)
signal_decrypt_message(
$0,
messageHandle.const(),
addressHandle.const(),
ffiSessionStore,
ffiIdentityStore
)
}
}
}
@@ -61,7 +74,17 @@ public func signalDecryptPreKey(
try withSignedPreKeyStore(signedPreKeyStore, context) { ffiSignedPreKeyStore in
try withKyberPreKeyStore(kyberPreKeyStore, context) { ffiKyberPreKeyStore in
try invokeFnReturningData {
signal_decrypt_pre_key_message($0, messageHandle.const(), addressHandle.const(), ffiSessionStore, ffiIdentityStore, ffiPreKeyStore, ffiSignedPreKeyStore, ffiKyberPreKeyStore, usePqRatchet)
signal_decrypt_pre_key_message(
$0,
messageHandle.const(),
addressHandle.const(),
ffiSessionStore,
ffiIdentityStore,
ffiPreKeyStore,
ffiSignedPreKeyStore,
ffiKyberPreKeyStore,
usePqRatchet
)
}
}
}
@@ -83,7 +106,16 @@ public func processPreKeyBundle(
return try withAllBorrowed(bundle, address) { bundleHandle, addressHandle in
try withSessionStore(sessionStore, context) { ffiSessionStore in
try withIdentityKeyStore(identityStore, context) { ffiIdentityStore in
try checkError(signal_process_prekey_bundle(bundleHandle.const(), addressHandle.const(), ffiSessionStore, ffiIdentityStore, UInt64(now.timeIntervalSince1970 * 1000), usePqRatchet))
try checkError(
signal_process_prekey_bundle(
bundleHandle.const(),
addressHandle.const(),
ffiSessionStore,
ffiIdentityStore,
UInt64(now.timeIntervalSince1970 * 1000),
usePqRatchet
)
)
}
}
}
@@ -128,11 +160,13 @@ public func processSenderKeyDistributionMessage(
) throws {
return try withAllBorrowed(sender, message) { senderHandle, messageHandle in
try withSenderKeyStore(store, context) {
try checkError(signal_process_sender_key_distribution_message(
senderHandle.const(),
messageHandle.const(),
$0
))
try checkError(
signal_process_sender_key_distribution_message(
senderHandle.const(),
messageHandle.const(),
$0
)
)
}
}
}

View File

@@ -16,11 +16,15 @@ public class PublicKey: ClonableHandleOwner<SignalMutPointerPublicKey>, @uncheck
self.init(owned: NonNull(handle)!)
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerPublicKey>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerPublicKey>) -> SignalFfiErrorRef?
{
return signal_publickey_destroy(handle.pointer)
}
override internal class func cloneNativeHandle(_ newHandle: inout SignalMutPointerPublicKey, currentHandle: SignalConstPointerPublicKey) -> SignalFfiErrorRef? {
override internal class func cloneNativeHandle(
_ newHandle: inout SignalMutPointerPublicKey,
currentHandle: SignalConstPointerPublicKey
) -> SignalFfiErrorRef? {
return signal_publickey_clone(&newHandle, currentHandle)
}

View File

@@ -71,7 +71,9 @@ public enum RegistrationError: Error {
public class RegistrationService: NativeHandleOwner<SignalMutPointerRegistrationService>, @unchecked Sendable {
private let asyncContext: TokioAsyncContext
override internal class func destroyNativeHandle(_ nativeHandle: NonNull<SignalMutPointerRegistrationService>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ nativeHandle: NonNull<SignalMutPointerRegistrationService>
) -> SignalFfiErrorRef? {
signal_registration_service_destroy(nativeHandle.pointer)
}
@@ -107,7 +109,10 @@ public class RegistrationService: NativeHandleOwner<SignalMutPointerRegistration
let service: SignalMutPointerRegistrationService =
try await net.asyncContext.invokeAsyncFunction { promise, tokioContext in
SignalFfiRegistrationCreateSessionRequest.withNativeStruct(
e164: e164, pushToken: pushToken, mcc: mcc, mnc: mnc
e164: e164,
pushToken: pushToken,
mcc: mcc,
mnc: mnc
) { request in
withUnsafePointer(to: connectChatBridge) { connectChatBridge in
signal_registration_service_create_session(
@@ -115,7 +120,8 @@ public class RegistrationService: NativeHandleOwner<SignalMutPointerRegistration
tokioContext.const(),
request,
SignalConstPointerFfiConnectChatBridgeStruct(
raw: connectChatBridge)
raw: connectChatBridge
)
)
}
}
@@ -150,9 +156,11 @@ public class RegistrationService: NativeHandleOwner<SignalMutPointerRegistration
signal_registration_service_resume_session(
promise,
tokioContext.const(),
sessionId, number,
sessionId,
number,
SignalConstPointerFfiConnectChatBridgeStruct(
raw: connectChatBridge)
raw: connectChatBridge
)
)
}
}
@@ -170,7 +178,13 @@ public class RegistrationService: NativeHandleOwner<SignalMutPointerRegistration
public func requestPushChallenge(apnPushToken: String) async throws {
let _: Bool = try await self.asyncContext.invokeAsyncFunction { promise, asyncContext in
self.withNativeHandle {
signal_registration_service_request_push_challenge(promise, asyncContext.const(), $0.const(), apnPushToken, nil)
signal_registration_service_request_push_challenge(
promise,
asyncContext.const(),
$0.const(),
apnPushToken,
nil
)
}
}
}
@@ -186,7 +200,12 @@ public class RegistrationService: NativeHandleOwner<SignalMutPointerRegistration
public func submitPushChallenge(pushChallenge: String) async throws {
let _: Bool = try await self.asyncContext.invokeAsyncFunction { promise, asyncContext in
self.withNativeHandle {
signal_registration_service_submit_push_challenge(promise, asyncContext.const(), $0.const(), pushChallenge)
signal_registration_service_submit_push_challenge(
promise,
asyncContext.const(),
$0.const(),
pushChallenge
)
}
}
}
@@ -211,8 +230,12 @@ public class RegistrationService: NativeHandleOwner<SignalMutPointerRegistration
languages.withUnsafeBorrowedBytestringArray { languages in
self.withNativeHandle {
signal_registration_service_request_verification_code(
promise, asyncContext.const(), $0.const(), transport.description,
client, languages
promise,
asyncContext.const(),
$0.const(),
transport.description,
client,
languages
)
}
}
@@ -232,7 +255,10 @@ public class RegistrationService: NativeHandleOwner<SignalMutPointerRegistration
let _: Bool = try await self.asyncContext.invokeAsyncFunction { promise, asyncContext in
self.withNativeHandle {
signal_registration_service_submit_verification_code(
promise, asyncContext.const(), $0.const(), code
promise,
asyncContext.const(),
$0.const(),
code
)
}
}
@@ -250,7 +276,10 @@ public class RegistrationService: NativeHandleOwner<SignalMutPointerRegistration
let _: Bool = try await self.asyncContext.invokeAsyncFunction { promise, asyncContext in
self.withNativeHandle {
signal_registration_service_submit_verification_code(
promise, asyncContext.const(), $0.const(), captchaValue
promise,
asyncContext.const(),
$0.const(),
captchaValue
)
}
}
@@ -271,7 +300,12 @@ public class RegistrationService: NativeHandleOwner<SignalMutPointerRegistration
var result = try await self.asyncContext.invokeAsyncFunction { promise, asyncContext in
svrTokens.withUnsafeBorrowedBytestringArray { svrTokens in
self.withNativeHandle {
signal_registration_service_check_svr2_credentials(promise, asyncContext.const(), $0.const(), svrTokens)
signal_registration_service_check_svr2_credentials(
promise,
asyncContext.const(),
$0.const(),
svrTokens
)
}
}
}
@@ -343,7 +377,13 @@ public class RegistrationService: NativeHandleOwner<SignalMutPointerRegistration
self.withNativeHandle { registrationService in
request.withNativeHandle { request in
accountAttributes.withNativeHandle { accountAttributes in
signal_registration_service_register_account(promise, asyncContext.const(), registrationService.const(), request.const(), accountAttributes.const())
signal_registration_service_register_account(
promise,
asyncContext.const(),
registrationService.const(),
request.const(),
accountAttributes.const()
)
}
}
}
@@ -417,233 +457,6 @@ public class RegistrationService: NativeHandleOwner<SignalMutPointerRegistration
}
}
public class RegistrationSessionState: NativeHandleOwner<SignalMutPointerRegistrationSession> {
override internal class func destroyNativeHandle(
_ nativeHandle: NonNull<SignalMutPointerRegistrationSession>
) -> SignalFfiErrorRef? {
signal_registration_session_destroy(nativeHandle.pointer)
}
public var allowedToRequestCode: Bool {
return failOnError {
try invokeFnReturningBool { out in
self.withNativeHandle {
signal_registration_session_get_allowed_to_request_code(out, $0.const())
}
}
}
}
public var verified: Bool {
return failOnError {
try invokeFnReturningBool { out in
self.withNativeHandle {
signal_registration_session_get_verified(out, $0.const())
}
}
}
}
public var nextSms: TimeInterval? {
return failOnError {
try invokeFnReturningOptionalInteger { out in
self.withNativeHandle {
signal_registration_session_get_next_sms_seconds(out, $0.const())
}
}.map { TimeInterval($0) }
}
}
public var nextCall: TimeInterval? {
return failOnError {
try invokeFnReturningOptionalInteger { out in
self.withNativeHandle {
signal_registration_session_get_next_call_seconds(out, $0.const())
}
}.map { TimeInterval($0) }
}
}
public var nextVerificationAttempt: TimeInterval? {
return failOnError {
try invokeFnReturningOptionalInteger { out in
self.withNativeHandle {
signal_registration_session_get_next_verification_attempt_seconds(out, $0.const())
}
}.map { TimeInterval($0) }
}
}
public var requestedInformation: Set<ChallengeOption> {
return failOnError {
let items = try invokeFnReturningData { out in
self.withNativeHandle {
signal_registration_session_get_requested_information(out, $0.const())
}
}
return Set(try items.map { try ChallengeOption(fromNative: $0) })
}
}
}
extension ChallengeOption {
internal init(fromNative value: UInt8) throws {
self = switch UInt32(value) {
case SignalChallengeOptionCaptcha.rawValue:
.captcha
case SignalChallengeOptionPushChallenge.rawValue:
.pushChallenge
default:
throw SignalError.internalError("unknown requested information")
}
}
}
public class RegisterAccountResponse: NativeHandleOwner<SignalMutPointerRegisterAccountResponse>, @unchecked Sendable {
override internal class func destroyNativeHandle(_ nativeHandle: NonNull<SignalMutPointerRegisterAccountResponse>) -> SignalFfiErrorRef? {
signal_register_account_response_destroy(nativeHandle.pointer)
}
public var aci: Aci {
return failOnError {
try self.withNativeHandle { native in
try invokeFnReturningServiceId {
signal_register_account_response_get_identity($0, native.const(), ServiceIdKind.aci.rawValue)
}
}
}
}
public var pni: Pni {
return failOnError {
try self.withNativeHandle { native in
try invokeFnReturningServiceId {
signal_register_account_response_get_identity($0, native.const(), ServiceIdKind.pni.rawValue)
}
}
}
}
public var number: String {
return failOnError {
try self.withNativeHandle { native in
try invokeFnReturningString {
signal_register_account_response_get_number($0, native.const())
}
}
}
}
public var usernameHash: Data? {
return failOnError {
try self.withNativeHandle { native in
try invokeFnReturningOptionalArray {
signal_register_account_response_get_username_hash($0, native.const())
}
}
}
}
public var usernameLinkHandle: UUID? {
return failOnError {
try self.withNativeHandle { native in
try invokeFnReturningOptionalUuid {
signal_register_account_response_get_username_link_handle($0, native.const())
}
}
}
}
public var storageCapable: Bool {
return failOnError {
try self.withNativeHandle { native in
try invokeFnReturningBool {
signal_register_account_response_get_storage_capable($0, native.const())
}
}
}
}
public var reregistration: Bool {
return failOnError {
try self.withNativeHandle { native in
try invokeFnReturningBool {
signal_register_account_response_get_reregistration($0, native.const())
}
}
}
}
public var entitlements: ([BadgeEntitlement], BackupEntitlement?) {
return failOnError {
try self.withNativeHandle { native in
let badges = try invokeFnReturningBadgeEntitlementArray {
signal_register_account_response_get_entitlement_badges($0, native.const())
}
let backup = try BackupEntitlement(fromResponse: native.const())
return (badges, backup)
}
}
}
}
public struct BadgeEntitlement: Equatable {
public let id: String
public let visible: Bool
public let expiration: TimeInterval
}
public struct BackupEntitlement: Equatable {
public let expiration: TimeInterval
public let level: UInt64
public init(expiration: TimeInterval, level: UInt64) {
self.expiration = expiration
self.level = level
}
fileprivate init?(fromResponse native: SignalConstPointerRegisterAccountResponse) throws {
let backupExpiration = try invokeFnReturningOptionalInteger {
signal_register_account_response_get_entitlement_backup_expiration_seconds($0, native)
}
guard case .some(let expiration) = backupExpiration else {
return nil
}
let level = try invokeFnReturningOptionalInteger {
signal_register_account_response_get_entitlement_backup_level($0, native)
}
guard case .some(let level) = level else {
return nil
}
self.init(expiration: TimeInterval(expiration), level: level)
}
}
public enum VerificationTransport: CustomStringConvertible {
case voice
case sms
public var description: String {
return switch self {
case .voice: "voice"
case .sms: "sms"
}
}
}
public enum Svr2CredentialsResult {
case match
case noMatch
case invalid
}
public enum ChallengeOption: Hashable, Sendable {
case captcha
case pushChallenge
}
private class RegisterAccountRequst: NativeHandleOwner<SignalMutPointerRegisterAccountRequest> {
override internal class func destroyNativeHandle(
_ nativeHandle: NonNull<SignalMutPointerRegisterAccountRequest>
@@ -662,41 +475,83 @@ private class RegisterAccountRequst: NativeHandleOwner<SignalMutPointerRegisterA
aciPqSignedPreKey: SignedPublicPreKey<KEMPublicKey>,
pniPqSignedPreKey: SignedPublicPreKey<KEMPublicKey>
) -> Self {
let request: Self = failOnError { try invokeFnReturningNativeHandle {
signal_register_account_request_create($0)
} }
let request: Self = failOnError {
try invokeFnReturningNativeHandle {
signal_register_account_request_create($0)
}
}
failOnError {
try request.withNativeHandle { native in
try checkError(accountPassword.withCString {
signal_register_account_request_set_account_password(native.const(), $0)
})
try checkError(
accountPassword.withCString {
signal_register_account_request_set_account_password(native.const(), $0)
}
)
if let apnPushToken {
try checkError(apnPushToken.withCString {
signal_register_account_request_set_apn_push_token(native.const(), $0)
})
try checkError(
apnPushToken.withCString {
signal_register_account_request_set_apn_push_token(native.const(), $0)
}
)
}
if skipDeviceTransfer {
try checkError(signal_register_account_request_set_skip_device_transfer(native.const()))
}
try checkError(aciIdentityKey.withNativeHandle {
signal_register_account_request_set_identity_public_key(native.const(), ServiceIdKind.aci.rawValue, $0.const())
})
try checkError(pniIdentityKey.withNativeHandle {
signal_register_account_request_set_identity_public_key(native.const(), ServiceIdKind.pni.rawValue, $0.const())
})
try checkError(aciSignedPreKey.withNativeStruct {
signal_register_account_request_set_identity_signed_pre_key(native.const(), ServiceIdKind.aci.rawValue, $0)
})
try checkError(pniSignedPreKey.withNativeStruct {
signal_register_account_request_set_identity_signed_pre_key(native.const(), ServiceIdKind.pni.rawValue, $0)
})
try checkError(aciPqSignedPreKey.withNativeStruct {
signal_register_account_request_set_identity_pq_last_resort_pre_key(native.const(), ServiceIdKind.aci.rawValue, $0)
})
try checkError(pniPqSignedPreKey.withNativeStruct {
signal_register_account_request_set_identity_pq_last_resort_pre_key(native.const(), ServiceIdKind.pni.rawValue, $0)
})
try checkError(
aciIdentityKey.withNativeHandle {
signal_register_account_request_set_identity_public_key(
native.const(),
ServiceIdKind.aci.rawValue,
$0.const()
)
}
)
try checkError(
pniIdentityKey.withNativeHandle {
signal_register_account_request_set_identity_public_key(
native.const(),
ServiceIdKind.pni.rawValue,
$0.const()
)
}
)
try checkError(
aciSignedPreKey.withNativeStruct {
signal_register_account_request_set_identity_signed_pre_key(
native.const(),
ServiceIdKind.aci.rawValue,
$0
)
}
)
try checkError(
pniSignedPreKey.withNativeStruct {
signal_register_account_request_set_identity_signed_pre_key(
native.const(),
ServiceIdKind.pni.rawValue,
$0
)
}
)
try checkError(
aciPqSignedPreKey.withNativeStruct {
signal_register_account_request_set_identity_pq_last_resort_pre_key(
native.const(),
ServiceIdKind.aci.rawValue,
$0
)
}
)
try checkError(
pniPqSignedPreKey.withNativeStruct {
signal_register_account_request_set_identity_pq_last_resort_pre_key(
native.const(),
ServiceIdKind.pni.rawValue,
$0
)
}
)
}
}
@@ -704,59 +559,6 @@ private class RegisterAccountRequst: NativeHandleOwner<SignalMutPointerRegisterA
}
}
/// Account attributes sent as part of a ``RegistrationService/registerAccount(accountPassword:skipDeviceTransfer:accountAttributes:apnPushToken:aciPublicKey:pniPublicKey:aciSignedPreKey:pniSignedPreKey:aciPqLastResortPreKey:pniPqLastResortPreKey:)`` request.
public class RegisterAccountAttributes: NativeHandleOwner<SignalMutPointerRegistrationAccountAttributes> {
/// Constructs the set of attributes to pass to the server.
/// - Throws: ``SignalError/invalidArgument(_:)`` if the `unidentifiedAccessKey` is not 16 bytes.
public convenience init(
recoveryPassword: Data,
aciRegistrationId: UInt16,
pniRegistrationId: UInt16,
registrationLock: String?,
unidentifiedAccessKey: Data,
unrestrictedUnidentifiedAccess: Bool,
capabilities: [String],
discoverableByPhoneNumber: Bool
) throws {
var uak = SignalUnidentifiedAccessKey(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
try withUnsafeMutableBytes(of: &uak) { uakBytes in
if uakBytes.count != unidentifiedAccessKey.count {
throw SignalError.invalidArgument("unidentifiedAccessKey has \(unidentifiedAccessKey.count) bytes; expected \(uakBytes.count)")
}
uakBytes.copyBytes(from: unidentifiedAccessKey)
}
let nativeHandle = failOnError {
try recoveryPassword.withUnsafeBorrowedBuffer { recoveryPassword in
try registrationLock.withCString { registrationLock in
try withUnsafePointer(to: &uak) { unidentifiedAccessKey in
try capabilities.withUnsafeBorrowedBytestringArray { capabilities in
var nativeHandle = SignalMutPointerRegistrationAccountAttributes()
try checkError(
signal_registration_account_attributes_create(
&nativeHandle,
recoveryPassword,
aciRegistrationId,
pniRegistrationId,
registrationLock,
unidentifiedAccessKey,
unrestrictedUnidentifiedAccess,
capabilities,
discoverableByPhoneNumber
))
return nativeHandle
}
}
}
}
}
self.init(owned: NonNull(nativeHandle)!)
}
override internal class func destroyNativeHandle(_ nativeHandle: NonNull<SignalMutPointerRegistrationAccountAttributes>) -> SignalFfiErrorRef? {
signal_registration_account_attributes_destroy(nativeHandle.pointer)
}
}
extension SignalFfiConnectChatBridgeStruct {
/// Constructs a ``SignalFfiConnectChatBridgeStruct`` that uses the given
/// ``ConnectionManager`` to create chat connections.
@@ -776,77 +578,40 @@ extension SignalFfiConnectChatBridgeStruct {
}
}
extension SignalFfiRegistrationCreateSessionRequest {
internal static func withNativeStruct<Result>(
e164: String,
pushToken: String?,
mcc: String?,
mnc: String?,
_ fn: (Self) throws -> Result
) rethrows -> Result {
try e164.withCString { e164 in
try pushToken.withCString { pushToken in
try mcc.withCString { mcc in
try mnc.withCString { mnc in
let request = SignalFfiRegistrationCreateSessionRequest(
number: e164, push_token: pushToken,
mcc: mcc, mnc: mnc
)
return try fn(request)
}
}
}
}
}
}
/// Invoke a function returning an unsigned integral result where `nil` is bridged as the maximum value.
///
/// Bridging `nil` as max isn't a convention we want to rely on generally. It's
/// true for the getters in this file, though, hence `fileprivate`.
private func invokeFnReturningOptionalInteger<Result: FixedWidthInteger & UnsignedInteger>(fn: (UnsafeMutablePointer<Result>?) -> SignalFfiErrorRef?) throws -> Result? {
let output = try invokeFnReturningInteger(fn: fn)
return if output == Result.max { nil } else { output }
}
private func invokeFnReturningBadgeEntitlementArray(fn: (_ out: UnsafeMutablePointer<SignalOwnedBufferOfFfiRegisterResponseBadge>) -> SignalFfiErrorRef?) throws -> [BadgeEntitlement] {
var out = SignalOwnedBufferOfFfiRegisterResponseBadge()
try checkError(fn(&out))
defer { signal_free_list_of_register_response_badges(out) }
return UnsafeBufferPointer(start: out.base, count: out.length).map {
BadgeEntitlement(id: String(cString: $0.id), visible: $0.visible, expiration: TimeInterval($0.expiration_secs))
}
}
// Exposed for testing.
internal func invokeFnReturningCheckSvr2CredentialsResponse(fn: (_ out: UnsafeMutablePointer<SignalFfiCheckSvr2CredentialsResponse>?) -> SignalFfiErrorRef?) throws -> [String: Svr2CredentialsResult] {
let entries = try invokeFnReturningSomeBytestringArray(fn: { out in
// This is just a named wrapper around a bytestring array.
var wrapper = SignalFfiCheckSvr2CredentialsResponse()
let err = fn(&wrapper)
// Copy the wrapped pointer into the provided output. The outer function
// will also take care of deallocating.
if err == nil {
out!.update(from: &wrapper.entries, count: 1)
internal func invokeFnReturningCheckSvr2CredentialsResponse(
fn: (_ out: UnsafeMutablePointer<SignalFfiCheckSvr2CredentialsResponse>?) -> SignalFfiErrorRef?
) throws -> [String: Svr2CredentialsResult] {
let entries = try invokeFnReturningSomeBytestringArray(
fn: { out in
// This is just a named wrapper around a bytestring array.
var wrapper = SignalFfiCheckSvr2CredentialsResponse()
let err = fn(&wrapper)
// Copy the wrapped pointer into the provided output. The outer function
// will also take care of deallocating.
if err == nil {
out!.update(from: &wrapper.entries, count: 1)
}
return err
},
transform: { view in
// The format for entries is a UTF-8 key with the value as a single byte at the end.
let key = String(decoding: view.dropLast(), as: Unicode.UTF8.self)
let valueByte = UInt32(view.last!)
let value =
switch SignalSvr2CredentialsResult(valueByte) {
case SignalSvr2CredentialsResultInvalid:
Svr2CredentialsResult.invalid
case SignalSvr2CredentialsResultMatch:
Svr2CredentialsResult.match
case SignalSvr2CredentialsResultNoMatch:
Svr2CredentialsResult.noMatch
default:
fatalError("unknown SVR2 credentials result value \(valueByte)")
}
return (key, value)
}
return err
}, transform: { view in
// The format for entries is a UTF-8 key with the value as a single byte at the end.
let key = String(decoding: view.dropLast(), as: Unicode.UTF8.self)
let valueByte = UInt32(view.last!)
let value = switch SignalSvr2CredentialsResult(valueByte) {
case SignalSvr2CredentialsResultInvalid:
Svr2CredentialsResult.invalid
case SignalSvr2CredentialsResultMatch:
Svr2CredentialsResult.match
case SignalSvr2CredentialsResultNoMatch:
Svr2CredentialsResult.noMatch
default:
fatalError("unknown SVR2 credentials result value \(valueByte)")
}
return (key, value)
})
)
return Dictionary(uniqueKeysWithValues: entries)
}
@@ -872,91 +637,3 @@ extension SignalConstPointerRegistrationService: SignalConstPointer {
self.raw
}
}
extension SignalMutPointerRegistrationSession: SignalMutPointer {
public typealias ConstPointer = SignalConstPointerRegistrationSession
public init(untyped: OpaquePointer?) {
self.init(raw: untyped)
}
public func toOpaque() -> OpaquePointer? {
self.raw
}
public func const() -> Self.ConstPointer {
SignalConstPointerRegistrationSession(raw: self.raw)
}
}
extension SignalConstPointerRegistrationSession: SignalConstPointer {
public func toOpaque() -> OpaquePointer? {
self.raw
}
}
extension SignalMutPointerRegisterAccountResponse: SignalMutPointer {
public typealias ConstPointer = SignalConstPointerRegisterAccountResponse
public init(untyped: OpaquePointer?) {
self.init(raw: untyped)
}
public func toOpaque() -> OpaquePointer? {
self.raw
}
public func const() -> Self.ConstPointer {
SignalConstPointerRegisterAccountResponse(raw: self.raw)
}
}
extension SignalConstPointerRegisterAccountResponse: SignalConstPointer {
public func toOpaque() -> OpaquePointer? {
self.raw
}
}
extension SignalMutPointerRegisterAccountRequest: SignalMutPointer {
public typealias ConstPointer = SignalConstPointerRegisterAccountRequest
public init(untyped: OpaquePointer?) {
self.init(raw: untyped)
}
public func toOpaque() -> OpaquePointer? {
self.raw
}
public func const() -> Self.ConstPointer {
SignalConstPointerRegisterAccountRequest(raw: self.raw)
}
}
extension SignalConstPointerRegisterAccountRequest: SignalConstPointer {
public func toOpaque() -> OpaquePointer? {
self.raw
}
}
extension SignalMutPointerRegistrationAccountAttributes: SignalMutPointer {
public typealias ConstPointer = SignalConstPointerRegistrationAccountAttributes
public init(untyped: OpaquePointer?) {
self.init(raw: untyped)
}
public func toOpaque() -> OpaquePointer? {
self.raw
}
public func const() -> Self.ConstPointer {
SignalConstPointerRegistrationAccountAttributes(raw: self.raw)
}
}
extension SignalConstPointerRegistrationAccountAttributes: SignalConstPointer {
public func toOpaque() -> OpaquePointer? {
self.raw
}
}

View File

@@ -0,0 +1,432 @@
//
// Copyright 2025 Signal Messenger, LLC.
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
import SignalFfi
public class RegistrationSessionState: NativeHandleOwner<SignalMutPointerRegistrationSession> {
override internal class func destroyNativeHandle(
_ nativeHandle: NonNull<SignalMutPointerRegistrationSession>
) -> SignalFfiErrorRef? {
signal_registration_session_destroy(nativeHandle.pointer)
}
public var allowedToRequestCode: Bool {
return failOnError {
try invokeFnReturningBool { out in
self.withNativeHandle {
signal_registration_session_get_allowed_to_request_code(out, $0.const())
}
}
}
}
public var verified: Bool {
return failOnError {
try invokeFnReturningBool { out in
self.withNativeHandle {
signal_registration_session_get_verified(out, $0.const())
}
}
}
}
public var nextSms: TimeInterval? {
return failOnError {
try invokeFnReturningOptionalInteger { out in
self.withNativeHandle {
signal_registration_session_get_next_sms_seconds(out, $0.const())
}
}.map { TimeInterval($0) }
}
}
public var nextCall: TimeInterval? {
return failOnError {
try invokeFnReturningOptionalInteger { out in
self.withNativeHandle {
signal_registration_session_get_next_call_seconds(out, $0.const())
}
}.map { TimeInterval($0) }
}
}
public var nextVerificationAttempt: TimeInterval? {
return failOnError {
try invokeFnReturningOptionalInteger { out in
self.withNativeHandle {
signal_registration_session_get_next_verification_attempt_seconds(out, $0.const())
}
}.map { TimeInterval($0) }
}
}
public var requestedInformation: Set<ChallengeOption> {
return failOnError {
let items = try invokeFnReturningData { out in
self.withNativeHandle {
signal_registration_session_get_requested_information(out, $0.const())
}
}
return Set(try items.map { try ChallengeOption(fromNative: $0) })
}
}
}
extension ChallengeOption {
internal init(fromNative value: UInt8) throws {
self =
switch UInt32(value) {
case SignalChallengeOptionCaptcha.rawValue:
.captcha
case SignalChallengeOptionPushChallenge.rawValue:
.pushChallenge
default:
throw SignalError.internalError("unknown requested information")
}
}
}
public class RegisterAccountResponse: NativeHandleOwner<SignalMutPointerRegisterAccountResponse>, @unchecked Sendable {
override internal class func destroyNativeHandle(
_ nativeHandle: NonNull<SignalMutPointerRegisterAccountResponse>
) -> SignalFfiErrorRef? {
signal_register_account_response_destroy(nativeHandle.pointer)
}
public var aci: Aci {
return failOnError {
try self.withNativeHandle { native in
try invokeFnReturningServiceId {
signal_register_account_response_get_identity($0, native.const(), ServiceIdKind.aci.rawValue)
}
}
}
}
public var pni: Pni {
return failOnError {
try self.withNativeHandle { native in
try invokeFnReturningServiceId {
signal_register_account_response_get_identity($0, native.const(), ServiceIdKind.pni.rawValue)
}
}
}
}
public var number: String {
return failOnError {
try self.withNativeHandle { native in
try invokeFnReturningString {
signal_register_account_response_get_number($0, native.const())
}
}
}
}
public var usernameHash: Data? {
return failOnError {
try self.withNativeHandle { native in
try invokeFnReturningOptionalArray {
signal_register_account_response_get_username_hash($0, native.const())
}
}
}
}
public var usernameLinkHandle: UUID? {
return failOnError {
try self.withNativeHandle { native in
try invokeFnReturningOptionalUuid {
signal_register_account_response_get_username_link_handle($0, native.const())
}
}
}
}
public var storageCapable: Bool {
return failOnError {
try self.withNativeHandle { native in
try invokeFnReturningBool {
signal_register_account_response_get_storage_capable($0, native.const())
}
}
}
}
public var reregistration: Bool {
return failOnError {
try self.withNativeHandle { native in
try invokeFnReturningBool {
signal_register_account_response_get_reregistration($0, native.const())
}
}
}
}
public var entitlements: ([BadgeEntitlement], BackupEntitlement?) {
return failOnError {
try self.withNativeHandle { native in
let badges = try invokeFnReturningBadgeEntitlementArray {
signal_register_account_response_get_entitlement_badges($0, native.const())
}
let backup = try BackupEntitlement(fromResponse: native.const())
return (badges, backup)
}
}
}
}
public struct BadgeEntitlement: Equatable {
public let id: String
public let visible: Bool
public let expiration: TimeInterval
}
public struct BackupEntitlement: Equatable {
public let expiration: TimeInterval
public let level: UInt64
public init(expiration: TimeInterval, level: UInt64) {
self.expiration = expiration
self.level = level
}
fileprivate init?(fromResponse native: SignalConstPointerRegisterAccountResponse) throws {
let backupExpiration = try invokeFnReturningOptionalInteger {
signal_register_account_response_get_entitlement_backup_expiration_seconds($0, native)
}
guard case .some(let expiration) = backupExpiration else {
return nil
}
let level = try invokeFnReturningOptionalInteger {
signal_register_account_response_get_entitlement_backup_level($0, native)
}
guard case .some(let level) = level else {
return nil
}
self.init(expiration: TimeInterval(expiration), level: level)
}
}
public enum VerificationTransport: CustomStringConvertible {
case voice
case sms
public var description: String {
return switch self {
case .voice: "voice"
case .sms: "sms"
}
}
}
public enum Svr2CredentialsResult {
case match
case noMatch
case invalid
}
public enum ChallengeOption: Hashable, Sendable {
case captcha
case pushChallenge
}
/// Account attributes sent as part of a ``RegistrationService/registerAccount(accountPassword:skipDeviceTransfer:accountAttributes:apnPushToken:aciPublicKey:pniPublicKey:aciSignedPreKey:pniSignedPreKey:aciPqLastResortPreKey:pniPqLastResortPreKey:)`` request.
public class RegisterAccountAttributes: NativeHandleOwner<SignalMutPointerRegistrationAccountAttributes> {
/// Constructs the set of attributes to pass to the server.
/// - Throws: ``SignalError/invalidArgument(_:)`` if the `unidentifiedAccessKey` is not 16 bytes.
public convenience init(
recoveryPassword: Data,
aciRegistrationId: UInt16,
pniRegistrationId: UInt16,
registrationLock: String?,
unidentifiedAccessKey: Data,
unrestrictedUnidentifiedAccess: Bool,
capabilities: [String],
discoverableByPhoneNumber: Bool
) throws {
var uak = SignalUnidentifiedAccessKey(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
try withUnsafeMutableBytes(of: &uak) { uakBytes in
if uakBytes.count != unidentifiedAccessKey.count {
throw SignalError.invalidArgument(
"unidentifiedAccessKey has \(unidentifiedAccessKey.count) bytes; expected \(uakBytes.count)"
)
}
uakBytes.copyBytes(from: unidentifiedAccessKey)
}
let nativeHandle = failOnError {
try recoveryPassword.withUnsafeBorrowedBuffer { recoveryPassword in
try registrationLock.withCString { registrationLock in
try withUnsafePointer(to: &uak) { unidentifiedAccessKey in
try capabilities.withUnsafeBorrowedBytestringArray { capabilities in
var nativeHandle = SignalMutPointerRegistrationAccountAttributes()
try checkError(
signal_registration_account_attributes_create(
&nativeHandle,
recoveryPassword,
aciRegistrationId,
pniRegistrationId,
registrationLock,
unidentifiedAccessKey,
unrestrictedUnidentifiedAccess,
capabilities,
discoverableByPhoneNumber
)
)
return nativeHandle
}
}
}
}
}
self.init(owned: NonNull(nativeHandle)!)
}
override internal class func destroyNativeHandle(
_ nativeHandle: NonNull<SignalMutPointerRegistrationAccountAttributes>
) -> SignalFfiErrorRef? {
signal_registration_account_attributes_destroy(nativeHandle.pointer)
}
}
extension SignalFfiRegistrationCreateSessionRequest {
internal static func withNativeStruct<Result>(
e164: String,
pushToken: String?,
mcc: String?,
mnc: String?,
_ fn: (Self) throws -> Result
) rethrows -> Result {
try e164.withCString { e164 in
try pushToken.withCString { pushToken in
try mcc.withCString { mcc in
try mnc.withCString { mnc in
let request = SignalFfiRegistrationCreateSessionRequest(
number: e164,
push_token: pushToken,
mcc: mcc,
mnc: mnc
)
return try fn(request)
}
}
}
}
}
}
/// Invoke a function returning an unsigned integral result where `nil` is bridged as the maximum value.
///
/// Bridging `nil` as max isn't a convention we want to rely on generally. It's
/// true for the getters in this file, though, hence `fileprivate`.
private func invokeFnReturningOptionalInteger<Result: FixedWidthInteger & UnsignedInteger>(
fn: (UnsafeMutablePointer<Result>?) -> SignalFfiErrorRef?
) throws -> Result? {
let output = try invokeFnReturningInteger(fn: fn)
return if output == Result.max { nil } else { output }
}
private func invokeFnReturningBadgeEntitlementArray(
fn: (_ out: UnsafeMutablePointer<SignalOwnedBufferOfFfiRegisterResponseBadge>) -> SignalFfiErrorRef?
) throws -> [BadgeEntitlement] {
var out = SignalOwnedBufferOfFfiRegisterResponseBadge()
try checkError(fn(&out))
defer { signal_free_list_of_register_response_badges(out) }
return UnsafeBufferPointer(start: out.base, count: out.length).map {
BadgeEntitlement(id: String(cString: $0.id), visible: $0.visible, expiration: TimeInterval($0.expiration_secs))
}
}
extension SignalMutPointerRegistrationSession: SignalMutPointer {
public typealias ConstPointer = SignalConstPointerRegistrationSession
public init(untyped: OpaquePointer?) {
self.init(raw: untyped)
}
public func toOpaque() -> OpaquePointer? {
self.raw
}
public func const() -> Self.ConstPointer {
SignalConstPointerRegistrationSession(raw: self.raw)
}
}
extension SignalConstPointerRegistrationSession: SignalConstPointer {
public func toOpaque() -> OpaquePointer? {
self.raw
}
}
extension SignalMutPointerRegisterAccountResponse: SignalMutPointer {
public typealias ConstPointer = SignalConstPointerRegisterAccountResponse
public init(untyped: OpaquePointer?) {
self.init(raw: untyped)
}
public func toOpaque() -> OpaquePointer? {
self.raw
}
public func const() -> Self.ConstPointer {
SignalConstPointerRegisterAccountResponse(raw: self.raw)
}
}
extension SignalConstPointerRegisterAccountResponse: SignalConstPointer {
public func toOpaque() -> OpaquePointer? {
self.raw
}
}
extension SignalMutPointerRegisterAccountRequest: SignalMutPointer {
public typealias ConstPointer = SignalConstPointerRegisterAccountRequest
public init(untyped: OpaquePointer?) {
self.init(raw: untyped)
}
public func toOpaque() -> OpaquePointer? {
self.raw
}
public func const() -> Self.ConstPointer {
SignalConstPointerRegisterAccountRequest(raw: self.raw)
}
}
extension SignalConstPointerRegisterAccountRequest: SignalConstPointer {
public func toOpaque() -> OpaquePointer? {
self.raw
}
}
extension SignalMutPointerRegistrationAccountAttributes: SignalMutPointer {
public typealias ConstPointer = SignalConstPointerRegistrationAccountAttributes
public init(untyped: OpaquePointer?) {
self.init(raw: untyped)
}
public func toOpaque() -> OpaquePointer? {
self.raw
}
public func const() -> Self.ConstPointer {
SignalConstPointerRegistrationAccountAttributes(raw: self.raw)
}
}
extension SignalConstPointerRegistrationAccountAttributes: SignalConstPointer {
public func toOpaque() -> OpaquePointer? {
self.raw
}
}

View File

@@ -53,7 +53,8 @@ public class UnidentifiedSenderMessageContent: NativeHandleOwner<SignalMutPointe
&result,
messageBuffer,
ffiIdentityStore
))
)
)
}
}
self.init(owned: NonNull(result)!)
@@ -74,7 +75,8 @@ public class UnidentifiedSenderMessageContent: NativeHandleOwner<SignalMutPointe
senderHandle.const(),
contentHint.rawValue,
groupIdBuffer
))
)
)
}
self.init(owned: NonNull(result)!)
}
@@ -96,12 +98,15 @@ public class UnidentifiedSenderMessageContent: NativeHandleOwner<SignalMutPointe
senderHandle.const(),
contentHint.rawValue,
groupIdBuffer
))
)
)
}
self.init(owned: NonNull(result)!)
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerUnidentifiedSenderMessageContent>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerUnidentifiedSenderMessageContent>
) -> SignalFfiErrorRef? {
return signal_unidentified_sender_message_content_destroy(handle.pointer)
}

View File

@@ -20,12 +20,16 @@ public class ServerCertificate: NativeHandleOwner<SignalMutPointerServerCertific
public convenience init(keyId: UInt32, publicKey: PublicKey, trustRoot: PrivateKey) throws {
var result = SignalMutPointerServerCertificate()
try withAllBorrowed(publicKey, trustRoot) { publicKeyHandle, trustRootHandle in
try checkError(signal_server_certificate_new(&result, keyId, publicKeyHandle.const(), trustRootHandle.const()))
try checkError(
signal_server_certificate_new(&result, keyId, publicKeyHandle.const(), trustRootHandle.const())
)
}
self.init(owned: NonNull(result)!)
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerServerCertificate>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerServerCertificate>
) -> SignalFfiErrorRef? {
return signal_server_certificate_destroy(handle.pointer)
}
@@ -113,24 +117,37 @@ public class SenderCertificate: NativeHandleOwner<SignalMutPointerSenderCertific
}
// For testing
public convenience init(sender: SealedSenderAddress, publicKey: PublicKey, expiration: UInt64, signerCertificate: ServerCertificate, signerKey: PrivateKey) throws {
public convenience init(
sender: SealedSenderAddress,
publicKey: PublicKey,
expiration: UInt64,
signerCertificate: ServerCertificate,
signerKey: PrivateKey
) throws {
var result = SignalMutPointerSenderCertificate()
try withAllBorrowed(publicKey, signerCertificate, signerKey) { publicKeyHandle, signerCertificateHandle, signerKeyHandle in
try checkError(signal_sender_certificate_new(
&result,
sender.uuidString,
sender.e164,
sender.deviceId,
publicKeyHandle.const(),
expiration,
signerCertificateHandle.const(),
signerKeyHandle.const()
))
try withAllBorrowed(publicKey, signerCertificate, signerKey) {
publicKeyHandle,
signerCertificateHandle,
signerKeyHandle in
try checkError(
signal_sender_certificate_new(
&result,
sender.uuidString,
sender.e164,
sender.deviceId,
publicKeyHandle.const(),
expiration,
signerCertificateHandle.const(),
signerKeyHandle.const()
)
)
}
self.init(owned: NonNull(result)!)
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerSenderCertificate>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerSenderCertificate>
) -> SignalFfiErrorRef? {
return signal_sender_certificate_destroy(handle.pointer)
}
@@ -240,7 +257,9 @@ public class SenderCertificate: NativeHandleOwner<SignalMutPointerSenderCertific
public func validate(trustRoot: PublicKey, time: UInt64) throws -> Bool {
var result = false
try withAllBorrowed(self, trustRoot) { certificateHandle, trustRootHandle in
try checkError(signal_sender_certificate_validate(&result, certificateHandle.const(), trustRootHandle.const(), time))
try checkError(
signal_sender_certificate_validate(&result, certificateHandle.const(), trustRootHandle.const(), time)
)
}
return result
}

View File

@@ -9,6 +9,8 @@ import SignalFfi
internal typealias ServiceIdStorage = SignalServiceIdFixedWidthBinaryBytes
internal func == (_ lhs: ServiceIdStorage, _ rhs: ServiceIdStorage) -> Bool {
// swift-format-ignore
// (vertical alignment is clearer)
return lhs.0 == rhs.0 &&
lhs.1 == rhs.1 &&
lhs.2 == rhs.2 &&
@@ -152,7 +154,9 @@ public class ServiceId: @unchecked Sendable {
return try result.downcast(to: Self.self)
}
internal func withPointerToFixedWidthBinary<R>(_ callback: (UnsafePointer<ServiceIdStorage>) throws -> R) rethrows -> R {
internal func withPointerToFixedWidthBinary<R>(
_ callback: (UnsafePointer<ServiceIdStorage>) throws -> R
) rethrows -> R {
return try callback(&self.storage)
}

View File

@@ -25,7 +25,9 @@ import SignalFfi
/// which decrypts and verifies it, passing the plaintext back to the client for processing.
///
public class SgxClient: NativeHandleOwner<SignalMutPointerSgxClientState> {
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerSgxClientState>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerSgxClientState>
) -> SignalFfiErrorRef? {
return signal_sgx_client_state_destroy(handle.pointer)
}

View File

@@ -19,12 +19,14 @@ public class Svr2Client: SgxClient {
let handle = try attestationMessage.withUnsafeBorrowedBuffer { attestationMessageBuffer in
try mrenclave.withUnsafeBorrowedBuffer { mrenclaveBuffer in
var result = SignalMutPointerSgxClientState()
try checkError(signal_svr2_client_new(
&result,
mrenclaveBuffer,
attestationMessageBuffer,
UInt64(currentDate.timeIntervalSince1970 * 1000)
))
try checkError(
signal_svr2_client_new(
&result,
mrenclaveBuffer,
attestationMessageBuffer,
UInt64(currentDate.timeIntervalSince1970 * 1000)
)
)
return result
}
}

View File

@@ -13,7 +13,9 @@ internal class TokioAsyncContext: NativeHandleOwner<SignalMutPointerTokioAsyncCo
self.init(owned: NonNull(handle)!)
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerTokioAsyncContext>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerTokioAsyncContext>
) -> SignalFfiErrorRef? {
signal_tokio_async_context_destroy(handle.pointer)
}
@@ -88,7 +90,12 @@ internal class TokioAsyncContext: NativeHandleOwner<SignalMutPointerTokioAsyncCo
try checkError(signal_tokio_async_context_cancel($0.const(), id))
}
} catch {
LoggerBridge.shared?.logger.log(level: .warn, file: #fileID, line: #line, message: "failed to cancel libsignal task \(id): \(error)")
LoggerBridge.shared?.logger.log(
level: .warn,
file: #fileID,
line: #line,
message: "failed to cancel libsignal task \(id): \(error)"
)
}
}
}
@@ -106,17 +113,23 @@ internal class TokioAsyncContext: NativeHandleOwner<SignalMutPointerTokioAsyncCo
_ body: (UnsafeMutablePointer<Promise>, SignalMutPointerTokioAsyncContext) -> SignalFfiErrorRef?
) async throws -> Promise.Result {
let cancellationHelper = CancellationHandoffHelper(context: self)
return try await withTaskCancellationHandler(operation: {
try await LibSignalClient.invokeAsyncFunction({ promise in
withNativeHandle { handle in
body(promise, handle)
}
}, saveCancellationId: {
cancellationHelper.setCancellationId($0)
})
}, onCancel: {
cancellationHelper.cancel()
})
return try await withTaskCancellationHandler(
operation: {
try await LibSignalClient.invokeAsyncFunction(
{ promise in
withNativeHandle { handle in
body(promise, handle)
}
},
saveCancellationId: {
cancellationHelper.setCancellationId($0)
}
)
},
onCancel: {
cancellationHelper.cancel()
}
)
}
}

View File

@@ -33,11 +33,18 @@ public struct Username: Sendable {
try self.init(username)
}
public init(nickname: String, discriminator: String, withValidLengthWithin lengthRange: ClosedRange<UInt32>) throws {
public init(nickname: String, discriminator: String, withValidLengthWithin lengthRange: ClosedRange<UInt32>) throws
{
self.hash = try nickname.withCString { nickname in
try discriminator.withCString { discriminator in
try invokeFnReturningFixedLengthArray {
signal_username_hash_from_parts($0, nickname, discriminator, lengthRange.lowerBound, lengthRange.upperBound)
signal_username_hash_from_parts(
$0,
nickname,
discriminator,
lengthRange.lowerBound,
lengthRange.upperBound
)
}
}
}

View File

@@ -10,11 +10,19 @@ import SignalFfi
import Security
#endif
internal func invokeFnReturningString(fn: (UnsafeMutablePointer<UnsafePointer<CChar>?>?) -> SignalFfiErrorRef?) throws -> String {
internal func invokeFnReturningString(
fn: (UnsafeMutablePointer<UnsafePointer<CChar>?>?) -> SignalFfiErrorRef?
) throws
-> String
{
try invokeFnReturningOptionalString(fn: fn)!
}
internal func invokeFnReturningOptionalString(fn: (UnsafeMutablePointer<UnsafePointer<CChar>?>?) -> SignalFfiErrorRef?) throws -> String? {
internal func invokeFnReturningOptionalString(
fn: (UnsafeMutablePointer<UnsafePointer<CChar>?>?) -> SignalFfiErrorRef?
)
throws -> String?
{
var output: UnsafePointer<Int8>?
try checkError(fn(&output))
if output == nil {
@@ -25,7 +33,10 @@ internal func invokeFnReturningOptionalString(fn: (UnsafeMutablePointer<UnsafePo
return result
}
internal func invokeFnReturningSomeBytestringArray<Element>(fn: (UnsafeMutablePointer<SignalBytestringArray>?) -> SignalFfiErrorRef?, transform: (UnsafeBufferPointer<UInt8>) -> Element) throws -> [Element] {
internal func invokeFnReturningSomeBytestringArray<Element>(
fn: (UnsafeMutablePointer<SignalBytestringArray>?) -> SignalFfiErrorRef?,
transform: (UnsafeBufferPointer<UInt8>) -> Element
) throws -> [Element] {
var array = SignalFfi.SignalBytestringArray()
try checkError(fn(&array))
@@ -42,41 +53,64 @@ internal func invokeFnReturningSomeBytestringArray<Element>(fn: (UnsafeMutablePo
return result
}
internal func invokeFnReturningStringArray(fn: (UnsafeMutablePointer<SignalStringArray>?) -> SignalFfiErrorRef?) throws -> [String] {
internal func invokeFnReturningStringArray(
fn: (UnsafeMutablePointer<SignalStringArray>?) -> SignalFfiErrorRef?
) throws
-> [String]
{
return try invokeFnReturningSomeBytestringArray(fn: fn) {
String(decoding: $0, as: Unicode.UTF8.self)
}
}
internal func invokeFnReturningBytestringArray(fn: (UnsafeMutablePointer<SignalBytestringArray>?) -> SignalFfiErrorRef?) throws -> [Data] {
internal func invokeFnReturningBytestringArray(
fn: (UnsafeMutablePointer<SignalBytestringArray>?) -> SignalFfiErrorRef?
)
throws -> [Data]
{
return try invokeFnReturningSomeBytestringArray(fn: fn) {
Data($0)
}
}
internal func invokeFnReturningOptionalArray(fn: (UnsafeMutablePointer<SignalOwnedBuffer>?) -> SignalFfiErrorRef?) throws -> Data? {
internal func invokeFnReturningOptionalArray(
fn: (UnsafeMutablePointer<SignalOwnedBuffer>?) -> SignalFfiErrorRef?
)
throws -> Data?
{
var output = SignalOwnedBuffer()
try checkError(fn(&output))
return if output.base == nil {
nil
} else {
Data(bytesNoCopy: output.base, count: output.length, deallocator: .custom { base, length in
signal_free_buffer(base, length)
})
Data(
bytesNoCopy: output.base,
count: output.length,
deallocator: .custom { base, length in
signal_free_buffer(base, length)
}
)
}
}
internal func invokeFnReturningData(fn: (UnsafeMutablePointer<SignalOwnedBuffer>?) -> SignalFfiErrorRef?) throws -> Data {
internal func invokeFnReturningData(fn: (UnsafeMutablePointer<SignalOwnedBuffer>?) -> SignalFfiErrorRef?) throws -> Data
{
var output = SignalOwnedBuffer()
try checkError(fn(&output))
guard let base = output.base else { return Data() }
return Data(bytesNoCopy: base, count: output.length, deallocator: .custom { base, length in
signal_free_buffer(base, length)
})
return Data(
bytesNoCopy: base,
count: output.length,
deallocator: .custom { base, length in
signal_free_buffer(base, length)
}
)
}
internal func invokeFnReturningFixedLengthArray<ResultAsTuple>(fn: (UnsafeMutablePointer<ResultAsTuple>) -> SignalFfiErrorRef?) throws -> Data {
internal func invokeFnReturningFixedLengthArray<ResultAsTuple>(
fn: (UnsafeMutablePointer<ResultAsTuple>) -> SignalFfiErrorRef?
) throws -> Data {
precondition(MemoryLayout<ResultAsTuple>.alignment == 1, "not a fixed-sized array (tuple) of UInt8")
var output = Data(count: MemoryLayout<ResultAsTuple>.size)
try output.withUnsafeMutableBytes { buffer in
@@ -86,17 +120,23 @@ internal func invokeFnReturningFixedLengthArray<ResultAsTuple>(fn: (UnsafeMutabl
return output
}
internal func invokeFnReturningSerialized<Result: ByteArray, SerializedResult>(fn: (UnsafeMutablePointer<SerializedResult>) -> SignalFfiErrorRef?) throws -> Result {
internal func invokeFnReturningSerialized<Result: ByteArray, SerializedResult>(
fn: (UnsafeMutablePointer<SerializedResult>) -> SignalFfiErrorRef?
) throws -> Result {
let output = try invokeFnReturningFixedLengthArray(fn: fn)
return try Result(contents: output)
}
internal func invokeFnReturningVariableLengthSerialized<Result: ByteArray>(fn: (UnsafeMutablePointer<SignalOwnedBuffer>?) -> SignalFfiErrorRef?) throws -> Result {
internal func invokeFnReturningVariableLengthSerialized<Result: ByteArray>(
fn: (UnsafeMutablePointer<SignalOwnedBuffer>?) -> SignalFfiErrorRef?
) throws -> Result {
let output = try invokeFnReturningData(fn: fn)
return try Result(contents: output)
}
internal func invokeFnReturningOptionalVariableLengthSerialized<Result: ByteArray>(fn: (UnsafeMutablePointer<SignalOwnedBuffer>?) -> SignalFfiErrorRef?) throws -> Result? {
internal func invokeFnReturningOptionalVariableLengthSerialized<Result: ByteArray>(
fn: (UnsafeMutablePointer<SignalOwnedBuffer>?) -> SignalFfiErrorRef?
) throws -> Result? {
let output = try invokeFnReturningData(fn: fn)
if output.isEmpty {
return nil
@@ -110,7 +150,9 @@ internal func invokeFnReturningUuid(fn: (UnsafeMutablePointer<uuid_t>?) -> Signa
return UUID(uuid: output)
}
internal func invokeFnReturningOptionalUuid(fn: (UnsafeMutablePointer<SignalOptionalUuid>?) -> SignalFfiErrorRef?) throws -> UUID? {
internal func invokeFnReturningOptionalUuid(
fn: (UnsafeMutablePointer<SignalOptionalUuid>?) -> SignalFfiErrorRef?
) throws -> UUID? {
var output: SignalOptionalUuid = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
try checkError(fn(&output))
let (isPresent, u0, u1, u2, u3, u4, u5, u6, u7, u8, u9, u10, u11, u12, u13, u14, u15) = output
@@ -120,13 +162,17 @@ internal func invokeFnReturningOptionalUuid(fn: (UnsafeMutablePointer<SignalOpti
return UUID(uuid: (u0, u1, u2, u3, u4, u5, u6, u7, u8, u9, u10, u11, u12, u13, u14, u15))
}
internal func invokeFnReturningServiceId<Id: ServiceId>(fn: (UnsafeMutablePointer<ServiceIdStorage>?) -> SignalFfiErrorRef?) throws -> Id {
internal func invokeFnReturningServiceId<Id: ServiceId>(
fn: (UnsafeMutablePointer<ServiceIdStorage>?) -> SignalFfiErrorRef?
) throws -> Id {
var output: ServiceIdStorage = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
try checkError(fn(&output))
return try Id.parseFrom(fixedWidthBinary: output)
}
internal func invokeFnReturningInteger<Result: FixedWidthInteger>(fn: (UnsafeMutablePointer<Result>?) -> SignalFfiErrorRef?) throws -> Result {
internal func invokeFnReturningInteger<Result: FixedWidthInteger>(
fn: (UnsafeMutablePointer<Result>?) -> SignalFfiErrorRef?
) throws -> Result {
var output: Result = 0
try checkError(fn(&output))
return output
@@ -138,13 +184,17 @@ internal func invokeFnReturningBool(fn: (UnsafeMutablePointer<Bool>?) -> SignalF
return output
}
internal func invokeFnReturningNativeHandle<Owner: NativeHandleOwner<PointerType>, PointerType>(fn: (UnsafeMutablePointer<PointerType>?) -> SignalFfiErrorRef?) throws -> Owner {
internal func invokeFnReturningNativeHandle<Owner: NativeHandleOwner<PointerType>, PointerType>(
fn: (UnsafeMutablePointer<PointerType>?) -> SignalFfiErrorRef?
) throws -> Owner {
var handle = PointerType(untyped: nil)
try checkError(fn(&handle))
return Owner(owned: NonNull(handle)!)
}
internal func invokeFnReturningOptionalNativeHandle<Owner: NativeHandleOwner<PointerType>, PointerType>(fn: (UnsafeMutablePointer<PointerType>?) -> SignalFfiErrorRef?) throws -> Owner? {
internal func invokeFnReturningOptionalNativeHandle<Owner: NativeHandleOwner<PointerType>, PointerType>(
fn: (UnsafeMutablePointer<PointerType>?) -> SignalFfiErrorRef?
) throws -> Owner? {
var handle = PointerType(untyped: nil)
try checkError(fn(&handle))
return NonNull<PointerType>(handle).map { Owner(owned: $0) }
@@ -178,7 +228,9 @@ internal func withUnsafeOptionalBorrowedSlice<
}
extension Sequence where Self.Element == String {
func withUnsafeBorrowedBytestringArray<Result>(_ body: (SignalBorrowedBytestringArray) throws -> Result) rethrows -> Result {
func withUnsafeBorrowedBytestringArray<Result>(
_ body: (SignalBorrowedBytestringArray) throws -> Result
) rethrows -> Result {
let lengths = self.map { $0.utf8.count }
var concatenated = Data(capacity: lengths.reduce(0) { $0 + $1 })
for s in self {
@@ -187,10 +239,12 @@ extension Sequence where Self.Element == String {
return try concatenated.withUnsafeBorrowedBuffer { bytes in
try lengths.withUnsafeBufferPointer { lengths in
try body(SignalBorrowedBytestringArray(
bytes: bytes,
lengths: SignalBorrowedSliceOfusize(base: lengths.baseAddress, length: lengths.count)
))
try body(
SignalBorrowedBytestringArray(
bytes: bytes,
lengths: SignalBorrowedSliceOfusize(base: lengths.baseAddress, length: lengths.count)
)
)
}
}
}
@@ -211,9 +265,13 @@ extension SignalBorrowedMutableBuffer {
extension Data {
internal init(consuming buffer: SignalOwnedBuffer) {
if let base = buffer.base {
self.init(bytesNoCopy: base, count: buffer.length, deallocator: .custom { base, length in
signal_free_buffer(base, length)
})
self.init(
bytesNoCopy: base,
count: buffer.length,
deallocator: .custom { base, length in
signal_free_buffer(base, length)
}
)
} else {
self.init()
}
@@ -227,16 +285,16 @@ internal func fillRandom(_ buffer: UnsafeMutableRawBufferPointer) throws {
return
}
#if canImport(Security)
#if canImport(Security)
let result = SecRandomCopyBytes(kSecRandomDefault, buffer.count, baseAddress)
guard result == errSecSuccess else {
throw SignalError.internalError("SecRandomCopyBytes failed (error code \(result))")
}
#else
#else
for i in buffer.indices {
buffer[i] = UInt8.random(in: .min ... .max)
}
#endif
#endif
}
/// Wraps a store while providing a place to hang on to any user-thrown errors.
@@ -258,7 +316,10 @@ internal struct ErrorHandlingContext<Store> {
}
}
internal func rethrowCallbackErrors<Store, Result>(_ store: Store, _ body: (UnsafeMutablePointer<ErrorHandlingContext<Store>>) throws -> Result) rethrows -> Result {
internal func rethrowCallbackErrors<Store, Result>(
_ store: Store,
_ body: (UnsafeMutablePointer<ErrorHandlingContext<Store>>) throws -> Result
) rethrows -> Result {
var context = ErrorHandlingContext(store)
do {
return try withUnsafeMutablePointer(to: &context) {
@@ -323,7 +384,9 @@ extension Data {
}
extension [String: String] {
internal func withBridgedStringMap<Result>(_ callback: (SignalMutPointerBridgedStringMap) throws -> Result) rethrows -> Result {
internal func withBridgedStringMap<Result>(
_ callback: (SignalMutPointerBridgedStringMap) throws -> Result
) rethrows -> Result {
var map = SignalMutPointerBridgedStringMap()
failOnError(signal_bridged_string_map_new(&map, UInt32(clamping: self.count)))
defer { signal_bridged_string_map_destroy(map) }

View File

@@ -34,7 +34,9 @@ public class CiphertextMessage: NativeHandleOwner<SignalMutPointerCiphertextMess
}
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerCiphertextMessage>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerCiphertextMessage>
) -> SignalFfiErrorRef? {
return signal_ciphertext_message_destroy(handle.pointer)
}

View File

@@ -7,7 +7,9 @@ import Foundation
import SignalFfi
public class PlaintextContent: NativeHandleOwner<SignalMutPointerPlaintextContent> {
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerPlaintextContent>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerPlaintextContent>
) -> SignalFfiErrorRef? {
return signal_plaintext_content_destroy(handle.pointer)
}
@@ -71,7 +73,9 @@ extension SignalConstPointerPlaintextContent: SignalConstPointer {
}
public class DecryptionErrorMessage: NativeHandleOwner<SignalMutPointerDecryptionErrorMessage> {
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerDecryptionErrorMessage>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerDecryptionErrorMessage>
) -> SignalFfiErrorRef? {
return signal_decryption_error_message_destroy(handle.pointer)
}
@@ -83,16 +87,31 @@ public class DecryptionErrorMessage: NativeHandleOwner<SignalMutPointerDecryptio
self.init(owned: NonNull(result)!)
}
public convenience init<Bytes: ContiguousBytes>(originalMessageBytes bytes: Bytes, type: CiphertextMessage.MessageType, timestamp: UInt64, originalSenderDeviceId: UInt32) throws {
public convenience init<Bytes: ContiguousBytes>(
originalMessageBytes bytes: Bytes,
type: CiphertextMessage.MessageType,
timestamp: UInt64,
originalSenderDeviceId: UInt32
) throws {
var result = SignalMutPointerDecryptionErrorMessage()
try bytes.withUnsafeBorrowedBuffer {
try checkError(signal_decryption_error_message_for_original_message(&result, $0, type.rawValue, timestamp, originalSenderDeviceId))
try checkError(
signal_decryption_error_message_for_original_message(
&result,
$0,
type.rawValue,
timestamp,
originalSenderDeviceId
)
)
}
self.init(owned: NonNull(result)!)
}
// For testing
public static func extractFromSerializedContent<Bytes: ContiguousBytes>(_ bytes: Bytes) throws -> DecryptionErrorMessage {
public static func extractFromSerializedContent<Bytes: ContiguousBytes>(
_ bytes: Bytes
) throws -> DecryptionErrorMessage {
return try bytes.withUnsafeBorrowedBuffer { buffer in
try invokeFnReturningNativeHandle {
signal_decryption_error_message_extract_from_serialized_content($0, buffer)

View File

@@ -7,7 +7,9 @@ import Foundation
import SignalFfi
public class PreKeySignalMessage: NativeHandleOwner<SignalMutPointerPreKeySignalMessage> {
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerPreKeySignalMessage>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerPreKeySignalMessage>
) -> SignalFfiErrorRef? {
return signal_pre_key_signal_message_destroy(handle.pointer)
}

View File

@@ -7,7 +7,9 @@ import Foundation
import SignalFfi
public class SenderKeyDistributionMessage: NativeHandleOwner<SignalMutPointerSenderKeyDistributionMessage> {
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerSenderKeyDistributionMessage>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerSenderKeyDistributionMessage>
) -> SignalFfiErrorRef? {
return signal_sender_key_distribution_message_destroy(handle.pointer)
}
@@ -21,12 +23,14 @@ public class SenderKeyDistributionMessage: NativeHandleOwner<SignalMutPointerSen
try sender.withNativeHandle { senderHandle in
try withUnsafePointer(to: distributionId.uuid) { distributionId in
try withSenderKeyStore(store, context) {
try checkError(signal_sender_key_distribution_message_create(
&result,
senderHandle.const(),
distributionId,
$0
))
try checkError(
signal_sender_key_distribution_message_create(
&result,
senderHandle.const(),
distributionId,
$0
)
)
}
}
}

View File

@@ -7,7 +7,9 @@ import Foundation
import SignalFfi
public class SenderKeyMessage: NativeHandleOwner<SignalMutPointerSenderKeyMessage> {
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerSenderKeyMessage>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerSenderKeyMessage>
) -> SignalFfiErrorRef? {
return signal_sender_key_message_destroy(handle.pointer)
}
@@ -72,7 +74,9 @@ public class SenderKeyMessage: NativeHandleOwner<SignalMutPointerSenderKeyMessag
public func verifySignature(against key: PublicKey) throws -> Bool {
var result = false
try withAllBorrowed(self, key) { messageHandle, keyHandle in
try checkError(signal_sender_key_message_verify_signature(&result, messageHandle.const(), keyHandle.const()))
try checkError(
signal_sender_key_message_verify_signature(&result, messageHandle.const(), keyHandle.const())
)
}
return result
}

View File

@@ -7,7 +7,9 @@ import Foundation
import SignalFfi
public class SignalMessage: NativeHandleOwner<SignalMutPointerSignalMessage> {
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerSignalMessage>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerSignalMessage>
) -> SignalFfiErrorRef? {
return signal_message_destroy(handle.pointer)
}
@@ -81,13 +83,15 @@ public class SignalMessage: NativeHandleOwner<SignalMutPointerSignalMessage> {
.bytes(macKey)
) { messageHandle, senderHandle, receiverHandle, macKey in
var result = false
try checkError(signal_message_verify_mac(
&result,
messageHandle.const(),
senderHandle.const(),
receiverHandle.const(),
macKey
))
try checkError(
signal_message_verify_mac(
&result,
messageHandle.const(),
senderHandle.const(),
receiverHandle.const(),
macKey
)
)
return result
}
}

View File

@@ -7,11 +7,16 @@ import Foundation
import SignalFfi
public class KyberPreKeyRecord: ClonableHandleOwner<SignalMutPointerKyberPreKeyRecord> {
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerKyberPreKeyRecord>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerKyberPreKeyRecord>
) -> SignalFfiErrorRef? {
return signal_kyber_pre_key_record_destroy(handle.pointer)
}
override internal class func cloneNativeHandle(_ newHandle: inout SignalMutPointerKyberPreKeyRecord, currentHandle: SignalConstPointerKyberPreKeyRecord) -> SignalFfiErrorRef? {
override internal class func cloneNativeHandle(
_ newHandle: inout SignalMutPointerKyberPreKeyRecord,
currentHandle: SignalConstPointerKyberPreKeyRecord
) -> SignalFfiErrorRef? {
return signal_kyber_pre_key_record_clone(&newHandle, currentHandle)
}

View File

@@ -7,7 +7,9 @@ import Foundation
import SignalFfi
public class PreKeyBundle: NativeHandleOwner<SignalMutPointerPreKeyBundle> {
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerPreKeyBundle>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerPreKeyBundle>
) -> SignalFfiErrorRef? {
return signal_pre_key_bundle_destroy(handle.pointer)
}
@@ -36,21 +38,29 @@ public class PreKeyBundle: NativeHandleOwner<SignalMutPointerPreKeyBundle> {
kyberPrekey,
.bytes(signedPrekeySignature),
.bytes(kyberPrekeySignature)
) { prekeyHandle, signedPrekeyHandle, identityKeyHandle, kyberKeyHandle, ecSignatureBuffer, kyberSignatureBuffer in
try checkError(signal_pre_key_bundle_new(
&result,
registrationId,
deviceId,
prekeyId,
prekeyHandle.const(),
signedPrekeyId,
signedPrekeyHandle.const(),
ecSignatureBuffer,
identityKeyHandle.const(),
kyberPrekeyId,
kyberKeyHandle.const(),
kyberSignatureBuffer
))
) {
prekeyHandle,
signedPrekeyHandle,
identityKeyHandle,
kyberKeyHandle,
ecSignatureBuffer,
kyberSignatureBuffer in
try checkError(
signal_pre_key_bundle_new(
&result,
registrationId,
deviceId,
prekeyId,
prekeyHandle.const(),
signedPrekeyId,
signedPrekeyHandle.const(),
ecSignatureBuffer,
identityKeyHandle.const(),
kyberPrekeyId,
kyberKeyHandle.const(),
kyberSignatureBuffer
)
)
}
self.init(owned: NonNull(result)!)
}
@@ -78,20 +88,22 @@ public class PreKeyBundle: NativeHandleOwner<SignalMutPointerPreKeyBundle> {
.bytes(signedPrekeySignature),
.bytes(kyberPrekeySignature)
) { signedPrekeyHandle, identityKeyHandle, kyberKeyHandle, ecSignatureBuffer, kyberSignatureBuffer in
try checkError(signal_pre_key_bundle_new(
&result,
registrationId,
deviceId,
~0,
SignalConstPointerPublicKey(),
signedPrekeyId,
signedPrekeyHandle.const(),
ecSignatureBuffer,
identityKeyHandle.const(),
kyberPrekeyId,
kyberKeyHandle.const(),
kyberSignatureBuffer
))
try checkError(
signal_pre_key_bundle_new(
&result,
registrationId,
deviceId,
~0,
SignalConstPointerPublicKey(),
signedPrekeyId,
signedPrekeyHandle.const(),
ecSignatureBuffer,
identityKeyHandle.const(),
kyberPrekeyId,
kyberKeyHandle.const(),
kyberSignatureBuffer
)
)
}
self.init(owned: NonNull(result)!)
}

View File

@@ -7,11 +7,16 @@ import Foundation
import SignalFfi
public class PreKeyRecord: ClonableHandleOwner<SignalMutPointerPreKeyRecord> {
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerPreKeyRecord>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerPreKeyRecord>
) -> SignalFfiErrorRef? {
return signal_pre_key_record_destroy(handle.pointer)
}
override internal class func cloneNativeHandle(_ newHandle: inout SignalMutPointerPreKeyRecord, currentHandle: SignalConstPointerPreKeyRecord) -> SignalFfiErrorRef? {
override internal class func cloneNativeHandle(
_ newHandle: inout SignalMutPointerPreKeyRecord,
currentHandle: SignalConstPointerPreKeyRecord
) -> SignalFfiErrorRef? {
return signal_pre_key_record_clone(&newHandle, currentHandle)
}

View File

@@ -7,11 +7,16 @@ import Foundation
import SignalFfi
public class SenderKeyRecord: ClonableHandleOwner<SignalMutPointerSenderKeyRecord> {
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerSenderKeyRecord>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerSenderKeyRecord>
) -> SignalFfiErrorRef? {
return signal_sender_key_record_destroy(handle.pointer)
}
override internal class func cloneNativeHandle(_ newHandle: inout SignalMutPointerSenderKeyRecord, currentHandle: SignalConstPointerSenderKeyRecord) -> SignalFfiErrorRef? {
override internal class func cloneNativeHandle(
_ newHandle: inout SignalMutPointerSenderKeyRecord,
currentHandle: SignalConstPointerSenderKeyRecord
) -> SignalFfiErrorRef? {
return signal_sender_key_record_clone(&newHandle, currentHandle)
}

View File

@@ -7,11 +7,16 @@ import Foundation
import SignalFfi
public class SessionRecord: ClonableHandleOwner<SignalMutPointerSessionRecord> {
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerSessionRecord>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerSessionRecord>
) -> SignalFfiErrorRef? {
return signal_session_record_destroy(handle.pointer)
}
override internal class func cloneNativeHandle(_ newHandle: inout SignalMutPointerSessionRecord, currentHandle: SignalConstPointerSessionRecord) -> SignalFfiErrorRef? {
override internal class func cloneNativeHandle(
_ newHandle: inout SignalMutPointerSessionRecord,
currentHandle: SignalConstPointerSessionRecord
) -> SignalFfiErrorRef? {
return signal_session_record_clone(&newHandle, currentHandle)
}
@@ -41,7 +46,13 @@ public class SessionRecord: ClonableHandleOwner<SignalMutPointerSessionRecord> {
public func hasCurrentState(now: Date) -> Bool {
var result = false
self.withNativeHandle { nativeHandle in
failOnError(signal_session_record_has_usable_sender_chain(&result, nativeHandle.const(), UInt64(now.timeIntervalSince1970 * 1000)))
failOnError(
signal_session_record_has_usable_sender_chain(
&result,
nativeHandle.const(),
UInt64(now.timeIntervalSince1970 * 1000)
)
)
}
return result
}
@@ -63,7 +74,9 @@ public class SessionRecord: ClonableHandleOwner<SignalMutPointerSessionRecord> {
public func currentRatchetKeyMatches(_ key: PublicKey) throws -> Bool {
var result = false
try withAllBorrowed(self, key) { sessionHandle, keyHandle in
try checkError(signal_session_record_current_ratchet_key_matches(&result, sessionHandle.const(), keyHandle.const()))
try checkError(
signal_session_record_current_ratchet_key_matches(&result, sessionHandle.const(), keyHandle.const())
)
}
return result
}

View File

@@ -7,11 +7,16 @@ import Foundation
import SignalFfi
public class SignedPreKeyRecord: ClonableHandleOwner<SignalMutPointerSignedPreKeyRecord> {
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerSignedPreKeyRecord>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerSignedPreKeyRecord>
) -> SignalFfiErrorRef? {
return signal_signed_pre_key_record_destroy(handle.pointer)
}
override internal class func cloneNativeHandle(_ newHandle: inout SignalMutPointerSignedPreKeyRecord, currentHandle: SignalConstPointerSignedPreKeyRecord) -> SignalFfiErrorRef? {
override internal class func cloneNativeHandle(
_ newHandle: inout SignalMutPointerSignedPreKeyRecord,
currentHandle: SignalConstPointerSignedPreKeyRecord
) -> SignalFfiErrorRef? {
return signal_signed_pre_key_record_clone(&newHandle, currentHandle)
}
@@ -33,14 +38,16 @@ public class SignedPreKeyRecord: ClonableHandleOwner<SignalMutPointerSignedPreKe
let publicKey = privateKey.publicKey
var result = SignalMutPointerSignedPreKeyRecord()
try withAllBorrowed(publicKey, privateKey, .bytes(signature)) { publicKeyHandle, privateKeyHandle, signature in
try checkError(signal_signed_pre_key_record_new(
&result,
id,
timestamp,
publicKeyHandle.const(),
privateKeyHandle.const(),
signature
))
try checkError(
signal_signed_pre_key_record_new(
&result,
id,
timestamp,
publicKeyHandle.const(),
privateKeyHandle.const(),
signature
)
)
}
self.init(owned: NonNull(result)!)
}

View File

@@ -17,7 +17,10 @@ public class BackupAuthCredential: ByteArray, @unchecked Sendable {
}
}
public func present(serverParams: GenericServerPublicParams, randomness: Randomness) -> BackupAuthCredentialPresentation {
public func present(
serverParams: GenericServerPublicParams,
randomness: Randomness
) -> BackupAuthCredentialPresentation {
return failOnError {
try withAllBorrowed(self, serverParams, randomness) { contents, serverParams, randomness in
try invokeFnReturningVariableLengthSerialized {

View File

@@ -13,7 +13,13 @@ public class BackupAuthCredentialPresentation: ByteArray, @unchecked Sendable {
public func verify(now: Date = Date(), serverParams: GenericServerSecretParams) throws {
try withAllBorrowed(self, serverParams) { contents, serverParams in
try checkError(signal_backup_auth_credential_presentation_verify(contents, UInt64(now.timeIntervalSince1970), serverParams))
try checkError(
signal_backup_auth_credential_presentation_verify(
contents,
UInt64(now.timeIntervalSince1970),
serverParams
)
)
}
}
}

View File

@@ -11,17 +11,42 @@ public class BackupAuthCredentialRequest: ByteArray, @unchecked Sendable {
try super.init(contents, checkValid: signal_backup_auth_credential_request_check_valid_contents)
}
public func issueCredential(timestamp: Date, backupLevel: BackupLevel, type: BackupCredentialType, params: GenericServerSecretParams) -> BackupAuthCredentialResponse {
public func issueCredential(
timestamp: Date,
backupLevel: BackupLevel,
type: BackupCredentialType,
params: GenericServerSecretParams
) -> BackupAuthCredentialResponse {
return failOnError {
self.issueCredential(timestamp: timestamp, backupLevel: backupLevel, type: type, params: params, randomness: try .generate())
self.issueCredential(
timestamp: timestamp,
backupLevel: backupLevel,
type: type,
params: params,
randomness: try .generate()
)
}
}
public func issueCredential(timestamp: Date, backupLevel: BackupLevel, type: BackupCredentialType, params: GenericServerSecretParams, randomness: Randomness) -> BackupAuthCredentialResponse {
public func issueCredential(
timestamp: Date,
backupLevel: BackupLevel,
type: BackupCredentialType,
params: GenericServerSecretParams,
randomness: Randomness
) -> BackupAuthCredentialResponse {
return failOnError {
try withAllBorrowed(self, params, randomness) { contents, params, randomness in
try invokeFnReturningVariableLengthSerialized {
signal_backup_auth_credential_request_issue_deterministic($0, contents, UInt64(timestamp.timeIntervalSince1970), backupLevel.rawValue, type.rawValue, params, randomness)
signal_backup_auth_credential_request_issue_deterministic(
$0,
contents,
UInt64(timestamp.timeIntervalSince1970),
backupLevel.rawValue,
type.rawValue,
params,
randomness
)
}
}
}

View File

@@ -34,10 +34,20 @@ public class BackupAuthCredentialRequestContext: ByteArray, @unchecked Sendable
}
}
public func receive(_ response: BackupAuthCredentialResponse, timestamp: Date, params: GenericServerPublicParams) throws -> BackupAuthCredential {
public func receive(
_ response: BackupAuthCredentialResponse,
timestamp: Date,
params: GenericServerPublicParams
) throws -> BackupAuthCredential {
return try withAllBorrowed(self, response, params) { contents, response, params in
try invokeFnReturningVariableLengthSerialized {
signal_backup_auth_credential_request_context_receive_response($0, contents, response, UInt64(timestamp.timeIntervalSince1970), params)
signal_backup_auth_credential_request_context_receive_response(
$0,
contents,
response,
UInt64(timestamp.timeIntervalSince1970),
params
)
}
}
}

View File

@@ -8,10 +8,12 @@ import SignalFfi
public enum BackupLevel: UInt8, Sendable {
// This must match the Rust version of the enum.
case free = 200, paid = 201
case free = 200
case paid = 201
}
public enum BackupCredentialType: UInt8 {
// This must match the Rust version of the enum.
case messages = 1, media = 2
case messages = 1
case media = 2
}

View File

@@ -18,7 +18,9 @@ public class ByteArray {
init(newContents: Data, expectedLength: Int, unrecoverable: Bool = false) throws {
if newContents.count != expectedLength {
throw SignalError.invalidType("\(type(of: self)) uses \(expectedLength) bytes, but tried to deserialize from an array of \(newContents.count) bytes")
throw SignalError.invalidType(
"\(type(of: self)) uses \(expectedLength) bytes, but tried to deserialize from an array of \(newContents.count) bytes"
)
}
self.contents = newContents
}
@@ -42,13 +44,17 @@ public class ByteArray {
/// tuples representing a fixed-size array; using another type, or using the wrong size of
/// array, is considered a programmer error and can result in arbitrary behavior (including
/// violating type safety). So, uh, don't do that.
func withUnsafePointerToSerialized<Serialized, Result>(_ callback: (UnsafePointer<Serialized>) throws -> Result) throws -> Result {
func withUnsafePointerToSerialized<Serialized, Result>(
_ callback: (UnsafePointer<Serialized>) throws -> Result
) throws -> Result {
precondition(MemoryLayout<Serialized>.alignment == 1, "not a fixed-sized array (tuple) of UInt8")
return try self.contents.withUnsafeBytes { buffer in
let expectedSize = MemoryLayout<Serialized>.size
guard expectedSize == buffer.count else {
throw SignalError.invalidType("\(type(of: self)) uses \(buffer.count) bytes, but was passed to a callback that uses \(expectedSize) bytes")
throw SignalError.invalidType(
"\(type(of: self)) uses \(buffer.count) bytes, but was passed to a callback that uses \(expectedSize) bytes"
)
}
// Use assumingMemoryBound(to:) here rather than bindMemory(to:)

View File

@@ -11,13 +11,30 @@ public class CallLinkAuthCredential: ByteArray, @unchecked Sendable {
try super.init(contents, checkValid: signal_call_link_auth_credential_check_valid_contents)
}
public func present(userId: Aci, redemptionTime: Date, serverParams: GenericServerPublicParams, callLinkParams: CallLinkSecretParams) -> CallLinkAuthCredentialPresentation {
public func present(
userId: Aci,
redemptionTime: Date,
serverParams: GenericServerPublicParams,
callLinkParams: CallLinkSecretParams
) -> CallLinkAuthCredentialPresentation {
return failOnError {
self.present(userId: userId, redemptionTime: redemptionTime, serverParams: serverParams, callLinkParams: callLinkParams, randomness: try .generate())
self.present(
userId: userId,
redemptionTime: redemptionTime,
serverParams: serverParams,
callLinkParams: callLinkParams,
randomness: try .generate()
)
}
}
public func present(userId: Aci, redemptionTime: Date, serverParams: GenericServerPublicParams, callLinkParams: CallLinkSecretParams, randomness: Randomness) -> CallLinkAuthCredentialPresentation {
public func present(
userId: Aci,
redemptionTime: Date,
serverParams: GenericServerPublicParams,
callLinkParams: CallLinkSecretParams,
randomness: Randomness
) -> CallLinkAuthCredentialPresentation {
return failOnError {
try withAllBorrowed(
self,
@@ -27,7 +44,15 @@ public class CallLinkAuthCredential: ByteArray, @unchecked Sendable {
randomness
) { contents, userId, serverParams, callLinkParams, randomness in
try invokeFnReturningVariableLengthSerialized {
signal_call_link_auth_credential_present_deterministic($0, contents, userId, UInt64(redemptionTime.timeIntervalSince1970), serverParams, callLinkParams, randomness)
signal_call_link_auth_credential_present_deterministic(
$0,
contents,
userId,
UInt64(redemptionTime.timeIntervalSince1970),
serverParams,
callLinkParams,
randomness
)
}
}
}

View File

@@ -11,9 +11,20 @@ public class CallLinkAuthCredentialPresentation: ByteArray, @unchecked Sendable
try super.init(contents, checkValid: signal_call_link_auth_credential_presentation_check_valid_contents)
}
public func verify(now: Date = Date(), serverParams: GenericServerSecretParams, callLinkParams: CallLinkPublicParams) throws {
public func verify(
now: Date = Date(),
serverParams: GenericServerSecretParams,
callLinkParams: CallLinkPublicParams
) throws {
try withAllBorrowed(self, serverParams, callLinkParams) { contents, serverParams, callLinkParams in
try checkError(signal_call_link_auth_credential_presentation_verify(contents, UInt64(now.timeIntervalSince1970), serverParams, callLinkParams))
try checkError(
signal_call_link_auth_credential_presentation_verify(
contents,
UInt64(now.timeIntervalSince1970),
serverParams,
callLinkParams
)
)
}
}

View File

@@ -11,26 +11,56 @@ public class CallLinkAuthCredentialResponse: ByteArray, @unchecked Sendable {
try super.init(contents, checkValid: signal_call_link_auth_credential_response_check_valid_contents)
}
public static func issueCredential(userId: Aci, redemptionTime: Date, params: GenericServerSecretParams) -> CallLinkAuthCredentialResponse {
public static func issueCredential(
userId: Aci,
redemptionTime: Date,
params: GenericServerSecretParams
) -> CallLinkAuthCredentialResponse {
return failOnError {
self.issueCredential(userId: userId, redemptionTime: redemptionTime, params: params, randomness: try .generate())
self.issueCredential(
userId: userId,
redemptionTime: redemptionTime,
params: params,
randomness: try .generate()
)
}
}
public static func issueCredential(userId: Aci, redemptionTime: Date, params: GenericServerSecretParams, randomness: Randomness) -> CallLinkAuthCredentialResponse {
public static func issueCredential(
userId: Aci,
redemptionTime: Date,
params: GenericServerSecretParams,
randomness: Randomness
) -> CallLinkAuthCredentialResponse {
return failOnError {
try withAllBorrowed(userId, params, randomness) { userId, params, randomness in
try invokeFnReturningVariableLengthSerialized {
signal_call_link_auth_credential_response_issue_deterministic($0, userId, UInt64(redemptionTime.timeIntervalSince1970), params, randomness)
signal_call_link_auth_credential_response_issue_deterministic(
$0,
userId,
UInt64(redemptionTime.timeIntervalSince1970),
params,
randomness
)
}
}
}
}
public func receive(userId: Aci, redemptionTime: Date, params: GenericServerPublicParams) throws -> CallLinkAuthCredential {
public func receive(
userId: Aci,
redemptionTime: Date,
params: GenericServerPublicParams
) throws -> CallLinkAuthCredential {
return try withAllBorrowed(self, userId, params) { contents, userId, params in
try invokeFnReturningVariableLengthSerialized {
signal_call_link_auth_credential_response_receive($0, contents, userId, UInt64(redemptionTime.timeIntervalSince1970), params)
signal_call_link_auth_credential_response_receive(
$0,
contents,
userId,
UInt64(redemptionTime.timeIntervalSince1970),
params
)
}
}
}

View File

@@ -16,13 +16,25 @@ public class ClientZkAuthOperations {
/// Produces the `AuthCredentialWithPni` from a server-generated `AuthCredentialWithPniResponse`.
///
/// - parameter redemptionTime: This is provided by the server as an integer, and should be passed through directly.
public func receiveAuthCredentialWithPniAsServiceId(aci: Aci, pni: Pni, redemptionTime: UInt64, authCredentialResponse: AuthCredentialWithPniResponse) throws -> AuthCredentialWithPni {
public func receiveAuthCredentialWithPniAsServiceId(
aci: Aci,
pni: Pni,
redemptionTime: UInt64,
authCredentialResponse: AuthCredentialWithPniResponse
) throws -> AuthCredentialWithPni {
return try self.serverPublicParams.withNativeHandle { serverPublicParams in
try aci.withPointerToFixedWidthBinary { aci in
try pni.withPointerToFixedWidthBinary { pni in
try authCredentialResponse.withUnsafeBorrowedBuffer { authCredentialResponse in
try invokeFnReturningVariableLengthSerialized {
signal_server_public_params_receive_auth_credential_with_pni_as_service_id($0, serverPublicParams.const(), aci, pni, redemptionTime, authCredentialResponse)
signal_server_public_params_receive_auth_credential_with_pni_as_service_id(
$0,
serverPublicParams.const(),
aci,
pni,
redemptionTime,
authCredentialResponse
)
}
}
}
@@ -30,17 +42,34 @@ public class ClientZkAuthOperations {
}
}
public func createAuthCredentialPresentation(groupSecretParams: GroupSecretParams, authCredential: AuthCredentialWithPni) throws -> AuthCredentialPresentation {
return try self.createAuthCredentialPresentation(randomness: Randomness.generate(), groupSecretParams: groupSecretParams, authCredential: authCredential)
public func createAuthCredentialPresentation(
groupSecretParams: GroupSecretParams,
authCredential: AuthCredentialWithPni
) throws -> AuthCredentialPresentation {
return try self.createAuthCredentialPresentation(
randomness: Randomness.generate(),
groupSecretParams: groupSecretParams,
authCredential: authCredential
)
}
public func createAuthCredentialPresentation(randomness: Randomness, groupSecretParams: GroupSecretParams, authCredential: AuthCredentialWithPni) throws -> AuthCredentialPresentation {
public func createAuthCredentialPresentation(
randomness: Randomness,
groupSecretParams: GroupSecretParams,
authCredential: AuthCredentialWithPni
) throws -> AuthCredentialPresentation {
return try self.serverPublicParams.withNativeHandle { contents in
try randomness.withUnsafePointerToBytes { randomness in
try groupSecretParams.withUnsafePointerToSerialized { groupSecretParams in
try authCredential.withUnsafeBorrowedBuffer { authCredential in
try invokeFnReturningVariableLengthSerialized {
signal_server_public_params_create_auth_credential_with_pni_presentation_deterministic($0, contents.const(), randomness, groupSecretParams, authCredential)
signal_server_public_params_create_auth_credential_with_pni_presentation_deterministic(
$0,
contents.const(),
randomness,
groupSecretParams,
authCredential
)
}
}
}

View File

@@ -50,7 +50,12 @@ public class ClientZkGroupCipher {
try profileKeyCiphertext.withUnsafePointerToSerialized { profileKeyCiphertext in
try userId.withPointerToFixedWidthBinary { userId in
try invokeFnReturningSerialized {
signal_group_secret_params_decrypt_profile_key($0, groupSecretParams, profileKeyCiphertext, userId)
signal_group_secret_params_decrypt_profile_key(
$0,
groupSecretParams,
profileKeyCiphertext,
userId
)
}
}
}
@@ -66,7 +71,13 @@ public class ClientZkGroupCipher {
try randomness.withUnsafePointerToBytes { randomness in
try plaintext.withUnsafeBorrowedBuffer { plaintext in
try invokeFnReturningData {
signal_group_secret_params_encrypt_blob_with_padding_deterministic($0, groupSecretParams, randomness, plaintext, 0)
signal_group_secret_params_encrypt_blob_with_padding_deterministic(
$0,
groupSecretParams,
randomness,
plaintext,
0
)
}
}
}

View File

@@ -13,17 +13,34 @@ public class ClientZkProfileOperations {
self.serverPublicParams = serverPublicParams
}
public func createProfileKeyCredentialRequestContext(userId: Aci, profileKey: ProfileKey) throws -> ProfileKeyCredentialRequestContext {
return try self.createProfileKeyCredentialRequestContext(randomness: Randomness.generate(), userId: userId, profileKey: profileKey)
public func createProfileKeyCredentialRequestContext(
userId: Aci,
profileKey: ProfileKey
) throws -> ProfileKeyCredentialRequestContext {
return try self.createProfileKeyCredentialRequestContext(
randomness: Randomness.generate(),
userId: userId,
profileKey: profileKey
)
}
public func createProfileKeyCredentialRequestContext(randomness: Randomness, userId: Aci, profileKey: ProfileKey) throws -> ProfileKeyCredentialRequestContext {
public func createProfileKeyCredentialRequestContext(
randomness: Randomness,
userId: Aci,
profileKey: ProfileKey
) throws -> ProfileKeyCredentialRequestContext {
return try self.serverPublicParams.withNativeHandle { serverPublicParams in
try randomness.withUnsafePointerToBytes { randomness in
try userId.withPointerToFixedWidthBinary { userId in
try profileKey.withUnsafePointerToSerialized { profileKey in
try invokeFnReturningSerialized {
signal_server_public_params_create_profile_key_credential_request_context_deterministic($0, serverPublicParams.const(), randomness, userId, profileKey)
signal_server_public_params_create_profile_key_credential_request_context_deterministic(
$0,
serverPublicParams.const(),
randomness,
userId,
profileKey
)
}
}
}
@@ -40,24 +57,47 @@ public class ClientZkProfileOperations {
try profileKeyCredentialRequestContext.withUnsafePointerToSerialized { requestContext in
try profileKeyCredentialResponse.withUnsafePointerToSerialized { response in
try invokeFnReturningSerialized {
signal_server_public_params_receive_expiring_profile_key_credential($0, serverPublicParams.const(), requestContext, response, UInt64(now.timeIntervalSince1970))
signal_server_public_params_receive_expiring_profile_key_credential(
$0,
serverPublicParams.const(),
requestContext,
response,
UInt64(now.timeIntervalSince1970)
)
}
}
}
}
}
public func createProfileKeyCredentialPresentation(groupSecretParams: GroupSecretParams, profileKeyCredential: ExpiringProfileKeyCredential) throws -> ProfileKeyCredentialPresentation {
return try self.createProfileKeyCredentialPresentation(randomness: Randomness.generate(), groupSecretParams: groupSecretParams, profileKeyCredential: profileKeyCredential)
public func createProfileKeyCredentialPresentation(
groupSecretParams: GroupSecretParams,
profileKeyCredential: ExpiringProfileKeyCredential
) throws -> ProfileKeyCredentialPresentation {
return try self.createProfileKeyCredentialPresentation(
randomness: Randomness.generate(),
groupSecretParams: groupSecretParams,
profileKeyCredential: profileKeyCredential
)
}
public func createProfileKeyCredentialPresentation(randomness: Randomness, groupSecretParams: GroupSecretParams, profileKeyCredential: ExpiringProfileKeyCredential) throws -> ProfileKeyCredentialPresentation {
public func createProfileKeyCredentialPresentation(
randomness: Randomness,
groupSecretParams: GroupSecretParams,
profileKeyCredential: ExpiringProfileKeyCredential
) throws -> ProfileKeyCredentialPresentation {
return try self.serverPublicParams.withNativeHandle { serverPublicParams in
try randomness.withUnsafePointerToBytes { randomness in
try groupSecretParams.withUnsafePointerToSerialized { groupSecretParams in
try profileKeyCredential.withUnsafePointerToSerialized { profileKeyCredential in
try invokeFnReturningVariableLengthSerialized {
signal_server_public_params_create_expiring_profile_key_credential_presentation_deterministic($0, serverPublicParams.const(), randomness, groupSecretParams, profileKeyCredential)
signal_server_public_params_create_expiring_profile_key_credential_presentation_deterministic(
$0,
serverPublicParams.const(),
randomness,
groupSecretParams,
profileKeyCredential
)
}
}
}

View File

@@ -13,44 +13,78 @@ public class ClientZkReceiptOperations {
self.serverPublicParams = serverPublicParams
}
public func createReceiptCredentialRequestContext(receiptSerial: ReceiptSerial) throws -> ReceiptCredentialRequestContext {
return try self.createReceiptCredentialRequestContext(randomness: Randomness.generate(), receiptSerial: receiptSerial)
public func createReceiptCredentialRequestContext(
receiptSerial: ReceiptSerial
) throws -> ReceiptCredentialRequestContext {
return try self.createReceiptCredentialRequestContext(
randomness: Randomness.generate(),
receiptSerial: receiptSerial
)
}
public func createReceiptCredentialRequestContext(randomness: Randomness, receiptSerial: ReceiptSerial) throws -> ReceiptCredentialRequestContext {
public func createReceiptCredentialRequestContext(
randomness: Randomness,
receiptSerial: ReceiptSerial
) throws -> ReceiptCredentialRequestContext {
return try self.serverPublicParams.withNativeHandle { serverPublicParams in
try randomness.withUnsafePointerToBytes { randomness in
try receiptSerial.withUnsafePointerToSerialized { receiptSerial in
try invokeFnReturningSerialized {
signal_server_public_params_create_receipt_credential_request_context_deterministic($0, serverPublicParams.const(), randomness, receiptSerial)
signal_server_public_params_create_receipt_credential_request_context_deterministic(
$0,
serverPublicParams.const(),
randomness,
receiptSerial
)
}
}
}
}
}
public func receiveReceiptCredential(receiptCredentialRequestContext: ReceiptCredentialRequestContext, receiptCredentialResponse: ReceiptCredentialResponse) throws -> ReceiptCredential {
public func receiveReceiptCredential(
receiptCredentialRequestContext: ReceiptCredentialRequestContext,
receiptCredentialResponse: ReceiptCredentialResponse
) throws -> ReceiptCredential {
return try self.serverPublicParams.withNativeHandle { serverPublicParams in
try receiptCredentialRequestContext.withUnsafePointerToSerialized { requestContext in
try receiptCredentialResponse.withUnsafePointerToSerialized { response in
try invokeFnReturningSerialized {
signal_server_public_params_receive_receipt_credential($0, serverPublicParams.const(), requestContext, response)
signal_server_public_params_receive_receipt_credential(
$0,
serverPublicParams.const(),
requestContext,
response
)
}
}
}
}
}
public func createReceiptCredentialPresentation(receiptCredential: ReceiptCredential) throws -> ReceiptCredentialPresentation {
return try self.createReceiptCredentialPresentation(randomness: Randomness.generate(), receiptCredential: receiptCredential)
public func createReceiptCredentialPresentation(
receiptCredential: ReceiptCredential
) throws -> ReceiptCredentialPresentation {
return try self.createReceiptCredentialPresentation(
randomness: Randomness.generate(),
receiptCredential: receiptCredential
)
}
public func createReceiptCredentialPresentation(randomness: Randomness, receiptCredential: ReceiptCredential) throws -> ReceiptCredentialPresentation {
public func createReceiptCredentialPresentation(
randomness: Randomness,
receiptCredential: ReceiptCredential
) throws -> ReceiptCredentialPresentation {
return try self.serverPublicParams.withNativeHandle { serverPublicParams in
try randomness.withUnsafePointerToBytes { randomness in
try receiptCredential.withUnsafePointerToSerialized { receiptCredential in
try invokeFnReturningSerialized {
signal_server_public_params_create_receipt_credential_presentation_deterministic($0, serverPublicParams.const(), randomness, receiptCredential)
signal_server_public_params_create_receipt_credential_presentation_deterministic(
$0,
serverPublicParams.const(),
randomness,
receiptCredential
)
}
}
}

View File

@@ -11,13 +11,30 @@ public class CreateCallLinkCredential: ByteArray, @unchecked Sendable {
try super.init(contents, checkValid: signal_create_call_link_credential_check_valid_contents)
}
public func present<RoomId: ContiguousBytes>(roomId: RoomId, userId: Aci, serverParams: GenericServerPublicParams, callLinkParams: CallLinkSecretParams) -> CreateCallLinkCredentialPresentation {
public func present<RoomId: ContiguousBytes>(
roomId: RoomId,
userId: Aci,
serverParams: GenericServerPublicParams,
callLinkParams: CallLinkSecretParams
) -> CreateCallLinkCredentialPresentation {
return failOnError {
self.present(roomId: roomId, userId: userId, serverParams: serverParams, callLinkParams: callLinkParams, randomness: try .generate())
self.present(
roomId: roomId,
userId: userId,
serverParams: serverParams,
callLinkParams: callLinkParams,
randomness: try .generate()
)
}
}
public func present<RoomId: ContiguousBytes>(roomId: RoomId, userId: Aci, serverParams: GenericServerPublicParams, callLinkParams: CallLinkSecretParams, randomness: Randomness) -> CreateCallLinkCredentialPresentation {
public func present<RoomId: ContiguousBytes>(
roomId: RoomId,
userId: Aci,
serverParams: GenericServerPublicParams,
callLinkParams: CallLinkSecretParams,
randomness: Randomness
) -> CreateCallLinkCredentialPresentation {
return failOnError {
try withUnsafeBorrowedBuffer { contents in
try roomId.withUnsafeBorrowedBuffer { roomId in
@@ -26,7 +43,15 @@ public class CreateCallLinkCredential: ByteArray, @unchecked Sendable {
try callLinkParams.withUnsafeBorrowedBuffer { callLinkParams in
try randomness.withUnsafePointerToBytes { randomness in
try invokeFnReturningVariableLengthSerialized {
signal_create_call_link_credential_present_deterministic($0, contents, roomId, userId, serverParams, callLinkParams, randomness)
signal_create_call_link_credential_present_deterministic(
$0,
contents,
roomId,
userId,
serverParams,
callLinkParams,
randomness
)
}
}
}

View File

@@ -11,12 +11,25 @@ public class CreateCallLinkCredentialPresentation: ByteArray, @unchecked Sendabl
try super.init(contents, checkValid: signal_create_call_link_credential_presentation_check_valid_contents)
}
public func verify<RoomId: ContiguousBytes>(roomId: RoomId, now: Date = Date(), serverParams: GenericServerSecretParams, callLinkParams: CallLinkPublicParams) throws {
public func verify<RoomId: ContiguousBytes>(
roomId: RoomId,
now: Date = Date(),
serverParams: GenericServerSecretParams,
callLinkParams: CallLinkPublicParams
) throws {
try withUnsafeBorrowedBuffer { contents in
try roomId.withUnsafeBorrowedBuffer { roomId in
try serverParams.withUnsafeBorrowedBuffer { serverParams in
try callLinkParams.withUnsafeBorrowedBuffer { callLinkParams in
try checkError(signal_create_call_link_credential_presentation_verify(contents, roomId, UInt64(now.timeIntervalSince1970), serverParams, callLinkParams))
try checkError(
signal_create_call_link_credential_presentation_verify(
contents,
roomId,
UInt64(now.timeIntervalSince1970),
serverParams,
callLinkParams
)
)
}
}
}

View File

@@ -11,20 +11,36 @@ public class CreateCallLinkCredentialRequest: ByteArray, @unchecked Sendable {
try super.init(contents, checkValid: signal_create_call_link_credential_request_check_valid_contents)
}
public func issueCredential(userId: Aci, timestamp: Date, params: GenericServerSecretParams) -> CreateCallLinkCredentialResponse {
public func issueCredential(
userId: Aci,
timestamp: Date,
params: GenericServerSecretParams
) -> CreateCallLinkCredentialResponse {
return failOnError {
self.issueCredential(userId: userId, timestamp: timestamp, params: params, randomness: try .generate())
}
}
public func issueCredential(userId: Aci, timestamp: Date, params: GenericServerSecretParams, randomness: Randomness) -> CreateCallLinkCredentialResponse {
public func issueCredential(
userId: Aci,
timestamp: Date,
params: GenericServerSecretParams,
randomness: Randomness
) -> CreateCallLinkCredentialResponse {
return failOnError {
try withUnsafeBorrowedBuffer { contents in
try userId.withPointerToFixedWidthBinary { userId in
try params.withUnsafeBorrowedBuffer { params in
try randomness.withUnsafePointerToBytes { randomness in
try invokeFnReturningVariableLengthSerialized {
signal_create_call_link_credential_request_issue_deterministic($0, contents, userId, UInt64(timestamp.timeIntervalSince1970), params, randomness)
signal_create_call_link_credential_request_issue_deterministic(
$0,
contents,
userId,
UInt64(timestamp.timeIntervalSince1970),
params,
randomness
)
}
}
}

View File

@@ -39,13 +39,23 @@ public class CreateCallLinkCredentialRequestContext: ByteArray, @unchecked Senda
}
}
public func receive(_ response: CreateCallLinkCredentialResponse, userId: Aci, params: GenericServerPublicParams) throws -> CreateCallLinkCredential {
public func receive(
_ response: CreateCallLinkCredentialResponse,
userId: Aci,
params: GenericServerPublicParams
) throws -> CreateCallLinkCredential {
return try withUnsafeBorrowedBuffer { contents in
try response.withUnsafeBorrowedBuffer { response in
try userId.withPointerToFixedWidthBinary { userId in
try params.withUnsafeBorrowedBuffer { params in
try invokeFnReturningVariableLengthSerialized {
signal_create_call_link_credential_request_context_receive_response($0, contents, response, userId, params)
signal_create_call_link_credential_request_context_receive_response(
$0,
contents,
response,
userId,
params
)
}
}
}

View File

@@ -28,7 +28,11 @@ public class GroupSendDerivedKeyPair: ByteArray, @unchecked Sendable {
return failOnError {
try params.withNativeHandle { params in
try invokeFnReturningVariableLengthSerialized {
signal_group_send_derived_key_pair_for_expiration($0, UInt64(expiration.timeIntervalSince1970), params.const())
signal_group_send_derived_key_pair_for_expiration(
$0,
UInt64(expiration.timeIntervalSince1970),
params.const()
)
}
}
}

View File

@@ -72,7 +72,10 @@ public class GroupSendEndorsement: ByteArray, @unchecked Sendable {
return slices.withUnsafeBufferPointer { slices in
failOnError {
try invokeFnReturningVariableLengthSerialized {
signal_group_send_endorsement_combine($0, SignalBorrowedSliceOfBuffers(base: slices.baseAddress, length: slices.count))
signal_group_send_endorsement_combine(
$0,
SignalBorrowedSliceOfBuffers(base: slices.baseAddress, length: slices.count)
)
}
}
}

View File

@@ -45,7 +45,12 @@ public class GroupSendEndorsementsResponse: ByteArray, @unchecked Sendable {
try keyPair.withUnsafeBorrowedBuffer { keyPair in
try randomness.withUnsafePointerToBytes { randomness in
try invokeFnReturningVariableLengthSerialized {
signal_group_send_endorsements_response_issue_deterministic($0, concatenated, keyPair, randomness)
signal_group_send_endorsements_response_issue_deterministic(
$0,
concatenated,
keyPair,
randomness
)
}
}
}
@@ -99,7 +104,15 @@ public class GroupSendEndorsementsResponse: ByteArray, @unchecked Sendable {
try groupParams.withUnsafePointerToSerialized { groupParams in
try serverParams.withNativeHandle { serverParams in
try invokeFnReturningBytestringArray {
signal_group_send_endorsements_response_receive_and_combine_with_service_ids($0, response, groupMembers, localUser, UInt64(now.timeIntervalSince1970), groupParams, serverParams.const())
signal_group_send_endorsements_response_receive_and_combine_with_service_ids(
$0,
response,
groupMembers,
localUser,
UInt64(now.timeIntervalSince1970),
groupParams,
serverParams.const()
)
}
}
}
@@ -137,7 +150,14 @@ public class GroupSendEndorsementsResponse: ByteArray, @unchecked Sendable {
try localUser.withUnsafeBorrowedBuffer { localUser in
try serverParams.withNativeHandle { serverParams in
try invokeFnReturningBytestringArray {
signal_group_send_endorsements_response_receive_and_combine_with_ciphertexts($0, response, groupMembers, localUser, UInt64(now.timeIntervalSince1970), serverParams.const())
signal_group_send_endorsements_response_receive_and_combine_with_ciphertexts(
$0,
response,
groupMembers,
localUser,
UInt64(now.timeIntervalSince1970),
serverParams.const()
)
}
}
}

View File

@@ -13,14 +13,18 @@ public struct Randomness: Sendable {
}
static func generate() throws -> Randomness {
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)
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
)
try withUnsafeMutableBytes(of: &bytes) {
try fillRandom($0)
}
return Randomness(bytes)
}
func withUnsafePointerToBytes<Result>(_ callback: (UnsafePointer<SignalRandomnessBytes>) throws -> Result) rethrows -> Result {
func withUnsafePointerToBytes<Result>(
_ callback: (UnsafePointer<SignalRandomnessBytes>) throws -> Result
) rethrows -> Result {
try withUnsafePointer(to: self.bytes, callback)
}
}

View File

@@ -38,7 +38,9 @@ public class ServerPublicParams: NativeHandleOwner<SignalMutPointerServerPublicP
try withNativeHandle { contents in
try message.withUnsafeBorrowedBuffer { message in
try notarySignature.withUnsafePointerToSerialized { notarySignature in
try checkError(signal_server_public_params_verify_signature(contents.const(), message, notarySignature))
try checkError(
signal_server_public_params_verify_signature(contents.const(), message, notarySignature)
)
}
}
}
@@ -54,7 +56,9 @@ public class ServerPublicParams: NativeHandleOwner<SignalMutPointerServerPublicP
}
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerServerPublicParams>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerServerPublicParams>
) -> SignalFfiErrorRef? {
signal_server_public_params_destroy(handle.pointer)
}
}

View File

@@ -65,7 +65,9 @@ public class ServerSecretParams: NativeHandleOwner<SignalMutPointerServerSecretP
}
}
override internal class func destroyNativeHandle(_ handle: NonNull<SignalMutPointerServerSecretParams>) -> SignalFfiErrorRef? {
override internal class func destroyNativeHandle(
_ handle: NonNull<SignalMutPointerServerSecretParams>
) -> SignalFfiErrorRef? {
signal_server_secret_params_destroy(handle.pointer)
}
}

View File

@@ -13,17 +13,38 @@ public class ServerZkAuthOperations {
self.serverSecretParams = serverSecretParams
}
public func issueAuthCredentialWithPniZkc(aci: Aci, pni: Pni, redemptionTime: UInt64) throws -> AuthCredentialWithPniResponse {
return try self.issueAuthCredentialWithPniZkc(randomness: Randomness.generate(), aci: aci, pni: pni, redemptionTime: redemptionTime)
public func issueAuthCredentialWithPniZkc(
aci: Aci,
pni: Pni,
redemptionTime: UInt64
) throws -> AuthCredentialWithPniResponse {
return try self.issueAuthCredentialWithPniZkc(
randomness: Randomness.generate(),
aci: aci,
pni: pni,
redemptionTime: redemptionTime
)
}
public func issueAuthCredentialWithPniZkc(randomness: Randomness, aci: Aci, pni: Pni, redemptionTime: UInt64) throws -> AuthCredentialWithPniResponse {
public func issueAuthCredentialWithPniZkc(
randomness: Randomness,
aci: Aci,
pni: Pni,
redemptionTime: UInt64
) throws -> AuthCredentialWithPniResponse {
return try self.serverSecretParams.withNativeHandle { serverSecretParams in
try randomness.withUnsafePointerToBytes { randomness in
try aci.withPointerToFixedWidthBinary { aci in
try pni.withPointerToFixedWidthBinary { pni in
try invokeFnReturningVariableLengthSerialized {
signal_server_secret_params_issue_auth_credential_with_pni_zkc_deterministic($0, serverSecretParams.const(), randomness, aci, pni, redemptionTime)
signal_server_secret_params_issue_auth_credential_with_pni_zkc_deterministic(
$0,
serverSecretParams.const(),
randomness,
aci,
pni,
redemptionTime
)
}
}
}
@@ -31,11 +52,22 @@ public class ServerZkAuthOperations {
}
}
public func verifyAuthCredentialPresentation(groupPublicParams: GroupPublicParams, authCredentialPresentation: AuthCredentialPresentation, now: Date = Date()) throws {
public func verifyAuthCredentialPresentation(
groupPublicParams: GroupPublicParams,
authCredentialPresentation: AuthCredentialPresentation,
now: Date = Date()
) throws {
try self.serverSecretParams.withNativeHandle { serverSecretParams in
try groupPublicParams.withUnsafePointerToSerialized { groupPublicParams in
try authCredentialPresentation.withUnsafeBorrowedBuffer { authCredentialPresentation in
try checkError(signal_server_secret_params_verify_auth_credential_presentation(serverSecretParams.const(), groupPublicParams, authCredentialPresentation, UInt64(now.timeIntervalSince1970)))
try checkError(
signal_server_secret_params_verify_auth_credential_presentation(
serverSecretParams.const(),
groupPublicParams,
authCredentialPresentation,
UInt64(now.timeIntervalSince1970)
)
)
}
}
}

View File

@@ -13,18 +13,43 @@ public class ServerZkProfileOperations {
self.serverSecretParams = serverSecretParams
}
public func issueExpiringProfileKeyCredential(profileKeyCredentialRequest: ProfileKeyCredentialRequest, userId: Aci, profileKeyCommitment: ProfileKeyCommitment, expiration: UInt64) throws -> ExpiringProfileKeyCredentialResponse {
return try self.issueExpiringProfileKeyCredential(randomness: Randomness.generate(), profileKeyCredentialRequest: profileKeyCredentialRequest, userId: userId, profileKeyCommitment: profileKeyCommitment, expiration: expiration)
public func issueExpiringProfileKeyCredential(
profileKeyCredentialRequest: ProfileKeyCredentialRequest,
userId: Aci,
profileKeyCommitment: ProfileKeyCommitment,
expiration: UInt64
) throws -> ExpiringProfileKeyCredentialResponse {
return try self.issueExpiringProfileKeyCredential(
randomness: Randomness.generate(),
profileKeyCredentialRequest: profileKeyCredentialRequest,
userId: userId,
profileKeyCommitment: profileKeyCommitment,
expiration: expiration
)
}
public func issueExpiringProfileKeyCredential(randomness: Randomness, profileKeyCredentialRequest: ProfileKeyCredentialRequest, userId: Aci, profileKeyCommitment: ProfileKeyCommitment, expiration: UInt64) throws -> ExpiringProfileKeyCredentialResponse {
public func issueExpiringProfileKeyCredential(
randomness: Randomness,
profileKeyCredentialRequest: ProfileKeyCredentialRequest,
userId: Aci,
profileKeyCommitment: ProfileKeyCommitment,
expiration: UInt64
) throws -> ExpiringProfileKeyCredentialResponse {
return try self.serverSecretParams.withNativeHandle { serverSecretParams in
try randomness.withUnsafePointerToBytes { randomness in
try profileKeyCredentialRequest.withUnsafePointerToSerialized { request in
try userId.withPointerToFixedWidthBinary { userId in
try profileKeyCommitment.withUnsafePointerToSerialized { commitment in
try invokeFnReturningSerialized {
signal_server_secret_params_issue_expiring_profile_key_credential_deterministic($0, serverSecretParams.const(), randomness, request, userId, commitment, expiration)
signal_server_secret_params_issue_expiring_profile_key_credential_deterministic(
$0,
serverSecretParams.const(),
randomness,
request,
userId,
commitment,
expiration
)
}
}
}
@@ -41,7 +66,14 @@ public class ServerZkProfileOperations {
try self.serverSecretParams.withNativeHandle { serverSecretParams in
try groupPublicParams.withUnsafePointerToSerialized { groupPublicParams in
try profileKeyCredentialPresentation.withUnsafeBorrowedBuffer { presentation in
try checkError(signal_server_secret_params_verify_profile_key_credential_presentation(serverSecretParams.const(), groupPublicParams, presentation, UInt64(now.timeIntervalSince1970)))
try checkError(
signal_server_secret_params_verify_profile_key_credential_presentation(
serverSecretParams.const(),
groupPublicParams,
presentation,
UInt64(now.timeIntervalSince1970)
)
)
}
}
}

View File

@@ -13,26 +13,53 @@ public class ServerZkReceiptOperations {
self.serverSecretParams = serverSecretParams
}
public func issueReceiptCredential(receiptCredentialRequest: ReceiptCredentialRequest, receiptExpirationTime: UInt64, receiptLevel: UInt64) throws -> ReceiptCredentialResponse {
return try self.issueReceiptCredential(randomness: Randomness.generate(), receiptCredentialRequest: receiptCredentialRequest, receiptExpirationTime: receiptExpirationTime, receiptLevel: receiptLevel)
public func issueReceiptCredential(
receiptCredentialRequest: ReceiptCredentialRequest,
receiptExpirationTime: UInt64,
receiptLevel: UInt64
) throws -> ReceiptCredentialResponse {
return try self.issueReceiptCredential(
randomness: Randomness.generate(),
receiptCredentialRequest: receiptCredentialRequest,
receiptExpirationTime: receiptExpirationTime,
receiptLevel: receiptLevel
)
}
public func issueReceiptCredential(randomness: Randomness, receiptCredentialRequest: ReceiptCredentialRequest, receiptExpirationTime: UInt64, receiptLevel: UInt64) throws -> ReceiptCredentialResponse {
public func issueReceiptCredential(
randomness: Randomness,
receiptCredentialRequest: ReceiptCredentialRequest,
receiptExpirationTime: UInt64,
receiptLevel: UInt64
) throws -> ReceiptCredentialResponse {
return try self.serverSecretParams.withNativeHandle { serverSecretParams in
try randomness.withUnsafePointerToBytes { randomness in
try receiptCredentialRequest.withUnsafePointerToSerialized { receiptCredentialRequest in
try invokeFnReturningSerialized {
signal_server_secret_params_issue_receipt_credential_deterministic($0, serverSecretParams.const(), randomness, receiptCredentialRequest, receiptExpirationTime, receiptLevel)
signal_server_secret_params_issue_receipt_credential_deterministic(
$0,
serverSecretParams.const(),
randomness,
receiptCredentialRequest,
receiptExpirationTime,
receiptLevel
)
}
}
}
}
}
public func verifyReceiptCredentialPresentation(receiptCredentialPresentation: ReceiptCredentialPresentation) throws {
public func verifyReceiptCredentialPresentation(receiptCredentialPresentation: ReceiptCredentialPresentation) throws
{
try self.serverSecretParams.withNativeHandle { serverSecretParams in
try receiptCredentialPresentation.withUnsafePointerToSerialized { receiptCredentialPresentation in
try checkError(signal_server_secret_params_verify_receipt_credential_presentation(serverSecretParams.const(), receiptCredentialPresentation))
try checkError(
signal_server_secret_params_verify_receipt_credential_presentation(
serverSecretParams.const(),
receiptCredentialPresentation
)
)
}
}
}

View File

@@ -17,7 +17,10 @@ class AccountEntropyTests: TestCaseBase {
for _ in 0..<numTestIterations {
let pool = AccountEntropyPool.generate()
XCTAssertTrue(generatedEntropyPools.insert(pool).inserted, "Generated pool should be unique, got repeat: \(pool)")
XCTAssertTrue(
generatedEntropyPools.insert(pool).inserted,
"Generated pool should be unique, got repeat: \(pool)"
)
XCTAssertEqual(pool.count, 64, "Pool \(pool) is not the right length")
for c in pool {
XCTAssertTrue(validCharacters.contains(c), "Generated pool \(pool) contains invalid character \(c)")

View File

@@ -84,7 +84,9 @@ extension SignalFfi.SignalConstPointerTestingFutureCancellationCounter: LibSigna
}
}
private final class CancelCounter: NativeHandleOwner<SignalMutPointerTestingFutureCancellationCounter>, @unchecked Sendable {
private final class CancelCounter: NativeHandleOwner<SignalMutPointerTestingFutureCancellationCounter>, @unchecked
Sendable
{
public convenience init(initialValue: UInt8 = 0) {
var out = SignalMutPointerTestingFutureCancellationCounter()
failOnError {
@@ -96,12 +98,19 @@ private final class CancelCounter: NativeHandleOwner<SignalMutPointerTestingFutu
public func waitForCount(asyncContext: TokioAsyncContext, target: UInt8) async throws {
let _: Bool = try await asyncContext.invokeAsyncFunction { promise, asyncContext in
self.withNativeHandle {
signal_testing_future_cancellation_counter_wait_for_count(promise, asyncContext.const(), $0.const(), target)
signal_testing_future_cancellation_counter_wait_for_count(
promise,
asyncContext.const(),
$0.const(),
target
)
}
}
}
override static func destroyNativeHandle(_ nativeHandle: NonNull<SignalMutPointerTestingFutureCancellationCounter>) -> SignalFfiErrorRef? {
override static func destroyNativeHandle(
_ nativeHandle: NonNull<SignalMutPointerTestingFutureCancellationCounter>
) -> SignalFfiErrorRef? {
signal_testing_future_cancellation_counter_destroy(nativeHandle.pointer)
}
}
@@ -109,7 +118,11 @@ private final class CancelCounter: NativeHandleOwner<SignalMutPointerTestingFutu
final class AsyncTests: TestCaseBase {
func testSuccess() async throws {
let result: Int32 = try await invokeAsyncFunction {
signal_testing_future_success($0, SignalConstPointerNonSuspendingBackgroundThreadRuntime(raw: OpaquePointer(bitPattern: -1)), 21)
signal_testing_future_success(
$0,
SignalConstPointerNonSuspendingBackgroundThreadRuntime(raw: OpaquePointer(bitPattern: -1)),
21
)
}
XCTAssertEqual(42, result)
}
@@ -117,7 +130,11 @@ final class AsyncTests: TestCaseBase {
func testFailure() async throws {
do {
let _: Int32 = try await invokeAsyncFunction {
signal_testing_future_failure($0, SignalConstPointerNonSuspendingBackgroundThreadRuntime(raw: OpaquePointer(bitPattern: -1)), 21)
signal_testing_future_failure(
$0,
SignalConstPointerNonSuspendingBackgroundThreadRuntime(raw: OpaquePointer(bitPattern: -1)),
21
)
}
XCTFail("should have failed")
} catch SignalError.invalidArgument(_) {
@@ -129,27 +146,37 @@ final class AsyncTests: TestCaseBase {
do {
let value = UInt8(44)
let handle = try await invokeAsyncFunction {
signal_testing_future_produces_pointer_type($0, SignalConstPointerNonSuspendingBackgroundThreadRuntime(raw: OpaquePointer(bitPattern: -1)), value)
signal_testing_future_produces_pointer_type(
$0,
SignalConstPointerNonSuspendingBackgroundThreadRuntime(raw: OpaquePointer(bitPattern: -1)),
value
)
}
defer { signal_testing_handle_type_destroy(handle) }
XCTAssertEqual(
try invokeFnReturningInteger { result in
signal_testing_testing_handle_type_get_value(result, handle.const())
}, value
},
value
)
}
do {
let value = "into the future"
let otherHandle = try await invokeAsyncFunction {
signal_testing_future_produces_other_pointer_type($0, SignalConstPointerNonSuspendingBackgroundThreadRuntime(raw: OpaquePointer(bitPattern: -1)), value)
signal_testing_future_produces_other_pointer_type(
$0,
SignalConstPointerNonSuspendingBackgroundThreadRuntime(raw: OpaquePointer(bitPattern: -1)),
value
)
}
defer { signal_other_testing_handle_type_destroy(otherHandle) }
XCTAssertEqual(
try invokeFnReturningString { result in
signal_testing_other_testing_handle_type_get_value(result, otherHandle.const())
}, value
},
value
)
}
}

View File

@@ -188,10 +188,15 @@ final class BridgingTests: XCTestCase {
let result = try first.withUnsafeBytes { first in
try empty.withUnsafeBytes { empty in
try second.withUnsafeBytes { second in
let slices = [SignalBorrowedBuffer(first), SignalBorrowedBuffer(empty), SignalBorrowedBuffer(second)]
let slices = [
SignalBorrowedBuffer(first), SignalBorrowedBuffer(empty), SignalBorrowedBuffer(second),
]
return try slices.withUnsafeBufferPointer { slices in
try invokeFnReturningBytestringArray {
signal_testing_process_bytestring_array($0, SignalBorrowedSliceOfBuffers(base: slices.baseAddress, length: slices.count))
signal_testing_process_bytestring_array(
$0,
SignalBorrowedSliceOfBuffers(base: slices.baseAddress, length: slices.count)
)
}
}
}
@@ -204,7 +209,10 @@ final class BridgingTests: XCTestCase {
let slices: [SignalBorrowedBuffer] = []
let result = try slices.withUnsafeBufferPointer { slices in
try invokeFnReturningBytestringArray {
signal_testing_process_bytestring_array($0, SignalBorrowedSliceOfBuffers(base: slices.baseAddress, length: slices.count))
signal_testing_process_bytestring_array(
$0,
SignalBorrowedSliceOfBuffers(base: slices.baseAddress, length: slices.count)
)
}
}
XCTAssertEqual(result, [])
@@ -223,13 +231,16 @@ final class BridgingTests: XCTestCase {
signal_testing_bridged_string_map_dump_to_json($0, map.const())
}
}
XCTAssertEqual(dumped, """
XCTAssertEqual(
dumped,
"""
{
"a": "aaa",
"b": "bbb",
"c": "ccc"
}
""")
"""
)
}
func testReturnOptionalUuid() throws {

View File

@@ -4,15 +4,16 @@
//
import Foundation
@testable import LibSignalClient
import SignalFfi
import XCTest
@testable import LibSignalClient
extension ConnectionManager {
func assertIsUsingProxyIs(_ value: Int32) {
// The testing native function used to implement this isn't available on device
// builds to save on code size. If it's present use it, otherwise this is a no-op.
#if !os(iOS) || targetEnvironment(simulator)
// The testing native function used to implement this isn't available on device
// builds to save on code size. If it's present use it, otherwise this is a no-op.
#if !os(iOS) || targetEnvironment(simulator)
let isUsingProxy =
withNativeHandle { handle in
failOnError {
@@ -22,15 +23,15 @@ extension ConnectionManager {
}
}
XCTAssertEqual(isUsingProxy, value)
#endif
#endif
}
}
final class ChatServiceTests: TestCaseBase {
private static let userAgent = "test"
// These testing endpoints aren't generated in device builds, to save on code size.
#if !os(iOS) || targetEnvironment(simulator)
// These testing endpoints aren't generated in device builds, to save on code size.
#if !os(iOS) || targetEnvironment(simulator)
private static let expectedStatus: UInt16 = 200
private static let expectedMessage = "OK"
@@ -127,27 +128,45 @@ final class ChatServiceTests: TestCaseBase {
let expectedMethod = "GET"
let expectedPathAndQuery = "/test"
let request = ChatConnection.Request(method: expectedMethod, pathAndQuery: expectedPathAndQuery, headers: Self.expectedHeaders, body: Self.expectedContent, timeout: 5)
let request = ChatConnection.Request(
method: expectedMethod,
pathAndQuery: expectedPathAndQuery,
headers: Self.expectedHeaders,
body: Self.expectedContent,
timeout: 5
)
let internalRequest = try ChatConnection.Request.InternalRequest(request)
try internalRequest.withNativeHandle { internalRequest in
XCTAssertEqual(expectedMethod, try invokeFnReturningString {
signal_testing_chat_request_get_method($0, internalRequest.const())
})
XCTAssertEqual(expectedPathAndQuery, try invokeFnReturningString {
signal_testing_chat_request_get_path($0, internalRequest.const())
})
XCTAssertEqual(Self.expectedContent, try invokeFnReturningData {
signal_testing_chat_request_get_body($0, internalRequest.const())
})
XCTAssertEqual(
expectedMethod,
try invokeFnReturningString {
signal_testing_chat_request_get_method($0, internalRequest.const())
}
)
XCTAssertEqual(
expectedPathAndQuery,
try invokeFnReturningString {
signal_testing_chat_request_get_path($0, internalRequest.const())
}
)
XCTAssertEqual(
Self.expectedContent,
try invokeFnReturningData {
signal_testing_chat_request_get_body($0, internalRequest.const())
}
)
for (k, v) in Self.expectedHeaders {
XCTAssertEqual(v, try invokeFnReturningString {
signal_testing_chat_request_get_header_value($0, internalRequest.const(), k)
})
XCTAssertEqual(
v,
try invokeFnReturningString {
signal_testing_chat_request_get_header_value($0, internalRequest.const(), k)
}
)
}
}
}
#endif
#endif
func testInvalidProxyRejected() {
let net = Net(env: .production, userAgent: Self.userAgent)
@@ -182,8 +201,8 @@ final class ChatServiceTests: TestCaseBase {
final class ChatConnectionTests: TestCaseBase {
private static let userAgent = "test"
// These testing endpoints aren't generated in device builds, to save on code size.
#if !os(iOS) || targetEnvironment(simulator)
// These testing endpoints aren't generated in device builds, to save on code size.
#if !os(iOS) || targetEnvironment(simulator)
func testListenerCallbacks() async throws {
class Listener: ChatConnectionListener {
let queueEmpty: XCTestExpectation
@@ -193,7 +212,10 @@ final class ChatConnectionTests: TestCaseBase {
let connectionInterrupted: XCTestExpectation
var expectations: [XCTestExpectation] {
[self.alertsReceived, self.firstMessageReceived, self.secondMessageReceived, self.queueEmpty, self.connectionInterrupted]
[
self.alertsReceived, self.firstMessageReceived, self.secondMessageReceived, self.queueEmpty,
self.connectionInterrupted,
]
}
init(
@@ -210,7 +232,12 @@ final class ChatConnectionTests: TestCaseBase {
self.connectionInterrupted = connectionInterrupted
}
func chatConnection(_: AuthenticatedChatConnection, didReceiveIncomingMessage envelope: Data, serverDeliveryTimestamp: UInt64, sendAck: () throws -> Void) {
func chatConnection(
_: AuthenticatedChatConnection,
didReceiveIncomingMessage envelope: Data,
serverDeliveryTimestamp: UInt64,
sendAck: () throws -> Void
) {
// This assumes a little-endian platform.
XCTAssertEqual(envelope, withUnsafeBytes(of: serverDeliveryTimestamp) { Data($0) })
switch serverDeliveryTimestamp {
@@ -263,13 +290,17 @@ final class ChatConnectionTests: TestCaseBase {
// 3: {1000i64}
// 5: {"x-signal-timestamp:1000"}
// 4: 1
fakeRemote.injectServerRequest(base64: "CgNQVVQSDy9hcGkvdjEvbWVzc2FnZRoI6AMAAAAAAAAqF3gtc2lnbmFsLXRpbWVzdGFtcDoxMDAwIAE=")
fakeRemote.injectServerRequest(
base64: "CgNQVVQSDy9hcGkvdjEvbWVzc2FnZRoI6AMAAAAAAAAqF3gtc2lnbmFsLXRpbWVzdGFtcDoxMDAwIAE="
)
// 1: {"PUT"}
// 2: {"/api/v1/message"}
// 3: {2000i64}
// 5: {"x-signal-timestamp:2000"}
// 4: 2
fakeRemote.injectServerRequest(base64: "CgNQVVQSDy9hcGkvdjEvbWVzc2FnZRoI0AcAAAAAAAAqF3gtc2lnbmFsLXRpbWVzdGFtcDoyMDAwIAI=")
fakeRemote.injectServerRequest(
base64: "CgNQVVQSDy9hcGkvdjEvbWVzc2FnZRoI0AcAAAAAAAAqF3gtc2lnbmFsLXRpbWVzdGFtcDoyMDAwIAI="
)
// Sending an invalid message should not affect the listener at all, nor should it stop future requests.
// 1: {"PUT"}
@@ -289,15 +320,29 @@ final class ChatConnectionTests: TestCaseBase {
func testAuthenticatedSending() async throws {
class NoOpListener: ChatConnectionListener {
func chatConnection(_: AuthenticatedChatConnection, didReceiveIncomingMessage envelope: Data, serverDeliveryTimestamp: UInt64, sendAck: () throws -> Void) {}
func chatConnection(
_: AuthenticatedChatConnection,
didReceiveIncomingMessage envelope: Data,
serverDeliveryTimestamp: UInt64,
sendAck: () throws -> Void
) {}
func connectionWasInterrupted(_: AuthenticatedChatConnection, error: Error?) {}
}
let tokioAsyncContext = TokioAsyncContext()
let (chat, fakeRemote) = AuthenticatedChatConnection.fakeConnect(tokioAsyncContext: tokioAsyncContext, listener: NoOpListener())
let (chat, fakeRemote) = AuthenticatedChatConnection.fakeConnect(
tokioAsyncContext: tokioAsyncContext,
listener: NoOpListener()
)
defer { withExtendedLifetime(chat) {} }
let request = ChatRequest(method: "PUT", pathAndQuery: "/some/path", headers: ["purpose": "test request"], body: Data([1, 1, 2, 3]), timeout: TimeInterval(5))
let request = ChatRequest(
method: "PUT",
pathAndQuery: "/some/path",
headers: ["purpose": "test request"],
body: Data([1, 1, 2, 3]),
timeout: TimeInterval(5)
)
async let responseFuture = chat.send(request)
let (requestFromServer, id) = try await fakeRemote.getNextIncomingRequest()
@@ -326,10 +371,19 @@ final class ChatConnectionTests: TestCaseBase {
func connectionWasInterrupted(_: UnauthenticatedChatConnection, error: Error?) {}
}
let tokioAsyncContext = TokioAsyncContext()
let (chat, fakeRemote) = UnauthenticatedChatConnection.fakeConnect(tokioAsyncContext: tokioAsyncContext, listener: NoOpListener())
let (chat, fakeRemote) = UnauthenticatedChatConnection.fakeConnect(
tokioAsyncContext: tokioAsyncContext,
listener: NoOpListener()
)
defer { withExtendedLifetime(chat) {} }
let request = ChatRequest(method: "PUT", pathAndQuery: "/some/path", headers: ["purpose": "test request"], body: Data([1, 1, 2, 3]), timeout: TimeInterval(5))
let request = ChatRequest(
method: "PUT",
pathAndQuery: "/some/path",
headers: ["purpose": "test request"],
body: Data([1, 1, 2, 3]),
timeout: TimeInterval(5)
)
async let responseFuture = chat.send(request)
let (requestFromServer, id) = try await fakeRemote.getNextIncomingRequest()
@@ -352,7 +406,7 @@ final class ChatConnectionTests: TestCaseBase {
XCTAssertEqual(responseFromServer.headers, ["purpose": "test response"])
XCTAssertEqual(responseFromServer.body, Data([5]))
}
#endif
#endif
func testListenerCleanup() async throws {
// Use the presence of the environment setting to know whether we should make network requests in our tests.

View File

@@ -3,9 +3,10 @@
// SPDX-License-Identifier: AGPL-3.0-only
//
@testable import LibSignalClient
import XCTest
@testable import LibSignalClient
private struct FakeHandle {
// We're using the tuple to guarantee in-memory layout for this test.
// It's a little sketchy but it keeps the test from getting more complicated.
@@ -14,7 +15,10 @@ private struct FakeHandle {
}
private class MockClonableHandleOwner: ClonableHandleOwner<OpaquePointer?> {
override class func cloneNativeHandle(_ newHandle: inout OpaquePointer?, currentHandle: OpaquePointer?) -> SignalFfiErrorRef? {
override class func cloneNativeHandle(
_ newHandle: inout OpaquePointer?,
currentHandle: OpaquePointer?
) -> SignalFfiErrorRef? {
XCTAssertFalse(UnsafePointer<Bool>(currentHandle!).pointee)
newHandle = OpaquePointer(UnsafePointer<Bool>(currentHandle!) + 1)
return nil

File diff suppressed because one or more lines are too long

View File

@@ -10,14 +10,18 @@ class HsmEnclaveTests: TestCaseBase {
func testCreateClient() {
let validKey = IdentityKeyPair.generate().publicKey
var hashes = HsmCodeHashList()
try! hashes.append(Data([
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]))
try! hashes.append(Data([
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
]))
try! hashes.append(
Data([
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
])
)
try! hashes.append(
Data([
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
])
)
let hsmEnclaveClient = try! HsmEnclaveClient(publicKey: validKey.keyBytes, codeHashes: hashes)
let initialMessage = hsmEnclaveClient.initialRequest()
XCTAssertEqual(112, initialMessage.count)
@@ -32,10 +36,12 @@ class HsmEnclaveTests: TestCaseBase {
func testCompleteHandshakeWithoutInitialRequest() {
let validKey = IdentityKeyPair.generate().publicKey
var hashes = HsmCodeHashList()
try! hashes.append(Data([
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]))
try! hashes.append(
Data([
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
])
)
let hsmEnclaveClient = try! HsmEnclaveClient(publicKey: validKey.keyBytes, codeHashes: hashes)
let handshakeResponse: [UInt8] = [0x01, 0x02, 0x03]
XCTAssertThrowsError(try hsmEnclaveClient.completeHandshake(handshakeResponse))
@@ -44,10 +50,12 @@ class HsmEnclaveTests: TestCaseBase {
func testEstablishedSendFailsPriorToEstablishment() {
let validKey = IdentityKeyPair.generate().publicKey
var hashes = HsmCodeHashList()
try! hashes.append(Data([
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]))
try! hashes.append(
Data([
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
])
)
let hsmEnclaveClient = try! HsmEnclaveClient(publicKey: validKey.keyBytes, codeHashes: hashes)
let plaintextToSend: [UInt8] = [0x01, 0x02, 0x03]
XCTAssertThrowsError(try hsmEnclaveClient.establishedSend(plaintextToSend))
@@ -56,10 +64,12 @@ class HsmEnclaveTests: TestCaseBase {
func testEstablishedRecvFailsPriorToEstablishment() {
let validKey = IdentityKeyPair.generate().publicKey
var hashes = HsmCodeHashList()
try! hashes.append(Data([
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
]))
try! hashes.append(
Data([
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
])
)
let hsmEnclaveClient = try! HsmEnclaveClient(publicKey: validKey.keyBytes, codeHashes: hashes)
let receivedCiphertext: [UInt8] = [0x01, 0x02, 0x03]
XCTAssertThrowsError(try hsmEnclaveClient.establishedRecv(receivedCiphertext))

View File

@@ -16,14 +16,17 @@ class InMemorySignalProtocolStoreTests: TestCaseBase {
let firstIdentity = IdentityKeyPair.generate().identityKey
XCTAssert(
try store.isTrustedIdentity(firstIdentity, for: address, direction: .sending, context: context))
try store.isTrustedIdentity(firstIdentity, for: address, direction: .sending, context: context)
)
XCTAssertEqual(
try store.saveIdentity(firstIdentity, for: address, context: context), .newOrUnchanged
try store.saveIdentity(firstIdentity, for: address, context: context),
.newOrUnchanged
)
// Idempotent
XCTAssertEqual(
try store.saveIdentity(firstIdentity, for: address, context: context), .newOrUnchanged
try store.saveIdentity(firstIdentity, for: address, context: context),
.newOrUnchanged
)
XCTAssert(try store.isTrustedIdentity(firstIdentity, for: address, direction: .sending, context: context))
XCTAssertEqual(try store.identity(for: address, context: context), firstIdentity)
@@ -31,7 +34,8 @@ class InMemorySignalProtocolStoreTests: TestCaseBase {
let secondIdentity = IdentityKeyPair.generate().identityKey
XCTAssertFalse(
try store.isTrustedIdentity(secondIdentity, for: address, direction: .sending, context: context))
try store.isTrustedIdentity(secondIdentity, for: address, direction: .sending, context: context)
)
XCTAssertEqual(
try store.saveIdentity(secondIdentity, for: address, context: context),
.replacedExisting
@@ -43,7 +47,8 @@ class InMemorySignalProtocolStoreTests: TestCaseBase {
)
XCTAssert(
try store.isTrustedIdentity(secondIdentity, for: address, direction: .sending, context: context))
try store.isTrustedIdentity(secondIdentity, for: address, direction: .sending, context: context)
)
XCTAssertEqual(try store.identity(for: address, context: context), secondIdentity)
}
}

View File

@@ -10,7 +10,9 @@ import XCTest
class IncrementalMacTests: TestCaseBase {
private let TEST_KEY = Data(base64Encoded: "qDSBRX7+zGmtE0LiHZwCl/cd679ckwS0wbLkM8Gnj5g=")!
private let TEST_INPUT = ["this is a test", " input to the incremental ", "mac stream"].map { Data($0.utf8) }
private let TEST_DIGEST = Data(base64Encoded: "hIkvcGAOVJ+3KHlmep2WonPxRLaY/571p2BipWBhqQmIT22fQpGKnkdu1RjErI9xS9M/BFFSrgSYd/09Gw2yWg==")!
private let TEST_DIGEST = Data(
base64Encoded: "hIkvcGAOVJ+3KHlmep2WonPxRLaY/571p2BipWBhqQmIT22fQpGKnkdu1RjErI9xS9M/BFFSrgSYd/09Gw2yWg=="
)!
private let CHUNK_SIZE = SizeChoice.bytes(32)
func testIncrementalDigestCreation() throws {

View File

@@ -3,13 +3,14 @@
// SPDX-License-Identifier: AGPL-3.0-only
//
@testable import LibSignalClient
@testable import SignalFfi
import XCTest
@testable import LibSignalClient
@testable import SignalFfi
class IoTests: TestCaseBase {
// These testing endpoints aren't generated in device builds, to save on code size.
#if !os(iOS) || targetEnvironment(simulator)
// These testing endpoints aren't generated in device builds, to save on code size.
#if !os(iOS) || targetEnvironment(simulator)
func testReadIntoEmptyBuffer() throws {
let input = Data("ABCDEFGHIJKLMNOPQRSTUVWXYZ".utf8)
let inputStream = SignalInputStreamAdapter(input)
@@ -20,5 +21,5 @@ class IoTests: TestCaseBase {
}
XCTAssertEqual(input, output)
}
#endif
#endif
}

Some files were not shown because too many files have changed in this diff Show More