Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issue 1111 only initialize Realm and KeyChainService once #1117

Merged
merged 30 commits into from
Dec 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
cf00351
issue 1111 only initialize Realm and KeyChainService once
tomholub Nov 29, 2021
35f2086
wip
tomholub Nov 30, 2021
0e2a495
wip
tomholub Nov 30, 2021
aca0f96
wip
tomholub Nov 30, 2021
f2d01f8
[skip ci] fixed controllers
tomholub Nov 30, 2021
353ff23
[skip ci] more fixes
tomholub Nov 30, 2021
7302dbd
[skip ci] a few more
tomholub Nov 30, 2021
bd91385
[skip ci] fix services
tomholub Nov 30, 2021
f62f156
mail provider fixes [skip ci]
tomholub Nov 30, 2021
70509db
a few more fixes [skip ci]
tomholub Nov 30, 2021
7e5accd
a few more fixes [skip ci]
tomholub Nov 30, 2021
bbf37a9
it builds
tomholub Nov 30, 2021
08941db
add to test scope
tomholub Nov 30, 2021
143f9b7
Merge branch 'master' into issue-1111-realm-keychain-init
tomholub Nov 30, 2021
40738e5
[skip ci] remove AppReset, fix some test usages
tomholub Nov 30, 2021
2f8df6d
Project file fixed
ivan-ushakov Nov 30, 2021
418572d
removed unwanted files from test target
tomholub Nov 30, 2021
a87d35a
Merge branch 'issue-1111-realm-keychain-init' of github.com:FlowCrypt…
tomholub Nov 30, 2021
bd556c0
intermediate
tomholub Nov 30, 2021
dc66c8c
fix
tomholub Nov 30, 2021
120af70
PR fixes
tomholub Nov 30, 2021
aae17fb
PR fixes II
tomholub Nov 30, 2021
e786059
less verbose backup service init
tomholub Nov 30, 2021
5767e3a
cleanup
tomholub Nov 30, 2021
90bfac3
controller cleanup
tomholub Nov 30, 2021
2458d9b
fix
tomholub Nov 30, 2021
8eda81f
cleanup
tomholub Nov 30, 2021
5947f39
issue #1111 fix unit tests running
sosnovsky Dec 1, 2021
050d226
issue #1131 use in-memory Realm for tests
sosnovsky Dec 1, 2021
359030b
issue #1111 fix tests
sosnovsky Dec 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 39 additions & 21 deletions FlowCrypt.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

133 changes: 133 additions & 0 deletions FlowCrypt/App/AppContext.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
//
// AppContext.swift
// FlowCrypt
//
// Created by Tom on 30.11.2021
// Copyright © 2017-present FlowCrypt a. s. All rights reserved.
//

import Foundation
import UIKit

