Skip to content

Commit

Permalink
Fix a bug where iOS autofill failed every other time
Browse files Browse the repository at this point in the history
Only worked when iOS first instantiated the AutoFill extension.

Because on the 2nd execution, 1 == 0

Based on the successful workaround code change, current theory
is that this relates to over-eager Swift compiler optimisation of
an array literal.
  • Loading branch information
luckyrat committed Jul 13, 2023
1 parent 271b4ae commit 875ab80
Show file tree
Hide file tree
Showing 37 changed files with 455 additions and 454 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,5 @@ ios/fastlane/.env.default
ios/android/.env.default
ios/Flutter/KeeVault-generated.xcconfig
ios/fastlane/report.xml
ios/Runner.app.dSYM.zip
ios/Runner.ipa
12 changes: 12 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@
"--dart-define",
"KEEVAULT_CHANNEL=dev"
]
},
{
"name": "keevault release local device",
"request": "launch",
"type": "dart",
"flutterMode": "release",
"args": [
"--dart-define",
"KEEVAULT_STAGE=",
"--dart-define",
"KEEVAULT_CHANNEL=play"
]
}
]
}
23 changes: 14 additions & 9 deletions ios/KdbxSwift/Sources/KdbxSwift/DatabaseFileManager.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Foundation
import os.log

