From 34dcb9f459fb7828cd9232b9f5ce2424ec6694b3 Mon Sep 17 00:00:00 2001 From: Roma Sosnovsky Date: Tue, 14 Dec 2021 17:42:23 +0200 Subject: [PATCH 1/4] #1091 add performTokenRefresh() method --- FlowCrypt/Extensions/BundleExtensions.swift | 4 +-- .../Extensions/CommandLineExtensions.swift | 6 ++-- FlowCrypt/Extensions/String+Extension.swift | 2 +- .../Extensions/UIViewController+Spinner.swift | 2 +- .../DataManager/SessionService.swift | 2 +- .../Services/GoogleUserService.swift | 28 ++++++++++++++----- .../KeyService.swift | 4 ++- .../PassPhraseService.swift | 6 ++-- .../Remote Pub Key Services/AttesterApi.swift | 2 +- Podfile.lock | 4 +-- 10 files changed, 38 insertions(+), 22 deletions(-) diff --git a/FlowCrypt/Extensions/BundleExtensions.swift b/FlowCrypt/Extensions/BundleExtensions.swift index 0a249741f..d54aabadf 100644 --- a/FlowCrypt/Extensions/BundleExtensions.swift +++ b/FlowCrypt/Extensions/BundleExtensions.swift @@ -5,7 +5,7 @@ // Created by Tom on 03.12.2021 // Copyright © 2017-present FlowCrypt a. s. All rights reserved. // - + import Foundation enum FlowCryptBundleType: String { @@ -20,5 +20,5 @@ extension Bundle { guard let bundleIdentifier = Bundle.main.bundleIdentifier else { return .debug } return FlowCryptBundleType(rawValue: bundleIdentifier) ?? .debug } - + } diff --git a/FlowCrypt/Extensions/CommandLineExtensions.swift b/FlowCrypt/Extensions/CommandLineExtensions.swift index 3bc85d4b1..8c0bcbbde 100644 --- a/FlowCrypt/Extensions/CommandLineExtensions.swift +++ b/FlowCrypt/Extensions/CommandLineExtensions.swift @@ -6,15 +6,13 @@ // Copyright © 2017-present FlowCrypt a. s. All rights reserved. // - - import Foundation extension CommandLine { - + static func isDebugBundleWithArgument(_ argument: String) -> Bool { guard Bundle.flowCryptBundleType == .debug else { return false } return CommandLine.arguments.contains(argument) } - + } diff --git a/FlowCrypt/Extensions/String+Extension.swift b/FlowCrypt/Extensions/String+Extension.swift index 8966f1f52..859066bd3 100644 --- a/FlowCrypt/Extensions/String+Extension.swift +++ b/FlowCrypt/Extensions/String+Extension.swift @@ -14,7 +14,7 @@ extension String { let emailPredicate = NSPredicate(format: "SELF MATCHES %@", emailFormat) return emailPredicate.evaluate(with: self) } - + func capitalizingFirstLetter() -> String { prefix(1).uppercased() + self.lowercased().dropFirst() } diff --git a/FlowCrypt/Extensions/UIViewController+Spinner.swift b/FlowCrypt/Extensions/UIViewController+Spinner.swift index 653a0d68c..0f5764910 100644 --- a/FlowCrypt/Extensions/UIViewController+Spinner.swift +++ b/FlowCrypt/Extensions/UIViewController+Spinner.swift @@ -72,7 +72,7 @@ extension UIViewController { currentProgressHUD.mode = .customView currentProgressHUD.label.text = label } - + @MainActor func showIndeterminateHUD(with title: String) { self.currentProgressHUD.mode = .indeterminate diff --git a/FlowCrypt/Functionality/DataManager/SessionService.swift b/FlowCrypt/Functionality/DataManager/SessionService.swift index e081c0398..8554f4aea 100644 --- a/FlowCrypt/Functionality/DataManager/SessionService.swift +++ b/FlowCrypt/Functionality/DataManager/SessionService.swift @@ -102,7 +102,7 @@ extension SessionService: SessionServiceType { } } let users = encryptedStorage.getAllUsers() - if !users.contains(where: { $0.isActive }), let user = users.first(where: { encryptedStorage.doesAnyKeypairExist(for: $0.email ) }) { + if !users.contains(where: { $0.isActive }), let user = users.first(where: { encryptedStorage.doesAnyKeypairExist(for: $0.email) }) { try switchActiveSession(for: user) } } diff --git a/FlowCrypt/Functionality/Services/GoogleUserService.swift b/FlowCrypt/Functionality/Services/GoogleUserService.swift index 72a93e937..fe6a12b20 100644 --- a/FlowCrypt/Functionality/Services/GoogleUserService.swift +++ b/FlowCrypt/Functionality/Services/GoogleUserService.swift @@ -73,16 +73,16 @@ final class GoogleUserService: NSObject, GoogleUserServiceType { private lazy var logger = Logger.nested(in: Self.self, with: .userAppStart) + private var tokenResponse: OIDTokenResponse? { + authorization?.authState.lastTokenResponse + } + var userToken: String? { - authorization?.authState - .lastTokenResponse? - .accessToken + tokenResponse?.accessToken } var idToken: String? { - authorization?.authState - .lastTokenResponse? - .idToken + tokenResponse?.idToken } var authorization: GTMAppAuthFetcherAuthorization? { @@ -110,7 +110,7 @@ extension GoogleUserService: UserServiceType { let error = self.parseSignInError(authError) return continuation.resume(throwing: error) } else { - let error = AppErr.unexpected("Shouldn't happen because received non nil error and non nil authState") + let error = AppErr.unexpected("Shouldn't happen because received nil error and nil authState") return continuation.resume(throwing: error) } } @@ -126,6 +126,20 @@ extension GoogleUserService: UserServiceType { } } + func performTokenRefresh() async throws -> (accessToken: String, idToken: String) { + return try await withCheckedThrowingContinuation { continuation in + authorization?.authState.setNeedsTokenRefresh() + authorization?.authState.performAction { accessToken, idToken, error in + guard let accessToken = accessToken, let idToken = idToken else { + let tokenError = error ?? AppErr.unexpected("Shouldn't happen because received nil error and nil token") + return continuation.resume(throwing: tokenError) + } + let result = (accessToken, idToken) + return continuation.resume(with: .success(result)) + } + } + } + func signOut(user email: String) { DispatchQueue.main.async { self.appDelegateGoogleSessionContainer?.googleAuthSession = nil diff --git a/FlowCrypt/Functionality/Services/Local Private Key Services/KeyService.swift b/FlowCrypt/Functionality/Services/Local Private Key Services/KeyService.swift index b08595744..851eb8fbe 100644 --- a/FlowCrypt/Functionality/Services/Local Private Key Services/KeyService.swift +++ b/FlowCrypt/Functionality/Services/Local Private Key Services/KeyService.swift @@ -108,7 +108,9 @@ final class KeyService: KeyServiceType { logger.logDebug("findKeyByUserEmail: found key \(primaryEmailMatch.1.primaryFingerprint) by primary email match") return primaryEmailMatch.0 } - if let alternativeEmailMatch = keys.first(where: { $0.1.pgpUserEmails.map { $0.lowercased() }.contains(email.lowercased()) == true }) { + if let alternativeEmailMatch = keys.first(where: { + $0.1.pgpUserEmails.map { $0.lowercased() }.contains(email.lowercased()) == true + }) { logger.logDebug("findKeyByUserEmail: found key \(alternativeEmailMatch.1.primaryFingerprint) by alternative email match") return alternativeEmailMatch.0 } diff --git a/FlowCrypt/Functionality/Services/Local Private Key Services/PassPhraseService.swift b/FlowCrypt/Functionality/Services/Local Private Key Services/PassPhraseService.swift index fe7548262..d5e62a726 100644 --- a/FlowCrypt/Functionality/Services/Local Private Key Services/PassPhraseService.swift +++ b/FlowCrypt/Functionality/Services/Local Private Key Services/PassPhraseService.swift @@ -89,8 +89,10 @@ final class PassPhraseService: PassPhraseServiceType { case .persistent: try encryptedStorage.save(passPhrase: passPhrase) case .memory: - if encryptedStorage.getPassPhrases().contains(where: { $0.primaryFingerprintOfAssociatedKey == passPhrase.primaryFingerprintOfAssociatedKey }) { - logger.logInfo("\(StorageMethod.persistent): removing pass phrase from for key \(passPhrase.primaryFingerprintOfAssociatedKey)") + let storedPassPhrases = encryptedStorage.getPassPhrases() + let fingerprint = passPhrase.primaryFingerprintOfAssociatedKey + if storedPassPhrases.contains(where: { $0.primaryFingerprintOfAssociatedKey == fingerprint }) { + logger.logInfo("\(StorageMethod.persistent): removing pass phrase for key \(fingerprint)") try encryptedStorage.remove(passPhrase: passPhrase) } try inMemoryStorage.save(passPhrase: passPhrase) diff --git a/FlowCrypt/Functionality/Services/Remote Pub Key Services/AttesterApi.swift b/FlowCrypt/Functionality/Services/Remote Pub Key Services/AttesterApi.swift index 374fa5f60..275c8620e 100644 --- a/FlowCrypt/Functionality/Services/Remote Pub Key Services/AttesterApi.swift +++ b/FlowCrypt/Functionality/Services/Remote Pub Key Services/AttesterApi.swift @@ -37,7 +37,7 @@ final class AttesterApi: AttesterApiType { } return "https://flowcrypt.com/attester" // live } - + private func pubUrl(email: String) -> String { let normalizedEmail = email .lowercased() diff --git a/Podfile.lock b/Podfile.lock index 95812844b..549bf8ae0 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -15,7 +15,7 @@ PODS: - PINRemoteImage/PINCache (3.0.3): - PINCache (~> 3.0.3) - PINRemoteImage/Core - - SwiftFormat/CLI (0.48.18) + - SwiftFormat/CLI (0.49.1) - SwiftLint (0.45.1) - SwiftyRSA (1.7.0): - SwiftyRSA/ObjC (= 1.7.0) @@ -64,7 +64,7 @@ SPEC CHECKSUMS: PINCache: 7a8fc1a691173d21dbddbf86cd515de6efa55086 PINOperation: 00c935935f1e8cf0d1e2d6b542e75b88fc3e5e20 PINRemoteImage: f1295b29f8c5e640e25335a1b2bd9d805171bd01 - SwiftFormat: 7dd2b33a0a3d61095b61c911b6d89ff962ae695c + SwiftFormat: 16b41f3229f5e7edb130ac4cd631cceed7af7d5e SwiftLint: 06ac37e4d38c7068e0935bb30cda95f093bec761 SwiftyRSA: 8c6dd1ea7db1b8dc4fb517a202f88bb1354bc2c6 Texture: 2e8ab2519452515f7f5a520f5a8f7e0a413abfa3 From bf89b0120a1fb184db3738aace29b460707118e9 Mon Sep 17 00:00:00 2001 From: Roma Sosnovsky Date: Tue, 14 Dec 2021 22:43:15 +0200 Subject: [PATCH 2/4] #1091 add refresh for expired id tokens --- .../xcshareddata/swiftpm/Package.resolved | 4 +- .../Services/GoogleUserService.swift | 77 +++++++++++++++---- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/FlowCrypt.xcworkspace/xcshareddata/swiftpm/Package.resolved b/FlowCrypt.xcworkspace/xcshareddata/swiftpm/Package.resolved index 0819df7bf..9f5ced7f3 100644 --- a/FlowCrypt.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/FlowCrypt.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -87,8 +87,8 @@ "repositoryURL": "https://github.com/realm/realm-cocoa", "state": { "branch": null, - "revision": "bdbbd57f411a0f4e72b359113dbc6d23fdf96680", - "version": "10.20.0" + "revision": "f483fa0a52f6d49897d133a827510a35e21183c1", + "version": "10.20.1" } }, { diff --git a/FlowCrypt/Functionality/Services/GoogleUserService.swift b/FlowCrypt/Functionality/Services/GoogleUserService.swift index fe6a12b20..57ec802ae 100644 --- a/FlowCrypt/Functionality/Services/GoogleUserService.swift +++ b/FlowCrypt/Functionality/Services/GoogleUserService.swift @@ -42,6 +42,20 @@ struct GoogleUser: Codable { let picture: URL? } +struct IdToken: Codable { + let exp: Int +} + +extension IdToken { + var isExpired: Bool { + Double(exp) < Date().timeIntervalSince1970 + } +} + +enum TokenError: Error { + case missingToken, invalidJWTFormat, invalidBase64EncodedData +} + protocol GoogleUserServiceType { var authorization: GTMAppAuthFetcherAuthorization? { get } func renewSession() async throws @@ -126,20 +140,6 @@ extension GoogleUserService: UserServiceType { } } - func performTokenRefresh() async throws -> (accessToken: String, idToken: String) { - return try await withCheckedThrowingContinuation { continuation in - authorization?.authState.setNeedsTokenRefresh() - authorization?.authState.performAction { accessToken, idToken, error in - guard let accessToken = accessToken, let idToken = idToken else { - let tokenError = error ?? AppErr.unexpected("Shouldn't happen because received nil error and nil token") - return continuation.resume(throwing: tokenError) - } - let result = (accessToken, idToken) - return continuation.resume(with: .success(result)) - } - } - } - func signOut(user email: String) { DispatchQueue.main.async { self.appDelegateGoogleSessionContainer?.googleAuthSession = nil @@ -243,6 +243,55 @@ extension GoogleUserService { } } +// MARK: - Tokens +extension GoogleUserService { + func getIdToken() async throws -> String { + guard let idToken = idToken else { throw(TokenError.missingToken) } + + let decodedToken = try decode(idToken: idToken) + + guard !decodedToken.isExpired else { + let (_, updatedToken) = try await performTokenRefresh() + return updatedToken + } + + return idToken + } + + func decode(idToken: String) throws -> IdToken { + let components = idToken.components(separatedBy: ".") + + guard components.count == 3 else { throw(TokenError.invalidJWTFormat) } + + var decodedString = components[1] + .replacingOccurrences(of: "-", with: "+") + .replacingOccurrences(of: "_", with: "/") + + while decodedString.utf16.count % 4 != 0 { + decodedString += "=" + } + + guard let decodedData = Data(base64Encoded: decodedString) + else { throw(TokenError.invalidBase64EncodedData) } + + return try JSONDecoder().decode(IdToken.self, from: decodedData) + } + + func performTokenRefresh() async throws -> (accessToken: String, idToken: String) { + return try await withCheckedThrowingContinuation { continuation in + authorization?.authState.setNeedsTokenRefresh() + authorization?.authState.performAction { accessToken, idToken, error in + guard let accessToken = accessToken, let idToken = idToken else { + let tokenError = error ?? AppErr.unexpected("Shouldn't happen because received nil error and nil token") + return continuation.resume(throwing: tokenError) + } + let result = (accessToken, idToken) + return continuation.resume(with: .success(result)) + } + } + } +} + // MARK: - OIDAuthStateChangeDelegate extension GoogleUserService: OIDAuthStateChangeDelegate { func didChange(_ state: OIDAuthState) { From df850c8ce81f454191f16c6742e8158ac26f9792 Mon Sep 17 00:00:00 2001 From: Roma Sosnovsky Date: Tue, 14 Dec 2021 23:06:58 +0200 Subject: [PATCH 3/4] #1091 code updates --- .../Functionality/Services/GoogleUserService.swift | 14 +++++++------- .../EmailKeyManagerApi.swift | 9 +++++---- .../Mail Provider/GmailServiceTest.swift | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/FlowCrypt/Functionality/Services/GoogleUserService.swift b/FlowCrypt/Functionality/Services/GoogleUserService.swift index 57ec802ae..ba0cbe521 100644 --- a/FlowCrypt/Functionality/Services/GoogleUserService.swift +++ b/FlowCrypt/Functionality/Services/GoogleUserService.swift @@ -91,12 +91,12 @@ final class GoogleUserService: NSObject, GoogleUserServiceType { authorization?.authState.lastTokenResponse } - var userToken: String? { - tokenResponse?.accessToken + private var idToken: String? { + tokenResponse?.idToken } - var idToken: String? { - tokenResponse?.idToken + var userToken: String? { + tokenResponse?.accessToken } var authorization: GTMAppAuthFetcherAuthorization? { @@ -258,7 +258,7 @@ extension GoogleUserService { return idToken } - func decode(idToken: String) throws -> IdToken { + private func decode(idToken: String) throws -> IdToken { let components = idToken.components(separatedBy: ".") guard components.count == 3 else { throw(TokenError.invalidJWTFormat) } @@ -273,11 +273,11 @@ extension GoogleUserService { guard let decodedData = Data(base64Encoded: decodedString) else { throw(TokenError.invalidBase64EncodedData) } - + return try JSONDecoder().decode(IdToken.self, from: decodedData) } - func performTokenRefresh() async throws -> (accessToken: String, idToken: String) { + private func performTokenRefresh() async throws -> (accessToken: String, idToken: String) { return try await withCheckedThrowingContinuation { continuation in authorization?.authState.setNeedsTokenRefresh() authorization?.authState.performAction { accessToken, idToken, error in diff --git a/FlowCrypt/Functionality/Services/Remote Private Key Services/EmailKeyManagerApi.swift b/FlowCrypt/Functionality/Services/Remote Private Key Services/EmailKeyManagerApi.swift index 95734a5f8..85a7e41d0 100644 --- a/FlowCrypt/Functionality/Services/Remote Private Key Services/EmailKeyManagerApi.swift +++ b/FlowCrypt/Functionality/Services/Remote Private Key Services/EmailKeyManagerApi.swift @@ -56,12 +56,13 @@ actor EmailKeyManagerApi: EmailKeyManagerApiType { throw EmailKeyManagerApiError.noPrivateKeysUrlString } - guard let idToken = GoogleUserService( + let googleService = GoogleUserService( currentUserEmail: currentUserEmail, appDelegateGoogleSessionContainer: nil // only needed when signing in/out - ).idToken else { - throw EmailKeyManagerApiError.noGoogleIdToken - } + ) + + guard let idToken = try? await googleService.getIdToken() + else { throw EmailKeyManagerApiError.noGoogleIdToken } let headers = [ URLHeader( diff --git a/FlowCryptAppTests/Functionality/Mail Provider/GmailServiceTest.swift b/FlowCryptAppTests/Functionality/Mail Provider/GmailServiceTest.swift index 493b6b503..1e071767c 100644 --- a/FlowCryptAppTests/Functionality/Mail Provider/GmailServiceTest.swift +++ b/FlowCryptAppTests/Functionality/Mail Provider/GmailServiceTest.swift @@ -46,7 +46,7 @@ class GmailServiceTest: XCTestCase { class GoogleUserServiceMock: GoogleUserServiceType { var authorization: GTMAppAuthFetcherAuthorization? func renewSession() async throws { - await Task.sleep(1_000_000_000) + try await Task.sleep(nanoseconds: 1_000_000_000) } } From 39de1e4834b0f91a5a7d72ef7e63d539c37d3da3 Mon Sep 17 00:00:00 2001 From: Roma Sosnovsky Date: Wed, 15 Dec 2021 13:32:57 +0200 Subject: [PATCH 4/4] #1091 pr updates --- .../Setup/SetupInitialViewController.swift | 14 +++++++++-- .../DataManager/DataService.swift | 2 +- .../Services/GoogleUserService.swift | 21 +++++++++++----- .../EmailKeyManagerApi.swift | 25 +++++-------------- .../Resources/en.lproj/Localizable.strings | 5 ++-- 5 files changed, 37 insertions(+), 30 deletions(-) diff --git a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift index af2f73314..a03955b03 100644 --- a/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift +++ b/FlowCrypt/Controllers/Setup/SetupInitialViewController.swift @@ -157,10 +157,20 @@ extension SetupInitialViewController { } } + private func getIdToken() async throws -> String { + let googleService = GoogleUserService( + currentUserEmail: user.email, + appDelegateGoogleSessionContainer: nil + ) + + return try await googleService.getCachedOrRefreshedIdToken() + } + private func fetchKeysFromEKM() { Task { do { - let result = try await emailKeyManagerApi.getPrivateKeys(currentUserEmail: user.email) + let idToken = try await getIdToken() + let result = try await emailKeyManagerApi.getPrivateKeys(idToken: idToken) switch result { case .success(keys: let keys): proceedToSetupWithEKMKeys(keys: keys) @@ -183,7 +193,7 @@ extension SetupInitialViewController { if case .noPrivateKeysUrlString = error as? EmailKeyManagerApiError { return } - showAlert(message: error.localizedDescription, onOk: { [weak self] in + showAlert(message: error.errorMessage, onOk: { [weak self] in self?.state = .decidingIfEKMshouldBeUsed }) } diff --git a/FlowCrypt/Functionality/DataManager/DataService.swift b/FlowCrypt/Functionality/DataManager/DataService.swift index 80403692d..485ae8ee7 100644 --- a/FlowCrypt/Functionality/DataManager/DataService.swift +++ b/FlowCrypt/Functionality/DataManager/DataService.swift @@ -102,7 +102,7 @@ extension DataService: DataServiceType { return GoogleUserService( currentUserEmail: currentUser?.email, appDelegateGoogleSessionContainer: nil // needed only when signing in/out - ).userToken + ).accessToken default: return nil } diff --git a/FlowCrypt/Functionality/Services/GoogleUserService.swift b/FlowCrypt/Functionality/Services/GoogleUserService.swift index ba0cbe521..32344d0b6 100644 --- a/FlowCrypt/Functionality/Services/GoogleUserService.swift +++ b/FlowCrypt/Functionality/Services/GoogleUserService.swift @@ -52,8 +52,17 @@ extension IdToken { } } -enum TokenError: Error { +enum IdTokenError: Error, CustomStringConvertible { case missingToken, invalidJWTFormat, invalidBase64EncodedData + + var description: String { + switch self { + case .missingToken: + return "id_token_missing_error_description".localized + case .invalidJWTFormat, .invalidBase64EncodedData: + return "id_token_invalid_error_description".localized + } + } } protocol GoogleUserServiceType { @@ -95,7 +104,7 @@ final class GoogleUserService: NSObject, GoogleUserServiceType { tokenResponse?.idToken } - var userToken: String? { + var accessToken: String? { tokenResponse?.accessToken } @@ -245,8 +254,8 @@ extension GoogleUserService { // MARK: - Tokens extension GoogleUserService { - func getIdToken() async throws -> String { - guard let idToken = idToken else { throw(TokenError.missingToken) } + func getCachedOrRefreshedIdToken() async throws -> String { + guard let idToken = idToken else { throw(IdTokenError.missingToken) } let decodedToken = try decode(idToken: idToken) @@ -261,7 +270,7 @@ extension GoogleUserService { private func decode(idToken: String) throws -> IdToken { let components = idToken.components(separatedBy: ".") - guard components.count == 3 else { throw(TokenError.invalidJWTFormat) } + guard components.count == 3 else { throw(IdTokenError.invalidJWTFormat) } var decodedString = components[1] .replacingOccurrences(of: "-", with: "+") @@ -272,7 +281,7 @@ extension GoogleUserService { } guard let decodedData = Data(base64Encoded: decodedString) - else { throw(TokenError.invalidBase64EncodedData) } + else { throw(IdTokenError.invalidBase64EncodedData) } return try JSONDecoder().decode(IdToken.self, from: decodedData) } diff --git a/FlowCrypt/Functionality/Services/Remote Private Key Services/EmailKeyManagerApi.swift b/FlowCrypt/Functionality/Services/Remote Private Key Services/EmailKeyManagerApi.swift index 85a7e41d0..fc6709c2f 100644 --- a/FlowCrypt/Functionality/Services/Remote Private Key Services/EmailKeyManagerApi.swift +++ b/FlowCrypt/Functionality/Services/Remote Private Key Services/EmailKeyManagerApi.swift @@ -9,11 +9,10 @@ import Foundation protocol EmailKeyManagerApiType { - func getPrivateKeys(currentUserEmail: String) async throws -> EmailKeyManagerApiResult + func getPrivateKeys(idToken: String) async throws -> EmailKeyManagerApiResult } enum EmailKeyManagerApiError: Error { - case noGoogleIdToken case noPrivateKeysUrlString } @@ -26,7 +25,6 @@ enum EmailKeyManagerApiResult { extension EmailKeyManagerApiError: LocalizedError { var errorDescription: String? { switch self { - case .noGoogleIdToken: return "emai_keymanager_api_no_google_id_token_error_description".localized case .noPrivateKeysUrlString: return "" } } @@ -51,19 +49,8 @@ actor EmailKeyManagerApi: EmailKeyManagerApiType { self.core = core } - func getPrivateKeys(currentUserEmail: String) async throws -> EmailKeyManagerApiResult { - guard let urlString = getPrivateKeysUrlString() else { - throw EmailKeyManagerApiError.noPrivateKeysUrlString - } - - let googleService = GoogleUserService( - currentUserEmail: currentUserEmail, - appDelegateGoogleSessionContainer: nil // only needed when signing in/out - ) - - guard let idToken = try? await googleService.getIdToken() - else { throw EmailKeyManagerApiError.noGoogleIdToken } - + func getPrivateKeys(idToken: String) async throws -> EmailKeyManagerApiResult { + let urlString = try getPrivateKeysUrlString() let headers = [ URLHeader( value: "Bearer \(idToken)", @@ -84,7 +71,7 @@ actor EmailKeyManagerApi: EmailKeyManagerApiType { } let privateKeysArmored = decryptedPrivateKeysResponse.privateKeys - .map { $0.decryptedPrivateKey } + .map(\.decryptedPrivateKey) .joined(separator: "\n") .data() let parsedPrivateKeys = try await core.parseKeys(armoredOrBinary: privateKeysArmored) @@ -98,9 +85,9 @@ actor EmailKeyManagerApi: EmailKeyManagerApiType { return .success(keys: parsedPrivateKeys.keyDetails) } - private func getPrivateKeysUrlString() -> String? { + private func getPrivateKeysUrlString() throws -> String { guard let keyManagerUrlString = clientConfiguration.keyManagerUrlString else { - return nil + throw EmailKeyManagerApiError.noPrivateKeysUrlString } return "\(keyManagerUrlString)v1/keys/private" } diff --git a/FlowCrypt/Resources/en.lproj/Localizable.strings b/FlowCrypt/Resources/en.lproj/Localizable.strings index 4d4e6f868..3949bcd71 100644 --- a/FlowCrypt/Resources/en.lproj/Localizable.strings +++ b/FlowCrypt/Resources/en.lproj/Localizable.strings @@ -248,8 +248,9 @@ "organisational_rules_ekm_keys_are_not_decrypted_error" = "Received private keys are not fully decrypted. Please try login flow again"; "organisational_wrong_email_error" = "Not a valid email %@"; -// Email key manager api error -"emai_keymanager_api_no_google_id_token_error_description" = "There is no Google ID token were found while getting client configuration"; +// Google id token errors +"id_token_missing_error_description" = "There is no Google ID token was found while getting client configuration"; +"id_token_invalid_error_description" = "There is no valid Google ID token was found while getting client configuration"; // Gmail Service errors "gmail_service_failed_to_parse_data_error_message" = "Failed to parse Gmail data";