Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions WireCoreCrypto/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@ let package = Package(
targets: [
.binaryTarget(
name: "WireCoreCrypto",
url: "https://github.com/wireapp/core-crypto/releases/download/v8.0.0/WireCoreCrypto.xcframework.zip",
checksum: "d372f1eda32f5fc4bfa0ac0ee51468fb06336072e50d6d0b254fce90853080e7"
url: "https://github.com/wireapp/core-crypto/releases/download/v9.1.2/WireCoreCrypto.xcframework.zip",
checksum: "152fa5e1f43c05c283106df2ab51267092d8b92f02b15debc91f8b237dda1490"
),
// this is an internal dependency to WireCoreCrypto but currently needs to explictly
// added as a dependency due to limitations of Swift packages.
.binaryTarget(
name: "WireCoreCryptoUniffi",
url: "https://github.com/wireapp/core-crypto/releases/download/v8.0.0/WireCoreCryptoUniffi.xcframework.zip",
checksum: "21ccdb11ec709eec593f5fb9dd3b77df01195e81560740e7ecbc6a2d189be3a6"
url: "https://github.com/wireapp/core-crypto/releases/download/v9.1.2/WireCoreCryptoUniffi.xcframework.zip",
checksum: "bf5a9b2cc90e1311f245fe0772530230e49a330a43cb688be5a2e2f6c6dd0f87"
)
]
)
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,23 @@ public class CoreCryptoKeyMigrationManager: CoreCryptoKeyMigrationManagerProtoco
attributes: .safePublic
)

try await migrateDatabaseKeyTypeToBytes(path: path, oldKey: oldKey, newKey: newKey)
try await migrateDatabaseKeyTypeToBytes(
path: path,
oldKey: oldKey,
newKey: DatabaseKey(key: newKey)
)
journal[.isCoreCryptoKeyMigrationToBytesRequired] = false

WireLogger.coreCrypto.info("Core crypto key is migrated to bytes successfully", attributes: .safePublic)
}

