From 80976112078d5040d2689817ad574eb91fcd7779 Mon Sep 17 00:00:00 2001 From: Evgeny Poberezkin <2769109+epoberezkin@users.noreply.github.com> Date: Wed, 7 Sep 2022 20:06:16 +0100 Subject: [PATCH] ios: NSE without passphrase in keychain (#1030) --- apps/ios/Shared/Model/ChatModel.swift | 2 ++ apps/ios/Shared/Model/SuspendChat.swift | 18 ++++++++++------- apps/ios/Shared/SimpleXApp.swift | 2 +- .../ios/SimpleX NSE/NotificationService.swift | 20 +++++++++++++------ apps/ios/SimpleXChat/Notifications.swift | 20 +++++++++++++++++++ 5 files changed, 48 insertions(+), 14 deletions(-) diff --git a/apps/ios/Shared/Model/ChatModel.swift b/apps/ios/Shared/Model/ChatModel.swift index d349294a0f..19ba23766f 100644 --- a/apps/ios/Shared/Model/ChatModel.swift +++ b/apps/ios/Shared/Model/ChatModel.swift @@ -53,6 +53,8 @@ final class ChatModel: ObservableObject { static let shared = ChatModel() + static var ok: Bool { ChatModel.shared.chatDbStatus == .ok } + func hasChat(_ id: String) -> Bool { chats.first(where: { $0.id == id }) != nil } diff --git a/apps/ios/Shared/Model/SuspendChat.swift b/apps/ios/Shared/Model/SuspendChat.swift index 33ad5af8ed..499dbbb1f7 100644 --- a/apps/ios/Shared/Model/SuspendChat.swift +++ b/apps/ios/Shared/Model/SuspendChat.swift @@ -19,10 +19,14 @@ let bgSuspendTimeout: Int = 5 // seconds let terminationTimeout: Int = 3 // seconds private func _suspendChat(timeout: Int) { - appStateGroupDefault.set(.suspending) - apiSuspendChat(timeoutMicroseconds: timeout * 1000000) - let endTask = beginBGTask(chatSuspended) - DispatchQueue.global().asyncAfter(deadline: .now() + Double(timeout) + 1, execute: endTask) + if ChatModel.ok { + appStateGroupDefault.set(.suspending) + apiSuspendChat(timeoutMicroseconds: timeout * 1000000) + let endTask = beginBGTask(chatSuspended) + DispatchQueue.global().asyncAfter(deadline: .now() + Double(timeout) + 1, execute: endTask) + } else { + appStateGroupDefault.set(.suspended) + } } func suspendChat() { @@ -47,7 +51,7 @@ func terminateChat() { case .suspending: // suspend instantly if already suspending _chatSuspended() - apiSuspendChat(timeoutMicroseconds: 0) + if ChatModel.ok { apiSuspendChat(timeoutMicroseconds: 0) } case .stopped: () default: _suspendChat(timeout: terminationTimeout) @@ -71,9 +75,9 @@ private func _chatSuspended() { } } -func activateChat(appState: AppState = .active, databaseReady: Bool = true) { +func activateChat(appState: AppState = .active) { suspendLockQueue.sync { appStateGroupDefault.set(appState) - if databaseReady { apiActivateChat() } + if ChatModel.ok { apiActivateChat() } } } diff --git a/apps/ios/Shared/SimpleXApp.swift b/apps/ios/Shared/SimpleXApp.swift index 6061e7ce52..386ae0c431 100644 --- a/apps/ios/Shared/SimpleXApp.swift +++ b/apps/ios/Shared/SimpleXApp.swift @@ -64,7 +64,7 @@ struct SimpleXApp: App { ChatReceiver.shared.start() } let appState = appStateGroupDefault.get() - activateChat(databaseReady: chatModel.chatDbStatus == .ok) + activateChat() if appState.inactive && chatModel.chatRunning == true { updateChats() updateCallInvitations() diff --git a/apps/ios/SimpleX NSE/NotificationService.swift b/apps/ios/SimpleX NSE/NotificationService.swift index 969645e45f..0e8ebd852c 100644 --- a/apps/ios/SimpleX NSE/NotificationService.swift +++ b/apps/ios/SimpleX NSE/NotificationService.swift @@ -105,9 +105,9 @@ class NotificationService: UNNotificationServiceExtension { if let ntfData = userInfo["notificationData"] as? [AnyHashable : Any], let nonce = ntfData["nonce"] as? String, let encNtfInfo = ntfData["message"] as? String, - let _ = startChat() { - logger.debug("NotificationService: receiveNtfMessages: chat is started") - if let ntfMsgInfo = apiGetNtfMessage(nonce: nonce, encNtfInfo: encNtfInfo) { + let dbStatus = startChat() { + if case .ok = dbStatus, + let ntfMsgInfo = apiGetNtfMessage(nonce: nonce, encNtfInfo: encNtfInfo) { logger.debug("NotificationService: receiveNtfMessages: apiGetNtfMessage \(String(describing: ntfMsgInfo), privacy: .public)") if let connEntity = ntfMsgInfo.connEntity { setBestAttemptNtf(createConnectionEventNtf(connEntity)) @@ -118,9 +118,11 @@ class NotificationService: UNNotificationServiceExtension { await PendingNtfs.shared.readStream(id, for: self, msgCount: ntfMsgInfo.ntfMessages.count) deliverBestAttemptNtf() } + return } } - return + } else { + setBestAttemptNtf(createErrorNtf(dbStatus)) } } deliverBestAttemptNtf() @@ -151,20 +153,26 @@ class NotificationService: UNNotificationServiceExtension { } } -func startChat() -> User? { +var chatStarted = false + +func startChat() -> DBMigrationResult? { hs_init(0, nil) + if chatStarted { return .ok } + let (_, dbStatus) = migrateChatDatabase() + if dbStatus != .ok { return dbStatus } if let user = apiGetActiveUser() { logger.debug("active user \(String(describing: user))") do { try setNetworkConfig(getNetCfg()) let justStarted = try apiStartChat() + chatStarted = true if justStarted { try apiSetFilesFolder(filesFolder: getAppFilesDirectory().path) try apiSetIncognito(incognito: incognitoGroupDefault.get()) chatLastStartGroupDefault.set(Date.now) Task { await receiveMessages() } } - return user + return .ok } catch { logger.error("NotificationService startChat error: \(responseError(error), privacy: .public)") } diff --git a/apps/ios/SimpleXChat/Notifications.swift b/apps/ios/SimpleXChat/Notifications.swift index 2a4a1f6b75..6432b36506 100644 --- a/apps/ios/SimpleXChat/Notifications.swift +++ b/apps/ios/SimpleXChat/Notifications.swift @@ -119,6 +119,26 @@ public func createConnectionEventNtf(_ connEntity: ConnectionEntity) -> UNMutabl ) } +public func createErrorNtf(_ dbStatus: DBMigrationResult) -> UNMutableNotificationContent { + var title: String + switch dbStatus { + case .errorNotADatabase: + title = NSLocalizedString("Encrypted message: no passphrase", comment: "notification") + case .error: + title = NSLocalizedString("Encrypted message: database error", comment: "notification") + case .errorKeychain: + title = NSLocalizedString("Encrypted message: keychain error", comment: "notification") + case .unknown: + title = NSLocalizedString("Encrypted message: unexpexted error", comment: "notification") + case .ok: + title = NSLocalizedString("Encrypted message or another event", comment: "notification") + } + return createNotification( + categoryIdentifier: ntfCategoryConnectionEvent, + title: title + ) +} + private func groupMsgNtfTitle(_ groupInfo: GroupInfo, _ groupMember: GroupMember, hideContent: Bool) -> String { hideContent ? NSLocalizedString("Group message:", comment: "notification")