mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 21:33:26 +00:00
Require acknowledgement to send to verified users who have unsigned devices or have changed their identity. (#3215)
* Refactor HeroImage style. * Add a screen to resolve (crypto-related) timeline item send failures. * Refactor send failures. * Update the SDK.
This commit is contained in:
@@ -20,7 +20,7 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
||||
private var innerPinnedEventsTimelineTask: Task<TimelineProxyProtocol?, Never>?
|
||||
var pinnedEventsTimeline: TimelineProxyProtocol? {
|
||||
get async {
|
||||
// Check if is alrrady available.
|
||||
// Check if is already available.
|
||||
if let innerPinnedEventsTimeline {
|
||||
return innerPinnedEventsTimeline
|
||||
// Otherwise check if there is already a task loading it, and wait for it.
|
||||
@@ -35,7 +35,10 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
||||
}
|
||||
|
||||
do {
|
||||
let timeline = try await TimelineProxy(timeline: room.pinnedEventsTimeline(internalIdPrefix: nil, maxEventsToLoad: 100), kind: .pinned)
|
||||
let timeline = try await TimelineProxy(timeline: room.pinnedEventsTimeline(internalIdPrefix: nil,
|
||||
maxEventsToLoad: 100,
|
||||
maxConcurrentRequests: 10),
|
||||
kind: .pinned)
|
||||
await timeline.subscribeForUpdates()
|
||||
innerPinnedEventsTimeline = timeline
|
||||
return timeline
|
||||
@@ -377,6 +380,51 @@ class JoinedRoomProxy: JoinedRoomProxyProtocol {
|
||||
}
|
||||
}
|
||||
|
||||
func resend(itemID: TimelineItemIdentifier) async -> Result<Void, RoomProxyError> {
|
||||
guard let transactionID = itemID.transactionID else {
|
||||
MXLog.error("Attempting to resend an item that has no transaction ID: \(itemID)")
|
||||
return .failure(.missingTransactionID)
|
||||
}
|
||||
|
||||
do {
|
||||
try await room.tryResend(transactionId: transactionID)
|
||||
return .success(())
|
||||
} catch {
|
||||
MXLog.error("Failed resending \(transactionID) with error: \(error)")
|
||||
return .failure(.sdkError(error))
|
||||
}
|
||||
}
|
||||
|
||||
func ignoreDeviceTrustAndResend(devices: [String: [String]], itemID: TimelineItemIdentifier) async -> Result<Void, RoomProxyError> {
|
||||
guard let transactionID = itemID.transactionID else {
|
||||
MXLog.error("Attempting to resend an item that has no transaction ID: \(itemID)")
|
||||
return .failure(.missingTransactionID)
|
||||
}
|
||||
|
||||
do {
|
||||
try await room.ignoreDeviceTrustAndResend(devices: devices, transactionId: transactionID)
|
||||
return .success(())
|
||||
} catch {
|
||||
MXLog.error("Failed trusting devices \(devices) and resending \(transactionID) with error: \(error)")
|
||||
return .failure(.sdkError(error))
|
||||
}
|
||||
}
|
||||
|
||||
func withdrawVerificationAndResend(userIDs: [String], itemID: TimelineItemIdentifier) async -> Result<Void, RoomProxyError> {
|
||||
guard let transactionID = itemID.transactionID else {
|
||||
MXLog.error("Attempting to resend an item that has no transaction ID: \(itemID)")
|
||||
return .failure(.missingTransactionID)
|
||||
}
|
||||
|
||||
do {
|
||||
try await room.withdrawVerificationAndResend(userIds: userIDs, transactionId: transactionID)
|
||||
return .success(())
|
||||
} catch {
|
||||
MXLog.error("Failed withdrawing verification of \(userIDs) and resending \(transactionID) with error: \(error)")
|
||||
return .failure(.sdkError(error))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Room flags
|
||||
|
||||
func flagAsUnread(_ isUnread: Bool) async -> Result<Void, RoomProxyError> {
|
||||
|
||||
@@ -15,6 +15,7 @@ enum RoomProxyError: Error {
|
||||
case invalidURL
|
||||
case invalidMedia
|
||||
case eventNotFound
|
||||
case missingTransactionID
|
||||
}
|
||||
|
||||
enum RoomProxyType {
|
||||
@@ -111,6 +112,12 @@ protocol JoinedRoomProxyProtocol: RoomProxyProtocol {
|
||||
/// https://spec.matrix.org/v1.9/client-server-api/#typing-notifications
|
||||
@discardableResult func sendTypingNotification(isTyping: Bool) async -> Result<Void, RoomProxyError>
|
||||
|
||||
func resend(itemID: TimelineItemIdentifier) async -> Result<Void, RoomProxyError>
|
||||
|
||||
func ignoreDeviceTrustAndResend(devices: [String: [String]], itemID: TimelineItemIdentifier) async -> Result<Void, RoomProxyError>
|
||||
|
||||
func withdrawVerificationAndResend(userIDs: [String], itemID: TimelineItemIdentifier) async -> Result<Void, RoomProxyError>
|
||||
|
||||
// MARK: - Room Flags
|
||||
|
||||
func flagAsUnread(_ isUnread: Bool) async -> Result<Void, RoomProxyError>
|
||||
|
||||
@@ -59,13 +59,7 @@ enum TimelineItemProxy {
|
||||
enum TimelineItemDeliveryStatus: Hashable {
|
||||
case sending
|
||||
case sent
|
||||
case sendingFailed(SendFailureReason)
|
||||
|
||||
enum SendFailureReason: Hashable {
|
||||
case verifiedUserHasUnsignedDevice(devices: [String: [String]])
|
||||
case verifiedUserChangedIdentity(users: [String])
|
||||
case unknown
|
||||
}
|
||||
case sendingFailed(TimelineItemSendFailure)
|
||||
|
||||
var isSendingFailed: Bool {
|
||||
switch self {
|
||||
@@ -75,6 +69,24 @@ enum TimelineItemDeliveryStatus: Hashable {
|
||||
}
|
||||
}
|
||||
|
||||
/// The reason a timeline item failed to send.
|
||||
enum TimelineItemSendFailure: Hashable {
|
||||
enum VerifiedUser: Hashable {
|
||||
case hasUnsignedDevice(devices: [String: [String]])
|
||||
case changedIdentity(users: [String])
|
||||
|
||||
var affectedUserIDs: [String] {
|
||||
switch self {
|
||||
case .hasUnsignedDevice(let devices): Array(devices.keys)
|
||||
case .changedIdentity(let users): users
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case verifiedUser(VerifiedUser)
|
||||
case unknown
|
||||
}
|
||||
|
||||
/// A light wrapper around event timeline items returned from Rust.
|
||||
class EventTimelineItemProxy {
|
||||
let item: MatrixRustSDK.EventTimelineItem
|
||||
@@ -98,9 +110,9 @@ class EventTimelineItemProxy {
|
||||
case .sent:
|
||||
return .sent
|
||||
case .verifiedUserHasUnsignedDevice(devices: let devices):
|
||||
return .sendingFailed(.verifiedUserHasUnsignedDevice(devices: devices))
|
||||
return .sendingFailed(.verifiedUser(.hasUnsignedDevice(devices: devices)))
|
||||
case .verifiedUserChangedIdentity(users: let users):
|
||||
return .sendingFailed(.verifiedUserChangedIdentity(users: users))
|
||||
return .sendingFailed(.verifiedUser(.changedIdentity(users: users)))
|
||||
case .crossSigningNotSetup, .sendingFromUnverifiedDevice:
|
||||
return .sendingFailed(.unknown)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user