diff --git a/DBSyn/DatabaseModel.swift b/DBSyn/DatabaseModel.swift index 3998f99..58ca954 100644 --- a/DBSyn/DatabaseModel.swift +++ b/DBSyn/DatabaseModel.swift @@ -74,17 +74,53 @@ enum PasswordStore { return "" } - static func save(_ password: String, id: UUID) { + @discardableResult + static func save(_ password: String, id: UUID) -> Bool { 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) + + if password.isEmpty { + let status = SecItemDelete(query as CFDictionary) + return status == errSecSuccess || status == errSecItemNotFound + } + + let data = Data(password.utf8) + + let update: [String: Any] = [ + kSecValueData as String: data + ] + + let updateStatus = SecItemUpdate( + query as CFDictionary, + update as CFDictionary + ) + + if updateStatus == errSecSuccess { + return true + } + + if updateStatus == errSecItemNotFound { + var attributes = query + attributes[kSecValueData as String] = data + + let addStatus = SecItemAdd( + attributes as CFDictionary, + nil + ) + + if addStatus == errSecSuccess { + return true + } + + NSLog("DBSyn Keychain add failed: %d", addStatus) + return false + } + + NSLog("DBSyn Keychain update failed: %d", updateStatus) + return false } static func delete(_ id: UUID) { diff --git a/DBSyn/MySQLProtocol.swift b/DBSyn/MySQLProtocol.swift index 1627420..f9172e0 100644 --- a/DBSyn/MySQLProtocol.swift +++ b/DBSyn/MySQLProtocol.swift @@ -422,6 +422,13 @@ final class MySQLWireConnection { ) } let plugin = (try? c.nulString()) ?? "mysql_native_password" + + NSLog( + "DBSyn MySQL authentication: plugin=%@ saltLength=%d tlsRequired=%@", + plugin, + salt.count, + requireTLS ? "YES" : "NO" + ) if requireTLS { let clientSSL = 0x00000800 guard capabilities & clientSSL != 0 else { @@ -443,6 +450,13 @@ final class MySQLWireConnection { body += Array(plugin.utf8) + [0] try send(body) var reply = try readPacket() + + NSLog( + "DBSyn MySQL initial authentication response: type=0x%02X length=%d", + Int(reply.first ?? 0), + reply.count + ) + try checkError(reply) var currentPlugin = plugin var currentSalt = Array(salt) @@ -461,6 +475,12 @@ final class MySQLWireConnection { guard currentPlugin == "caching_sha2_password", reply.count >= 2 else { throw MySQLWireError(message: "Unsupported authentication continuation") } + NSLog( + "DBSyn MySQL authentication continuation: code=0x%02X TLS=%@", + Int(reply[1]), + tlsActive ? "YES" : "NO" + ) + switch reply[1] { case 0x03: // Fast authentication accepted; wait for OK. reply = try readPacket() @@ -496,6 +516,12 @@ final class MySQLWireConnection { throw MySQLWireError(message: "Unsupported caching_sha2_password response: \(reply[1])") } } + NSLog( + "DBSyn MySQL final authentication response: type=0x%02X length=%d", + Int(reply.first ?? 0), + reply.count + ) + try checkError(reply) guard reply.first == 0x00 else { throw MySQLWireError(message: "Authentication did not complete") } if !database.isEmpty { _ = try query("USE `\(database.replacingOccurrences(of: "`", with: "``"))`") }