public class DatabaseFileManager {
public enum Error {
Expand Down Expand Up @@ -32,6 +33,7 @@ public class DatabaseFileManager {
sharedGroupName: String,
sharedDefaults: UserDefaults
) {
Logger.mainLog.debug("DatabaseFileManager.init started")
self.preTransformedKeyMaterial = preTransformedKeyMaterial.clone()
self.status = status

Expand All @@ -43,10 +45,10 @@ public class DatabaseFileManager {

private func initDatabase(signature data: ByteArray) -> Database? {
if Database2.isSignatureMatches(data: data) {
Diag.info("DB signature: KDBX")
Logger.mainLog.info("DB signature: KDBX")
return Database2()
} else {
Diag.info("DB signature: no match")
Logger.mainLog.info("DB signature: no match")
return nil
}
}
Expand All @@ -58,19 +60,21 @@ public class DatabaseFileManager {
do {
let autofillFileData = try ByteArray(contentsOf: kdbxAutofillURL, options: [.uncached, .mappedIfSafe])
fileData = autofillFileData
Logger.mainLog.debug("Loaded autofill KDBX")
} catch {
Diag.info("Autofill file not found. Expected unless recent changes have been made via autofill and main app not opened yet.")
Logger.mainLog.info("Autofill file not found. Expected unless recent changes have been made via autofill and main app not opened yet.")
do {
fileData = try ByteArray(contentsOf: kdbxCurrentURL, options: [.uncached, .mappedIfSafe])
Logger.mainLog.debug("Loaded main KDBX")

} catch {
Diag.error("Failed to read current KDBX file [message: \(error.localizedDescription)]")
fatalError("couldn't read KDBX file")
Logger.mainLog.error("Failed to read current KDBX file [message: \(error.localizedDescription, privacy: .public)]")
Logger.fatalError("couldn't read KDBX file")
}
}

guard let db = initDatabase(signature: fileData) else {
fatalError("database init failed")
Logger.fatalError("database init failed")
}

let dbFile = DatabaseFile(
Expand All @@ -89,20 +93,21 @@ public class DatabaseFileManager {
database = db

} catch {
fatalError("Unprocessed exception while opening database. Possibly hardware failure has corrupted the data on this device.")
Logger.fatalError("Unprocessed exception while opening database. Possibly hardware failure has corrupted the data on this device.")
}
return dbFile
}

public func saveToFile(db: Database?) {
do {
Logger.mainLog.debug("Saving to autofill KDBX")
guard let targetDatabase = db ?? database else {
fatalError("No database to save")
Logger.fatalError("No database to save")
}
let fileData = try targetDatabase.save()
try fileData.write(to: kdbxAutofillURL, options: .atomic)
} catch {
Diag.error("Failed to write autofill KDBX file [message: \(error.localizedDescription)]")
Logger.mainLog.error("Failed to write autofill KDBX file [message: \(error.localizedDescription, privacy: .public)]")
}
}
}
3 changes: 2 additions & 1 deletion ios/KdbxSwift/Sources/KdbxSwift/base32/Base32.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
// THE SOFTWARE.

import Foundation
import os.log

// https://tools.ietf.org/html/rfc4648

Expand Down Expand Up @@ -232,7 +233,7 @@ private func base32encode(_ data: UnsafeRawPointer, _ length: Int, _ table: [Int
return base32Encoded
} else {
resultBuffer.deallocate()
fatalError("internal error")
Logger.fatalError("internal error")
}
}

Expand Down
3 changes: 2 additions & 1 deletion ios/KdbxSwift/Sources/KdbxSwift/crypto/CryptoManager.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import Foundation
import CommonCrypto.CommonHMAC
import os.log

public enum CryptoError: Error {
case invalidKDFParam(kdfName: String, paramName: String)
Expand Down Expand Up @@ -36,7 +37,7 @@ public final class CryptoManager {
return SecRandomCopyBytes(kSecRandomDefault, outBytes.count, &outBytes)
}
if status != errSecSuccess {
Diag.warning("Failed to generate random bytes [count: \(count), status: \(status)]")
Logger.mainLog.warning("Failed to generate random bytes [count: \(count, privacy: .public), status: \(status, privacy: .public)]")
throw CryptoError.rngError(code: Int(status))
}
return output
Expand Down
25 changes: 14 additions & 11 deletions ios/KdbxSwift/Sources/KdbxSwift/db/Database.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import Foundation
import os.log

public struct SearchQuery {
public let includeSubgroups: Bool
public let includeDeleted: Bool
Expand Down Expand Up @@ -40,7 +43,7 @@ open class Database: Eraseable {
}

public var keyHelper: KeyHelper {
fatalError("Pure virtual method")
Logger.fatalError("Pure virtual method")
}

internal init() {
Expand All @@ -57,27 +60,27 @@ open class Database: Eraseable {
}

public class func isSignatureMatches(data: ByteArray) -> Bool {
fatalError("Pure virtual method")
Logger.fatalError("Pure virtual method")
}

public func load(
dbFileName: String,
dbFileData: ByteArray,
preTransformedKeyMaterial: ByteArray
) throws {
fatalError("Pure virtual method")
Logger.fatalError("Pure virtual method")
}

public func save() throws -> ByteArray {
fatalError("Pure virtual method")
Logger.fatalError("Pure virtual method")
}

public func changeCompositeKey(to newKey: CompositeKey) {
fatalError("Pure virtual method")
Logger.fatalError("Pure virtual method")
}

public func getBackupGroup(createIfMissing: Bool) -> Group? {
fatalError("Pure virtual method")
Logger.fatalError("Pure virtual method")
}

public func count(includeGroups: Bool = true, includeEntries: Bool = true) -> Int {
Expand All @@ -99,22 +102,22 @@ open class Database: Eraseable {
}

public func delete(group: Group) {
fatalError("Pure virtual method")
Logger.fatalError("Pure virtual method")
}

public func delete(entry: Entry) {
fatalError("Pure virtual method")
Logger.fatalError("Pure virtual method")
}

public func makeAttachment(name: String, data: ByteArray) -> Attachment {
fatalError("Pure virtual method")
Logger.fatalError("Pure virtual method")
}

internal func resolveReferences<T>(
allEntries: T)
where T: Collection, T.Element: Entry
{
Diag.debug("Resolving references")
Logger.mainLog.debug("Resolving references")

allEntries.forEach { entry in
entry.fields.forEach { field in
Expand All @@ -127,6 +130,6 @@ open class Database: Eraseable {
field.resolveReferences(entries: allEntries)
}
}
Diag.debug("References resolved OK")
Logger.mainLog.debug("References resolved OK")
}
}
4 changes: 3 additions & 1 deletion ios/KdbxSwift/Sources/KdbxSwift/db/DatabaseItem.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os.log

open class DatabaseItem {
public enum TouchMode {
case accessed
Expand All @@ -18,6 +20,6 @@ open class DatabaseItem {
}

public func touch(_ mode: TouchMode, updateParents: Bool = true) {
fatalError("Pure abstract method")
Logger.fatalError("Pure abstract method")
}
}
7 changes: 4 additions & 3 deletions ios/KdbxSwift/Sources/KdbxSwift/db/Entry.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Foundation
import os.log

public class EntryField: Eraseable {
public static let title = "Title"
Expand Down Expand Up @@ -203,7 +204,7 @@ public class Entry: DatabaseItem, Eraseable {

public var isHiddenFromSearch: Bool {
get { return false }
set { fatalError("This property can be modified only in some DB formats") }
set { Logger.fatalError("This property can be modified only in some DB formats") }
}

public var attachments: Array<Attachment>
Expand Down Expand Up @@ -298,7 +299,7 @@ public class Entry: DatabaseItem, Eraseable {
}

public func clone(makeNewUUID: Bool) -> Entry {
fatalError("Pure virtual method")
Logger.fatalError("Pure virtual method")
}

public func apply(to target: Entry, makeNewUUID: Bool) {
Expand Down Expand Up @@ -326,7 +327,7 @@ public class Entry: DatabaseItem, Eraseable {
}

public func backupState() {
fatalError("Pure virtual method")
Logger.fatalError("Pure virtual method")
}

override public func touch(_ mode: DatabaseItem.TouchMode, updateParents: Bool = true) {
Expand Down
13 changes: 7 additions & 6 deletions ios/KdbxSwift/Sources/KdbxSwift/db/EntryFieldReference.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Foundation
import os.log

public class EntryFieldReference {
public enum Status {
Expand Down Expand Up @@ -81,7 +82,7 @@ public class EntryFieldReference {
where T: Collection, T.Element: Entry
{
guard maxDepth > 0 else {
Diag.warning("Too many chained references")
Logger.mainLog.warning("Too many chained references")
return .tooDeepReferences
}

Expand Down Expand Up @@ -132,20 +133,20 @@ public class EntryFieldReference {
guard let targetFieldCode = string[targetFieldCodeRange].first,
let targetFieldType = FieldType.fromCode(targetFieldCode) else
{
Diag.debug("Unrecognized target field")
Logger.mainLog.debug("Unrecognized target field")
continue
}

guard let searchFieldCode = string[searchFieldCodeRange].first,
let searchFieldType = FieldType.fromCode(searchFieldCode) else
{
Diag.debug("Unrecognized search field")
Logger.mainLog.debug("Unrecognized search field")
continue
}

let searchValue = string[searchValueRange]
guard !searchValue.isEmpty else {
Diag.debug("Empty search criterion")
Logger.mainLog.debug("Empty search criterion")
continue
}
let ref = EntryFieldReference(
Expand Down Expand Up @@ -225,7 +226,7 @@ public class EntryFieldReference {
_uuid = UUID(uuidString: String(value))
}
guard let uuid = _uuid else {
Diag.debug("Malformed UUID: \(value)")
Logger.mainLog.debug("Malformed UUID: \(value)")
return nil
}
result = entries.first(where: { $0.uuid == uuid })
Expand Down Expand Up @@ -260,7 +261,7 @@ extension EntryFieldReference {
case EntryField.notes:
fieldCode = "N"
default:
Diag.warning("References to custom fields are not supported")
Logger.mainLog.warning("References to custom fields are not supported")
return nil
}
let result = "{REF:\(fieldCode)@I:\(entry.uuid.uuidString)}"
Expand Down
7 changes: 4 additions & 3 deletions ios/KdbxSwift/Sources/KdbxSwift/db/Group.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Foundation
import os.log

public class Group: DatabaseItem, Eraseable {
public static let defaultIconID = IconID.folder
Expand Down Expand Up @@ -79,7 +80,7 @@ public class Group: DatabaseItem, Eraseable {
}

public func clone(makeNewUUID: Bool) -> Group {
fatalError("Pure virtual method")
Logger.fatalError("Pure virtual method")
}

public func deepClone(makeNewUUIDs: Bool) -> Group {
Expand Down Expand Up @@ -192,11 +193,11 @@ public class Group: DatabaseItem, Eraseable {
}

public func createEntry(detached: Bool = false) -> Entry {
fatalError("Pure virtual method")
Logger.fatalError("Pure virtual method")
}

public func createGroup(detached: Bool = false) -> Group {
fatalError("Pure virtual method")
Logger.fatalError("Pure virtual method")
}

override public func touch(_ mode: DatabaseItem.TouchMode, updateParents: Bool = true) {
Expand Down
13 changes: 7 additions & 6 deletions ios/KdbxSwift/Sources/KdbxSwift/db/KeyHelper.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Foundation
import os.log

public class KeyHelper {
public static let compositeKeyLength = 32
Expand All @@ -8,32 +9,32 @@ public class KeyHelper {
passwordData: ByteArray,
keyFileData: ByteArray
) throws -> ByteArray {
fatalError("Pure virtual method")
Logger.fatalError("Pure virtual method")
}

public func getKey(fromCombinedComponents combinedComponents: ByteArray) -> ByteArray {
fatalError("Pure virtual method")
Logger.fatalError("Pure virtual method")
}

public func getPasswordData(password: String) -> ByteArray {
fatalError("Pure virtual method")
Logger.fatalError("Pure virtual method")
}

public func processKeyFile(keyFileData: ByteArray) throws -> ByteArray {
assert(!keyFileData.isEmpty, "keyFileData cannot be empty here")

let keyFileDataSize = keyFileData.count
if keyFileDataSize == keyFileKeyLength {
Diag.debug("Key file format is: binary")
Logger.mainLog.debug("Key file format is: binary")
return keyFileData
}

if let key = try processXmlKeyFile(keyFileData: keyFileData) {
Diag.debug("Key file format is: XML")
Logger.mainLog.debug("Key file format is: XML")
return key
}

Diag.debug("Key file format is: other")
Logger.mainLog.debug("Key file format is: other")
return keyFileData.sha256
}

Expand Down
Loading

0 comments on commit 875ab80

Please sign in to comment.