mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 13:37:11 +00:00
Two sync loop experimental solution to decrypt push notifications (#1082)
* Experimental two sync loop solution * better logging * improved the code and handled invite notifications display better * improved invite notifications * new exerimental branch * new sync loop * code updated * code improvements * code improvements * fix typo * code improvements * removed some unused code and added a respawn * fixing some NSE issues * code improvements * new version of the branch * more logging * running the nse process ONLY IF necessary * finally works! made also the feature flag * also the encryption value of the room list api will depend on the flag now * changelog * code improvements * code improvement * updated proj * fixing some compilation error after the rebase * opt-in for the encryption sync * fix
This commit is contained in:
parent
652fd3cf76
commit
afc4332716
@ -264,6 +264,7 @@
|
||||
6860721DB3091BE08164C132 /* MapAssets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B48B7AD4908C5C374517B892 /* MapAssets.xcassets */; };
|
||||
68AC3C84E2B438036B174E30 /* EmoteRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 471EB7D96AFEA8D787659686 /* EmoteRoomTimelineView.swift */; };
|
||||
695825D20A761C678809345D /* MessageForwardingScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52135BD9E0E7A091688F627A /* MessageForwardingScreenModels.swift */; };
|
||||
69ABFBAF05D7EF11E7C88CEA /* EncryptionSyncListenerProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68356CB936A8814A3FEA66A8 /* EncryptionSyncListenerProxy.swift */; };
|
||||
69BCBB4FB2DC3D61A28D3FD8 /* TimelineStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DC2C9E0E15C79BBDA80F0A2 /* TimelineStyle.swift */; };
|
||||
69C7B956B74BEC3DB88224EA /* NavigationSplitCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 78913D6E120D46138E97C107 /* NavigationSplitCoordinatorTests.swift */; };
|
||||
6A0E7551E0D1793245F34CDD /* ClientError.swift in Sources */ = {isa = PBXBuildFile; fileRef = D09A267106B9585D3D0CFC0D /* ClientError.swift */; };
|
||||
@ -672,6 +673,7 @@
|
||||
F7BC744FFA7FE248FAE7F570 /* UserIndicatorToastView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F57C8022B8A871A1DCD1750A /* UserIndicatorToastView.swift */; };
|
||||
F86102DC2C68BBBB0521BAAE /* SoftLogoutScreenModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2BB385E148DE55C85C0A02D6 /* SoftLogoutScreenModels.swift */; };
|
||||
F8E725D42023ECA091349245 /* AudioRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 57EAAF82432B0B53881CF826 /* AudioRoomTimelineItem.swift */; };
|
||||
F91B4629E4AF51A4FE8E7608 /* EncryptionSyncListenerProxy.swift in Sources */ = {isa = PBXBuildFile; fileRef = 68356CB936A8814A3FEA66A8 /* EncryptionSyncListenerProxy.swift */; };
|
||||
F94000E3D91B11C527DA8807 /* UserProfileCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 923485F85E1D765EF9D20E88 /* UserProfileCell.swift */; };
|
||||
F9842667B68DC6FA1F9ECCBB /* NSItemProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72EFC8C634469F9262659C7 /* NSItemProvider.swift */; };
|
||||
F99FB21EFC6D99D247FE7CBE /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = DE8DC9B3FBA402117DC4C49F /* Kingfisher */; };
|
||||
@ -992,6 +994,7 @@
|
||||
6654859746B0BE9611459391 /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = cs; path = cs.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
669F35C505ACE1110589F875 /* MediaUploadingPreprocessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaUploadingPreprocessor.swift; sourceTree = "<group>"; };
|
||||
66F2402D738694F98729A441 /* RoomTimelineProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomTimelineProvider.swift; sourceTree = "<group>"; };
|
||||
68356CB936A8814A3FEA66A8 /* EncryptionSyncListenerProxy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncryptionSyncListenerProxy.swift; sourceTree = "<group>"; };
|
||||
6861FE915C7B5466E6962BBA /* StartChatScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartChatScreen.swift; sourceTree = "<group>"; };
|
||||
686BCFA37AC6C67FF973CE67 /* OnboardingBackgroundImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingBackgroundImage.swift; sourceTree = "<group>"; };
|
||||
69219A908D7C22E6EE6689AE /* UserNotificationCenterSpy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNotificationCenterSpy.swift; sourceTree = "<group>"; };
|
||||
@ -2519,6 +2522,7 @@
|
||||
832FC81F760220239E285294 /* Proxy */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
68356CB936A8814A3FEA66A8 /* EncryptionSyncListenerProxy.swift */,
|
||||
25F7FE40EF7490A7E09D7BE6 /* NotificationItemProxy.swift */,
|
||||
);
|
||||
path = Proxy;
|
||||
@ -3766,6 +3770,7 @@
|
||||
9A3B0CDF097E3838FB1B9595 /* Bundle.swift in Sources */,
|
||||
DFCA89C4EC2A5332ED6B441F /* DataProtectionManager.swift in Sources */,
|
||||
24A75F72EEB7561B82D726FD /* Date.swift in Sources */,
|
||||
F91B4629E4AF51A4FE8E7608 /* EncryptionSyncListenerProxy.swift in Sources */,
|
||||
A33784831AD880A670CAA9F9 /* FileManager.swift in Sources */,
|
||||
59F940FCBE6BC343AECEF75E /* ImageCache.swift in Sources */,
|
||||
A3E390675E9730C176B59E1B /* ImageProviderProtocol.swift in Sources */,
|
||||
@ -4006,6 +4011,7 @@
|
||||
8B1D5CE017EEC734CF5FE130 /* Encodable.swift in Sources */,
|
||||
4C5A638DAA8AF64565BA4866 /* EncryptedRoomTimelineItem.swift in Sources */,
|
||||
B5903E48CF43259836BF2DBF /* EncryptedRoomTimelineView.swift in Sources */,
|
||||
69ABFBAF05D7EF11E7C88CEA /* EncryptionSyncListenerProxy.swift in Sources */,
|
||||
F78BAD28482A467287A9A5A3 /* EventBasedMessageTimelineItemProtocol.swift in Sources */,
|
||||
02D8DF8EB7537EB4E9019DDB /* EventBasedTimelineItemProtocol.swift in Sources */,
|
||||
63E46D18B91D08E15FC04125 /* ExpiringTaskRunner.swift in Sources */,
|
||||
|
@ -11,7 +11,7 @@
|
||||
{
|
||||
"identity" : "compound-ios",
|
||||
"kind" : "remoteSourceControl",
|
||||
"location" : "https://github.com/vector-im/compound-ios.git",
|
||||
"location" : "https://github.com/vector-im/compound-ios",
|
||||
"state" : {
|
||||
"revision" : "d1a28b8a311e33ddb517d10391037f1547a3c7b6"
|
||||
}
|
||||
|
@ -563,6 +563,16 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationCoordinatorDelegate,
|
||||
selector: #selector(applicationDidBecomeActive),
|
||||
name: UIApplication.didBecomeActiveNotification,
|
||||
object: nil)
|
||||
|
||||
NotificationCenter.default.addObserver(self,
|
||||
selector: #selector(applicationWillTerminate),
|
||||
name: UIApplication.willTerminateNotification,
|
||||
object: nil)
|
||||
}
|
||||
|
||||
@objc
|
||||
private func applicationWillTerminate() {
|
||||
userSession?.clientProxy.stopSync()
|
||||
}
|
||||
|
||||
@objc
|
||||
|
@ -163,9 +163,9 @@ final class AppSettings {
|
||||
@UserPreference(key: UserDefaultsKeys.pusherProfileTag, storageType: .userDefaults(store))
|
||||
var pusherProfileTag: String?
|
||||
|
||||
/// A set of all the notification identifiers that have been served so far, it's reset every time the app is launched
|
||||
@UserPreference(key: SharedUserDefaultsKeys.servedNotificationIdentifiers, initialValue: [], storageType: .userDefaults(store))
|
||||
var servedNotificationIdentifiers: Set<String>
|
||||
/// Tag describing if the app and the NSE should use the encryption sync
|
||||
@UserPreference(key: SharedUserDefaultsKeys.isEncryptionSyncEnabled, defaultValue: false, storageType: .userDefaults(store))
|
||||
var isEncryptionSyncEnabled
|
||||
|
||||
// MARK: - Other
|
||||
|
||||
|
@ -33,10 +33,6 @@ extension UNNotificationContent {
|
||||
userInfo[NotificationConstants.UserInfoKey.receiverIdentifier] as? String
|
||||
}
|
||||
|
||||
@objc var notificationID: String? {
|
||||
userInfo[NotificationConstants.UserInfoKey.notificationIdentifier] as? String
|
||||
}
|
||||
|
||||
@objc var roomID: String? {
|
||||
userInfo[NotificationConstants.UserInfoKey.roomIdentifier] as? String
|
||||
}
|
||||
@ -74,15 +70,6 @@ extension UNMutableNotificationContent {
|
||||
}
|
||||
}
|
||||
|
||||
override var notificationID: String? {
|
||||
get {
|
||||
userInfo[NotificationConstants.UserInfoKey.notificationIdentifier] as? String
|
||||
}
|
||||
set {
|
||||
userInfo[NotificationConstants.UserInfoKey.notificationIdentifier] = newValue
|
||||
}
|
||||
}
|
||||
|
||||
func addMediaAttachment(using mediaProvider: MediaProviderProtocol?,
|
||||
mediaSource: MediaSourceProxy) async -> UNMutableNotificationContent {
|
||||
guard let mediaProvider else {
|
||||
|
@ -15,5 +15,5 @@
|
||||
//
|
||||
|
||||
enum SharedUserDefaultsKeys: String {
|
||||
case servedNotificationIdentifiers
|
||||
case isEncryptionSyncEnabled
|
||||
}
|
||||
|
@ -28,11 +28,13 @@ struct DeveloperOptionsScreenViewStateBindings {
|
||||
var shouldCollapseRoomStateEvents: Bool
|
||||
var userSuggestionsEnabled: Bool
|
||||
var readReceiptsEnabled: Bool
|
||||
var isEncryptionSyncEnabled: Bool
|
||||
}
|
||||
|
||||
enum DeveloperOptionsScreenViewAction {
|
||||
case changedShouldCollapseRoomStateEvents
|
||||
case changedUserSuggestionsEnabled
|
||||
case changedReadReceiptsEnabled
|
||||
case changedIsEncryptionSyncEnabled
|
||||
case clearCache
|
||||
}
|
||||
|
@ -27,7 +27,8 @@ class DeveloperOptionsScreenViewModel: DeveloperOptionsScreenViewModelType, Deve
|
||||
appSettings = ServiceLocator.shared.settings
|
||||
let bindings = DeveloperOptionsScreenViewStateBindings(shouldCollapseRoomStateEvents: appSettings.shouldCollapseRoomStateEvents,
|
||||
userSuggestionsEnabled: appSettings.userSuggestionsEnabled,
|
||||
readReceiptsEnabled: appSettings.readReceiptsEnabled)
|
||||
readReceiptsEnabled: appSettings.readReceiptsEnabled,
|
||||
isEncryptionSyncEnabled: appSettings.isEncryptionSyncEnabled)
|
||||
let state = DeveloperOptionsScreenViewState(bindings: bindings)
|
||||
|
||||
super.init(initialViewState: state)
|
||||
@ -45,6 +46,8 @@ class DeveloperOptionsScreenViewModel: DeveloperOptionsScreenViewModelType, Deve
|
||||
appSettings.userSuggestionsEnabled = state.bindings.userSuggestionsEnabled
|
||||
case .changedReadReceiptsEnabled:
|
||||
appSettings.readReceiptsEnabled = state.bindings.readReceiptsEnabled
|
||||
case .changedIsEncryptionSyncEnabled:
|
||||
appSettings.isEncryptionSyncEnabled = state.bindings.isEncryptionSyncEnabled
|
||||
case .clearCache:
|
||||
callback?(.clearCache)
|
||||
}
|
||||
|
@ -44,6 +44,14 @@ struct DeveloperOptionsScreen: View {
|
||||
.onChange(of: context.readReceiptsEnabled) { _ in
|
||||
context.send(viewAction: .changedReadReceiptsEnabled)
|
||||
}
|
||||
|
||||
Toggle(isOn: $context.isEncryptionSyncEnabled) {
|
||||
Text("Use notification encryption sync")
|
||||
Text("requires app reboot")
|
||||
}
|
||||
.onChange(of: context.isEncryptionSyncEnabled) { _ in
|
||||
context.send(viewAction: .changedIsEncryptionSyncEnabled)
|
||||
}
|
||||
}
|
||||
|
||||
Section {
|
||||
|
@ -28,7 +28,10 @@ class ClientProxy: ClientProxyProtocol {
|
||||
|
||||
private var roomListService: RoomListService?
|
||||
private var roomListStateUpdateTaskHandle: TaskHandle?
|
||||
|
||||
|
||||
private var encryptionSyncService: EncryptionSync?
|
||||
private var isEncryptionSyncing = false
|
||||
|
||||
var roomSummaryProvider: RoomSummaryProviderProtocol?
|
||||
var inviteSummaryProvider: RoomSummaryProviderProtocol?
|
||||
|
||||
@ -103,7 +106,7 @@ class ClientProxy: ClientProxyProtocol {
|
||||
}
|
||||
|
||||
var isSyncing: Bool {
|
||||
roomListService?.isSyncing() ?? false
|
||||
roomListService?.isSyncing() ?? false && isEncryptionSyncing
|
||||
}
|
||||
|
||||
func startSync() {
|
||||
@ -111,18 +114,30 @@ class ClientProxy: ClientProxyProtocol {
|
||||
guard !isSyncing else {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
startEncryptionSyncService()
|
||||
roomListService?.sync()
|
||||
}
|
||||
|
||||
func stopSync() {
|
||||
MXLog.info("Stopping sync")
|
||||
stopEncryptionSyncService()
|
||||
|
||||
do {
|
||||
try roomListService?.stopSync()
|
||||
} catch {
|
||||
MXLog.error("Failed stopping room list service with error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
private func stopEncryptionSyncService() {
|
||||
guard isEncryptionSyncing else {
|
||||
return
|
||||
}
|
||||
isEncryptionSyncing = false
|
||||
encryptionSyncService?.stop()
|
||||
MXLog.info("Stopping Encryption Sync service")
|
||||
}
|
||||
|
||||
func directRoomForUserID(_ userID: String) async -> Result<String?, ClientProxyError> {
|
||||
await Task.dispatch(on: clientQueue) {
|
||||
@ -359,14 +374,47 @@ class ClientProxy: ClientProxyProtocol {
|
||||
self.avatarURLSubject.value = urlString.flatMap(URL.init)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func startEncryptionSyncService() {
|
||||
guard ServiceLocator.shared.settings.isEncryptionSyncEnabled else {
|
||||
return
|
||||
}
|
||||
configureEncryptionSyncService()
|
||||
}
|
||||
|
||||
private func configureEncryptionSyncService() {
|
||||
do {
|
||||
let listener = EncryptionSyncListenerProxy { [weak self] reason in
|
||||
switch reason {
|
||||
case .done:
|
||||
MXLog.info("Encryption Sync has finished for user: \(self?.userID ?? "unknown")")
|
||||
case .error(let msg):
|
||||
MXLog.error("Encryption Sync has terminated for user: \(self?.userID ?? "unknown") for reason: \(msg)")
|
||||
guard let self else {
|
||||
return
|
||||
}
|
||||
Task {
|
||||
self.configureEncryptionSyncService()
|
||||
}
|
||||
}
|
||||
}
|
||||
let encryptionSync = try client.mainEncryptionSync(id: "Main App", listener: listener)
|
||||
encryptionSync.reloadCaches()
|
||||
isEncryptionSyncing = true
|
||||
encryptionSyncService = encryptionSync
|
||||
MXLog.info("Encryption sync started for user: \(userID)")
|
||||
} catch {
|
||||
MXLog.error("Configure encryption sync failed with error: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
private func configureRoomListService() async {
|
||||
guard roomListService == nil else {
|
||||
fatalError("This shouldn't be called more than once")
|
||||
}
|
||||
|
||||
do {
|
||||
let roomListService = try client.roomListServiceWithEncryption()
|
||||
let roomListService = try ServiceLocator.shared.settings.isEncryptionSyncEnabled ? client.roomListService() : client.roomListServiceWithEncryption()
|
||||
roomListStateUpdateTaskHandle = roomListService.state(listener: RoomListStateListenerProxy { [weak self] state in
|
||||
guard let self else { return }
|
||||
MXLog.info("Received room list update: \(state)")
|
||||
|
@ -0,0 +1,31 @@
|
||||
//
|
||||
// Copyright 2023 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
import MatrixRustSDK
|
||||
|
||||
final class EncryptionSyncListenerProxy: EncryptionSyncListener {
|
||||
private let didTerminateClosure: (EncryptionSyncTerminationReason) -> Void
|
||||
|
||||
init(_ didTerminateClosure: @escaping (EncryptionSyncTerminationReason) -> Void) {
|
||||
self.didTerminateClosure = didTerminateClosure
|
||||
}
|
||||
|
||||
func didTerminate(reason: EncryptionSyncTerminationReason) {
|
||||
didTerminateClosure(reason)
|
||||
}
|
||||
}
|
@ -48,17 +48,6 @@ protocol NotificationItemProxyProtocol {
|
||||
var isEncrypted: Bool { get }
|
||||
}
|
||||
|
||||
extension NotificationItemProxyProtocol {
|
||||
var id: String? {
|
||||
let identifiers = receiverID + roomID + event.eventID
|
||||
guard let data = identifiers.data(using: .utf8) else {
|
||||
return nil
|
||||
}
|
||||
let digest = SHA256.hash(data: data)
|
||||
return digest.compactMap { String(format: "%02x", $0) }.joined()
|
||||
}
|
||||
}
|
||||
|
||||
struct NotificationItemProxy: NotificationItemProxyProtocol {
|
||||
let notificationItem: NotificationItem
|
||||
let receiverID: String
|
||||
@ -168,7 +157,6 @@ extension NotificationItemProxyProtocol {
|
||||
notification.receiverID = receiverID
|
||||
notification.roomID = roomID
|
||||
notification.eventID = event.eventID
|
||||
notification.notificationID = id
|
||||
notification.sound = isNoisy ? UNNotificationSound(named: UNNotificationSoundName(rawValue: "message.caf")) : nil
|
||||
// So that the UI groups notification that are received for the same room but also for the same user
|
||||
notification.threadIdentifier = "\(receiverID)\(roomID)"
|
||||
|
@ -24,6 +24,7 @@ class NotificationServiceExtension: UNNotificationServiceExtension {
|
||||
accessGroup: InfoPlistReader.main.keychainAccessGroupIdentifier)
|
||||
private var handler: ((UNNotificationContent) -> Void)?
|
||||
private var modifiedContent: UNMutableNotificationContent?
|
||||
private var userSession: NSEUserSession?
|
||||
|
||||
override func didReceive(_ request: UNNotificationRequest,
|
||||
withContentHandler contentHandler: @escaping (UNNotificationContent) -> Void) {
|
||||
@ -71,9 +72,26 @@ class NotificationServiceExtension: UNNotificationServiceExtension {
|
||||
|
||||
do {
|
||||
let userSession = try NSEUserSession(credentials: credentials)
|
||||
|
||||
guard let itemProxy = try await userSession.notificationItemProxy(roomID: roomId, eventID: eventId) else {
|
||||
MXLog.info("\(tag) no notification for this event")
|
||||
self.userSession = userSession
|
||||
var itemProxy = await userSession.notificationItemProxy(roomID: roomId, eventID: eventId)
|
||||
if settings.isEncryptionSyncEnabled,
|
||||
itemProxy?.isEncrypted == true,
|
||||
let _ = try? userSession.startEncryptionSync() {
|
||||
// TODO: The following wait with a timeout should be handled by the SDK
|
||||
// We try to decrypt the notification for 10 seconds at most
|
||||
let date = Date()
|
||||
repeat {
|
||||
// if the sync terminated we try one last time then we break from the loop
|
||||
guard userSession.isSyncing else {
|
||||
itemProxy = await userSession.notificationItemProxy(roomID: roomId, eventID: eventId)
|
||||
break
|
||||
}
|
||||
itemProxy = await userSession.notificationItemProxy(roomID: roomId, eventID: eventId)
|
||||
} while itemProxy?.isEncrypted == true && date.timeIntervalSinceNow > -10
|
||||
}
|
||||
|
||||
guard let itemProxy else {
|
||||
MXLog.info("\(tag) no notification for the event, discard")
|
||||
return discard()
|
||||
}
|
||||
|
||||
@ -110,31 +128,29 @@ class NotificationServiceExtension: UNNotificationServiceExtension {
|
||||
return discard()
|
||||
}
|
||||
|
||||
guard let identifier = modifiedContent.notificationID,
|
||||
!settings.servedNotificationIdentifiers.contains(identifier) else {
|
||||
MXLog.info("\(tag) notify: notification already served")
|
||||
return discard()
|
||||
}
|
||||
|
||||
settings.servedNotificationIdentifiers.insert(identifier)
|
||||
handler?(modifiedContent)
|
||||
handler = nil
|
||||
self.modifiedContent = nil
|
||||
cleanUp()
|
||||
}
|
||||
|
||||
private func discard() {
|
||||
MXLog.info("\(tag) discard")
|
||||
|
||||
handler?(UNMutableNotificationContent())
|
||||
handler = nil
|
||||
modifiedContent = nil
|
||||
cleanUp()
|
||||
}
|
||||
|
||||
private var tag: String {
|
||||
"[NSE][\(Unmanaged.passUnretained(self).toOpaque())][\(Unmanaged.passUnretained(Thread.current).toOpaque())]"
|
||||
}
|
||||
|
||||
private func cleanUp() {
|
||||
handler = nil
|
||||
modifiedContent = nil
|
||||
userSession?.stopEncryptionSync()
|
||||
}
|
||||
|
||||
deinit {
|
||||
cleanUp()
|
||||
NSELogger.logMemory(with: tag)
|
||||
MXLog.info("\(tag) deinit")
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ final class NSESettings {
|
||||
/// UserDefaults to be used on reads and writes.
|
||||
private static var store: UserDefaults! = UserDefaults(suiteName: suiteName)
|
||||
|
||||
/// A set of all the notification identifiers that have been served so far, it's reset every time the app is launched
|
||||
@UserPreference(key: SharedUserDefaultsKeys.servedNotificationIdentifiers, defaultValue: [], storageType: .userDefaults(store))
|
||||
var servedNotificationIdentifiers: Set<String>
|
||||
/// Tag describing if the app and the NSE should use the encryption sync
|
||||
@UserPreference(key: SharedUserDefaultsKeys.isEncryptionSyncEnabled, defaultValue: false, storageType: .userDefaults(store))
|
||||
var isEncryptionSyncEnabled
|
||||
}
|
||||
|
@ -19,11 +19,18 @@ import MatrixRustSDK
|
||||
|
||||
final class NSEUserSession {
|
||||
private let client: ClientProtocol
|
||||
private let userID: String
|
||||
private var encryptionSyncService: EncryptionSync?
|
||||
private(set) lazy var mediaProvider: MediaProviderProtocol = MediaProvider(mediaLoader: MediaLoader(client: client),
|
||||
imageCache: .onlyOnDisk,
|
||||
backgroundTaskService: nil)
|
||||
|
||||
var isSyncing: Bool {
|
||||
encryptionSyncService != nil
|
||||
}
|
||||
|
||||
init(credentials: KeychainCredentials) throws {
|
||||
userID = credentials.userID
|
||||
let builder = ClientBuilder()
|
||||
.basePath(path: URL.sessionsBaseDirectory.path)
|
||||
.username(username: credentials.userID)
|
||||
@ -32,18 +39,35 @@ final class NSEUserSession {
|
||||
try client.restoreSession(session: credentials.restorationToken.session)
|
||||
}
|
||||
|
||||
func notificationItemProxy(roomID: String, eventID: String) async throws -> NotificationItemProxyProtocol? {
|
||||
let userID = try client.userId()
|
||||
return await Task.dispatch(on: .global()) {
|
||||
func startEncryptionSync() throws {
|
||||
let listener = EncryptionSyncListenerProxy { [weak self] reason in
|
||||
MXLog.info("NSE: Encryption sync terminated for user: \(self?.userID ?? "unknown") with reason: \(reason)")
|
||||
self?.encryptionSyncService = nil
|
||||
}
|
||||
encryptionSyncService = try client.notificationEncryptionSync(id: "NSE", listener: listener, numIters: 2)
|
||||
MXLog.info("NSE: Encryption sync started for user: \(userID)")
|
||||
}
|
||||
|
||||
func notificationItemProxy(roomID: String, eventID: String) async -> NotificationItemProxyProtocol? {
|
||||
await Task.dispatch(on: .global()) {
|
||||
do {
|
||||
guard let notification = try self.client.getNotificationItem(roomId: roomID, eventId: eventID) else {
|
||||
return nil
|
||||
}
|
||||
return NotificationItemProxy(notificationItem: notification, receiverID: userID)
|
||||
return NotificationItemProxy(notificationItem: notification, receiverID: self.userID)
|
||||
} catch {
|
||||
MXLog.error("NSE: Could not get notification's content creating an empty notification instead, error: \(error)")
|
||||
return EmptyNotificationItemProxy(eventID: eventID, roomID: roomID, receiverID: userID)
|
||||
return EmptyNotificationItemProxy(eventID: eventID, roomID: roomID, receiverID: self.userID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func stopEncryptionSync() {
|
||||
encryptionSyncService?.stop()
|
||||
}
|
||||
|
||||
deinit {
|
||||
MXLog.info("NSE: NSEUserSession deinit called for user: \(userID)")
|
||||
stopEncryptionSync()
|
||||
}
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ targets:
|
||||
- path: ../../ElementX/Sources/Services/Keychain/KeychainControllerProtocol.swift
|
||||
- path: ../../ElementX/Sources/Services/Keychain/KeychainController.swift
|
||||
- path: ../../ElementX/Sources/Services/UserSession/RestorationToken.swift
|
||||
- path: ../../ElementX/Sources/Services/Notification/Proxy/NotificationItemProxy.swift
|
||||
- path: ../../ElementX/Sources/Services/Notification/Proxy
|
||||
- path: ../../ElementX/Sources/Services/Notification/NotificationConstants.swift
|
||||
- path: ../../ElementX/Sources/Services/Media/Provider
|
||||
- path: ../../ElementX/Sources/Services/Background/BackgroundTaskServiceProtocol.swift
|
||||
|
1
changelog.d/1083.feature
Normal file
1
changelog.d/1083.feature
Normal file
@ -0,0 +1 @@
|
||||
Two sync loop implementation to allow to fetch and update decryption keys also from the NSE.
|
@ -11,7 +11,7 @@ options:
|
||||
deploymentTarget:
|
||||
iOS: "16.4"
|
||||
macOS: "13.3"
|
||||
groupOrdering:
|
||||
groupOrdering:
|
||||
- order: [ElementX, UnitTests, UITests, IntegrationTests, Tools]
|
||||
- pattern: ElementX
|
||||
order: [Sources, Resources, SupportingFiles]
|
||||
|
Loading…
x
Reference in New Issue
Block a user