Merge pull request #1062 from mastodon/migrate-auth
Authentication Migrations
This commit is contained in:
commit
dea59ac820
@ -17,7 +17,7 @@ final class SendPostIntentHandler: NSObject {
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
let coreDataStack = CoreDataStack()
|
||||
let coreDataStack = CoreDataStack(isInMemory: true)
|
||||
lazy var managedObjectContext = coreDataStack.persistentContainer.viewContext
|
||||
lazy var api: APIService = {
|
||||
let backgroundManagedObjectContext = coreDataStack.newTaskContext()
|
||||
|
@ -65,7 +65,7 @@
|
||||
<attribute name="version" optional="YES" attributeType="String"/>
|
||||
<relationship name="authentications" toMany="YES" deletionRule="Nullify" destinationEntity="MastodonAuthentication" inverseName="instance" inverseEntity="MastodonAuthentication"/>
|
||||
</entity>
|
||||
<entity name="MastodonAuthentication" representedClassName="CoreDataStack.MastodonAuthentication" syncable="YES">
|
||||
<entity name="MastodonAuthentication" representedClassName="CoreDataStack.MastodonAuthenticationLegacy" syncable="YES">
|
||||
<attribute name="activedAt" attributeType="Date" usesScalarValueType="NO"/>
|
||||
<attribute name="appAccessToken" attributeType="String"/>
|
||||
<attribute name="clientID" attributeType="String"/>
|
||||
|
@ -22,10 +22,14 @@ public final class CoreDataStack {
|
||||
self.storeDescriptions = storeDescriptions
|
||||
}
|
||||
|
||||
public convenience init(databaseName: String = "shared") {
|
||||
public convenience init(databaseName: String = "shared", isInMemory: Bool) {
|
||||
let storeURL = URL.storeURL(for: AppName.groupID, databaseName: databaseName)
|
||||
let storeDescription = NSPersistentStoreDescription(url: storeURL)
|
||||
storeDescription.url = URL(fileURLWithPath: "/dev/null") /// in-memory store with all features in favor of NSInMemoryStoreType
|
||||
let storeDescription: NSPersistentStoreDescription
|
||||
if isInMemory {
|
||||
storeDescription = NSPersistentStoreDescription(url: URL(string: "file:///dev/null")!) /// in-memory store with all features in favor of NSInMemoryStoreType
|
||||
} else {
|
||||
storeDescription = NSPersistentStoreDescription(url: storeURL)
|
||||
}
|
||||
self.init(persistentStoreDescriptions: [storeDescription])
|
||||
}
|
||||
|
||||
@ -123,16 +127,18 @@ extension CoreDataStack {
|
||||
}
|
||||
}
|
||||
|
||||
extension CoreDataStack {
|
||||
|
||||
public func rebuild() {
|
||||
public extension CoreDataStack {
|
||||
func tearDown() {
|
||||
let oldStoreURL = persistentContainer.persistentStoreCoordinator.url(for: persistentContainer.persistentStoreCoordinator.persistentStores.first!)
|
||||
try! persistentContainer.persistentStoreCoordinator.destroyPersistentStore(at: oldStoreURL, ofType: NSSQLiteStoreType, options: nil)
|
||||
}
|
||||
|
||||
func rebuild() {
|
||||
tearDown()
|
||||
|
||||
CoreDataStack.load(persistentContainer: persistentContainer) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.didFinishLoad.value = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -47,8 +47,22 @@ public class AppContext: ObservableObject {
|
||||
.eraseToAnyPublisher()
|
||||
|
||||
public init() {
|
||||
let _coreDataStack = CoreDataStack()
|
||||
|
||||
let authProvider = AuthenticationServiceProvider.shared
|
||||
let _coreDataStack: CoreDataStack
|
||||
if authProvider.authenticationMigrationRequired {
|
||||
_coreDataStack = CoreDataStack(isInMemory: false)
|
||||
authProvider.migrateLegacyAuthentications(
|
||||
in: _coreDataStack.persistentContainer.viewContext
|
||||
)
|
||||
} else {
|
||||
_coreDataStack = CoreDataStack(isInMemory: true)
|
||||
}
|
||||
|
||||
let _managedObjectContext = _coreDataStack.persistentContainer.viewContext
|
||||
_coreDataStack.persistentContainer.persistentStoreDescriptions.forEach {
|
||||
$0.url = URL(fileURLWithPath: "/dev/null")
|
||||
}
|
||||
let _backgroundManagedObjectContext = _coreDataStack.persistentContainer.newBackgroundContext()
|
||||
coreDataStack = _coreDataStack
|
||||
managedObjectContext = _managedObjectContext
|
||||
|
@ -6,10 +6,14 @@ import CoreDataStack
|
||||
import MastodonSDK
|
||||
import KeychainAccess
|
||||
import MastodonCommon
|
||||
import os.log
|
||||
|
||||
public class AuthenticationServiceProvider: ObservableObject {
|
||||
private let logger = Logger(subsystem: "AuthenticationServiceProvider", category: "Authentication")
|
||||
|
||||
public static let shared = AuthenticationServiceProvider()
|
||||
private static let keychain = Keychain(service: "org.joinmastodon.app.authentications", accessGroup: AppName.groupID)
|
||||
private let userDefaults: UserDefaults = .shared
|
||||
|
||||
private init() {}
|
||||
|
||||
@ -63,6 +67,41 @@ public extension AuthenticationServiceProvider {
|
||||
return try? JSONDecoder().decode(MastodonAuthentication.self, from: data)
|
||||
}
|
||||
}
|
||||
|
||||
func migrateLegacyAuthentications(in context: NSManagedObjectContext) {
|
||||
do {
|
||||
let legacyAuthentications = try context.fetch(MastodonAuthenticationLegacy.sortedFetchRequest)
|
||||
let migratedAuthentications = legacyAuthentications.compactMap { auth -> MastodonAuthentication? in
|
||||
return MastodonAuthentication(
|
||||
identifier: auth.identifier,
|
||||
domain: auth.domain,
|
||||
username: auth.username,
|
||||
appAccessToken: auth.appAccessToken,
|
||||
userAccessToken: auth.userAccessToken,
|
||||
clientID: auth.clientID,
|
||||
clientSecret: auth.clientSecret,
|
||||
createdAt: auth.createdAt,
|
||||
updatedAt: auth.updatedAt,
|
||||
activedAt: auth.activedAt,
|
||||
userID: auth.userID
|
||||
)
|
||||
}
|
||||
|
||||
if migratedAuthentications.count != legacyAuthentications.count {
|
||||
logger.log(level: .default, "Not all account authentications could be migrated.")
|
||||
}
|
||||
|
||||
self.authentications = migratedAuthentications
|
||||
userDefaults.didMigrateAuthentications = true
|
||||
} catch {
|
||||
userDefaults.didMigrateAuthentications = false
|
||||
logger.log(level: .error, "Could not migrate legacy authentications")
|
||||
}
|
||||
}
|
||||
|
||||
var authenticationMigrationRequired: Bool {
|
||||
userDefaults.didMigrateAuthentications == false
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
@ -0,0 +1,20 @@
|
||||
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension UserDefaults {
|
||||
|
||||
enum Keys {
|
||||
static let didMigrateAuthenticationsKey = "didMigrateAuthentications"
|
||||
}
|
||||
|
||||
@objc dynamic var didMigrateAuthentications: Bool {
|
||||
get {
|
||||
return bool(forKey: Keys.didMigrateAuthenticationsKey)
|
||||
}
|
||||
|
||||
set {
|
||||
set(newValue, forKey: Keys.didMigrateAuthenticationsKey)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user