new tests
This commit is contained in:
+63
-12
@@ -17,27 +17,54 @@ struct QueryResult {
|
||||
}
|
||||
|
||||
enum PasswordStore {
|
||||
static func read(_ id: UUID) -> String {
|
||||
let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
|
||||
kSecAttrService as String: "WorkbenchReplacement.MySQL",
|
||||
kSecAttrAccount as String: id.uuidString,
|
||||
kSecReturnData as String: true,
|
||||
kSecMatchLimit as String: kSecMatchLimitOne]
|
||||
private static let service = "DBSyn.MySQL"
|
||||
private static let legacyService = "WorkbenchReplacement.MySQL"
|
||||
|
||||
private static func lookup(_ id: UUID, service: String) -> String? {
|
||||
let query: [String: Any] = [
|
||||
kSecClass as String: kSecClassGenericPassword,
|
||||
kSecAttrService as String: service,
|
||||
kSecAttrAccount as String: id.uuidString,
|
||||
kSecReturnData as String: true,
|
||||
kSecMatchLimit as String: kSecMatchLimitOne
|
||||
]
|
||||
var value: CFTypeRef?
|
||||
guard SecItemCopyMatching(query as CFDictionary, &value) == errSecSuccess,
|
||||
let data = value as? Data else { return "" }
|
||||
return String(data: data, encoding: .utf8) ?? ""
|
||||
let data = value as? Data else { return nil }
|
||||
return String(data: data, encoding: .utf8)
|
||||
}
|
||||
|
||||
static func read(_ id: UUID) -> String {
|
||||
if let password = lookup(id, service: service) { return password }
|
||||
// One-time compatibility read. Never delete the legacy item.
|
||||
if let password = lookup(id, service: legacyService) {
|
||||
save(password, id: id)
|
||||
return password
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
static func save(_ password: String, id: UUID) {
|
||||
let query: [String: Any] = [kSecClass as String: kSecClassGenericPassword,
|
||||
kSecAttrService as String: "WorkbenchReplacement.MySQL",
|
||||
kSecAttrAccount as String: id.uuidString]
|
||||
let query: [String: Any] = [
|
||||
kSecClass as String: kSecClassGenericPassword,
|
||||
kSecAttrService as String: service,
|
||||
kSecAttrAccount as String: id.uuidString
|
||||
]
|
||||
SecItemDelete(query as CFDictionary)
|
||||
guard !password.isEmpty else { return }
|
||||
var attributes = query
|
||||
attributes[kSecValueData as String] = Data(password.utf8)
|
||||
SecItemAdd(attributes as CFDictionary, nil)
|
||||
}
|
||||
|
||||
static func delete(_ id: UUID) {
|
||||
let query: [String: Any] = [
|
||||
kSecClass as String: kSecClassGenericPassword,
|
||||
kSecAttrService as String: service,
|
||||
kSecAttrAccount as String: id.uuidString
|
||||
]
|
||||
SecItemDelete(query as CFDictionary)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -507,7 +534,8 @@ final class DatabaseModel: ObservableObject {
|
||||
let cached = try? JSONDecoder().decode([String: SchemaIntrospection].self, from: data) {
|
||||
introspections = cached.filter { entry in profiles.contains(where: { $0.id == entry.value.connectionID }) }
|
||||
}
|
||||
selectedID = profiles.first?.id
|
||||
let rememberedID = UserDefaults.standard.string(forKey: "DBSyn.selectedConnectionID")
|
||||
selectedID = profiles.first(where: { $0.id.uuidString == rememberedID })?.id ?? profiles.first?.id
|
||||
if let id = selectedID {
|
||||
for snapshot in introspections.values where snapshot.connectionID == id {
|
||||
applyIntrospection(snapshot)
|
||||
@@ -620,11 +648,34 @@ final class DatabaseModel: ObservableObject {
|
||||
}
|
||||
|
||||
var selected: ConnectionProfile? { profiles.first { $0.id == selectedID } }
|
||||
|
||||
func selectConnection(_ id: UUID) {
|
||||
guard let profile = profiles.first(where: { $0.id == id }) else { return }
|
||||
saveActiveQuery()
|
||||
selectedID = id
|
||||
UserDefaults.standard.set(id.uuidString, forKey: "DBSyn.selectedConnectionID")
|
||||
selectedDatabase = profile.database
|
||||
databases = []
|
||||
status = "Selected connection: \(profile.name)"
|
||||
loadDatabases()
|
||||
}
|
||||
|
||||
func deleteConnection(_ id: UUID) {
|
||||
guard profiles.count > 1 else { return }
|
||||
NativeMySQLRunner.disconnect(profileID: id)
|
||||
PasswordStore.delete(id)
|
||||
profiles.removeAll { $0.id == id }
|
||||
if selectedID == id, let first = profiles.first { selectConnection(first.id) }
|
||||
persist()
|
||||
}
|
||||
|
||||
func save(_ profile: ConnectionProfile, password: String) {
|
||||
if let i = profiles.firstIndex(where: { $0.id == profile.id }) { profiles[i] = profile }
|
||||
else { profiles.append(profile) }
|
||||
PasswordStore.save(password, id: profile.id)
|
||||
selectedID = profile.id
|
||||
selectedDatabase = profile.database
|
||||
UserDefaults.standard.set(profile.id.uuidString, forKey: "DBSyn.selectedConnectionID")
|
||||
persist()
|
||||
}
|
||||
private func persist() {
|
||||
|
||||
Reference in New Issue
Block a user