Skip to content

Commit

Permalink
v1.09.49
Browse files Browse the repository at this point in the history
Docs: update changelog
Release: version bump to 1.09.49
Refine(db): ignore missing Group/Times/* timestamps (MiniKeePass compatibility)
Fix(L10n): substring format for "Cannot parse database" error message
Chore(L10n): update localization
Refine: auto-size Key File Picker popover
Fix(ios13): limit FileInfo width on iOS 13
Refactor: switch FileInfo to use DismissablePopover
Refactor: replace some ad-hoc popover with PopoverAnchor
Feat(files): add long-press menu for file items
Fix(autoUnlock): fix AutoUnlock interrupted mid-way by DB lock timeout (fixes #88)
Chore(log): add more detailed logging to DB manager
Feat(dbUnlocker): after 3 presses on Cancel, show diagnostics
Fix: resolving of internal URLReferences
Chore: add debug description for URLReference
Refine(relocator): remove redundant localizable strings
Refine(db1): use DB file name as the root group name of KP1 DBs
Feat: colorful passwords
Fix(db2): re-generate missing CustomIcon UUID on load
Chore: cleanup unused code
Fix(db): generate new UUIDs when copying items
Refine(dbChooser): add long-press menu
Fix(dbCreator): add a pause between creating the DB and reading it
Feat: add support for copying items to other groups
Feat: add support for moving items to other groups
Refactor(ui): add dismiss handler to DismissableNavigationController
Refactor(db): move parent property to DatabaseItem
Refactor: rearrange generic coordinator stuff
Chore(ui): add constant for disabledText color
Refactor(db): add DatabaseItem as a common parent for groups and entries
Fix(urlRef): don't bookmark internal URLs at all (#71)
Chore: cherry-pick dismissable popover
Fix(urlRef): cache the original URL to avoid excessive resolving (related #71)
Fix(pwGen): add missing special symbols
Chore: add table cell support to PopoverAnchor
Refine(dbUnlocker): keep the entered password after unlock errors
Refine(dbUnlocker): add space above error messages
Fix(totp): add support for Steam TOTP with GAuth URI format (closes #85)
Feat(totp): add support TOTP based on SHA-256 and SHA-512 (closes #81)
Feat: add "Add Key File" button to key file pickers
Feat(db): switch to per-database settings
Fix(autoFill): fix FaceID loop on 13.1.3 (fixes #74, again)
  • Loading branch information
keepassium committed Jan 14, 2020
1 parent 1888f86 commit e02ad29
Show file tree
Hide file tree
Showing 115 changed files with 2,438 additions and 460 deletions.
27 changes: 27 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,32 @@
#CHANGELOG

## [1.09.49] - 2020-01-14

### Added

- Move/copy groups and entries to other groups (closes #48)
- Long-press menu for files, groups and entries
- Highlight digits and special symbols in stored passwords [thanks, Sean]
- Support for Steam TOTP with GAuth URI format (closes #85) [thanks, Nu11u5]
- Support for TOTP based on SHA-256 and SHA-512 (closes #81) [thanks, Walter]
- "Add Key File" button to key file pickers [thanks, Ron]

### Changed

- Use local URLs for local files, instead of resolving bookmarks (related #71, #88)
- Preserve the entered master password after DB unlock errors [thanks, Bertrand]

### Fixed

- Occassional freezing at "Loading... 0%" (fixes #88) [thanks, everyone]
- An attempt to fix random freezing when accessing local files on iOS 13 (#71)
- AutoFill FaceID loop on 13.1.3 (closes #74 again) [thanks, Quinn]
- Add missing special symbols in password generator [thanks, Justen]
- "Failed to open file" error after creating a new database [thanks, Craig]
- Loading MiniKeePass DBs with minor issues (missing custom icon UUIDs and group timestamps) [thanks, everyone]
- Overly wide popovers on iPadOS 13


## [1.08.48] - 2019-11-27

### Added
Expand Down
31 changes: 14 additions & 17 deletions KeePassium AutoFill/MainCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -211,14 +211,12 @@ class MainCoordinator: NSObject, Coordinator {

func removeDatabase(_ urlRef: URLReference) {
FileKeeper.shared.removeExternalReference(urlRef, fileType: .database)
try? Keychain.shared.removeDatabaseKey(databaseRef: urlRef)
Settings.current.forgetKeyFile(for: urlRef)
DatabaseSettingsManager.shared.removeSettings(for: urlRef)
refreshFileList()
}

func deleteDatabase(_ urlRef: URLReference) {
try? Keychain.shared.removeDatabaseKey(databaseRef: urlRef)
Settings.current.forgetKeyFile(for: urlRef)
DatabaseSettingsManager.shared.removeSettings(for: urlRef)
do {
try FileKeeper.shared.deleteFile(urlRef, fileType: .database, ignoreErrors: false)
} catch {
Expand All @@ -236,18 +234,13 @@ class MainCoordinator: NSObject, Coordinator {
}

func showDatabaseFileInfo(fileRef: URLReference) {
let databaseInfoVC = FileInfoVC.make(urlRef: fileRef, popoverSource: nil)
let databaseInfoVC = FileInfoVC.make(urlRef: fileRef, at: nil)
navigationController.pushViewController(databaseInfoVC, animated: true)
}

func showDatabaseUnlocker(database: URLReference, animated: Bool, completion: (()->Void)?) {
let storedDatabaseKey: SecureByteArray?
do {
storedDatabaseKey = try Keychain.shared.getDatabaseKey(databaseRef: database)
} catch {
storedDatabaseKey = nil
Diag.warning("Keychain error [message: \(error.localizedDescription)]")
}
let dbSettings = DatabaseSettingsManager.shared.getSettings(for: database)
let storedDatabaseKey = dbSettings?.masterKey

let vc = DatabaseUnlockerVC.instantiateFromStoryboard()
vc.delegate = self
Expand Down Expand Up @@ -446,12 +439,12 @@ extension MainCoordinator: DatabaseManagerObserver {
func databaseManager(database urlRef: URLReference, isCancelled: Bool) {
guard let databaseUnlockerVC = navigationController.topViewController
as? DatabaseUnlockerVC else { return }
do {
try Keychain.shared.removeDatabaseKey(databaseRef: urlRef)
} catch {
Diag.warning("Failed to remove database key [message: \(error.localizedDescription)]")

DatabaseSettingsManager.shared.updateSettings(for: urlRef) { (dbSettings) in
dbSettings.clearMasterKey()
}
Settings.current.isAutoFillFinishedOK = true
databaseUnlockerVC.clearPasswordField()
databaseUnlockerVC.hideProgressOverlay()
}

Expand Down Expand Up @@ -491,6 +484,10 @@ extension MainCoordinator: DatabaseManagerObserver {
}
guard let database = DatabaseManager.shared.database else { fatalError() }

guard let databaseUnlockerVC = navigationController.topViewController
as? DatabaseUnlockerVC else { return }
databaseUnlockerVC.clearPasswordField()

Settings.current.isAutoFillFinishedOK = true
showDatabaseContent(database: database, databaseRef: urlRef)
}
Expand Down Expand Up @@ -757,7 +754,7 @@ extension MainCoordinator: PasscodeInputDelegate {
HapticFeedback.play(.wrongPassword)
sender.animateWrongPassccode()
if Settings.current.isLockAllDatabasesOnFailedPasscode {
try? Keychain.shared.removeAllDatabaseKeys()
DatabaseSettingsManager.shared.eraseAllMasterKeys()
DatabaseManager.shared.closeDatabase(
clearStoredKey: true,
ignoreErrors: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@
<constraint firstItem="66o-BC-gwg" firstAttribute="top" secondItem="YUw-D5-oyJ" secondAttribute="bottom" constant="16" id="YPN-Bb-ccx"/>
<constraint firstItem="i0B-8N-nM0" firstAttribute="centerY" secondItem="66o-BC-gwg" secondAttribute="centerY" id="dSY-ts-aEq"/>
<constraint firstItem="QNs-Fg-BB8" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="fAZ-VX-s1Y" secondAttribute="leadingMargin" id="fe7-Qr-Ynk"/>
<constraint firstItem="YUw-D5-oyJ" firstAttribute="top" relation="greaterThanOrEqual" secondItem="QNs-Fg-BB8" secondAttribute="bottom" id="ftC-HR-biD"/>
<constraint firstItem="YUw-D5-oyJ" firstAttribute="top" relation="greaterThanOrEqual" secondItem="QNs-Fg-BB8" secondAttribute="bottom" constant="4" id="ftC-HR-biD"/>
<constraint firstAttribute="trailingMargin" relation="greaterThanOrEqual" secondItem="YUw-D5-oyJ" secondAttribute="trailing" id="gVV-A4-UAE"/>
<constraint firstItem="Q5g-RY-uXD" firstAttribute="centerY" secondItem="fAZ-VX-s1Y" secondAttribute="centerY" priority="250" id="gaS-ck-Wc3"/>
<constraint firstItem="i0B-8N-nM0" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="fAZ-VX-s1Y" secondAttribute="leading" constant="8" id="m4A-7S-ULI"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15400" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="dhm-DL-W1Z">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="dhm-DL-W1Z">
<device id="retina4_7" orientation="portrait" appearance="dark"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15404"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
Expand All @@ -16,6 +16,17 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<button key="tableFooterView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="Omh-Sn-jl2">
<rect key="frame" x="0.0" y="171" width="375" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleCallout"/>
<state key="normal" title="Add Key File">
<color key="titleColor" name="ActionTint"/>
</state>
<connections>
<action selector="didPressAddKeyFile:" destination="dhm-DL-W1Z" eventType="touchUpInside" id="KN1-DM-j3H"/>
</connections>
</button>
<prototypes>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="NoKeyFileCell" textLabel="9UZ-FK-v73" detailTextLabel="leO-vH-qBX" imageView="mtg-wq-fAX" style="IBUITableViewCellStyleSubtitle" id="maz-Ac-JmV">
<rect key="frame" x="0.0" y="28" width="375" height="57.5"/>
Expand Down Expand Up @@ -98,10 +109,13 @@
<navigationItem key="navigationItem" title="Key Files" id="r85-yz-wYI">
<barButtonItem key="rightBarButtonItem" title="Add Key File" image="create-item-toolbar" id="Lod-RE-tcd">
<connections>
<action selector="didPressAddKeyFile:" destination="dhm-DL-W1Z" id="ZQ9-pG-FEG"/>
<action selector="didPressAddKeyFile:" destination="dhm-DL-W1Z" id="p63-Ik-Vdx"/>
</connections>
</barButtonItem>
</navigationItem>
<connections>
<outlet property="addKeyFileBarButton" destination="Lod-RE-tcd" id="7vF-My-nJP"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Vox-O3-18P" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
Expand All @@ -112,14 +126,17 @@
<image name="create-item-toolbar" width="25" height="25"/>
<image name="keyfile-listitem" width="29" height="29"/>
<image name="no-keyfile-listitem" width="29" height="29"/>
<namedColor name="ActionTint">
<color red="0.0" green="0.4779999852180481" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="AuxiliaryText">
<color red="0.23499999940395355" green="0.23499999940395355" blue="0.2630000114440918" alpha="0.60000002384185791" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="IconTint">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color red="0.0" green="0.41176470588235292" blue="0.85098039215686272" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</namedColor>
<namedColor name="PrimaryText">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</namedColor>
</resources>
</document>
34 changes: 31 additions & 3 deletions KeePassium AutoFill/controllers/DatabaseChooserVC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,12 @@ class DatabaseChooserVC: UITableViewController, Refreshable {
}

@objc func didLongPressTableView(_ gestureRecognizer: UILongPressGestureRecognizer) {
Watchdog.shared.restart()
let point = gestureRecognizer.location(in: tableView)
guard gestureRecognizer.state == .began,
let indexPath = tableView.indexPathForRow(at: point),
tableView(tableView, canEditRowAt: indexPath),
let cell = tableView.cellForRow(at: indexPath) else { return }
cell.demoShowEditActions(lastActionColor: UIColor.destructiveTint)
tableView(tableView, canEditRowAt: indexPath) else { return }
showActions(for: indexPath)
}


Expand Down Expand Up @@ -164,4 +164,32 @@ class DatabaseChooserVC: UITableViewController, Refreshable {

return [deleteAction]
}

private func showActions(for indexPath: IndexPath) {
let urlRef = databaseRefs[indexPath.row]
let isInternalFile = urlRef.location.isInternal
let deleteAction = UIAlertAction(
title: isInternalFile ? LString.actionDeleteFile : LString.actionRemoveFile,
style: .destructive,
handler: { [weak self] _ in
guard let self = self else { return }
if isInternalFile {
self.delegate?.databaseChooser(self, shouldDeleteDatabase: urlRef)
} else {
self.delegate?.databaseChooser(self, shouldRemoveDatabase: urlRef)
}
}
)
let cancelAction = UIAlertAction(title: LString.actionCancel, style: .cancel, handler: nil)

let menu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
menu.addAction(deleteAction)
menu.addAction(cancelAction)

let pa = PopoverAnchor(tableView: tableView, at: indexPath)
if let popover = menu.popoverPresentationController {
pa.apply(to: popover)
}
present(menu, animated: true)
}
}
14 changes: 9 additions & 5 deletions KeePassium AutoFill/controllers/DatabaseUnlockerVC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ class DatabaseUnlockerVC: UIViewController, Refreshable {
}
}

public func clearPasswordField() {
passwordField.text = ""
}

func showErrorMessage(
_ text: String,
reason: String?=nil,
Expand Down Expand Up @@ -147,9 +151,8 @@ class DatabaseUnlockerVC: UIViewController, Refreshable {
databaseLocationIconImage.image = UIImage.databaseIcon(for: dbRef)
}

let associatedKeyFileRef = Settings.current
.premiumGetKeyFileForDatabase(databaseRef: dbRef)
if let associatedKeyFileRef = associatedKeyFileRef {
let dbSettings = DatabaseSettingsManager.shared.getSettings(for: dbRef)
if let associatedKeyFileRef = dbSettings?.associatedKeyFile {
let allAvailableKeyFiles = FileKeeper.shared
.getAllReferences(fileType: .keyFile, includeBackup: false)
if let availableKeyFileRef = associatedKeyFileRef
Expand All @@ -166,7 +169,9 @@ class DatabaseUnlockerVC: UIViewController, Refreshable {
hideErrorMessage(animated: false)

guard let databaseRef = databaseRef else { return }
Settings.current.setKeyFileForDatabase(databaseRef: databaseRef, keyFileRef: keyFileRef)
DatabaseSettingsManager.shared.updateSettings(for: databaseRef) { (dbSettings) in
dbSettings.maybeSetAssociatedKeyFile(keyFileRef)
}

guard let fileInfo = urlRef?.info else {
Diag.debug("No key file selected")
Expand Down Expand Up @@ -244,7 +249,6 @@ class DatabaseUnlockerVC: UIViewController, Refreshable {
database: databaseRef,
password: passwordField.text ?? "",
keyFile: keyFileRef)
passwordField.text = ""
}

@IBAction func didPressAnouncementButton(_ sender: Any) {
Expand Down
33 changes: 28 additions & 5 deletions KeePassium AutoFill/controllers/KeyFileChooserVC.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ class KeyFileChooserVC: UITableViewController, Refreshable {
static let keyFile = "KeyFileCell"
}

@IBOutlet weak var addKeyFileBarButton: UIBarButtonItem!

weak var delegate: KeyFileChooserDelegate?

var keyFileRefs = [URLReference]()
Expand Down Expand Up @@ -130,8 +132,8 @@ class KeyFileChooserVC: UITableViewController, Refreshable {
delegate?.didSelectFile(in: self, urlRef: keyFileRefs[selectedFileIndex])
}

@IBAction func didPressAddKeyFile(_ sender: UIBarButtonItem) {
let popoverAnchor = PopoverAnchor(barButtonItem: sender)
@IBAction func didPressAddKeyFile(_ sender: Any) {
let popoverAnchor = PopoverAnchor(barButtonItem: addKeyFileBarButton)
delegate?.didPressAddKeyFile(in: self, popoverAnchor: popoverAnchor)
}

Expand All @@ -146,8 +148,29 @@ class KeyFileChooserVC: UITableViewController, Refreshable {
let point = gestureRecognizer.location(in: tableView)
guard gestureRecognizer.state == .began,
let indexPath = tableView.indexPathForRow(at: point),
tableView(tableView, canEditRowAt: indexPath),
let cell = tableView.cellForRow(at: indexPath) else { return }
cell.demoShowEditActions(lastActionColor: UIColor.destructiveTint)
tableView(tableView, canEditRowAt: indexPath) else { return }
showActions(for: indexPath)
}

private func showActions(for indexPath: IndexPath) {
let removeAction = UIAlertAction(
title: LString.actionRemoveFile,
style: .destructive,
handler: { [weak self] _ in
guard let self = self else { return }
self.didPressRemoveKeyFile(at: indexPath)
}
)
let cancelAction = UIAlertAction(title: LString.actionCancel, style: .cancel, handler: nil)

let menu = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
menu.addAction(removeAction)
menu.addAction(cancelAction)

let pa = PopoverAnchor(tableView: tableView, at: indexPath)
if let popover = menu.popoverPresentationController {
pa.apply(to: popover)
}
present(menu, animated: true)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
/* Class = "UIBarButtonItem"; title = "Add Key File"; ObjectID = "Lod-RE-tcd"; */
"Lod-RE-tcd.title" = "Přidat soubor s klíčem";

