diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index b8bd6d684..684495a22 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -52,7 +52,6 @@ F5E7D8842B3877050009BB8A /* AuthenticationSSO.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E7D8832B3877050009BB8A /* AuthenticationSSO.swift */; }; F5E7D8862B3877390009BB8A /* TokenResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E7D8852B3877390009BB8A /* TokenResponse.swift */; }; F5E7D8882B38775C0009BB8A /* TokenRefreshManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E7D8872B38775C0009BB8A /* TokenRefreshManager.swift */; }; - F5E7D88A2B3877D30009BB8A /* NSEPusher.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E7D8892B3877D30009BB8A /* NSEPusher.swift */; }; F5E7D88D2B3878580009BB8A /* AuthenticationInterceptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5E7D88C2B3878580009BB8A /* AuthenticationInterceptor.swift */; }; F5EFC07D2B328B9F00829056 /* TwakeLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5EFC07C2B328B9F00829056 /* TwakeLogger.swift */; }; F5EFC07E2B328B9F00829056 /* TwakeLogger.swift in Sources */ = {isa = PBXBuildFile; fileRef = F5EFC07C2B328B9F00829056 /* TwakeLogger.swift */; }; @@ -155,7 +154,6 @@ F5E7D8832B3877050009BB8A /* AuthenticationSSO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationSSO.swift; sourceTree = ""; }; F5E7D8852B3877390009BB8A /* TokenResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenResponse.swift; sourceTree = ""; }; F5E7D8872B38775C0009BB8A /* TokenRefreshManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenRefreshManager.swift; sourceTree = ""; }; - F5E7D8892B3877D30009BB8A /* NSEPusher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSEPusher.swift; sourceTree = ""; }; F5E7D88C2B3878580009BB8A /* AuthenticationInterceptor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AuthenticationInterceptor.swift; sourceTree = ""; }; F5EFC07C2B328B9F00829056 /* TwakeLogger.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwakeLogger.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -349,7 +347,6 @@ F5630C7D2B2CE359003CC0FD /* InfoPlistReader.swift */, F5BBBF542B2EEF3D007930E1 /* BundleExtension.swift */, F5630C862B2D0387003CC0FD /* PayloadParser.swift */, - F5E7D8892B3877D30009BB8A /* NSEPusher.swift */, ); path = Utils; sourceTree = ""; @@ -687,7 +684,6 @@ F53D1E862B2E401B00051FD0 /* JmapRequestGenerator.swift in Sources */, F5E7D87A2B38763B0009BB8A /* DateExtensions.swift in Sources */, F5E7D88D2B3878580009BB8A /* AuthenticationInterceptor.swift in Sources */, - F5E7D88A2B3877D30009BB8A /* NSEPusher.swift in Sources */, F5630C7E2B2CE359003CC0FD /* InfoPlistReader.swift in Sources */, F53D1E662B2DE8B800051FD0 /* AlamofireService.swift in Sources */, F5BBBF532B2EECAA007930E1 /* JmapExceptions.swift in Sources */, diff --git a/ios/TwakeMailNSE/NotificationService.swift b/ios/TwakeMailNSE/NotificationService.swift index 1b0746fce..d2ef2bb41 100644 --- a/ios/TwakeMailNSE/NotificationService.swift +++ b/ios/TwakeMailNSE/NotificationService.swift @@ -2,7 +2,7 @@ import UserNotifications class NotificationService: UNNotificationServiceExtension { - private let timeIntervalNotificationTrigger: Int = 2 + private let timeIntervalNotificationTriggerInSecond: Int = 2 private let newEmailDefaultMessage: String = "You have new emails" private var handler: ((UNNotificationContent) -> Void)? @@ -74,7 +74,7 @@ class NotificationService: UNNotificationServiceExtension { self.scheduleLocalNotification(email: email) } - let delayTimeIntervalNotification: TimeInterval = TimeInterval(self.timeIntervalNotificationTrigger * (emails.count - 1)) + let delayTimeIntervalNotification: TimeInterval = TimeInterval(self.timeIntervalNotificationTriggerInSecond * (emails.count - 1)) DispatchQueue.main.asyncAfter(deadline: .now() + delayTimeIntervalNotification) { self.modifiedContent?.subtitle = emails.last?.subject ?? "" @@ -110,7 +110,7 @@ class NotificationService: UNNotificationServiceExtension { content.userInfo[JmapConstants.EMAIL_ID] = "\(email.id)" // Create a notification trigger - let trigger = UNTimeIntervalNotificationTrigger(timeInterval: TimeInterval(timeIntervalNotificationTrigger), repeats: false) + let trigger = UNTimeIntervalNotificationTrigger(timeInterval: TimeInterval(timeIntervalNotificationTriggerInSecond), repeats: false) // Create a notification request let request = UNNotificationRequest(identifier: "\(email.id)", content: content, trigger: trigger) diff --git a/lib/features/login/data/network/config/authorization_interceptors.dart b/lib/features/login/data/network/config/authorization_interceptors.dart index 214e240b2..59222915e 100644 --- a/lib/features/login/data/network/config/authorization_interceptors.dart +++ b/lib/features/login/data/network/config/authorization_interceptors.dart @@ -92,22 +92,17 @@ class AuthorizationInterceptors extends QueuedInterceptorsWrapper { if (_validateToRefreshToken(err)) { log('AuthorizationInterceptors::onError:>> _validateToRefreshToken'); - final newToken = await _authenticationClient.refreshingTokensOIDC( - _configOIDC!.clientId, - _configOIDC!.redirectUrl, - _configOIDC!.discoveryUrl, - _configOIDC!.scopes, - _token!.refreshToken - ); - _updateNewToken(newToken); - - await _updateCurrentAccount(tokenOIDC: newToken); + if (PlatformInfo.isIOS) { + _handleRefreshTokenOnIOSPlatform(); + } else { + _handleRefreshTokenOnOtherPlatform(); + } if (extraInRequest.containsKey(FileUploader.uploadAttachmentExtraKey)) { final uploadExtra = extraInRequest[FileUploader.uploadAttachmentExtraKey]; - requestOptions.headers[HttpHeaders.authorizationHeader] = _getTokenAsBearerHeader(newToken.token); + requestOptions.headers[HttpHeaders.authorizationHeader] = _getTokenAsBearerHeader(_token!.token); requestOptions.headers[HttpHeaders.contentTypeHeader] = uploadExtra[FileUploader.typeExtraKey]; requestOptions.headers[HttpHeaders.contentLengthHeader] = uploadExtra[FileUploader.sizeExtraKey]; @@ -125,7 +120,7 @@ class AuthorizationInterceptors extends QueuedInterceptorsWrapper { return handler.resolve(response); } else { - requestOptions.headers[HttpHeaders.authorizationHeader] = _getTokenAsBearerHeader(newToken.token); + requestOptions.headers[HttpHeaders.authorizationHeader] = _getTokenAsBearerHeader(_token!.token); final response = await _dio.fetch(requestOptions); return handler.resolve(response); @@ -202,7 +197,7 @@ class AuthorizationInterceptors extends QueuedInterceptorsWrapper { } } - Future _updateCurrentAccount({required TokenOIDC tokenOIDC}) async { + Future _updateCurrentAccount({required TokenOIDC tokenOIDC}) async { final currentAccount = await _accountCacheManager.getCurrentAccount(); await _accountCacheManager.deleteCurrentAccount(currentAccount.id); @@ -219,9 +214,66 @@ class AuthorizationInterceptors extends QueuedInterceptorsWrapper { ); await _accountCacheManager.setCurrentAccount(personalAccount); - if (PlatformInfo.isIOS) { - await _iosSharingManager.saveKeyChainSharingSession(personalAccount); + return personalAccount; + } + + Future _getTokenInKeychain(TokenOIDC currentTokenOidc) async { + final currentAccount = await _accountCacheManager.getCurrentAccount(); + log('AuthorizationInterceptors::_getTokenInKeychain:currentAccount: $currentAccount'); + if (currentAccount.accountId == null) { + return null; } + + final keychainSharingSession = await _iosSharingManager.getKeychainSharingSession(currentAccount.accountId!); + log('AuthorizationInterceptors::_getTokenInKeychain:keychainSharingSession: $keychainSharingSession'); + if (keychainSharingSession == null) { + return null; + } + + if (keychainSharingSession.tokenOIDC != null && + currentTokenOidc.token != keychainSharingSession.tokenOIDC!.token) { + return keychainSharingSession.tokenOIDC!; + } + + return null; + } + + Future _invokeRefreshTokenFromServer() async { + final newToken = await _authenticationClient.refreshingTokensOIDC( + _configOIDC!.clientId, + _configOIDC!.redirectUrl, + _configOIDC!.discoveryUrl, + _configOIDC!.scopes, + _token!.refreshToken + ); + log('AuthorizationInterceptors::_invokeRefreshTokenFromServer:newToken: $newToken'); + return newToken; + } + + Future _handleRefreshTokenOnIOSPlatform() async { + final keychainToken = await _getTokenInKeychain(_token!); + + if (keychainToken == null) { + final newToken = await _invokeRefreshTokenFromServer(); + + _updateNewToken(newToken); + + final newAccount = await _updateCurrentAccount(tokenOIDC: newToken); + + await _iosSharingManager.saveKeyChainSharingSession(newAccount); + } else { + _updateNewToken(keychainToken); + + await _updateCurrentAccount(tokenOIDC: keychainToken); + } + } + + Future _handleRefreshTokenOnOtherPlatform() async { + final newToken = await _invokeRefreshTokenFromServer(); + + _updateNewToken(newToken); + + await _updateCurrentAccount(tokenOIDC: newToken); } void clear() { diff --git a/lib/main/utils/ios_sharing_manager.dart b/lib/main/utils/ios_sharing_manager.dart index 8b9d896e8..1db216950 100644 --- a/lib/main/utils/ios_sharing_manager.dart +++ b/lib/main/utils/ios_sharing_manager.dart @@ -82,6 +82,19 @@ class IOSSharingManager { } } + Future getKeychainSharingSession(AccountId accountId) async { + try { + if (await _keychainSharingManager.isSessionExist(accountId)) { + final keychainSharingStored = await _keychainSharingManager.getSharingSession(accountId); + return keychainSharingStored; + } + return null; + } catch (e) { + logError('IOSSharingManager::getKeychainSharingSession: Exception: $e'); + return null; + } + } + Future _getTokenOidc({required String tokeHashId}) async { try { final tokenOidc = await _tokenOidcCacheManager.getTokenOidc(tokeHashId);