class AppContext {

let globalRouter: GlobalRouterType
let encryptedStorage: EncryptedStorageType
let session: SessionType?
// todo - session service should have maybe `.currentSession` on it, then we don't have to have `session` above?
let userAccountService: SessionServiceType
let dataService: DataServiceType
let keyStorage: KeyStorageType
let keyService: KeyServiceType
let passPhraseService: PassPhraseServiceType
let clientConfigurationService: ClientConfigurationServiceType

private init(
encryptedStorage: EncryptedStorageType,
session: SessionType?,
userAccountService: SessionServiceType,
dataService: DataServiceType,
keyStorage: KeyStorageType,
keyService: KeyServiceType,
passPhraseService: PassPhraseServiceType,
clientConfigurationService: ClientConfigurationServiceType,
globalRouter: GlobalRouterType
) {
self.encryptedStorage = encryptedStorage
self.session = session
self.userAccountService = userAccountService
self.dataService = dataService
self.keyStorage = keyStorage // todo - keyStorage and keyService should be the same
self.keyService = keyService
self.passPhraseService = passPhraseService
self.clientConfigurationService = clientConfigurationService
self.globalRouter = globalRouter
}

@MainActor
static func setUpAppContext(globalRouter: GlobalRouterType) throws -> AppContext {
let keyChainService = KeyChainService()
let encryptedStorage = EncryptedStorage(
storageEncryptionKey: try keyChainService.getStorageEncryptionKey()
)
let dataService = DataService(encryptedStorage: encryptedStorage)
let passPhraseService = PassPhraseService(encryptedStorage: encryptedStorage)
let keyStorage = KeyDataStorage(encryptedStorage: encryptedStorage)
let keyService = KeyService(
storage: keyStorage,
passPhraseService: passPhraseService,
currentUserEmail: { dataService.email }
)
let clientConfigurationService = ClientConfigurationService(
local: LocalClientConfiguration(
encryptedStorage: encryptedStorage
)
)
return AppContext(
encryptedStorage: encryptedStorage,
session: nil, // will be set later. But would be nice to already set here, if available
userAccountService: SessionService(
encryptedStorage: encryptedStorage,
dataService: dataService,
googleService: GoogleUserService(
currentUserEmail: dataService.currentUser?.email,
appDelegateGoogleSessionContainer: UIApplication.shared.delegate as? AppDelegate
)
),
dataService: dataService,
keyStorage: keyStorage,
keyService: keyService,
passPhraseService: passPhraseService,
clientConfigurationService: clientConfigurationService,
globalRouter: globalRouter
)
}

func withSession(_ session: SessionType?) -> AppContext {
return AppContext(
encryptedStorage: self.encryptedStorage,
session: session,
userAccountService: self.userAccountService,
dataService: self.dataService,
keyStorage: self.keyStorage,
keyService: self.keyService,
passPhraseService: self.passPhraseService,
clientConfigurationService: self.clientConfigurationService,
globalRouter: globalRouter
)
}

func getRequiredMailProvider() -> MailProvider {
guard let mailProvider = getOptionalMailProvider() else {
// todo - should throw instead
fatalError("wrongly using mail provider when not logged in")
}
return mailProvider
}

func getOptionalMailProvider() -> MailProvider? {
guard let currentUser = self.dataService.currentUser, let currentAuthType = self.dataService.currentAuthType else {
return nil
}
return MailProvider(
currentAuthType: currentAuthType,
currentUser: currentUser
)
}

func getBackupService() -> BackupService {
let mailProvider = self.getRequiredMailProvider()
return BackupService(
backupProvider: mailProvider.backupProvider,
messageSender: mailProvider.messageSender
)
}

func getFoldersService() -> FoldersService {
return FoldersService(
encryptedStorage: self.encryptedStorage,
remoteFoldersProvider: self.getRequiredMailProvider().remoteFoldersProvider
)
}

}
32 changes: 0 additions & 32 deletions FlowCrypt/App/AppReset.swift

This file was deleted.

13 changes: 0 additions & 13 deletions FlowCrypt/App/Configuration.swift

This file was deleted.

19 changes: 6 additions & 13 deletions FlowCrypt/App/main.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,9 @@
import Foundation
import UIKit

autoreleasepool {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure we could skip autoreleasepool here

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure either - the IDE was telling me that it's no longer needed. @sosnovsky may know

This comment was marked as resolved.

if ProcessInfo().arguments.contains(AppReset.reset.rawValue) {
AppReset.resetKeychain()
AppReset.resetUserDefaults()
}

UIApplicationMain(
CommandLine.argc,
CommandLine.unsafeArgv,
nil,
NSStringFromClass(AppDelegate.self)
)
}
UIApplicationMain(
CommandLine.argc,
CommandLine.unsafeArgv,
nil,
NSStringFromClass(AppDelegate.self)
)
8 changes: 4 additions & 4 deletions FlowCrypt/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@

import AppAuth
import UIKit
import GTMAppAuth

