Skip to content

Commit 561e8e9

Browse files
typfelnetbe
andauthored
chore: update core crypto to 5.x - WPB-15886 (#2806)
Co-authored-by: François Benaiteau <[email protected]>
1 parent 8551e3c commit 561e8e9

File tree

85 files changed

+2207
-3088
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

85 files changed

+2207
-3088
lines changed

WireAPI/Sources/WireAPI/APIs/MLSAPI/MLSAPI.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,14 @@ public protocol MLSAPI {
2525

2626
func getBackendMLSPublicKeys() async throws -> BackendMLSPublicKeys
2727

28+
/// Post a commit bundle.
29+
///
30+
/// - Parameter bundle: commit bundle to post
31+
/// - Returns: updates events generated by the commit
32+
///
33+
/// Available from ``APIVersion`` v5.
34+
///
35+
36+
func postCommitBundle(_ bundle: CommitBundle) async throws -> [UpdateEvent]
37+
2838
}

WireAPI/Sources/WireAPI/APIs/MLSAPI/MLSAPIError.swift

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,17 @@ import Foundation
2020

2121
/// Errors originating from `MLSAPI`.
2222

23-
public enum MLSAPIError: Error {
23+
public enum MLSAPIError: Error, Codable, Equatable {
24+
25+
public init(from string: String) throws {
26+
self = try JSONDecoder().decode(MLSAPIError.self, from: Data(string.utf8))
27+
}
28+
29+
public func encodeAsString() throws -> String {
30+
let encoder = JSONEncoder()
31+
encoder.outputFormatting = .sortedKeys
32+
return String(decoding: try encoder.encode(self), as: UTF8.self)
33+
}
2434

2535
/// Unsupported endpoint for API version
2636

@@ -30,4 +40,20 @@ public enum MLSAPIError: Error {
3040

3141
case mlsNotEnabled
3242

43+
/// Message was sent in an too old epoch
44+
45+
case mlsStaleMessage
46+
47+
/// A proposal of type Add or Remove does not apply to the full list of clients for a user
48+
49+
case mlsClientMismatch
50+
51+
/// The commit is not referencing all pending proposals
52+
53+
case mlsCommitMissingReferences
54+
55+
/// Generic error for all non recoverable MLS error
56+
57+
case mlsError(_ label: String, _ message: String)
58+
3359
}

WireAPI/Sources/WireAPI/APIs/MLSAPI/MLSAPIV0.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,8 @@ class MLSAPIV0: MLSAPI, VersionedAPI {
3838
throw MLSAPIError.unsupportedEndpointForAPIVersion
3939
}
4040

41+
func postCommitBundle(_ bundle: CommitBundle) async throws -> [UpdateEvent] {
42+
throw MLSAPIError.unsupportedEndpointForAPIVersion
43+
}
44+
4145
}

WireAPI/Sources/WireAPI/APIs/MLSAPI/MLSAPIV5.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,40 @@ class MLSAPIV5: MLSAPIV4 {
4141
.parse(code: response.statusCode, data: data)
4242
}
4343

44+
override func postCommitBundle(_ bundle: CommitBundle) async throws -> [UpdateEvent] {
45+
let request = try URLRequestBuilder(path: "\(pathPrefix)/mls/commit-bundles")
46+
.withMethod(.post)
47+
.withAcceptType(.json)
48+
.withBody(bundle.transportData(), contentType: .mls)
49+
.build()
50+
51+
let (data, response) = try await apiService.executeRequest(
52+
request,
53+
requiringAccessToken: true
54+
)
55+
56+
do {
57+
return try ResponseParser()
58+
.success(code: .created, type: CommitBundleResponseV5.self)
59+
.failure(code: .conflict, label: "mls-stale-message", error: MLSAPIError.mlsStaleMessage)
60+
.failure(code: .conflict, label: "mls-client-mismatch", error: MLSAPIError.mlsClientMismatch)
61+
.failure(
62+
code: .badRequest,
63+
label: "mls-commit-missing-references",
64+
error: MLSAPIError.mlsCommitMissingReferences
65+
)
66+
.failure(code: .conflict, decodableError: FailureResponse.self)
67+
.parse(code: response.statusCode, data: data)
68+
} catch {
69+
if let failureResponse = error as? FailureResponse {
70+
throw MLSAPIError.mlsError(failureResponse.label, failureResponse.message)
71+
} else {
72+
throw error
73+
}
74+
}
75+
76+
}
77+
4478
}
4579

4680
private struct BackendMLSPublicKeysResponseV5: Decodable, ToAPIModelConvertible {
@@ -52,3 +86,14 @@ private struct BackendMLSPublicKeysResponseV5: Decodable, ToAPIModelConvertible
5286
}
5387

5488
}
89+
90+
private struct CommitBundleResponseV5: Decodable, ToAPIModelConvertible {
91+
92+
let time: UTCTime?
93+
let events: [UpdateEventDecodingProxy]
94+
95+
func toAPIModel() -> [UpdateEvent] {
96+
events.map(\.updateEvent)
97+
}
98+
99+
}