/* Class = "UIButton"; normalTitle = "Add Key File"; ObjectID = "Omh-Sn-jl2"; */
"Omh-Sn-jl2.normalTitle" = "Přidat soubor s klíčem";

/* Class = "UINavigationItem"; title = "Key Files"; ObjectID = "r85-yz-wYI"; */
"r85-yz-wYI.title" = "Soubory s klíčem";

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"ebS-pB-Qan.title" = "Schließen";

/* Class = "UILabel"; text = "It seems that AutoFill did not close correctly the last time. \n\nThis can happen with large databases or memory-demanding database settings (Argon2).\n\nPlease contact us if you need help with this."; ObjectID = "kmV-si-Nrg"; */
"kmV-si-Nrg.text" = "Es scheint, dass AutoFill das letzte Mal nicht korrekt geschlossen hat. \n\nDies kann mit großen Datenbanken oder speicherintensiven Datenbankeinstellungen (Argon2) passieren.\n\nBitte kontaktieren Sie uns, wenn Sie Hilfe benötigen.";
"kmV-si-Nrg.text" = "Es scheint, dass sich AutoFill das letzte Mal nicht korrekt geschlossen hat. \n\nDies kann mit großen Datenbanken oder speicherintensiven Datenbankeinstellungen (Argon2) passieren.\n\nBitte kontaktieren Sie uns, wenn Sie Hilfe benötigen.";

/* Class = "UINavigationItem"; title = "We are sorry"; ObjectID = "zvf-PV-5l4"; */
"zvf-PV-5l4.title" = "Es tut uns leid";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"dPB-bK-tzh.title" = "Datenbank sperren";

/* Class = "UILabel"; text = "Nothing suitable found."; ObjectID = "NSB-dG-jRN"; Note = "Placeholder text for empty search results."; */
"NSB-dG-jRN.text" = "Nichts gefunden.";
"NSB-dG-jRN.text" = "Nichts passendes gefunden.";

/* Class = "UILabel"; text = "Related Entries"; ObjectID = "yLY-eZ-iAh"; Note = "Title of a list of entries similar to (but not exactly matching) the search query."; */
"yLY-eZ-iAh.text" = "Ähnliche Einträge";
Expand Down
Loading

0 comments on commit e02ad29

Please sign in to comment.