class AppDelegate: UIResponder, UIApplicationDelegate {
class AppDelegate: UIResponder, UIApplicationDelegate, AppDelegateGoogleSesssionContainer {
var blurViewController: BlurViewController?
var googleAuthSession: OIDExternalUserAgentSession?
let window: UIWindow = UIWindow(frame: UIScreen.main.bounds)

func application(_: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let isRunningTests = NSClassFromString("XCTestCase") != nil
if isRunningTests {
func application(_ application: UIApplication, didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if application.isRunningTests {
return true
}
GlobalRouter().proceed()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ final class InvalidStorageViewController: TableNodeViewController {
}

private let error: Error
private let encryptedStorage: EncryptedStorageType
private let encryptedStorage: EncryptedStorageType? // nil if failed to initialize
private let router: GlobalRouterType

init(error: Error, encryptedStorage: EncryptedStorageType, router: GlobalRouterType) {
init(error: Error, encryptedStorage: EncryptedStorageType?, router: GlobalRouterType) {
self.error = error
self.encryptedStorage = encryptedStorage
self.router = router
Expand All @@ -44,6 +44,10 @@ final class InvalidStorageViewController: TableNodeViewController {
}

@objc private func handleTap() {
guard let encryptedStorage = encryptedStorage else {
showAlert(message: "invalid_storage_failed_to_initialize".localized)
return
}
do {
try encryptedStorage.reset()
router.proceed()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ import FlowCryptUI
import UIKit

class CheckMailAuthViewController: TableNodeViewController {
private let globalRouter: GlobalRouterType
private let appContext: AppContext

init(globalRouter: GlobalRouterType = GlobalRouter()) {
self.globalRouter = globalRouter
init(appContext: AppContext) {
self.appContext = appContext
super.init(node: TableNode())
}

Expand Down Expand Up @@ -85,7 +85,7 @@ extension CheckMailAuthViewController {
case 2:
return ButtonCellNode(input: .signInAgain) { [weak self] in
guard let self = self else { return }
self.globalRouter.signIn(with: .gmailLogin(self))
self.appContext.globalRouter.signIn(appContext: self.appContext, route: .gmailLogin(self))
}
default:
return ASCellNode()
Expand Down
53 changes: 35 additions & 18 deletions FlowCrypt/Controllers/Compose/ComposeViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,18 @@ final class ComposeViewController: TableNodeViewController {
case subject, subjectDivider, text
}

private let appContext: AppContext
private let composeMessageService: ComposeMessageService
private let notificationCenter: NotificationCenter
private let decorator: ComposeViewDecorator
private let contactsService: ContactsServiceType
private let cloudContactProvider: CloudContactsProvider
private let filesManager: FilesManagerType
private let photosManager: PhotosManagerType
private let keyService: KeyServiceType
private let keyMethods: KeyMethodsType
private let service: ServiceActor
private let passPhraseService: PassPhraseService
private let router: GlobalRouterType
private let clientConfiguration: ClientConfiguration

private let search = PassthroughSubject<String, Never>()
private let userDefaults: UserDefaults
Expand All @@ -68,42 +68,59 @@ final class ComposeViewController: TableNodeViewController {
private var composedLatestDraft: ComposedDraft?

init(
email: String,
appContext: AppContext,
notificationCenter: NotificationCenter = .default,
decorator: ComposeViewDecorator = ComposeViewDecorator(),
input: ComposeMessageInput = .empty,
cloudContactProvider: CloudContactsProvider = UserContactsProvider(),
cloudContactProvider: CloudContactsProvider? = nil,
userDefaults: UserDefaults = .standard,
contactsService: ContactsServiceType = ContactsService(),
composeMessageService: ComposeMessageService = ComposeMessageService(),
contactsService: ContactsServiceType? = nil,
composeMessageService: ComposeMessageService? = nil,
filesManager: FilesManagerType = FilesManager(),
photosManager: PhotosManagerType = PhotosManager(),
keyService: KeyServiceType = KeyService(),
passPhraseService: PassPhraseService = PassPhraseService(),
keyMethods: KeyMethodsType = KeyMethods(),
router: GlobalRouterType = GlobalRouter()
) {
self.appContext = appContext
guard let email = appContext.dataService.email else {
fatalError("missing current user email") // todo - need a more elegant solution
}
self.email = email
self.notificationCenter = notificationCenter
self.input = input
self.decorator = decorator
self.userDefaults = userDefaults
self.contactsService = contactsService
let clientConfiguration = appContext.clientConfigurationService.getSaved(for: email)
self.contactsService = contactsService ?? ContactsService(
localContactsProvider: LocalContactsProvider(
encryptedStorage: appContext.encryptedStorage
),
clientConfiguration: clientConfiguration
)
let cloudContactProvider = cloudContactProvider ?? UserContactsProvider(
userService: GoogleUserService(
currentUserEmail: email,
appDelegateGoogleSessionContainer: UIApplication.shared.delegate as? AppDelegate
)
)
self.cloudContactProvider = cloudContactProvider
self.composeMessageService = composeMessageService
self.composeMessageService = composeMessageService ?? ComposeMessageService(
clientConfiguration: clientConfiguration,
encryptedStorage: appContext.encryptedStorage,
messageGateway: appContext.getRequiredMailProvider().messageSender
)
self.filesManager = filesManager
self.photosManager = photosManager
self.keyService = keyService
self.keyMethods = keyMethods
self.service = ServiceActor(
composeMessageService: composeMessageService,
contactsService: contactsService,
composeMessageService: self.composeMessageService,
contactsService: self.contactsService,
cloudContactProvider: cloudContactProvider
)
self.passPhraseService = passPhraseService
self.router = router
self.contextToSend.subject = input.subject
self.contextToSend.attachments = input.attachments
self.clientConfiguration = clientConfiguration
super.init(node: TableNode())
}

Expand Down Expand Up @@ -354,7 +371,7 @@ extension ComposeViewController {

extension ComposeViewController {
private func prepareSigningKey() async throws -> PrvKeyInfo {
guard let signingKey = try await keyService.getSigningKey() else {
guard let signingKey = try await appContext.keyService.getSigningKey() else {
throw AppErr.general("None of your private keys have your user id \"\(email)\". Please import the appropriate key.")
}

Expand Down Expand Up @@ -396,15 +413,15 @@ extension ComposeViewController {
private func handlePassPhraseEntry(_ passPhrase: String, for signingKey: PrvKeyInfo) async throws -> Bool {
// since pass phrase was entered (an inconvenient thing for user to do),
// let's find all keys that match and save the pass phrase for all
let allKeys = try await self.keyService.getPrvKeyInfo()
let allKeys = try await appContext.keyService.getPrvKeyInfo()
guard allKeys.isNotEmpty else {
// tom - todo - nonsensical error type choice https://github.com/FlowCrypt/flowcrypt-ios/issues/859
// I copied it from another usage, but has to be changed
throw KeyServiceError.retrieve
}
let matchingKeys = try await self.keyMethods.filterByPassPhraseMatch(keys: allKeys, passPhrase: passPhrase)
// save passphrase for all matching keys
self.passPhraseService.savePassPhrasesInMemory(passPhrase, for: matchingKeys)
appContext.passPhraseService.savePassPhrasesInMemory(passPhrase, for: matchingKeys)
// now figure out if the pass phrase also matched the signing prv itself
let matched = matchingKeys.first(where: { $0.fingerprints.first == signingKey.fingerprints.first })
return matched != nil// true if the pass phrase matched signing key
Expand Down Expand Up @@ -1110,7 +1127,7 @@ extension ComposeViewController {

Task {
do {
try await router.askForContactsPermission(for: .gmailLogin(self))
try await router.askForContactsPermission(for: .gmailLogin(self), appContext: appContext)
node.reloadSections([2], with: .automatic)
} catch {
handleContactsPermissionError(error)
Expand Down
Loading