From d1de81d919d5339913ec70055ff50c1ac93bd54d Mon Sep 17 00:00:00 2001 From: Mingshen Sun Date: Sat, 25 Jan 2025 15:40:12 -0800 Subject: [PATCH] Refactor core data classes (#671) --- pass.xcodeproj/project.pbxproj | 20 ++ pass/AppDelegate.swift | 54 +-- pass/Base.lproj/Main.storyboard | 78 ++--- .../AddPasswordTableViewController.swift | 4 +- .../EditPasswordTableViewController.swift | 6 +- .../PasswordDetailTableViewController.swift | 20 +- .../PasswordEditorTableViewController.swift | 12 +- .../PasswordNavigationViewController.swift | 6 +- .../PasswordNavigationDataSource.swift | 2 +- pass/Views/PasswordTableViewCell.swift | 4 +- .../CredentialProviderViewController.swift | 2 +- .../Controllers/ExtensionViewController.swift | 4 +- passKit/Controllers/CoreDataStack.swift | 90 +++++ passKit/Helpers/Globals.swift | 3 +- passKit/Models/Password.swift | 20 +- passKit/Models/PasswordEntity.swift | 212 ++++++++++-- passKit/Models/PasswordStore.swift | 323 +++++------------- passKit/Models/PasswordTableEntry.swift | 10 +- .../pass.xcdatamodel/contents | 21 +- passKitTests/CoreData/CoreDataTestCase.swift | 31 ++ .../CoreData/PasswordEntityTest.swift | 88 +++++ passKitTests/Models/PasswordStoreTest.swift | 5 +- passKitTests/Models/PasswordTest.swift | 18 +- passKitTests/Testbase/TestBase.swift | 5 +- 24 files changed, 605 insertions(+), 433 deletions(-) create mode 100644 passKit/Controllers/CoreDataStack.swift create mode 100644 passKitTests/CoreData/CoreDataTestCase.swift create mode 100644 passKitTests/CoreData/PasswordEntityTest.swift diff --git a/pass.xcodeproj/project.pbxproj b/pass.xcodeproj/project.pbxproj index 5103e12..2650037 100644 --- a/pass.xcodeproj/project.pbxproj +++ b/pass.xcodeproj/project.pbxproj @@ -195,6 +195,9 @@ DC4914961E434301007FF592 /* LabelTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC4914941E434301007FF592 /* LabelTableViewCell.swift */; }; DC4914991E434600007FF592 /* PasswordDetailTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC4914981E434600007FF592 /* PasswordDetailTableViewController.swift */; }; DC5F385B1E56AADB00C69ACA /* PGPKeyArmorImportTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC5F385A1E56AADB00C69ACA /* PGPKeyArmorImportTableViewController.swift */; }; + DC6474532D20DD0C004B4BBC /* CoreDataStack.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC6474522D20DD0C004B4BBC /* CoreDataStack.swift */; }; + DC64745C2D29BE9B004B4BBC /* PasswordEntityTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC6474592D29BD43004B4BBC /* PasswordEntityTest.swift */; }; + DC64745D2D29BEA9004B4BBC /* CoreDataTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC6474582D29BD43004B4BBC /* CoreDataTestCase.swift */; }; DC7CBBBD2D0FA3F2003BB4D2 /* YubiKit in Frameworks */ = {isa = PBXBuildFile; productRef = DC7CBBBC2D0FA3F2003BB4D2 /* YubiKit */; }; DC7CBBBF2D0FAC92003BB4D2 /* YKFSmartCardInterfaceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC7CBBBE2D0FAC8E003BB4D2 /* YKFSmartCardInterfaceExtension.swift */; }; DC8963C01E38EEB900828B09 /* SSHKeyURLImportTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC8963BF1E38EEB900828B09 /* SSHKeyURLImportTableViewController.swift */; }; @@ -493,6 +496,9 @@ DC4914941E434301007FF592 /* LabelTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LabelTableViewCell.swift; sourceTree = ""; }; DC4914981E434600007FF592 /* PasswordDetailTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PasswordDetailTableViewController.swift; sourceTree = ""; }; DC5F385A1E56AADB00C69ACA /* PGPKeyArmorImportTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PGPKeyArmorImportTableViewController.swift; sourceTree = ""; }; + DC6474522D20DD0C004B4BBC /* CoreDataStack.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataStack.swift; sourceTree = ""; }; + DC6474582D29BD43004B4BBC /* CoreDataTestCase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataTestCase.swift; sourceTree = ""; }; + DC6474592D29BD43004B4BBC /* PasswordEntityTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordEntityTest.swift; sourceTree = ""; }; DC7CBBBE2D0FAC8E003BB4D2 /* YKFSmartCardInterfaceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YKFSmartCardInterfaceExtension.swift; sourceTree = ""; }; DC8963BF1E38EEB900828B09 /* SSHKeyURLImportTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSHKeyURLImportTableViewController.swift; sourceTree = ""; }; DC917BD31E2E8231000FDF54 /* Pass.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Pass.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -868,6 +874,7 @@ A26075861EEC6F34005DB03E /* passKitTests */ = { isa = PBXGroup; children = ( + DC64745A2D29BD43004B4BBC /* CoreData */, 30A86F93230F235800F821A4 /* Crypto */, 30BAC8C322E3BA4300438475 /* Testbase */, 30697C5521F63F870064FCAC /* Extensions */, @@ -901,6 +908,7 @@ children = ( 30697C3121F63C8B0064FCAC /* PasscodeLockPresenter.swift */, 30697C3221F63C8B0064FCAC /* PasscodeLockViewController.swift */, + DC6474522D20DD0C004B4BBC /* CoreDataStack.swift */, ); path = Controllers; sourceTree = ""; @@ -1021,6 +1029,15 @@ path = Views; sourceTree = ""; }; + DC64745A2D29BD43004B4BBC /* CoreData */ = { + isa = PBXGroup; + children = ( + DC6474582D29BD43004B4BBC /* CoreDataTestCase.swift */, + DC6474592D29BD43004B4BBC /* PasswordEntityTest.swift */, + ); + path = CoreData; + sourceTree = ""; + }; DC917BCA1E2E8231000FDF54 = { isa = PBXGroup; children = ( @@ -1589,6 +1606,7 @@ 3087574F2343E42A00B971A2 /* Colors.swift in Sources */, 30697C2C21F63C5A0064FCAC /* FileManagerExtension.swift in Sources */, 30697C3321F63C8B0064FCAC /* PasscodeLockPresenter.swift in Sources */, + DC6474532D20DD0C004B4BBC /* CoreDataStack.swift in Sources */, 30697C3D21F63C990064FCAC /* UIViewExtension.swift in Sources */, 30697C3A21F63C990064FCAC /* UIViewControllerExtension.swift in Sources */, 30697C2E21F63C5A0064FCAC /* Utils.swift in Sources */, @@ -1619,9 +1637,11 @@ 30697C5F21F674800064FCAC /* String+UtilitiesTest.swift in Sources */, 3032328A22C9FBA2009EBD9C /* KeyFileManagerTest.swift in Sources */, 306623332406F1A8000E2AD6 /* PasswordGeneratorTest.swift in Sources */, + DC64745C2D29BE9B004B4BBC /* PasswordEntityTest.swift in Sources */, 30BAC8C722E3BAAF00438475 /* TestPGPKeys.swift in Sources */, 30A1D2AA21B32A0100E2D1F7 /* OTPTypeTest.swift in Sources */, 301F6468216165290071A4CE /* ConstantsTest.swift in Sources */, + DC64745D2D29BEA9004B4BBC /* CoreDataTestCase.swift in Sources */, 30A1D29C21AF451E00E2D1F7 /* PasswordGeneratorFlavorTest.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/pass/AppDelegate.swift b/pass/AppDelegate.swift index cb76274..6c18228 100644 --- a/pass/AppDelegate.swift +++ b/pass/AppDelegate.swift @@ -23,6 +23,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { lazy var passcodeLockPresenter = PasscodeLockPresenter(mainWindow: self.window) func application(_: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + PersistenceController.shared.setup() // Override point for customization after application launch. SVProgressHUD.setMinimumSize(CGSize(width: 150, height: 100)) passcodeLockPresenter.present(windowLevel: UIApplication.shared.windows.last?.windowLevel.rawValue) @@ -80,6 +81,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate { appIconView.center = (window?.center)! appIconView.tag = ViewTag.appicon.rawValue window?.addSubview(appIconView) + + PersistenceController.shared.save() } func applicationDidEnterBackground(_: UIApplication) { @@ -102,55 +105,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate { func applicationWillTerminate(_: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. // Saves changes in the application's managed object context before the application terminates. - saveContext() - } - - // MARK: - Core Data stack - - lazy var persistentContainer: NSPersistentContainer = { - // The persistent container for the application. This implementation - // creates and returns a container, having loaded the store for the - // application to it. This property is optional since there are legitimate - // error conditions that could cause the creation of the store to fail. - let modelURL = Bundle(identifier: Globals.passKitBundleIdentifier)!.url(forResource: "pass", withExtension: "momd")! - let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL) - let container = NSPersistentContainer(name: "pass", managedObjectModel: managedObjectModel!) - if FileManager.default.fileExists(atPath: Globals.documentPath) { - try! FileManager.default.createDirectory(atPath: Globals.documentPath, withIntermediateDirectories: true, attributes: nil) - } - container.persistentStoreDescriptions = [NSPersistentStoreDescription(url: URL(fileURLWithPath: Globals.dbPath))] - container.loadPersistentStores { _, error in - if let error = error as NSError? { - // Replace this implementation with code to handle the error appropriately. - // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. - - // Typical reasons for an error here include: - // - // * The parent directory does not exist, cannot be created, or disallows writing. - // * The persistent store is not accessible, due to permissions or data protection when the device is locked. - // * The device is out of space. - // * The store could not be migrated to the current model version. - // - // Check the error message to determine what the actual problem was. - fatalError("UnresolvedError".localize("\(error), \(error.userInfo)")) - } - } - return container - }() - - // MARK: - Core Data Saving support - - func saveContext() { - let context = persistentContainer.viewContext - if context.hasChanges { - do { - try context.save() - } catch { - // Replace this implementation with code to handle the error appropriately. - // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. - let nserror = error as NSError - fatalError("UnresolvedError".localize("\(nserror), \(nserror.userInfo)")) - } - } + PersistenceController.shared.save() } } diff --git a/pass/Base.lproj/Main.storyboard b/pass/Base.lproj/Main.storyboard index 4496a88..33f64a3 100644 --- a/pass/Base.lproj/Main.storyboard +++ b/pass/Base.lproj/Main.storyboard @@ -128,18 +128,18 @@ - +