public func updateKey(path: String, oldKey: Data, newKey: Data) async throws {
do {
try await updateDatabaseKey(name: path, oldKey: oldKey, newKey: newKey)
try await updateDatabaseKey(
name: path,
oldKey: DatabaseKey(key: oldKey),
newKey: DatabaseKey(key: newKey)
)
} catch {
throw CoreCryptoKeyMigrationManagerError.failedToUpdateKey(underlyingError: error)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import Foundation
import WireCoreCrypto
import WireDataModel
import WireLogging

Check warning on line 23 in WireDomain/Sources/WireDomain/Synchronization/IncrementalSyncV2.swift

View workflow job for this annotation

GitHub Actions / Test Results

Add '@preconcurrency' to suppress 'Sendable'-related warnings from module 'WireNetwork'

Add '@preconcurrency' to suppress 'Sendable'-related warnings from module 'WireNetwork'
import WireNetwork

public typealias CreatePushChannelStateClosure = () -> PushChannelStateProtocol
Expand Down Expand Up @@ -154,14 +154,14 @@
// because we might be interrupted when in background, we wrap the sync in an expiringActivity that will
// cancel the task (not keeping any file lock in suspend mode)
try await withExpiringActivity(reason: "processLiveStream IncrementalSyncV2") {
await processLiveStream(

Check warning on line 157 in WireDomain/Sources/WireDomain/Synchronization/IncrementalSyncV2.swift

View workflow job for this annotation

GitHub Actions / Test Results

Capture of 'liveEventStream' with non-Sendable type 'PushChannelV2.Stream' (aka 'AsyncThrowingStream<PushChannelV2.Element, any Error>') in a '@Sendable' closure; this is an error in the Swift 6 language mode

Capture of 'liveEventStream' with non-Sendable type 'PushChannelV2.Stream' (aka 'AsyncThrowingStream<PushChannelV2.Element, any Error>') in a '@sendable' closure; this is an error in the Swift 6 language mode

Check warning on line 157 in WireDomain/Sources/WireDomain/Synchronization/IncrementalSyncV2.swift

View workflow job for this annotation

GitHub Actions / Test Results

Capture of 'liveEventStream' with non-Sendable type 'PushChannelV2.Stream' (aka 'AsyncThrowingStream<PushChannelV2.Element, any Error>') in an isolated closure; this is an error in the Swift 6 language mode

Capture of 'liveEventStream' with non-Sendable type 'PushChannelV2.Stream' (aka 'AsyncThrowingStream<PushChannelV2.Element, any Error>') in an isolated closure; this is an error in the Swift 6 language mode
liveEventStream,
pushChannel: pushChannel,
syncMarker: syncMarker
)

WireLogger.sync.debug("Live stream ended, close push channel", attributes: logAttributes)
await pushChannel.close()

Check warning on line 164 in WireDomain/Sources/WireDomain/Synchronization/IncrementalSyncV2.swift

View workflow job for this annotation

GitHub Actions / Test Results

Capture of 'pushChannelState' with non-Sendable type 'any PushChannelStateProtocol' in a '@Sendable' closure; this is an error in the Swift 6 language mode

Capture of 'pushChannelState' with non-Sendable type 'any PushChannelStateProtocol' in a '@sendable' closure; this is an error in the Swift 6 language mode

Check warning on line 164 in WireDomain/Sources/WireDomain/Synchronization/IncrementalSyncV2.swift

View workflow job for this annotation

GitHub Actions / Test Results

Capture of 'pushChannelState' with non-Sendable type 'any PushChannelStateProtocol' in an isolated closure; this is an error in the Swift 6 language mode

Capture of 'pushChannelState' with non-Sendable type 'any PushChannelStateProtocol' in an isolated closure; this is an error in the Swift 6 language mode
await pushChannelState.markAsClosed()
}
} catch {
Expand Down Expand Up @@ -318,7 +318,7 @@
var storedEnvelopes: [(UpdateEventEnvelope, Int64)] = []

// decrypt
try await coreCryptoProvider.coreCrypto().perform { coreCryptoContext in
try await coreCryptoProvider.coreCrypto().transaction { coreCryptoContext in
for envelope in envelopes {
var envelope = envelope
envelope.events = await decryptEnvelope(envelope, in: coreCryptoContext)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public struct PullPendingUpdateEventsSync: PullPendingUpdateEventsSyncProtocol {
let currentIndex = try await store.indexOfLastEventEnvelope() + 1

// We are decrypting the batch within one core crypto transaction
try await coreCryptoProvider.coreCrypto().perform { context in
try await coreCryptoProvider.coreCrypto().transaction { context in

var lastEnvelopeID: UUID?
var decryptedEnvelopes: [UpdateEventEnvelope] = []
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public struct PullPendingUpdateEventsSyncV2: PullPendingUpdateEventsSyncV2Protoc
var storedEnvelopes: [(UpdateEventEnvelope, Int64)] = []

// decrypt
try await coreCryptoProvider.coreCrypto().perform { coreCryptoContext in
try await coreCryptoProvider.coreCrypto().transaction { coreCryptoContext in
for envelope in envelopes {
var envelope = envelope
envelope.events = await decryptEnvelope(envelope, in: coreCryptoContext)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ final class IncrementalSyncV2Tests: XCTestCase {
var databaseSaver: MockDatabaseSaverProtocol!
var syncStateSubject: CurrentValueSubject<SyncState, Never>!
var liveDelegate: MockLiveSyncDelegate!
var coreCrypto: MockSafeCoreCrypto!
var coreCryptoContext: MockCoreCryptoContextProtocol!
var coreCrypto: MockCoreCryptoProtocol!
var coreCryptoProvider: MockCoreCryptoProviderProtocol!
var pushChannelState: MockPushChannelStateProtocol!
var mlsGroupRepairAgent: MockMLSGroupRepairAgentProtocol!
Expand All @@ -53,7 +54,9 @@ final class IncrementalSyncV2Tests: XCTestCase {
databaseSaver = MockDatabaseSaverProtocol()
liveDelegate = MockLiveSyncDelegate()
syncStateSubject = .init(.idle)
coreCrypto = MockSafeCoreCrypto()
coreCryptoContext = MockCoreCryptoContextProtocol()
coreCrypto = MockCoreCryptoProtocol()
coreCrypto.mockTransaction(context: coreCryptoContext)
coreCryptoProvider = MockCoreCryptoProviderProtocol()
coreCryptoProvider.coreCrypto_MockValue = coreCrypto
journal = Journal(
Expand Down Expand Up @@ -107,6 +110,7 @@ final class IncrementalSyncV2Tests: XCTestCase {
liveDelegate = nil
coreCrypto = nil
coreCryptoProvider = nil
coreCryptoContext = nil
}

func testPerform_pendingEventsExist() async throws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ final class PullPendingUpdateEventsSyncTests: XCTestCase {
private var api: MockUpdateEventsAPI!
private var store: MockUpdateEventsLocalStoreProtocol!
private var decryptor: MockUpdateEventDecryptorProtocol!
private var coreCrypto: MockSafeCoreCrypto!
private var coreCryptoContext: MockCoreCryptoContextProtocol!
private var coreCrypto: MockCoreCryptoProtocol!
private var coreCryptoProvider: MockCoreCryptoProviderProtocol!

override func setUp() async throws {
Expand All @@ -41,7 +42,9 @@ final class PullPendingUpdateEventsSyncTests: XCTestCase {
api = MockUpdateEventsAPI()
store = MockUpdateEventsLocalStoreProtocol()
decryptor = MockUpdateEventDecryptorProtocol()
coreCrypto = MockSafeCoreCrypto()
coreCryptoContext = MockCoreCryptoContextProtocol()
coreCrypto = MockCoreCryptoProtocol()
coreCrypto.mockTransaction(context: coreCryptoContext)
coreCryptoProvider = MockCoreCryptoProviderProtocol()
coreCryptoProvider.coreCrypto_MockValue = coreCrypto

Expand All @@ -56,6 +59,9 @@ final class PullPendingUpdateEventsSyncTests: XCTestCase {
}

override func tearDown() async throws {
coreCrypto = nil
coreCryptoContext = nil
coreCryptoProvider = nil
api = nil
store = nil
decryptor = nil
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ class PullPendingUpdateEventsSyncV2Tests: XCTestCase {
var processor: MockUpdateEventProcessorProtocol!
var databaseSaver: MockDatabaseSaverProtocol!
var journal: Journal!
var coreCryptoContext: MockCoreCryptoContextProtocol!
var coreCryptoProvider: MockCoreCryptoProviderProtocol!
var coreCrypto: MockSafeCoreCrypto!
var coreCrypto: MockCoreCryptoProtocol!

override func setUp() {
pushChannelAPI = MockPushChannelV2API()
Expand All @@ -46,7 +47,9 @@ class PullPendingUpdateEventsSyncV2Tests: XCTestCase {
messageLocalStore = MockMessageLocalStoreProtocol()
processor = MockUpdateEventProcessorProtocol()
coreCryptoProvider = MockCoreCryptoProviderProtocol()
coreCrypto = MockSafeCoreCrypto()
coreCryptoContext = MockCoreCryptoContextProtocol()
coreCrypto = MockCoreCryptoProtocol()
coreCrypto.mockTransaction(context: coreCryptoContext)

journal = Journal(
userID: UUID(),
Expand Down Expand Up @@ -82,6 +85,7 @@ class PullPendingUpdateEventsSyncV2Tests: XCTestCase {
databaseSaver = nil
coreCryptoProvider = nil
coreCrypto = nil
coreCryptoContext = nil
journal = nil
}

Expand Down
50 changes: 21 additions & 29 deletions wire-ios-data-model/Source/Core Crypto/CoreCryptoProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public protocol CoreCryptoProviderProtocol {
/// Retrieve the shared core crypto instance or create one if one does not yet exist.
///
/// This function is safe to be called concurrently from multiple Tasks
func coreCrypto() async throws -> SafeCoreCryptoProtocol
func coreCrypto() async throws -> CoreCryptoProtocol

/// Initialise a new MLS client with basic credentials
///
Expand Down Expand Up @@ -66,13 +66,13 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
private let featureRespository: LegacyFeatureRepositoryInterface
private let syncContext: NSManagedObjectContext
private let allowCreation: Bool
private var coreCrypto: SafeCoreCrypto?
private var coreCrypto: CoreCrypto?
private var loadingCoreCrypto = false
private var initialisatingMLS = false
private var hasInitialisedMLS = false
private var hasRegisteredMlsTransport = false
private var hasRegisteredEpochObserver = false
private var coreCryptoContinuations: [CheckedContinuation<SafeCoreCrypto, Error>] = []
private var coreCryptoContinuations: [CheckedContinuation<CoreCrypto, Error>] = []
private nonisolated(unsafe) var mlsTransport: MlsTransport?
private var epochObserver: WireCoreCryptoUniffi.EpochObserver?
private let localDomain: String?
Expand All @@ -98,7 +98,7 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
self.localDomain = localDomain
}

public func coreCrypto() async throws -> SafeCoreCryptoProtocol {
public func coreCrypto() async throws -> CoreCryptoProtocol {
let coreCrypto = try await getCoreCrypto()
try await registerMlsTransportIfNecessary(with: coreCrypto)
return coreCrypto
Expand All @@ -108,7 +108,7 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
WireLogger.mls.info("Initialising MLS client with basic credentials")
let defaultCiphersuite = await featureRespository.fetchMLS().config.defaultCipherSuite.coreCryptoCipherSuite
let coreCrypto = try await coreCrypto()
_ = try await coreCrypto.perform { context in
_ = try await coreCrypto.transaction { context in
try await context.mlsInit(
clientId: .init(bytes: mlsClientID.data),
ciphersuites: [defaultCiphersuite],
Expand All @@ -124,7 +124,7 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
) async throws -> CRLsDistributionPoints? {
WireLogger.mls.info("Initialising MLS client from end-to-end identity enrollment")
let coreCrypto = try await coreCrypto()
return try await coreCrypto.perform { context in
return try await coreCrypto.transaction { context in
let crlsDistributionPoints = try await context.e2eiMlsInitOnly(
enrollment: enrollment,
certificateChain: certificateChain,
Expand All @@ -145,13 +145,11 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
}
}

private func registerEpochObserverIfNecessary(with coreCrypto: SafeCoreCryptoProtocol) async throws {
private func registerEpochObserverIfNecessary(with coreCrypto: CoreCryptoProtocol) async throws {
guard let epochObserver, !hasRegisteredEpochObserver else {
return
}
try await coreCrypto.configure { configure in
try await configure.registerEpochObserver(epochObserver)
}
try await coreCrypto.registerEpochObserver(epochObserver)
hasRegisteredEpochObserver = true
}

Expand All @@ -163,14 +161,12 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
coreCrypto = nil
}

private func registerMlsTransportIfNecessary(with coreCrypto: SafeCoreCrypto) async throws {
private func registerMlsTransportIfNecessary(with coreCrypto: CoreCryptoProtocol) async throws {
guard let mlsTransport, !hasRegisteredMlsTransport else {
return
}

try await coreCrypto.configure { coreCrypto in
try await coreCrypto.provideTransport(transport: mlsTransport)
}
try await coreCrypto.provideTransport(transport: mlsTransport)
hasRegisteredMlsTransport = true
}

Expand All @@ -179,7 +175,7 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
//
// Based on the structured caching in an actor:
// https://forums.swift.org/t/structured-caching-in-an-actor/65501/13
private func getCoreCrypto() async throws -> SafeCoreCrypto {
private func getCoreCrypto() async throws -> CoreCrypto {
guard !loadingCoreCrypto else {
return try await withCheckedThrowingContinuation { continuation in
coreCryptoContinuations.append(continuation)
Expand All @@ -190,7 +186,7 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
return coreCrypto
} else {
loadingCoreCrypto = true
let cc: SafeCoreCrypto
let cc: CoreCrypto
do {
cc = try await createCoreCrypto()
} catch {
Expand All @@ -206,14 +202,14 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
}
}

private func resumeCoreCryptoContinuations(with result: Result<SafeCoreCrypto, Error>) {
private func resumeCoreCryptoContinuations(with result: Result<CoreCrypto, Error>) {
for continuation in coreCryptoContinuations {
continuation.resume(with: result)
}
coreCryptoContinuations = []
}

func createCoreCrypto() async throws -> SafeCoreCrypto {
func createCoreCrypto() async throws -> CoreCrypto {
let coreCryptoKeyProvider = CoreCryptoKeyProvider(
coreCryptoKeyMigrationManager: coreCryptoKeyMigrationManager,
userID: selfUserID,
Expand All @@ -227,9 +223,9 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
allowKeyCreation: allowCreation
)

let coreCrypto = try await SafeCoreCrypto(
path: configuration.path,
key: configuration.key
let coreCrypto = try await CoreCrypto(
keystorePath: configuration.path,
key: DatabaseKey(key: configuration.key)
)

updateKeychainItemAccess()
Expand All @@ -240,15 +236,11 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
return coreCrypto
}

private func configureProteusClient(coreCrypto: SafeCoreCrypto) async throws {
// here we don't need to lock the context or restoreFromDisk()
// it fixes `Mls(WireCoreCrypto.MlsError.Other("Proteus client hasn\'t been initialized"))`
// Empty transaction was committed, this could be an indication of a programming error - [core_crypto_context:
// {}]
try await coreCrypto.unsafePerform { try await $0.proteusInit() }
private func configureProteusClient(coreCrypto: CoreCrypto) async throws {
try await coreCrypto.transaction { try await $0.proteusInit() }
}

private func configureMLSClient(coreCrypto: SafeCoreCrypto) async throws {
private func configureMLSClient(coreCrypto: CoreCrypto) async throws {
let mlsClientID: MLSClientID? = await syncContext.perform {
guard
let selfClient = ZMUser.selfUser(in: self.syncContext).selfClient(),
Expand All @@ -265,7 +257,7 @@ public actor CoreCryptoProvider: CoreCryptoProviderProtocol {
// Initialise MLS if we have previously registered an MLS client
if let mlsClientID {
let cipherSuite = await featureRespository.fetchMLS().config.defaultCipherSuite.coreCryptoCipherSuite
try await coreCrypto.perform { try await $0.mlsInit(
try await coreCrypto.transaction { try await $0.mlsInit(
clientId: .init(bytes: mlsClientID.data),
ciphersuites: [cipherSuite],
nbKeyPackage: nil
Expand Down
Loading
Loading