wire-ios-data-model/Source/MLS/ExternalCommitError.swift renamed to WireAPI/Sources/WireAPI/Models/MLS/CommitBundle.swift

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,35 +18,30 @@
1818

1919
import Foundation
2020

21-
enum ExternalCommitError: Error, Equatable {
21+
public struct CommitBundle: Sendable, Equatable {
2222

23-
case failedToSendCommit(recovery: RecoveryStrategy, cause: SendCommitBundleAction.Failure)
24-
case failedToMergePendingGroup
25-
case failedToClearPendingGroup
23+
public var welcome: Data?
2624

27-
enum RecoveryStrategy {
25+
public var commit: Data
2826

29-
/// Retry the action from the beginning
30-
case retry
31-
32-
/// Abort the action and log the error
33-
case giveUp
27+
public var groupInfo: Data
3428

29+
public init(welcome: Data?, commit: Data, groupInfo: Data) {
30+
self.welcome = welcome
31+
self.commit = commit
32+
self.groupInfo = groupInfo
3533
}
36-
}
3734

38-
extension ExternalCommitError.RecoveryStrategy {
35+
func transportData() -> Data {
36+
var data = Data()
37+
data.append(commit)
3938

40-
/// Whether the pending group should be cleared
39+
if let welcome {
40+
data.append(welcome)
41+
}
4142

42-
var shouldClearPendingGroup: Bool {
43-
switch self {
44-
case .retry:
45-
false
43+
data.append(groupInfo)
4644

47-
case .giveUp:
48-
true
49-
}
45+
return data
5046
}
51-
5247
}

WireAPI/Sources/WireAPI/Network/URLRequestBuilder/HTTPContentType.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@ enum HTTPContentType: String {
2020

2121
case json = "application/json"
2222

23+
case mls = "message/mls"
24+
2325
}

WireAPI/Tests/WireAPITests/APIs/MLSAPI/MLSAPITests.swift

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,83 @@ final class MLSAPITests: XCTestCase {
103103
try await api.getBackendMLSPublicKeys()
104104
}
105105
}
106+
107+
// MARK: - Send commit bundle
108+
109+
func testPostCommitBundleRequest() async throws {
110+
// Given
111+
let apiVersions = APIVersion.v5.andNextVersions
112+
113+
// Then
114+
try await apiSnapshotHelper.verifyRequest(for: apiVersions) { sut in
115+
// When
116+
_ = try await sut.postCommitBundle(Scaffolding.commitBundle)
117+
}
118+
}
119+
120+
func testPostCommitBundle_SuccessResponse_201_V5_And_Next_Versions() async throws {
121+
// Given
122+
try await withThrowingTaskGroup(of: [UpdateEvent].self) { taskGroup in
123+
let testedVersions = APIVersion.v5.andNextVersions
124+
125+
for version in testedVersions {
126+
let apiService = MockAPIServiceProtocol.withResponses([
127+
(.created, "PostCommitBundleSuccessResponse1")
128+
])
129+
let sut = version.buildAPI(apiService: apiService)
130+
131+
taskGroup.addTask {
132+
// When
133+
try await sut.postCommitBundle(Scaffolding.commitBundle)
134+
}
135+
136+
for try await value in taskGroup {
137+
// Then
138+
XCTAssertEqual(value, [], "should get 201 for APIVersion \(version)")
139+
}
140+
}
141+
}
142+
}
143+
144+
func testPostCommitBundle_SuccessResponseWithEvents_201_V5_And_Next_Versions() async throws {
145+
// Given
146+
try await withThrowingTaskGroup(of: [UpdateEvent].self) { taskGroup in
147+
let testedVersions = APIVersion.v5.andNextVersions
148+
149+
for version in testedVersions {
150+
let apiService = MockAPIServiceProtocol.withResponses([
151+
(.created, "PostCommitBundleSuccessResponse2")
152+
])
153+
let sut = version.buildAPI(apiService: apiService)
154+
155+
taskGroup.addTask {
156+
// When
157+
try await sut.postCommitBundle(Scaffolding.commitBundle)
158+
}
159+
160+
for try await value in taskGroup {
161+
// Then
162+
XCTAssertEqual(value, Scaffolding.updateEvents, "should get 201 for APIVersion \(version)")
163+
}
164+
}
165+
}
166+
}
167+
168+
func testPostCommitBundle_givenV5AndErrorResponse() async throws {
169+
// Given
170+
let apiService = MockAPIServiceProtocol.withError(
171+
statusCode: .conflict,
172+
label: "mls-stale-message"
173+
)
174+
175+
let api = MLSAPIV5(apiService: apiService)
176+
177+
// Then
178+
await XCTAssertThrowsErrorAsync(MLSAPIError.mlsStaleMessage) {
179+
// When
180+
try await api.postCommitBundle(Scaffolding.commitBundle)
181+
}
182+
}
106183
}
107184

108185
private extension APIVersion {
@@ -113,3 +190,19 @@ private extension APIVersion {
113190
}
114191

115192
}
193+
194+
// MARK: Helpers
195+
196+
private enum Scaffolding {
197+
198+
static let commitBundle = CommitBundle(
199+
welcome: nil,
200+
commit: Data("commit".utf8),
201+
groupInfo: Data("groupinfo".utf8)
202+
)
203+
204+
static let updateEvents = [
205+
UpdateEvent.unknown(eventType: "some event")
206+
]
207+
208+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"events":[],
3+
"time":"2025-03-31T15:09:38.196Z"
4+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"events":[{
3+
"type": "some event"
4+
}],
5+
"time":"2025-04-01T10:28:55.622Z"
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
curl \
2+
--request POST \
3+
--header "Accept: application/json" \
4+
--header "Content-Type: message/mls" \
5+
--data "commitgroupinfo" \
6+
"/v5/mls/commit-bundles"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
curl \
2+
--request POST \
3+
--header "Accept: application/json" \
4+
--header "Content-Type: message/mls" \
5+
--data "commitgroupinfo" \
6+
"/v6/mls/commit-bundles"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
curl \
2+
--request POST \
3+
--header "Accept: application/json" \
4+
--header "Content-Type: message/mls" \
5+
--data "commitgroupinfo" \
6+
"/v7/mls/commit-bundles"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
curl \
2+
--request POST \
3+
--header "Accept: application/json" \
4+
--header "Content-Type: message/mls" \
5+
--data "commitgroupinfo" \
6+
"/v8/mls/commit-bundles"

WireCoreCrypto/Package.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,25 @@ let package = Package(
1111
.library(
1212
name: "WireCoreCrypto",
1313
targets: ["WireCoreCrypto"]
14+
),
15+
.library(
16+
name: "WireCoreCryptoUniffi",
17+
targets: ["WireCoreCryptoUniffi"]
1418
)
1519
],
1620
dependencies: [],
1721
targets: [
1822
.binaryTarget(
1923
name: "WireCoreCrypto",
20-
url: "https://github.com/wireapp/core-crypto/releases/download/v3.1.1/WireCoreCrypto.xcframework.zip",
21-
checksum: "fc1ec9eb58d6324ab32c34d131c7a22838e076e16461b00da3506e3be3488011"
24+
url: "https://github.com/wireapp/core-crypto/releases/download/v5.3.0/WireCoreCrypto.xcframework.zip",
25+
checksum: "d291cf8ef997b1414448890446893465bb2147f23b396e92e6a8098de948b7f9"
26+
),
27+
// this is an internal dependency to WireCoreCrypto but currently needs to explictly
28+
// added as a dependency due to limitations of Swift packages.
29+
.binaryTarget(
30+
name: "WireCoreCryptoUniffi",
31+
url: "https://github.com/wireapp/core-crypto/releases/download/v5.3.0/WireCoreCryptoUniffi.xcframework.zip",
32+
checksum: "4931c7473c83e157f5c89a6e6dda9a087d746e97f9b0a4443b106cb56e5b8789"
2233
)
2334
]
2435
)

0 commit comments

Comments
 (0)