From e700195f0ac23e0225848ea31ac351bd97462338 Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Sun, 27 Aug 2023 21:54:53 -0400 Subject: [PATCH] Add 1Password 1PUX and Bitwarden JSON Importers * Closes #7545 - Support 1Password 1PUX import format based on https://support.1password.com/1pux-format/ * Closes #8367 - Support Bitwarden JSON import format (both unencrypted and encrypted) based on https://bitwarden.com/help/encrypted-export/ * Fixes #9577 - OPVault import when fields have the same name or type * Introduce the import wizard to handle all import tasks (CSV, KDBX1, OPVault, 1PUX, JSON) * Clean up CSV parser code to make it much more efficient and easier to read * Combine all importer tests (except CSV) into one test file --- CMakeLists.txt | 3 + COPYING | 3 + docs/images/csv_import.png | Bin 68581 -> 102561 bytes docs/images/import_wizard.png | Bin 0 -> 118208 bytes docs/topics/ImportExport.adoc | 65 +- .../scalable/actions/bitwarden.svg | 1 + .../application/scalable/actions/csv.svg | 1 + .../scalable/actions/onepassword.svg | 1 + share/icons/icons.qrc | 3 + share/translations/keepassxc_en.ts | 355 +++-- src/CMakeLists.txt | 9 +- src/autotype/AutoType.cpp | 1 + src/format/BitwardenReader.cpp | 313 ++++ .../format/BitwardenReader.h | 40 +- src/format/CsvParser.cpp | 110 +- src/format/CsvParser.h | 8 +- src/format/KeePass1Reader.cpp | 5 + src/format/OPUXReader.cpp | 288 ++++ .../OPUXReader.h} | 31 +- src/format/OpVaultReader.cpp | 89 +- src/format/OpVaultReader.h | 10 +- src/format/OpVaultReaderAttachments.cpp | 4 + src/format/OpVaultReaderSections.cpp | 8 +- src/gui/CloneDialog.h | 2 + src/gui/DatabaseTabWidget.cpp | 129 +- src/gui/DatabaseTabWidget.h | 4 +- src/gui/DatabaseWidget.cpp | 88 +- src/gui/DatabaseWidget.h | 28 +- src/gui/EntryPreviewWidget.cpp | 2 +- src/gui/EntryPreviewWidget.h | 1 + src/gui/Icons.cpp | 2 + src/gui/KeePass1OpenWidget.cpp | 63 - src/gui/MainWindow.cpp | 31 +- src/gui/MainWindow.h | 4 +- src/gui/MainWindow.ui | 23 +- src/gui/OpVaultOpenWidget.cpp | 50 - src/gui/PasswordWidget.h | 1 + src/gui/TotpDialog.h | 2 + src/gui/TotpExportSettingsDialog.cpp | 1 + src/gui/TotpExportSettingsDialog.h | 2 + src/gui/TotpSetupDialog.h | 2 + src/gui/WelcomeWidget.cpp | 7 +- src/gui/WelcomeWidget.h | 4 +- src/gui/WelcomeWidget.ui | 52 +- src/gui/csvImport/CsvImportWidget.cpp | 286 ++-- src/gui/csvImport/CsvImportWidget.h | 43 +- src/gui/csvImport/CsvImportWidget.ui | 1382 ++++++++--------- src/gui/csvImport/CsvImportWizard.cpp | 43 - src/gui/csvImport/CsvImportWizard.h | 51 - src/gui/csvImport/CsvParserModel.cpp | 60 +- src/gui/csvImport/CsvParserModel.h | 10 +- src/gui/tag/TagsEdit.cpp | 1 + src/gui/wizard/ImportWizard.cpp | 84 + src/gui/wizard/ImportWizard.h | 60 + src/gui/wizard/ImportWizardPageReview.cpp | 202 +++ src/gui/wizard/ImportWizardPageReview.h | 60 + src/gui/wizard/ImportWizardPageReview.ui | 95 ++ src/gui/wizard/ImportWizardPageSelect.cpp | 236 +++ src/gui/wizard/ImportWizardPageSelect.h | 56 + src/gui/wizard/ImportWizardPageSelect.ui | 276 ++++ src/keeshare/CMakeLists.txt | 2 - tests/CMakeLists.txt | 2 +- tests/TestImports.cpp | 267 ++++ .../TestImports.h | 23 +- tests/TestOpVaultReader.cpp | 139 -- tests/data/1PasswordExport.1pux | Bin 0 -> 31621 bytes tests/data/bitwarden_encrypted_export.json | 11 + tests/data/bitwarden_export.json | 180 +++ tests/gui/TestGui.cpp | 22 - tests/gui/TestGui.h | 1 - 70 files changed, 3562 insertions(+), 1876 deletions(-) create mode 100644 docs/images/import_wizard.png create mode 100644 share/icons/application/scalable/actions/bitwarden.svg create mode 100644 share/icons/application/scalable/actions/csv.svg create mode 100644 share/icons/application/scalable/actions/onepassword.svg create mode 100644 src/format/BitwardenReader.cpp rename tests/TestOpVaultReader.h => src/format/BitwardenReader.h (51%) create mode 100644 src/format/OPUXReader.cpp rename src/{gui/OpVaultOpenWidget.h => format/OPUXReader.h} (58%) delete mode 100644 src/gui/KeePass1OpenWidget.cpp delete mode 100644 src/gui/OpVaultOpenWidget.cpp delete mode 100644 src/gui/csvImport/CsvImportWizard.cpp delete mode 100644 src/gui/csvImport/CsvImportWizard.h create mode 100644 src/gui/wizard/ImportWizard.cpp create mode 100644 src/gui/wizard/ImportWizard.h create mode 100644 src/gui/wizard/ImportWizardPageReview.cpp create mode 100644 src/gui/wizard/ImportWizardPageReview.h create mode 100644 src/gui/wizard/ImportWizardPageReview.ui create mode 100644 src/gui/wizard/ImportWizardPageSelect.cpp create mode 100644 src/gui/wizard/ImportWizardPageSelect.h create mode 100644 src/gui/wizard/ImportWizardPageSelect.ui create mode 100644 tests/TestImports.cpp rename src/gui/KeePass1OpenWidget.h => tests/TestImports.h (64%) delete mode 100644 tests/TestOpVaultReader.cpp create mode 100644 tests/data/1PasswordExport.1pux create mode 100644 tests/data/bitwarden_encrypted_export.json create mode 100644 tests/data/bitwarden_export.json diff --git a/CMakeLists.txt b/CMakeLists.txt index c8b4da2be..2ef1863c3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -567,6 +567,9 @@ if(ZLIB_VERSION_STRING VERSION_LESS "1.2.0") endif() include_directories(SYSTEM ${ZLIB_INCLUDE_DIR}) +# Find Minizip +find_package(Minizip REQUIRED) + if(WITH_XC_YUBIKEY) find_package(PCSC REQUIRED) include_directories(SYSTEM ${PCSC_INCLUDE_DIRS}) diff --git a/COPYING b/COPYING index 480b01f07..6baf4c27e 100644 --- a/COPYING +++ b/COPYING @@ -143,11 +143,13 @@ License: MIT Files: share/icons/application/scalable/actions/application-exit.svg share/icons/application/scalable/actions/attributes-copy.svg share/icons/application/scalable/actions/auto-type.svg + share/icons/application/scalable/actions/bitwarden.svg share/icons/application/scalable/actions/bugreport.svg share/icons/application/scalable/actions/chevron-double-down.svg share/icons/application/scalable/actions/chevron-double-right.svg share/icons/application/scalable/actions/clipboard-text.svg share/icons/application/scalable/actions/configure.svg + share/icons/application/scalable/actions/csv.svg share/icons/application/scalable/actions/database-change-key.svg share/icons/application/scalable/actions/database-lock.svg share/icons/application/scalable/actions/database-lock-all.svg @@ -192,6 +194,7 @@ Files: share/icons/application/scalable/actions/application-exit.svg share/icons/application/scalable/actions/move-up.svg share/icons/application/scalable/actions/object-locked.svg share/icons/application/scalable/actions/object-unlocked.svg + share/icons/application/scalable/actions/onepassword.svg share/icons/application/scalable/actions/paperclip.svg share/icons/application/scalable/actions/password-copy.svg share/icons/application/scalable/actions/passkey.svg diff --git a/docs/images/csv_import.png b/docs/images/csv_import.png index 8fce05e57f1157474f2e95c1df868217c9297284..cddd2c4e04389c7a0adc0531ef0f30d21739c56e 100644 GIT binary patch literal 102561 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%0AT+G?{|~k^a%3wGhTIH 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

dDU55DxrzGOKxwND5M8CSol`E?}A! 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 drDoiOaLJa@oAREv2jF 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 N7u3&ZoW1qv{{zNvv~~ah literal 68581 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%0DW_ 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 diff --git a/docs/images/import_wizard.png b/docs/images/import_wizard.png new file mode 100644 index 0000000000000000000000000000000000000000..bba4cdd94d4c696553f65172a7981d9fe2289f47 GIT binary patch literal 118208 zcmbTdWmuKn6Fy3VAYDo;Aq`4Nvq39vx2}f;^?SEs4y@v=n@}4$icuM>cGIj&!E5oEm+=o=rFK@ zff64;3eL0p56CKbGYv-(X=}r+8-nc) zg~d{Mj`9tap2nBk=XE3kf�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 Import... to launch the Import Wizard. + +.Import Wizard +image::import_wizard.png[] + +For each of the import options, you will be prompted to select the file to import and then provide credentials to unlock the file, if necessary. You can then choose to import the file into a new database or into an existing database that is already unlocked in KeePassXC. === Importing CSV File -If you have been saving your URLs, usernames, passwords, and so on in a CSV file, you can migrate all that information from the CSV file to KeePassXC and start using KeePassXC to maintain your data. +WARNING: A CSV file is unencrypted and you should securely delete this file after successfully importing it into KeePassXC. -To open the CSV file, perform the following steps: +1. Follow the steps above and click `Continue`. The CSV import wizard will appear. -1. Open KeePassXC. - -2. Click Import from CSV button on the welcome screen or use the menu Database > Import > CSV File. - -3. Navigate to the location of your CSV file on your computer and open the file. The new database wizard will appear. Follow the steps of creating a new database in Chapter 1. - -4. After saving your new database file, the CSV import wizard will appear. On this dialog you can choose the various options for properly importing the data. You may need to select the _First line has field names_ checkbox before starting. Analyze the output in the preview at the bottom to determine the correct import settings. +2. On this dialog you can choose the various options for properly importing the data. Analyze the output in the preview at the bottom to determine the correct import settings. You may need to re-map the column associations to match the data in your CSV file. + .CSV Import Wizard image::csv_import.png[] -Your CSV file gets imported to KeePassXC and the data is converted to the KeePassXC format for further usage and maintenance. The new database file is saved on to your computer with the default `.kdbx` extension. +3. Click `Done` to complete the import. If you chose to create a new database, the New Database dialog will appear. Otherwise your entries will be nested under the group you chose for the existing database. + +=== Importing 1Password Export +WARNING: A 1Password Export file is unencrypted and you should securely delete this file after successfully importing it into KeePassXC. + +1. Open the Import Wizard as shown above. Select the 1Password Export option. + +2. Click `Continue` to unlock and preview the import. Click `Done` to complete the import. === Importing 1Password OPVault +NOTE: You must have 1Password version 7 or 8 to export your data to an OPVault. If you are using a newer version of 1Password, you should use the 1Password Export (1PUX) format instead. + Save your 1Password Vault locally to create an OPVault directory. Please see 1Password instructions on how to do this. Once an OPVault is created, perform the following steps: -1. Open KeePassXC. +1. Open the Import Wizard as shown above. Select the 1Password Vault option. -2. Use the menu Database > Import > 1Password Vault. Select the OPVault to import. +2. Enter the password for your vault and click `Continue` to unlock and preview the import. Click `Done` to complete the import. -3. Enter the password for your OPVault to unlock and import. +=== Importing Bitwarden +WARNING: A Bitwarden Export file may be unencrypted and you should securely delete this file after successfully importing it into KeePassXC. + +1. Open the Import Wizard as shown above. Select the Bitwarden option. + +2. Optionally provide a password to decrypt the Bitwarden export file. You should only need to do this if you have chosen the encrypted json export option within Bitwarden. + +3. Click `Continue` to unlock and preview the import. Click `Done` to complete the import. === Importing KeePass 1 Database -KeePass 1 database is an older format of the database created using legacy version of KeePass. KeePassXC lets your import this older format of the database and you can seamlessly start using this database in your new KeePassXC application. +KeePass 1 database is an older format of the database created using a legacy version of KeePass. KeePassXC lets your import this older format of the database and you can seamlessly start using this database in your new KeePassXC application. To import a KeePass 1 database file in KeePassXC, perform the following steps: -1. Open KeePassXC. +1. Open the Import Wizard as shown above. Select the KeePass1 Database option. -2. Click Import from KeePass 1 button on the welcome screen or use the menu Database > Import > KeePass 1 Database. +2. Enter the password for your database and optionally provide a key file if it was configured for your KeePass1 database. -3. Navigate to the location of your legacy KeePass 1 database file (`.kdb`) on your computer and open the file. You are prompted for the password and the Key file for your `.kdb` file. - -4. Enter the password for your old `.kdb` file and click *OK*. You are prompted to provide a name for the new database format that KeePassXC recognizes. - -5. Provide a name for the new database format, select a folder on your computer to save the file, and click Save. - -6. The data from the `.kdb` file gets imported and converted to the new format, which is compatible with KeePassXC. You can now start using the new database file (`.kdbx`) in KeePassXC. +3. Click `Continue` to unlock and preview the import. Click `Done` to complete the import. == Exporting Databases KeePassXC supports multiple ways to export your database for transfer to another program or to print out and archive. diff --git a/share/icons/application/scalable/actions/bitwarden.svg b/share/icons/application/scalable/actions/bitwarden.svg new file mode 100644 index 000000000..9d22e9adc --- /dev/null +++ b/share/icons/application/scalable/actions/bitwarden.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/share/icons/application/scalable/actions/csv.svg b/share/icons/application/scalable/actions/csv.svg new file mode 100644 index 000000000..e76afb0a8 --- /dev/null +++ b/share/icons/application/scalable/actions/csv.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/share/icons/application/scalable/actions/onepassword.svg b/share/icons/application/scalable/actions/onepassword.svg new file mode 100644 index 000000000..b43237abc --- /dev/null +++ b/share/icons/application/scalable/actions/onepassword.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/share/icons/icons.qrc b/share/icons/icons.qrc index 78980d971..a846bf7bc 100644 --- a/share/icons/icons.qrc +++ b/share/icons/icons.qrc @@ -8,11 +8,13 @@ application/scalable/actions/application-exit.svg application/scalable/actions/attributes-copy.svg application/scalable/actions/auto-type.svg + application/scalable/actions/bitwarden.svg application/scalable/actions/bugreport.svg application/scalable/actions/chevron-double-down.svg application/scalable/actions/chevron-double-right.svg application/scalable/actions/clipboard-text.svg application/scalable/actions/configure.svg + application/scalable/actions/csv.svg application/scalable/actions/database-change-key.svg application/scalable/actions/database-lock.svg application/scalable/actions/database-lock-all.svg @@ -58,6 +60,7 @@ application/scalable/actions/move-up.svg application/scalable/actions/object-locked.svg application/scalable/actions/object-unlocked.svg + application/scalable/actions/onepassword.svg application/scalable/actions/paperclip.svg application/scalable/actions/passkey.svg application/scalable/actions/password-copy.svg diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts index 1158a877c..9bbb8f013 100644 --- a/share/translations/keepassxc_en.ts +++ b/share/translations/keepassxc_en.ts @@ -1256,14 +1256,6 @@ Do you want to overwrite the Passkey in %1 - %2? CsvImportWidget - - Import CSV fields - - - - filename - - size, rows, columns @@ -1372,18 +1364,6 @@ Do you want to overwrite the Passkey in %1 - %2? Column %1 - - Imported from CSV file - - - - Original data: - - - - Error(s) detected in CSV file! - - [%n more message(s) skipped] @@ -1392,31 +1372,19 @@ Do you want to overwrite the Passkey in %1 - %2? - Error + Failed to parse CSV file: %1 - CSV import: writer has errors: -%1 + Imported from CSV file: %1 CsvParserModel - - %1, %2, %3 - file info: bytes, rows, columns - - - - %n byte(s) - - - - - %n row(s) + CSV row count @@ -1424,6 +1392,7 @@ Do you want to overwrite the Passkey in %1 - %2? %n column(s) + CSV column count @@ -1800,6 +1769,10 @@ Permissions to access entries will be revoked. This is only necessary if your database is a copy of another and the browser extension cannot connect. + + Convert legacy KeePassHTTP attributes to KeePassXC-Browser compatible custom data + + No keys found @@ -2287,26 +2260,10 @@ This is definitely a bug, please report it to the developers. CSV file - - Select CSV file - - Merge database - - KeePass 1 database - - - - Open KeePass 1 database - - - - Open OPVault - - Export database to CSV file @@ -2339,15 +2296,6 @@ This is definitely a bug, please report it to the developers. You are about to export your database to an unencrypted file. This will leave your passwords and sensitive information vulnerable! Are you sure you want to continue? - - New Database - - - - %1 [New Database] - Database tab name modifier - - %1 [Locked] Database tab name modifier @@ -2536,6 +2484,15 @@ Disable safe saves and try again? Could not find database file: %1 + + New Database + + + + %1 [New Database] + Database tab name modifier + + EditEntryWidget @@ -4299,6 +4256,147 @@ You can enable the DuckDuckGo website icon service in the security section of th + + ImportWizard + + Import Wizard + + + + + ImportWizardPageReview + + WizardPage + + + + Entry count: %1 + + + + Group + + + + Title + + + + Username + + + + Password + + + + Url + + + + + ImportWizardPageSelect + + Form + + + + Import File Selection + + + + Password: + + + + Key File: + + + + Browse… + + + + Import Into: + + + + New Database + + + + No unlocked databases available + + + + Existing Database: + + + + Import File: + + + + Comma Separated Values (.csv) + + + + 1Password Export (.1pux) + + + + 1Password Vault (.opvault) + + + + Bitwarden (.json) + + + + KeePass 1 Database (.kdb) + + + + Open OPVault + + + + Select import file + + + + All files + + + + Key files + + + + Select key file + + + + Comma Separated Values + + + + 1Password Export + + + + Bitwarden JSON Export + + + + 1Password Vault + + + + KeePass1 Database + + + KMessageWidget @@ -4726,17 +4824,6 @@ Line %2, column %3 - - KeePass1OpenWidget - - Import KeePass1 Database - - - - Unable to open the database. - - - KeePass1Reader @@ -5090,10 +5177,6 @@ Are you sure you want to continue with this file? &Recent Databases - - &Import - - &Export @@ -5500,6 +5583,18 @@ We recommend you use the AppImage available on our downloads page. Allow Screen Capture + + 1Password 1PUX... + + + + Import a 1Password 1PUX file + + + + Import… + + Passkeys… @@ -5948,14 +6043,6 @@ We recommend you use the AppImage available on our downloads page. - - OpVaultOpenWidget - - Read Database did not produce an instance -%1 - - - OpVaultReader @@ -8485,6 +8572,76 @@ Kernel: %3 %4 Failed to decrypt key data. + + Favorite + Tag for favorite entries + + + + File does not exist. + + + + Cannot open file: %1 + + + + Cannot parse file: %1 at position %2 + + + + Failed to decrypt json file: %1 + + + + Invalid encKeyValidation field + + + + Invalid cipher list within encKeyValidation field + + + + Wrong password + + + + Invalid encrypted data field + + + + Invalid cipher list within encrypted data field + + + + Cannot initialize cipher + + + + Cannot decrypt data + + + + Bitwarden Import + + + + Archived + Tag for archived entries + + + + Invalid 1PUX file format: Not a valid ZIP file. + + + + Invalid 1PUX file format: Missing export.data + + + + 1Password Import + + Origin is empty or not allowed @@ -9577,26 +9734,6 @@ Example: JBSWY3DPEHPK3PXP Start storing your passwords securely in a KeePassXC database - - Create new database - - - - Open existing database - - - - Import from KeePass 1 - - - - Import from 1Password - - - - Import from CSV - - Recent databases @@ -9609,6 +9746,18 @@ Example: JBSWY3DPEHPK3PXP Welcome to KeePassXC %1 + + Create Database + + + + Open Database + + + + Import File + + WinUtils diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8f1d6b055..a95e58f94 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -71,6 +71,7 @@ set(keepassx_SOURCES crypto/kdf/Kdf.cpp crypto/kdf/AesKdf.cpp crypto/kdf/Argon2Kdf.cpp + format/BitwardenReader.cpp format/CsvExporter.cpp format/CsvParser.cpp format/KeePass1Reader.cpp @@ -87,6 +88,7 @@ set(keepassx_SOURCES format/Kdbx4Writer.cpp format/KdbxXmlWriter.cpp format/OpData01.cpp + format/OPUXReader.cpp format/OpVaultReader.cpp format/OpVaultReaderAttachments.cpp format/OpVaultReaderBandEntry.cpp @@ -118,12 +120,10 @@ set(keepassx_SOURCES gui/GuiTools.cpp gui/HtmlExporter.cpp gui/IconModels.cpp - gui/KeePass1OpenWidget.cpp gui/KMessageWidget.cpp gui/MainWindow.cpp gui/MessageBox.cpp gui/MessageWidget.cpp - gui/OpVaultOpenWidget.cpp gui/PasswordWidget.cpp gui/PasswordGeneratorWidget.cpp gui/ApplicationSettingsWidget.cpp @@ -139,7 +139,6 @@ set(keepassx_SOURCES gui/URLEdit.cpp gui/WelcomeWidget.cpp gui/csvImport/CsvImportWidget.cpp - gui/csvImport/CsvImportWizard.cpp gui/csvImport/CsvParserModel.cpp gui/entry/AutoTypeAssociationsModel.cpp gui/entry/EditEntryWidget.cpp @@ -183,6 +182,9 @@ set(keepassx_SOURCES gui/widgets/KPToolBar.cpp gui/widgets/PopupHelpWidget.cpp gui/widgets/ShortcutWidget.cpp + gui/wizard/ImportWizard.cpp + gui/wizard/ImportWizardPageReview.cpp + gui/wizard/ImportWizardPageSelect.cpp gui/wizard/NewDatabaseWizard.cpp gui/wizard/NewDatabaseWizardPage.cpp gui/wizard/NewDatabaseWizardPageMetaData.cpp @@ -390,6 +392,7 @@ target_link_libraries(keepassx_core ${PCSC_LIBRARIES} ${ZXCVBN_LIBRARIES} ${ZLIB_LIBRARIES} + ${MINIZIP_LIBRARIES} ${ARGON2_LIBRARIES} ${KEYUTILS_LIBRARIES} ${thirdparty_LIBRARIES} diff --git a/src/autotype/AutoType.cpp b/src/autotype/AutoType.cpp index c39a13201..e69845a72 100644 --- a/src/autotype/AutoType.cpp +++ b/src/autotype/AutoType.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "config-keepassx.h" diff --git a/src/format/BitwardenReader.cpp b/src/format/BitwardenReader.cpp new file mode 100644 index 000000000..8f7a926fa --- /dev/null +++ b/src/format/BitwardenReader.cpp @@ -0,0 +1,313 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "BitwardenReader.h" + +#include "core/Database.h" +#include "core/Entry.h" +#include "core/Group.h" +#include "core/Metadata.h" +#include "core/Tools.h" +#include "core/Totp.h" +#include "crypto/CryptoHash.h" +#include "crypto/SymmetricCipher.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + Entry* readItem(const QJsonObject& item, QString& folderId) + { + // Create the item map and extract the folder id + const auto itemMap = item.toVariantMap(); + folderId = itemMap.value("folderId").toString(); + + // Create entry and assign basic values + QScopedPointer entry(new Entry()); + entry->setUuid(QUuid::createUuid()); + entry->setTitle(itemMap.value("name").toString()); + entry->setNotes(itemMap.value("notes").toString()); + + if (itemMap.value("favorite").toBool()) { + entry->addTag(QObject::tr("Favorite", "Tag for favorite entries")); + } + + // Parse login details if present + if (itemMap.contains("login")) { + const auto loginMap = itemMap.value("login").toMap(); + entry->setUsername(loginMap.value("username").toString()); + entry->setPassword(loginMap.value("password").toString()); + if (loginMap.contains("totp")) { + // Bitwarden stores TOTP as otpauth string + entry->setTotp(Totp::parseSettings(loginMap.value("totp").toString())); + } + + // Set the entry url(s) + int i = 1; + for (const auto& urlObj : loginMap.value("uris").toList()) { + const auto url = urlObj.toMap().value("uri").toString(); + if (entry->url().isEmpty()) { + // First url encountered is set as the primary url + entry->setUrl(url); + } else { + // Subsequent urls + entry->attributes()->set( + QString("%1_%2").arg(EntryAttributes::AdditionalUrlAttribute, QString::number(i)), url); + ++i; + } + } + } + + // Parse identity details if present + if (itemMap.contains("identity")) { + const auto idMap = itemMap.value("identity").toMap(); + + // Combine name attributes + auto attrs = QStringList({idMap.value("title").toString(), + idMap.value("firstName").toString(), + idMap.value("middleName").toString(), + idMap.value("lastName").toString()}); + attrs.removeAll(""); + entry->attributes()->set("identity_name", attrs.join(" ")); + + // Combine all the address attributes + attrs = QStringList({idMap.value("address1").toString(), + idMap.value("address2").toString(), + idMap.value("address3").toString()}); + attrs.removeAll(""); + auto address = attrs.join("\n") + "\n" + idMap.value("city").toString() + ", " + + idMap.value("state").toString() + " " + idMap.value("postalCode").toString() + "\n" + + idMap.value("country").toString(); + entry->attributes()->set("identity_address", address); + + // Add the remaining attributes + attrs = QStringList({"company", "email", "phone", "ssn", "passportNumber", "licenseNumber"}); + const QStringList sensitive({"ssn", "passportNumber", "licenseNumber"}); + for (const auto& attr : attrs) { + const auto value = idMap.value(attr).toString(); + if (!value.isEmpty()) { + entry->attributes()->set("identity_" + attr, value, sensitive.contains(attr)); + } + } + + // Set the username or push it into attributes if already set + const auto username = idMap.value("username").toString(); + if (!username.isEmpty()) { + if (entry->username().isEmpty()) { + entry->setUsername(username); + } else { + entry->attributes()->set("identity_username", username); + } + } + } + + // Parse card details if present + if (itemMap.contains("card")) { + const auto cardMap = itemMap.value("card").toMap(); + const QStringList attrs({"cardholderName", "brand", "number", "expMonth", "expYear", "code"}); + const QStringList sensitive({"code"}); + for (const auto& attr : attrs) { + auto value = cardMap.value(attr).toString(); + if (!value.isEmpty()) { + entry->attributes()->set("card_" + attr, value, sensitive.contains(attr)); + } + } + } + + // Parse remaining fields + for (const auto& field : itemMap.value("fields").toList()) { + // Derive a prefix for attribute names using the title or uuid if missing + const auto fieldMap = field.toMap(); + auto name = fieldMap.value("name").toString(); + if (entry->attributes()->hasKey(name)) { + name = QString("%1_%2").arg(name, QUuid::createUuid().toString().mid(1, 5)); + } + + const auto value = fieldMap.value("value").toString(); + const auto type = fieldMap.value("type").toInt(); + + entry->attributes()->set(name, value, type == 1); + } + + // Collapse any accumulated history + entry->removeHistoryItems(entry->historyItems()); + + return entry.take(); + } + + void writeVaultToDatabase(const QJsonObject& vault, QSharedPointer db) + { + if (!vault.contains("folders") || !vault.contains("items")) { + // Early out if the vault is missing critical items + return; + } + + // Create groups from folders and store a temporary map of id -> uuid + QMap folderMap; + for (const auto& folder : vault.value("folders").toArray()) { + auto group = new Group(); + group->setUuid(QUuid::createUuid()); + group->setName(folder.toObject().value("name").toString()); + group->setParent(db->rootGroup()); + + folderMap.insert(folder.toObject().value("id").toString(), group); + } + + QString folderId; + const auto items = vault.value("items").toArray(); + for (const auto& item : items) { + auto entry = readItem(item.toObject(), folderId); + if (entry) { + entry->setGroup(folderMap.value(folderId, db->rootGroup()), false); + } + } + } +} // namespace + +bool BitwardenReader::hasError() +{ + return !m_error.isEmpty(); +} + +QString BitwardenReader::errorString() +{ + return m_error; +} + +QSharedPointer BitwardenReader::convert(const QString& path, const QString& password) +{ + m_error.clear(); + + QFileInfo fileinfo(path); + if (!fileinfo.exists()) { + m_error = QObject::tr("File does not exist.").arg(path); + return {}; + } + + // Bitwarden uses a json file format + QFile file(fileinfo.absoluteFilePath()); + if (!file.open(QFile::ReadOnly)) { + m_error = QObject::tr("Cannot open file: %1").arg(file.errorString()); + return {}; + } + + QJsonParseError error; + auto json = QJsonDocument::fromJson(file.readAll(), &error).object(); + if (error.error != QJsonParseError::NoError) { + m_error = + QObject::tr("Cannot parse file: %1 at position %2").arg(error.errorString(), QString::number(error.offset)); + return {}; + } + + file.close(); + + // Check if this is an encrypted json + if (json.contains("encrypted") && json.value("encrypted").toBool()) { + auto buildError = [](const QString& errorString) { + return QObject::tr("Failed to decrypt json file: %1").arg(errorString); + }; + + QByteArray key(32, '\0'); + auto salt = json.value("salt").toString().toUtf8(); + + auto pwd_fam = Botan::PasswordHashFamily::create_or_throw("PBKDF2(SHA-256)"); + auto kdf = Botan::KDF::create_or_throw("HKDF-Expand(SHA-256)"); + + // Derive the Master Key + auto pwd_hash = pwd_fam->from_params(json.value("kdfIterations").toInt()); + pwd_hash->derive_key(reinterpret_cast(key.data()), + key.size(), + password.toUtf8().data(), + password.toUtf8().size(), + reinterpret_cast(salt.data()), + salt.size()); + // Derive the MAC Key + auto stretched_mac = kdf->derive_key(32, reinterpret_cast(key.data()), key.size(), "", "mac"); + auto mac = QByteArray(reinterpret_cast(stretched_mac.data()), stretched_mac.size()); + + // Stretch the Master Key + auto stretched_key = kdf->derive_key(32, reinterpret_cast(key.data()), key.size(), "", "enc"); + key = QByteArray(reinterpret_cast(stretched_key.data()), stretched_key.size()); + + // Validate the encryption key + auto keyList = json.value("encKeyValidation_DO_NOT_EDIT").toString().split("."); + if (keyList.size() < 2) { + m_error = buildError(QObject::tr("Invalid encKeyValidation field")); + return {}; + } + auto cipherList = keyList[1].split("|"); + if (cipherList.size() < 3) { + m_error = buildError(QObject::tr("Invalid cipher list within encKeyValidation field")); + return {}; + } + CryptoHash hash(CryptoHash::Sha256, true); + hash.setKey(mac); + hash.addData(QByteArray::fromBase64(cipherList[0].toUtf8())); // iv + hash.addData(QByteArray::fromBase64(cipherList[1].toUtf8())); // ciphertext + if (hash.result().toBase64() != cipherList[2].toUtf8()) { + // Calculated MAC doesn't equal the Validation + m_error = buildError(QObject::tr("Wrong password")); + return {}; + } + + // Decrypt data field using AES-256-CBC + keyList = json.value("data").toString().split("."); + if (keyList.size() < 2) { + m_error = buildError(QObject::tr("Invalid encrypted data field")); + return {}; + } + cipherList = keyList[1].split("|"); + if (cipherList.size() < 2) { + m_error = buildError(QObject::tr("Invalid cipher list within encrypted data field")); + return {}; + } + auto iv = QByteArray::fromBase64(cipherList[0].toUtf8()); + auto data = QByteArray::fromBase64(cipherList[1].toUtf8()); + + SymmetricCipher cipher; + if (!cipher.init(SymmetricCipher::Aes256_CBC, SymmetricCipher::Decrypt, key, iv)) { + m_error = buildError(QObject::tr("Cannot initialize cipher")); + return {}; + } + if (!cipher.finish(data)) { + m_error = buildError(QObject::tr("Cannot decrypt data")); + return {}; + } + + json = QJsonDocument::fromJson(data, &error).object(); + if (error.error != QJsonParseError::NoError) { + m_error = buildError(error.errorString()); + return {}; + } + } + + auto db = QSharedPointer::create(); + db->rootGroup()->setName(QObject::tr("Bitwarden Import")); + + writeVaultToDatabase(json, db); + + return db; +} diff --git a/tests/TestOpVaultReader.h b/src/format/BitwardenReader.h similarity index 51% rename from tests/TestOpVaultReader.h rename to src/format/BitwardenReader.h index feb904c6d..52e1e6f70 100644 --- a/tests/TestOpVaultReader.h +++ b/src/format/BitwardenReader.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,31 +15,29 @@ * along with this program. If not, see . */ -#ifndef TEST_OPVAULT_READER_H_ -#define TEST_OPVAULT_READER_H_ +#ifndef BITWARDEN_READER_H +#define BITWARDEN_READER_H -#include -#include +#include -class TestOpVaultReader : public QObject +class Database; + +/*! + * Imports a Bitwarden vault in JSON format: https://bitwarden.com/help/encrypted-export/ + */ +class BitwardenReader { - Q_OBJECT +public: + explicit BitwardenReader() = default; + ~BitwardenReader() = default; -private slots: - void initTestCase(); - void testReadIntoDatabase(); + QSharedPointer convert(const QString& path, const QString& password = {}); + + bool hasError(); + QString errorString(); private: - // absolute path to the .opvault directory - QString m_opVaultPath; - - /* - * Points to the file made by using the 1Password GUI to "Export all" - * to its text file format, which are almost key=value pairs - * except for multi-line strings. - */ - QString m_opVaultTextExportPath; - QStringList m_categories; + QString m_error; }; -#endif /* TEST_OPVAULT_READER_H_ */ +#endif // BITWARDEN_READER_H diff --git a/src/format/CsvParser.cpp b/src/format/CsvParser.cpp index a376e3662..0e174fe35 100644 --- a/src/format/CsvParser.cpp +++ b/src/format/CsvParser.cpp @@ -24,20 +24,13 @@ #include "core/Tools.h" CsvParser::CsvParser() - : m_ch(0) - , m_comment('#') - , m_currCol(1) - , m_currRow(1) + : m_comment('#') , m_isBackslashSyntax(false) - , m_isEof(false) , m_isFileLoaded(false) - , m_isGood(true) - , m_lastPos(-1) - , m_maxCols(0) , m_qualifier('"') , m_separator(',') - , m_statusMsg("") { + reset(); m_csv.setBuffer(&m_array); m_ts.setDevice(&m_csv); m_csv.open(QIODevice::ReadOnly); @@ -105,10 +98,10 @@ void CsvParser::reset() m_isGood = true; m_lastPos = -1; m_maxCols = 0; - m_statusMsg = ""; + m_statusMsg.clear(); m_ts.seek(0); m_table.clear(); - // the following are users' concern :) + // the following can be overridden by the user // m_comment = '#'; // m_backslashSyntax = false; // m_comment = '#'; @@ -148,7 +141,7 @@ void CsvParser::parseRecord() do { parseField(row); getChar(m_ch); - } while (isSeparator(m_ch) && !m_isEof); + } while (m_ch == m_separator && !m_isEof); if (!m_isEof) { ungetChar(); @@ -168,7 +161,7 @@ void CsvParser::parseField(CsvRow& row) { QString field; peek(m_ch); - if (!isTerminator(m_ch)) { + if (m_ch != m_separator && m_ch != '\n' && m_ch != '\r') { if (isQualifier(m_ch)) { parseQuoted(field); } else { @@ -182,7 +175,7 @@ void CsvParser::parseSimple(QString& s) { QChar c; getChar(c); - while ((isText(c)) && (!m_isEof)) { + while (c != '\n' && c != m_separator && !m_isEof) { s.append(c); getChar(c); } @@ -215,7 +208,7 @@ void CsvParser::parseEscaped(QString& s) void CsvParser::parseEscapedText(QString& s) { getChar(m_ch); - while ((!isQualifier(m_ch)) && !m_isEof) { + while (!isQualifier(m_ch) && !m_isEof) { s.append(m_ch); getChar(m_ch); } @@ -223,10 +216,9 @@ void CsvParser::parseEscapedText(QString& s) bool CsvParser::processEscapeMark(QString& s, QChar c) { - QChar buf; - peek(buf); QChar c2; - if (true == m_isBackslashSyntax) { + peek(c2); + if (m_isBackslashSyntax) { // escape-character syntax, e.g. \" if (c != '\\') { return false; @@ -237,25 +229,24 @@ bool CsvParser::processEscapeMark(QString& s, QChar c) c2 = '\\'; s.append('\\'); return false; - } else { - s.append(c2); - return true; - } - } else { - // double quote syntax, e.g. "" - if (!isQualifier(c)) { - return false; - } - peek(c2); - if (!m_isEof) { // not EOF, can read one char - if (isQualifier(c2)) { - s.append(c2); - getChar(c2); - return true; - } } + s.append(c2); + return true; + } + + // double quote syntax, e.g. "" + if (!isQualifier(c)) { return false; } + peek(c2); + if (!m_isEof) { // not EOF, can read one char + if (isQualifier(c2)) { + s.append(c2); + getChar(c2); + return true; + } + } + return false; } void CsvParser::fillColumns() @@ -282,7 +273,7 @@ void CsvParser::skipLine() bool CsvParser::skipEndline() { getChar(m_ch); - return (m_ch == '\n'); + return m_ch == '\n'; } void CsvParser::getChar(QChar& c) @@ -312,11 +303,10 @@ void CsvParser::peek(QChar& c) bool CsvParser::isQualifier(const QChar& c) const { - if (true == m_isBackslashSyntax && (c != m_qualifier)) { - return (c == '\\'); - } else { - return (c == m_qualifier); + if (m_isBackslashSyntax && c != m_qualifier) { + return c == '\\'; } + return c == m_qualifier; } bool CsvParser::isComment() @@ -327,7 +317,7 @@ bool CsvParser::isComment() do { getChar(c2); - } while ((isSpace(c2) || isTab(c2)) && (!m_isEof)); + } while ((c2 == ' ' || c2 == '\t') && !m_isEof); if (c2 == m_comment) { result = true; @@ -336,47 +326,16 @@ bool CsvParser::isComment() return result; } -bool CsvParser::isText(QChar c) const -{ - return !((isCRLF(c)) || (isSeparator(c))); -} - bool CsvParser::isEmptyRow(const CsvRow& row) const { - CsvRow::const_iterator it = row.constBegin(); - for (; it != row.constEnd(); ++it) { - if (((*it) != "\n") && ((*it) != "")) { + for (auto it = row.constBegin(); it != row.constEnd(); ++it) { + if (*it != "\n" && *it != "") { return false; } } return true; } -bool CsvParser::isCRLF(const QChar& c) const -{ - return (c == '\n'); -} - -bool CsvParser::isSpace(const QChar& c) const -{ - return (c == ' '); -} - -bool CsvParser::isTab(const QChar& c) const -{ - return (c == '\t'); -} - -bool CsvParser::isSeparator(const QChar& c) const -{ - return (c == m_separator); -} - -bool CsvParser::isTerminator(const QChar& c) const -{ - return (isSeparator(c) || (c == '\n') || (c == '\r')); -} - void CsvParser::setBackslashSyntax(bool set) { m_isBackslashSyntax = set; @@ -407,7 +366,7 @@ int CsvParser::getFileSize() const return m_csv.size(); } -const CsvTable CsvParser::getCsvTable() const +CsvTable CsvParser::getCsvTable() const { return m_table; } @@ -421,9 +380,8 @@ int CsvParser::getCsvCols() const { if (!m_table.isEmpty() && !m_table.at(0).isEmpty()) { return m_table.at(0).size(); - } else { - return 0; } + return 0; } int CsvParser::getCsvRows() const diff --git a/src/format/CsvParser.h b/src/format/CsvParser.h index 73fb13d24..afba9688d 100644 --- a/src/format/CsvParser.h +++ b/src/format/CsvParser.h @@ -47,7 +47,7 @@ public: int getCsvRows() const; int getCsvCols() const; QString getStatus() const; - const CsvTable getCsvTable() const; + CsvTable getCsvTable() const; protected: CsvTable m_table; @@ -74,15 +74,9 @@ private: void ungetChar(); void peek(QChar& c); void fillColumns(); - bool isTerminator(const QChar& c) const; - bool isSeparator(const QChar& c) const; bool isQualifier(const QChar& c) const; bool processEscapeMark(QString& s, QChar c); - bool isText(QChar c) const; bool isComment(); - bool isCRLF(const QChar& c) const; - bool isSpace(const QChar& c) const; - bool isTab(const QChar& c) const; bool isEmptyRow(const CsvRow& row) const; bool parseFile(); void parseRecord(); diff --git a/src/format/KeePass1Reader.cpp b/src/format/KeePass1Reader.cpp index 144e1b473..a7d8038df 100644 --- a/src/format/KeePass1Reader.cpp +++ b/src/format/KeePass1Reader.cpp @@ -18,6 +18,7 @@ #include "KeePass1Reader.h" #include +#include #include #include "core/Endian.h" @@ -275,6 +276,10 @@ KeePass1Reader::readDatabase(const QString& filename, const QString& password, c return {}; } + if (db) { + db->metadata()->setName(QFileInfo(filename).completeBaseName()); + } + return db; } diff --git a/src/format/OPUXReader.cpp b/src/format/OPUXReader.cpp new file mode 100644 index 000000000..d52aa4640 --- /dev/null +++ b/src/format/OPUXReader.cpp @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "OPUXReader.h" + +#include "core/Database.h" +#include "core/Entry.h" +#include "core/Group.h" +#include "core/Metadata.h" +#include "core/Totp.h" + +#include +#include +#include +#include +#include +#include + +#include + +namespace +{ + QByteArray extractFile(unzFile uf, QString filename) + { + if (unzLocateFile(uf, filename.toLatin1(), 2) != UNZ_OK) { + qWarning("Failed to extract 1PUX document: %s", qPrintable(filename)); + return {}; + } + + // Read export.data into memory + int bytes, bytesRead = 0; + QByteArray data; + unzOpenCurrentFile(uf); + do { + data.resize(data.size() + 8192); + bytes = unzReadCurrentFile(uf, data.data() + bytesRead, 8192); + if (bytes > 0) { + bytesRead += bytes; + } + } while (bytes > 0); + unzCloseCurrentFile(uf); + data.truncate(bytesRead); + + return data; + } + + Entry* readItem(const QJsonObject& item, unzFile uf = nullptr) + { + const auto itemMap = item.toVariantMap(); + const auto overviewMap = itemMap.value("overview").toMap(); + const auto detailsMap = itemMap.value("details").toMap(); + + // Create entry and assign basic values + QScopedPointer entry(new Entry()); + entry->setUuid(QUuid::createUuid()); + entry->setTitle(overviewMap.value("title").toString()); + entry->setUrl(overviewMap.value("url").toString()); + if (overviewMap.contains("urls")) { + int i = 1; + for (const auto& urlRaw : overviewMap.value("urls").toList()) { + const auto urlMap = urlRaw.toMap(); + const auto url = urlMap.value("url").toString(); + if (entry->url() != url) { + entry->attributes()->set( + QString("%1_%2").arg(EntryAttributes::AdditionalUrlAttribute, QString::number(i)), url); + ++i; + } + } + } + if (overviewMap.contains("tags")) { + entry->setTags(overviewMap.value("tags").toStringList().join(",")); + } + if (itemMap.value("favIndex").toString() == "1") { + entry->addTag(QObject::tr("Favorite", "Tag for favorite entries")); + } + if (itemMap.value("state").toString() == "archived") { + entry->addTag(QObject::tr("Archived", "Tag for archived entries")); + } + + // Parse the details map by setting the username, password, and notes first + const auto loginFields = detailsMap.value("loginFields").toList(); + for (const auto& field : loginFields) { + const auto fieldMap = field.toMap(); + const auto designation = fieldMap.value("designation").toString(); + if (designation.compare("username", Qt::CaseInsensitive) == 0) { + entry->setUsername(fieldMap.value("value").toString()); + } else if (designation.compare("password", Qt::CaseInsensitive) == 0) { + entry->setPassword(fieldMap.value("value").toString()); + } + } + entry->setNotes(detailsMap.value("notesPlain").toString()); + + // Dive into the item sections to pull out advanced attributes + const auto sections = detailsMap.value("sections").toList(); + for (const auto& section : sections) { + // Derive a prefix for attribute names using the title or uuid if missing + const auto sectionMap = section.toMap(); + auto prefix = sectionMap.value("title").toString(); + if (prefix.isEmpty()) { + prefix = QUuid::createUuid().toString().mid(1, 5); + } + + for (const auto& field : sectionMap.value("fields").toList()) { + // Form the name of the attribute using the prefix and title or id + const auto fieldMap = field.toMap(); + auto name = fieldMap.value("title").toString(); + if (name.isEmpty()) { + name = fieldMap.value("id").toString(); + } + name = QString("%1_%2").arg(prefix, name); + + const auto valueMap = fieldMap.value("value").toMap(); + const auto key = valueMap.firstKey(); + if (key == "totp") { + // Build otpauth url + QUrl otpurl(QString("otpauth://totp/%1:%2?secret=%3") + .arg(entry->title(), entry->username(), valueMap.value(key).toString())); + + if (entry->hasTotp()) { + // Store multiple TOTP definitions as additional otp attributes + int i = 0; + name = "otp"; + const auto attributes = entry->attributes()->keys(); + while (attributes.contains(name)) { + name = QString("otp_%1").arg(++i); + } + entry->attributes()->set(name, otpurl.toEncoded(), true); + } else { + // First otp value encountered gets formal storage + entry->setTotp(Totp::parseSettings(otpurl.toEncoded())); + } + } else if (key == "file") { + // Add a file to the entry attachments + const auto fileMap = valueMap.value(key).toMap(); + const auto fileName = fileMap.value("fileName").toString(); + const auto docId = fileMap.value("documentId").toString(); + const auto data = extractFile(uf, QString("files/%1__%2").arg(docId, fileName)); + if (!data.isNull()) { + entry->attachments()->set(fileName, data); + } + } else { + auto value = valueMap.value(key).toString(); + if (key == "date") { + // Convert date fields from Unix time + value = QDateTime::fromSecsSinceEpoch(valueMap.value(key).toULongLong(), Qt::UTC).toString(); + } else if (key == "email") { + // Email address is buried in a sub-value + value = valueMap.value(key).toMap().value("email_address").toString(); + } else if (key == "address") { + // Combine all the address attributes into a fully formed structure + const auto address = valueMap.value(key).toMap(); + value = address.value("street").toString() + "\n" + address.value("city").toString() + ", " + + address.value("state").toString() + " " + address.value("zip").toString() + "\n" + + address.value("country").toString(); + } + + if (!value.isEmpty()) { + entry->attributes()->set(name, value, key == "concealed"); + } + } + } + } + + // Add a document attachment if defined + if (detailsMap.contains("documentAttributes")) { + const auto document = detailsMap.value("documentAttributes").toMap(); + const auto fileName = document.value("fileName").toString(); + const auto docId = document.value("documentId").toString(); + const auto data = extractFile(uf, QString("files/%1__%2").arg(docId, fileName)); + if (!data.isNull()) { + entry->attachments()->set(fileName, data); + } + } + + // Collapse any accumulated history + entry->removeHistoryItems(entry->historyItems()); + + // Adjust the created and modified times + auto timeInfo = entry->timeInfo(); + const auto createdTime = QDateTime::fromSecsSinceEpoch(itemMap.value("createdAt").toULongLong(), Qt::UTC); + const auto modifiedTime = QDateTime::fromSecsSinceEpoch(itemMap.value("updatedAt").toULongLong(), Qt::UTC); + timeInfo.setCreationTime(createdTime); + timeInfo.setLastModificationTime(modifiedTime); + timeInfo.setLastAccessTime(modifiedTime); + entry->setTimeInfo(timeInfo); + + return entry.take(); + } + + void writeVaultToDatabase(const QJsonObject& vault, QSharedPointer db, unzFile uf = nullptr) + { + if (!vault.contains("attrs") || !vault.contains("items")) { + // Early out if the vault is missing critical items + return; + } + + const auto attr = vault.value("attrs").toObject().toVariantMap(); + + // Create group and assign basic values + auto group = new Group(); + group->setUuid(QUuid::createUuid()); + group->setName(attr.value("name").toString()); + group->setParent(db->rootGroup()); + + const auto items = vault.value("items").toArray(); + for (const auto& item : items) { + auto entry = readItem(item.toObject(), uf); + if (entry) { + entry->setGroup(group, false); + } + } + + // Add the group icon if present + const auto icon = attr.value("avatar").toString(); + if (!icon.isEmpty()) { + auto data = extractFile(uf, QString("files/%1").arg(icon)); + if (!data.isNull()) { + const auto uuid = QUuid::createUuid(); + db->metadata()->addCustomIcon(uuid, data); + group->setIcon(uuid); + } + } + } +} // namespace + +bool OPUXReader::hasError() +{ + return !m_error.isEmpty(); +} + +QString OPUXReader::errorString() +{ + return m_error; +} + +QSharedPointer OPUXReader::convert(const QString& path) +{ + m_error.clear(); + + QFileInfo fileinfo(path); + if (!fileinfo.exists()) { + m_error = QObject::tr("File does not exist.").arg(path); + return {}; + } + + // 1PUX is a zip file format, open it and process the contents in memory + auto uf = unzOpen64(fileinfo.absoluteFilePath().toLatin1().constData()); + if (!uf) { + m_error = QObject::tr("Invalid 1PUX file format: Not a valid ZIP file."); + return {}; + } + + // Find the export.data file, if not found this isn't a 1PUX file + auto data = extractFile(uf, "export.data"); + if (data.isNull()) { + m_error = QObject::tr("Invalid 1PUX file format: Missing export.data"); + unzClose(uf); + return {}; + } + + auto db = QSharedPointer::create(); + db->rootGroup()->setName(QObject::tr("1Password Import")); + const auto json = QJsonDocument::fromJson(data); + + const auto account = json.object().value("accounts").toArray().first().toObject(); + const auto vaults = account.value("vaults").toArray(); + + for (const auto& vault : vaults) { + writeVaultToDatabase(vault.toObject(), db, uf); + } + + unzClose(uf); + return db; +} diff --git a/src/gui/OpVaultOpenWidget.h b/src/format/OPUXReader.h similarity index 58% rename from src/gui/OpVaultOpenWidget.h rename to src/format/OPUXReader.h index aed96caba..e2779c814 100644 --- a/src/gui/OpVaultOpenWidget.h +++ b/src/format/OPUXReader.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 KeePassXC Team + * Copyright (C) 2023 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,20 +15,29 @@ * along with this program. If not, see . */ -#ifndef KEEPASSXC_OPVAULTOPENWIDGET_H -#define KEEPASSXC_OPVAULTOPENWIDGET_H +#ifndef OPUX_READER_H +#define OPUX_READER_H -#include "gui/DatabaseOpenWidget.h" +#include -class OpVaultOpenWidget : public DatabaseOpenWidget +class Database; + +/*! + * Imports a 1Password vault in 1PUX format: https://support.1password.com/1pux-format/ + */ +class OPUXReader { - Q_OBJECT - public: - explicit OpVaultOpenWidget(QWidget* parent = nullptr); + explicit OPUXReader() = default; + ~OPUXReader() = default; -protected: - void openDatabase() override; + QSharedPointer convert(const QString& path); + + bool hasError(); + QString errorString(); + +private: + QString m_error; }; -#endif // KEEPASSXC_OPVAULTOPENWIDGET_H +#endif // OPUX_READER_H diff --git a/src/format/OpVaultReader.cpp b/src/format/OpVaultReader.cpp index 44f0d85ec..779e25fda 100644 --- a/src/format/OpVaultReader.cpp +++ b/src/format/OpVaultReader.cpp @@ -31,68 +31,49 @@ OpVaultReader::OpVaultReader(QObject* parent) : QObject(parent) - , m_error(false) { } OpVaultReader::~OpVaultReader() = default; -Database* OpVaultReader::readDatabase(QDir& opdataDir, const QString& password) +QSharedPointer OpVaultReader::convert(QDir& opdataDir, const QString& password) { if (!opdataDir.exists()) { - m_error = true; - m_errorStr = tr("Directory .opvault must exist"); - return nullptr; + m_error = tr("Directory .opvault must exist"); + return {}; } if (!opdataDir.isReadable()) { - m_error = true; - m_errorStr = tr("Directory .opvault must be readable"); - return nullptr; + m_error = tr("Directory .opvault must be readable"); + return {}; } // https://support.1password.com/opvault-design/#directory-layout QDir defaultDir = QDir(opdataDir); if (!defaultDir.cd("default")) { - m_error = true; - m_errorStr = tr("Directory .opvault/default must exist"); - return nullptr; + m_error = tr("Directory .opvault/default must exist"); + return {}; } if (!defaultDir.isReadable()) { - m_error = true; - m_errorStr = tr("Directory .opvault/default must be readable"); - return nullptr; + m_error = tr("Directory .opvault/default must be readable"); + return {}; } auto vaultName = opdataDir.dirName(); - auto key = QSharedPointer::create(); - key->addKey(QSharedPointer::create(password)); - - QScopedPointer db(new Database()); - db->setKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D)); - db->setCipher(KeePass2::CIPHER_AES256); - db->setKey(key, true, false); - db->metadata()->setName(vaultName); - + auto db = QSharedPointer::create(); auto rootGroup = db->rootGroup(); - rootGroup->setTimeInfo({}); - rootGroup->setUpdateTimeinfo(false); rootGroup->setName(vaultName.remove(".opvault")); - rootGroup->setUuid(QUuid::createUuid()); populateCategoryGroups(rootGroup); QFile profileJsFile(defaultDir.absoluteFilePath("profile.js")); QJsonObject profileJson = readAndAssertJsonFile(profileJsFile, "var profile=", ";"); if (profileJson.isEmpty()) { - return nullptr; + return {}; } if (!processProfileJson(profileJson, password, rootGroup)) { zeroKeys(); - return nullptr; - } - if (profileJson.contains("uuid") and profileJson["uuid"].isString()) { - rootGroup->setUuid(Tools::hexToUuid(profileJson["uuid"].toString())); + return {}; } QFile foldersJsFile(defaultDir.filePath("folders.js")); @@ -100,7 +81,7 @@ Database* OpVaultReader::readDatabase(QDir& opdataDir, const QString& password) QJsonObject foldersJs = readAndAssertJsonFile(foldersJsFile, "loadFolders(", ");"); if (!processFolderJson(foldersJs, rootGroup)) { zeroKeys(); - return nullptr; + return {}; } } @@ -150,17 +131,17 @@ Database* OpVaultReader::readDatabase(QDir& opdataDir, const QString& password) } zeroKeys(); - return db.take(); + return db; } bool OpVaultReader::hasError() { - return m_error; + return !m_error.isEmpty(); } QString OpVaultReader::errorString() { - return m_errorStr; + return m_error; } bool OpVaultReader::processProfileJson(QJsonObject& profileJson, const QString& password, Group* rootGroup) @@ -182,38 +163,29 @@ bool OpVaultReader::processProfileJson(QJsonObject& profileJson, const QString& rootGroupTime.setLastModificationTime(QDateTime::fromTime_t(updatedAt, Qt::UTC)); rootGroup->setUuid(Tools::hexToUuid(profileJson["uuid"].toString())); - const auto derivedKeys = deriveKeysFromPassPhrase(salt, password, iterations); - if (derivedKeys->error) { - m_error = true; - m_errorStr = derivedKeys->errorStr; - delete derivedKeys; + QScopedPointer derivedKeys(deriveKeysFromPassPhrase(salt, password, iterations)); + if (!derivedKeys->error.isEmpty()) { + m_error = derivedKeys->error; return false; } QByteArray encKey = derivedKeys->encrypt; QByteArray hmacKey = derivedKeys->hmac; - delete derivedKeys; - auto masterKeys = decodeB64CompositeKeys(masterKeyB64, encKey, hmacKey); - if (masterKeys->error) { - m_error = true; - m_errorStr = masterKeys->errorStr; - delete masterKeys; + QScopedPointer masterKeys(decodeB64CompositeKeys(masterKeyB64, encKey, hmacKey)); + if (!masterKeys->error.isEmpty()) { + m_error = masterKeys->error; return false; } m_masterKey = masterKeys->encrypt; m_masterHmacKey = masterKeys->hmac; - delete masterKeys; - auto overviewKeys = decodeB64CompositeKeys(overviewKeyB64, encKey, hmacKey); - if (overviewKeys->error) { - m_error = true; - m_errorStr = overviewKeys->errorStr; - delete overviewKeys; + QScopedPointer overviewKeys(decodeB64CompositeKeys(overviewKeyB64, encKey, hmacKey)); + if (!overviewKeys->error.isEmpty()) { + m_error = overviewKeys->error; return false; } m_overviewKey = overviewKeys->encrypt; m_overviewHmacKey = overviewKeys->hmac; - delete overviewKeys; return true; } @@ -338,15 +310,13 @@ QJsonObject OpVaultReader::readAndAssertJsonFile(QFile& file, const QString& str OpVaultReader::DerivedKeyHMAC* OpVaultReader::decodeB64CompositeKeys(const QString& b64, const QByteArray& encKey, const QByteArray& hmacKey) { - auto result = new DerivedKeyHMAC(); OpData01 keyKey01; if (!keyKey01.decodeBase64(b64, encKey, hmacKey)) { - result->error = true; - result->errorStr = tr("Unable to decode masterKey: %1").arg(keyKey01.errorString()); + auto result = new DerivedKeyHMAC(); + result->error = tr("Unable to decode masterKey: %1").arg(keyKey01.errorString()); return result; } - delete result; const QByteArray keyKey = keyKey01.getClearText(); @@ -364,7 +334,6 @@ OpVaultReader::decodeB64CompositeKeys(const QString& b64, const QByteArray& encK OpVaultReader::DerivedKeyHMAC* OpVaultReader::decodeCompositeKeys(const QByteArray& keyKey) { auto result = new DerivedKeyHMAC; - result->error = false; auto digest = CryptoHash::hash(keyKey, CryptoHash::Sha512); result->encrypt = digest.left(32); @@ -383,7 +352,6 @@ OpVaultReader::DerivedKeyHMAC* OpVaultReader::deriveKeysFromPassPhrase(QByteArray& salt, const QString& password, unsigned long iterations) { auto result = new DerivedKeyHMAC; - result->error = false; QByteArray out(64, '\0'); try { @@ -395,8 +363,7 @@ OpVaultReader::deriveKeysFromPassPhrase(QByteArray& salt, const QString& passwor reinterpret_cast(salt.constData()), salt.size()); } catch (std::exception& e) { - result->error = true; - result->errorStr = tr("Unable to derive master key: %1").arg(e.what()); + result->error = tr("Unable to derive master key: %1").arg(e.what()); return result; } diff --git a/src/format/OpVaultReader.h b/src/format/OpVaultReader.h index 0dff45c2d..50ccf0b96 100644 --- a/src/format/OpVaultReader.h +++ b/src/format/OpVaultReader.h @@ -39,7 +39,7 @@ public: explicit OpVaultReader(QObject* parent = nullptr); ~OpVaultReader() override; - Database* readDatabase(QDir& opdataDir, const QString& password); + QSharedPointer convert(QDir& opdataDir, const QString& password); bool hasError(); QString errorString(); @@ -49,8 +49,7 @@ private: { QByteArray encrypt; QByteArray hmac; - bool error; - QString errorStr; + QString error; }; QJsonObject readAndAssertJsonFile(QFile& file, const QString& stripLeading, const QString& stripTrailing); @@ -106,15 +105,14 @@ private: /*! Used to blank the memory after the keys have been used. */ void zeroKeys(); - bool m_error; - QString m_errorStr; + QString m_error; QByteArray m_masterKey; QByteArray m_masterHmacKey; /*! Used to decrypt overview text, such as folder names. */ QByteArray m_overviewKey; QByteArray m_overviewHmacKey; - friend class TestOpVaultReader; + friend class TestImports; }; #endif /* OPVAULT_READER_H_ */ diff --git a/src/format/OpVaultReaderAttachments.cpp b/src/format/OpVaultReaderAttachments.cpp index 7c65b7f5a..c9dc6c76e 100644 --- a/src/format/OpVaultReaderAttachments.cpp +++ b/src/format/OpVaultReaderAttachments.cpp @@ -229,6 +229,10 @@ void OpVaultReader::fillAttachment(Entry* entry, qWarning() << QString("Unexpected type of attachment \"filename\": %1").arg(attFilename.type()); } } + if (entry->attachments()->hasKey(attachKey)) { + // Prepend a random string to the attachment name to avoid collisions + attachKey.prepend(QString("%1_").arg(QUuid::createUuid().toString().mid(1, 5))); + } entry->attachments()->set(attachKey, attachPayload); } diff --git a/src/format/OpVaultReaderSections.cpp b/src/format/OpVaultReaderSections.cpp index d05f8fca1..42da14bb6 100644 --- a/src/format/OpVaultReaderSections.cpp +++ b/src/format/OpVaultReaderSections.cpp @@ -92,7 +92,7 @@ void OpVaultReader::fillFromSectionField(Entry* entry, const QString& sectionNam while (attributes.contains(name)) { name = QString("otp_%1").arg(++i); } - entry->attributes()->set(name, attrValue); + entry->attributes()->set(name, attrValue, true); } else if (attrValue.startsWith("otpauth://")) { QUrlQuery query(attrValue); // at least as of 1Password 7, they don't append the digits= and period= which totp.cpp requires @@ -128,10 +128,14 @@ void OpVaultReader::fillFromSectionField(Entry* entry, const QString& sectionNam } else if (kind == "address") { // Expand address into multiple attributes auto addrFields = field.value("v").toObject().toVariantMap(); - for (auto part : addrFields.keys()) { + for (auto& part : addrFields.keys()) { entry->attributes()->set(attrName + QString("_%1").arg(part), addrFields.value(part).toString()); } } else { + if (entry->attributes()->hasKey(attrName)) { + // Append a random string to the attribute name to avoid collisions + attrName += QString("_%1").arg(QUuid::createUuid().toString().mid(1, 5)); + } entry->attributes()->set(attrName, attrValue, (kind == "password" || kind == "concealed")); } } diff --git a/src/gui/CloneDialog.h b/src/gui/CloneDialog.h index febf9d480..8e76a8d10 100644 --- a/src/gui/CloneDialog.h +++ b/src/gui/CloneDialog.h @@ -18,6 +18,8 @@ #ifndef KEEPASSX_CLONEDIALOG_H #define KEEPASSX_CLONEDIALOG_H +#include + #include "core/Database.h" #include "gui/DatabaseWidget.h" diff --git a/src/gui/DatabaseTabWidget.cpp b/src/gui/DatabaseTabWidget.cpp index 73a61fac3..b24a8b245 100644 --- a/src/gui/DatabaseTabWidget.cpp +++ b/src/gui/DatabaseTabWidget.cpp @@ -21,6 +21,7 @@ #include #include "autotype/AutoType.h" +#include "core/Merger.h" #include "core/Tools.h" #include "format/CsvExporter.h" #include "gui/Clipboard.h" @@ -28,13 +29,13 @@ #include "gui/DatabaseWidget.h" #include "gui/DatabaseWidgetStateSync.h" #include "gui/FileDialog.h" -#include "gui/HtmlExporter.h" #include "gui/MessageBox.h" #include "gui/export/ExportDialog.h" #ifdef Q_OS_MACOS #include "gui/osutils/macutils/MacUtils.h" #endif #include "gui/wizard/NewDatabaseWizard.h" +#include "wizard/ImportWizard.h" DatabaseTabWidget::DatabaseTabWidget(QWidget* parent) : QTabWidget(parent) @@ -250,24 +251,52 @@ void DatabaseTabWidget::addDatabaseTab(DatabaseWidget* dbWidget, bool inBackgrou connect(dbWidget, SIGNAL(databaseLocked()), SLOT(emitDatabaseLockChanged())); } -void DatabaseTabWidget::importCsv() +DatabaseWidget* DatabaseTabWidget::importFile() { - auto filter = QString("%1 (*.csv);;%2 (*)").arg(tr("CSV file"), tr("All files")); - auto fileName = fileDialog()->getOpenFileName(this, tr("Select CSV file"), FileDialog::getLastDir("csv"), filter); - if (fileName.isEmpty()) { - return; + // Show the import wizard + QScopedPointer wizard(new ImportWizard(this)); + if (!wizard->exec()) { + return nullptr; } - FileDialog::saveLastDir("csv", fileName, true); - - auto db = execNewDatabaseWizard(); + auto db = wizard->database(); if (!db) { - return; + // Import wizard was cancelled + return nullptr; } - auto* dbWidget = new DatabaseWidget(db, this); - addDatabaseTab(dbWidget); - dbWidget->switchToCsvImport(fileName); + auto importInto = wizard->importInto(); + if (importInto.first.isNull()) { + // Start the new database wizard with the imported database + auto newDb = execNewDatabaseWizard(); + if (newDb) { + // Merge the imported db into the new one + Merger merger(db.data(), newDb.data()); + merger.merge(); + // Show the new database + auto dbWidget = new DatabaseWidget(newDb, this); + addDatabaseTab(dbWidget); + newDb->markAsModified(); + return dbWidget; + } + } else { + for (int i = 0, c = count(); i < c; ++i) { + // Find the database and group to import into based on import wizard choice + auto dbWidget = databaseWidgetFromIndex(i); + if (!dbWidget->isLocked() && dbWidget->database()->uuid() == importInto.first) { + auto group = dbWidget->database()->rootGroup()->findGroupByUuid(importInto.second); + if (group) { + // Extract the root group from the import database + auto importGroup = db->setRootGroup(new Group()); + importGroup->setParent(group); + setCurrentIndex(i); + return dbWidget; + } + } + } + } + + return nullptr; } void DatabaseTabWidget::mergeDatabase() @@ -289,44 +318,6 @@ void DatabaseTabWidget::mergeDatabase(const QString& filePath) unlockDatabaseInDialog(currentDatabaseWidget(), DatabaseOpenDialog::Intent::Merge, filePath); } -void DatabaseTabWidget::importKeePass1Database() -{ - auto filter = QString("%1 (*.kdb);;%2 (*)").arg(tr("KeePass 1 database"), tr("All files")); - auto fileName = - fileDialog()->getOpenFileName(this, tr("Open KeePass 1 database"), FileDialog::getLastDir("kp1"), filter); - if (fileName.isEmpty()) { - return; - } - - FileDialog::saveLastDir("kp1", fileName, true); - - auto db = QSharedPointer::create(); - auto* dbWidget = new DatabaseWidget(db, this); - addDatabaseTab(dbWidget); - dbWidget->switchToImportKeepass1(fileName); -} - -void DatabaseTabWidget::importOpVaultDatabase() -{ - auto defaultDir = FileDialog::getLastDir("opvault"); -#ifdef Q_OS_MACOS - QString fileName = fileDialog()->getOpenFileName(this, tr("Open OPVault"), defaultDir, "OPVault (*.opvault)"); -#else - QString fileName = fileDialog()->getExistingDirectory(this, tr("Open OPVault"), defaultDir); -#endif - - if (fileName.isEmpty()) { - return; - } - - FileDialog::saveLastDir("opvault", fileName); - - auto db = QSharedPointer::create(); - auto* dbWidget = new DatabaseWidget(db, this); - addDatabaseTab(dbWidget); - dbWidget->switchToImportOpVault(fileName); -} - /** * Attempt to close the current database and remove its tab afterwards. * @@ -611,43 +602,18 @@ bool DatabaseTabWidget::hasLockableDatabases() const */ QString DatabaseTabWidget::tabName(int index) { - if (index == -1 || index > count()) { - return ""; + auto dbWidget = databaseWidgetFromIndex(index); + if (!dbWidget) { + return {}; } - auto* dbWidget = databaseWidgetFromIndex(index); - - auto db = dbWidget->database(); - Q_ASSERT(db); - if (!db) { - return ""; - } - - QString tabName; - - if (!db->filePath().isEmpty()) { - QFileInfo fileInfo(db->filePath()); - - if (db->metadata()->name().isEmpty()) { - tabName = fileInfo.fileName(); - } else { - tabName = db->metadata()->name(); - } - - setTabToolTip(index, fileInfo.absoluteFilePath()); - } else { - if (db->metadata()->name().isEmpty()) { - tabName = tr("New Database"); - } else { - tabName = tr("%1 [New Database]", "Database tab name modifier").arg(db->metadata()->name()); - } - } + auto tabName = dbWidget->displayName(); if (dbWidget->isLocked()) { tabName = tr("%1 [Locked]", "Database tab name modifier").arg(tabName); } - if (db->isModified()) { + if (dbWidget->database()->isModified()) { tabName.append("*"); } @@ -670,6 +636,7 @@ void DatabaseTabWidget::updateTabName(int index) } index = indexOf(dbWidget); setTabText(index, tabName(index)); + setTabToolTip(index, dbWidget->displayFilePath()); emit tabNameChanged(); } diff --git a/src/gui/DatabaseTabWidget.h b/src/gui/DatabaseTabWidget.h index 8f2703878..5c995b536 100644 --- a/src/gui/DatabaseTabWidget.h +++ b/src/gui/DatabaseTabWidget.h @@ -64,9 +64,7 @@ public slots: DatabaseWidget* newDatabase(); void openDatabase(); void mergeDatabase(); - void importCsv(); - void importKeePass1Database(); - void importOpVaultDatabase(); + DatabaseWidget* importFile(); bool saveDatabase(int index = -1); bool saveDatabaseAs(int index = -1); bool saveDatabaseBackup(int index = -1); diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 33fcd4571..816d3ace1 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -30,20 +30,20 @@ #include #include #include -#include #include "autotype/AutoType.h" #include "core/EntrySearcher.h" #include "core/Merger.h" +#include "core/Tools.h" #include "gui/Clipboard.h" #include "gui/CloneDialog.h" +#include "gui/DatabaseOpenDialog.h" +#include "gui/DatabaseOpenWidget.h" #include "gui/EntryPreviewWidget.h" #include "gui/FileDialog.h" #include "gui/GuiTools.h" -#include "gui/KeePass1OpenWidget.h" #include "gui/MainWindow.h" #include "gui/MessageBox.h" -#include "gui/OpVaultOpenWidget.h" #include "gui/TotpDialog.h" #include "gui/TotpExportSettingsDialog.h" #include "gui/TotpSetupDialog.h" @@ -79,15 +79,12 @@ DatabaseWidget::DatabaseWidget(QSharedPointer db, QWidget* parent) , m_previewSplitter(new QSplitter(m_mainWidget)) , m_searchingLabel(new QLabel(this)) , m_shareLabel(new ElidedLabel(this)) - , m_csvImportWizard(new CsvImportWizard(this)) , m_editEntryWidget(new EditEntryWidget(this)) , m_editGroupWidget(new EditGroupWidget(this)) , m_historyEditEntryWidget(new EditEntryWidget(this)) , m_reportsDialog(new ReportsDialog(this)) , m_databaseSettingDialog(new DatabaseSettingsDialog(this)) , m_databaseOpenWidget(new DatabaseOpenWidget(this)) - , m_keepass1OpenWidget(new KeePass1OpenWidget(this)) - , m_opVaultOpenWidget(new OpVaultOpenWidget(this)) , m_groupView(new GroupView(m_db.data(), this)) , m_tagView(new TagView(this)) , m_saveAttempts(0) @@ -179,12 +176,9 @@ DatabaseWidget::DatabaseWidget(QSharedPointer db, QWidget* parent) m_editEntryWidget->setObjectName("editEntryWidget"); m_editGroupWidget->setObjectName("editGroupWidget"); - m_csvImportWizard->setObjectName("csvImportWizard"); m_reportsDialog->setObjectName("reportsDialog"); m_databaseSettingDialog->setObjectName("databaseSettingsDialog"); m_databaseOpenWidget->setObjectName("databaseOpenWidget"); - m_keepass1OpenWidget->setObjectName("keepass1OpenWidget"); - m_opVaultOpenWidget->setObjectName("opVaultOpenWidget"); addChildWidget(m_mainWidget); addChildWidget(m_editEntryWidget); @@ -193,9 +187,6 @@ DatabaseWidget::DatabaseWidget(QSharedPointer db, QWidget* parent) addChildWidget(m_databaseSettingDialog); addChildWidget(m_historyEditEntryWidget); addChildWidget(m_databaseOpenWidget); - addChildWidget(m_csvImportWizard); - addChildWidget(m_keepass1OpenWidget); - addChildWidget(m_opVaultOpenWidget); // clang-format off connect(m_mainSplitter, SIGNAL(splitterMoved(int,int)), SIGNAL(splitterSizesChanged())); @@ -216,9 +207,6 @@ DatabaseWidget::DatabaseWidget(QSharedPointer db, QWidget* parent) connect(m_reportsDialog, SIGNAL(editFinished(bool)), SLOT(switchToMainView(bool))); connect(m_databaseSettingDialog, SIGNAL(editFinished(bool)), SLOT(switchToMainView(bool))); connect(m_databaseOpenWidget, SIGNAL(dialogFinished(bool)), SLOT(loadDatabase(bool))); - connect(m_keepass1OpenWidget, SIGNAL(dialogFinished(bool)), SLOT(loadDatabase(bool))); - connect(m_opVaultOpenWidget, SIGNAL(dialogFinished(bool)), SLOT(loadDatabase(bool))); - connect(m_csvImportWizard, SIGNAL(importFinished(bool)), SLOT(csvImportFinished(bool))); connect(this, SIGNAL(currentChanged(int)), SLOT(emitCurrentModeChanged())); connect(this, SIGNAL(requestGlobalAutoType(const QString&)), parent, SLOT(performGlobalAutoType(const QString&))); // clang-format on @@ -273,10 +261,8 @@ DatabaseWidget::Mode DatabaseWidget::currentMode() const return Mode::None; } else if (currentWidget() == m_mainWidget) { return Mode::ViewMode; - } else if (currentWidget() == m_databaseOpenWidget || currentWidget() == m_keepass1OpenWidget) { + } else if (currentWidget() == m_databaseOpenWidget) { return Mode::LockedMode; - } else if (currentWidget() == m_csvImportWizard) { - return Mode::ImportMode; } else { return Mode::EditMode; } @@ -327,6 +313,45 @@ bool DatabaseWidget::isEditWidgetModified() const return false; } +QString DatabaseWidget::displayName() const +{ + if (!m_db) { + return {}; + } + + auto displayName = m_db->metadata()->name(); + if (!m_db->filePath().isEmpty()) { + if (displayName.isEmpty()) { + displayName = displayFileName(); + } + } else { + if (displayName.isEmpty()) { + displayName = tr("New Database"); + } else { + displayName = tr("%1 [New Database]", "Database tab name modifier").arg(displayName); + } + } + + return displayName; +} + +QString DatabaseWidget::displayFileName() const +{ + if (m_db) { + QFileInfo fileinfo(m_db->filePath()); + return fileinfo.fileName(); + } + return {}; +} + +QString DatabaseWidget::displayFilePath() const +{ + if (m_db) { + return m_db->canonicalFilePath(); + } + return {}; +} + QHash> DatabaseWidget::splitterSizes() const { return {{Config::GUI_SplitterState, m_mainSplitter->sizes()}, @@ -1341,33 +1366,6 @@ void DatabaseWidget::switchToOpenDatabase(const QString& filePath, const QString m_databaseOpenWidget->enterKey(password, keyFile); } -void DatabaseWidget::switchToCsvImport(const QString& filePath) -{ - setCurrentWidget(m_csvImportWizard); - m_csvImportWizard->load(filePath, m_db.data()); -} - -void DatabaseWidget::csvImportFinished(bool accepted) -{ - if (!accepted) { - emit closeRequest(); - } else { - switchToMainView(); - } -} - -void DatabaseWidget::switchToImportKeepass1(const QString& filePath) -{ - m_keepass1OpenWidget->load(filePath); - setCurrentWidget(m_keepass1OpenWidget); -} - -void DatabaseWidget::switchToImportOpVault(const QString& fileName) -{ - m_opVaultOpenWidget->load(fileName); - setCurrentWidget(m_opVaultOpenWidget); -} - void DatabaseWidget::switchToEntryEdit() { auto entry = m_entryView->currentEntry(); diff --git a/src/gui/DatabaseWidget.h b/src/gui/DatabaseWidget.h index 1102245bd..681260009 100644 --- a/src/gui/DatabaseWidget.h +++ b/src/gui/DatabaseWidget.h @@ -19,35 +19,29 @@ #ifndef KEEPASSX_DATABASEWIDGET_H #define KEEPASSX_DATABASEWIDGET_H -#include -#include +#include #include -#include "DatabaseOpenDialog.h" -#include "config-keepassx.h" +#include "core/Database.h" +#include "core/Group.h" +#include "core/Metadata.h" #include "gui/MessageWidget.h" -#include "gui/csvImport/CsvImportWizard.h" #include "gui/entry/EntryModel.h" +class DatabaseOpenDialog; class DatabaseOpenWidget; -class KeePass1OpenWidget; -class OpVaultOpenWidget; class DatabaseSettingsDialog; class ReportsDialog; -class Database; class FileWatcher; class EditEntryWidget; class EditGroupWidget; -class Entry; class EntryView; class EntrySearcher; -class Group; class GroupView; class QFile; class QMenu; class QSplitter; class QLabel; -class MessageWidget; class EntryPreviewWidget; class TagView; class ElidedLabel; @@ -67,7 +61,6 @@ public: enum class Mode { None, - ImportMode, ViewMode, EditMode, LockedMode @@ -104,6 +97,10 @@ public: int numberOfSelectedEntries() const; int currentEntryIndex() const; + QString displayName() const; + QString displayFileName() const; + QString displayFilePath() const; + QStringList customEntryAttributes() const; bool isEditWidgetModified() const; void clearAllWidgets(); @@ -219,11 +216,7 @@ public slots: void switchToOpenDatabase(); void switchToOpenDatabase(const QString& filePath); void switchToOpenDatabase(const QString& filePath, const QString& password, const QString& keyFile); - void switchToCsvImport(const QString& filePath); void performUnlockDatabase(const QString& password, const QString& keyfile = {}); - void csvImportFinished(bool accepted); - void switchToImportKeepass1(const QString& filePath); - void switchToImportOpVault(const QString& fileName); void emptyRecycleBin(); // Search related slots @@ -288,15 +281,12 @@ private: QPointer m_previewSplitter; QPointer m_searchingLabel; QPointer m_shareLabel; - QPointer m_csvImportWizard; QPointer m_editEntryWidget; QPointer m_editGroupWidget; QPointer m_historyEditEntryWidget; QPointer m_reportsDialog; QPointer m_databaseSettingDialog; QPointer m_databaseOpenWidget; - QPointer m_keepass1OpenWidget; - QPointer m_opVaultOpenWidget; QPointer m_groupView; QPointer m_tagView; QPointer m_entryView; diff --git a/src/gui/EntryPreviewWidget.cpp b/src/gui/EntryPreviewWidget.cpp index 64b85a9a8..ce2e95a30 100644 --- a/src/gui/EntryPreviewWidget.cpp +++ b/src/gui/EntryPreviewWidget.cpp @@ -31,7 +31,7 @@ #endif #include - +#include namespace { constexpr int GeneralTabIndex = 0; diff --git a/src/gui/EntryPreviewWidget.h b/src/gui/EntryPreviewWidget.h index f4ea8be66..83af07ee9 100644 --- a/src/gui/EntryPreviewWidget.h +++ b/src/gui/EntryPreviewWidget.h @@ -26,6 +26,7 @@ namespace Ui class EntryPreviewWidget; } +class QTabWidget; class QTextEdit; class EntryPreviewWidget : public QWidget diff --git a/src/gui/Icons.cpp b/src/gui/Icons.cpp index 8dd0c8d0a..0935bd41e 100644 --- a/src/gui/Icons.cpp +++ b/src/gui/Icons.cpp @@ -18,6 +18,7 @@ #include "Icons.h" +#include #include #include #include @@ -25,6 +26,7 @@ #include "config-keepassx.h" #include "core/Config.h" +#include "core/Database.h" #include "gui/DatabaseIcons.h" #include "gui/MainWindow.h" #include "gui/osutils/OSUtils.h" diff --git a/src/gui/KeePass1OpenWidget.cpp b/src/gui/KeePass1OpenWidget.cpp deleted file mode 100644 index 9a485a7f1..000000000 --- a/src/gui/KeePass1OpenWidget.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2012 Felix Geyer - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 or (at your option) - * version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "KeePass1OpenWidget.h" -#include "ui_DatabaseOpenWidget.h" - -#include - -#include "core/Database.h" -#include "core/Metadata.h" -#include "format/KeePass1Reader.h" - -KeePass1OpenWidget::KeePass1OpenWidget(QWidget* parent) - : DatabaseOpenWidget(parent) -{ - m_ui->labelHeadline->setText(tr("Import KeePass1 Database")); -} - -void KeePass1OpenWidget::openDatabase() -{ - KeePass1Reader reader; - - QString password; - QString keyFileName = m_ui->keyFileLineEdit->text(); - - if (!m_ui->editPassword->text().isEmpty() || m_retryUnlockWithEmptyPassword) { - password = m_ui->editPassword->text(); - } - - QFile file(m_filename); - if (!file.open(QIODevice::ReadOnly)) { - m_ui->messageWidget->showMessage(tr("Unable to open the database.").append("\n").append(file.errorString()), - MessageWidget::Error); - return; - } - - QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - m_db = reader.readDatabase(&file, password, keyFileName); - QApplication::restoreOverrideCursor(); - - if (m_db) { - m_db->metadata()->setName(QFileInfo(m_filename).completeBaseName()); - emit dialogFinished(true); - clearForms(); - } else { - m_ui->messageWidget->showMessage(tr("Unable to open the database.").append("\n").append(reader.errorString()), - MessageWidget::Error); - } -} diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 2b92894f3..c97e04936 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -354,7 +354,7 @@ MainWindow::MainWindow() m_ui->actionLockAllDatabases->setIcon(icons()->icon("database-lock-all")); m_ui->actionQuit->setIcon(icons()->icon("application-exit")); m_ui->actionDatabaseMerge->setIcon(icons()->icon("database-merge")); - m_ui->menuImport->setIcon(icons()->icon("document-import")); + m_ui->actionImport->setIcon(icons()->icon("document-import")); m_ui->menuExport->setIcon(icons()->icon("document-export")); m_ui->actionEntryNew->setIcon(icons()->icon("entry-new")); @@ -464,9 +464,7 @@ MainWindow::MainWindow() connect(m_ui->actionImportPasskey, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importPasskey())); connect(m_ui->actionEntryImportPasskey, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importPasskeyToEntry())); #endif - connect(m_ui->actionImportCsv, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importCsv())); - connect(m_ui->actionImportKeePass1, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importKeePass1Database())); - connect(m_ui->actionImportOpVault, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importOpVaultDatabase())); + connect(m_ui->actionImport, SIGNAL(triggered()), m_ui->tabWidget, SLOT(importFile())); connect(m_ui->actionExportCsv, SIGNAL(triggered()), m_ui->tabWidget, SLOT(exportToCsv())); connect(m_ui->actionExportHtml, SIGNAL(triggered()), m_ui->tabWidget, SLOT(exportToHtml())); connect(m_ui->actionExportXML, SIGNAL(triggered()), m_ui->tabWidget, SLOT(exportToXML())); @@ -532,9 +530,7 @@ MainWindow::MainWindow() connect(m_ui->welcomeWidget, SIGNAL(newDatabase()), SLOT(switchToNewDatabase())); connect(m_ui->welcomeWidget, SIGNAL(openDatabase()), SLOT(switchToOpenDatabase())); connect(m_ui->welcomeWidget, SIGNAL(openDatabaseFile(QString)), SLOT(switchToDatabaseFile(QString))); - connect(m_ui->welcomeWidget, SIGNAL(importKeePass1Database()), SLOT(switchToKeePass1Database())); - connect(m_ui->welcomeWidget, SIGNAL(importOpVaultDatabase()), SLOT(switchToOpVaultDatabase())); - connect(m_ui->welcomeWidget, SIGNAL(importCsv()), SLOT(switchToCsvImport())); + connect(m_ui->welcomeWidget, SIGNAL(importFile()), m_ui->tabWidget, SLOT(importFile())); connect(m_ui->actionAbout, SIGNAL(triggered()), SLOT(showAboutDialog())); connect(m_ui->actionDonate, SIGNAL(triggered()), SLOT(openDonateUrl())); @@ -863,7 +859,7 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode) m_ui->actionDatabaseNew->setEnabled(inDatabaseTabWidgetOrWelcomeWidget); m_ui->actionDatabaseOpen->setEnabled(inDatabaseTabWidgetOrWelcomeWidget); m_ui->menuRecentDatabases->setEnabled(inDatabaseTabWidgetOrWelcomeWidget); - m_ui->menuImport->setEnabled(inDatabaseTabWidgetOrWelcomeWidget); + m_ui->actionImport->setEnabled(inDatabaseTabWidgetOrWelcomeWidget); m_ui->actionLockDatabase->setEnabled(m_ui->tabWidget->hasLockableDatabases()); m_ui->actionLockDatabaseToolbar->setEnabled(m_ui->tabWidget->hasLockableDatabases()); m_ui->actionLockAllDatabases->setEnabled(m_ui->tabWidget->hasLockableDatabases()); @@ -977,7 +973,6 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode) break; } case DatabaseWidget::Mode::EditMode: - case DatabaseWidget::Mode::ImportMode: case DatabaseWidget::Mode::LockedMode: { // Enable select actions when editing an entry bool editEntryActive = dbWidget->isEntryEditActive(); @@ -1291,24 +1286,6 @@ void MainWindow::switchToDatabaseFile(const QString& file) switchToDatabases(); } -void MainWindow::switchToKeePass1Database() -{ - m_ui->tabWidget->importKeePass1Database(); - switchToDatabases(); -} - -void MainWindow::switchToOpVaultDatabase() -{ - m_ui->tabWidget->importOpVaultDatabase(); - switchToDatabases(); -} - -void MainWindow::switchToCsvImport() -{ - m_ui->tabWidget->importCsv(); - switchToDatabases(); -} - void MainWindow::databaseStatusChanged(DatabaseWidget* dbWidget) { Q_UNUSED(dbWidget); diff --git a/src/gui/MainWindow.h b/src/gui/MainWindow.h index 5d6e07062..c47c0d205 100644 --- a/src/gui/MainWindow.h +++ b/src/gui/MainWindow.h @@ -24,6 +24,7 @@ #include #include #include +#include #include "core/SignalMultiplexer.h" #include "gui/DatabaseWidget.h" @@ -124,9 +125,6 @@ private slots: void switchToNewDatabase(); void switchToOpenDatabase(); void switchToDatabaseFile(const QString& file); - void switchToKeePass1Database(); - void switchToOpVaultDatabase(); - void switchToCsvImport(); void databaseStatusChanged(DatabaseWidget* dbWidget); void databaseTabChanged(int tabIndex); void openRecentDatabase(QAction* action); diff --git a/src/gui/MainWindow.ui b/src/gui/MainWindow.ui index d34d802b2..e1e1843a0 100644 --- a/src/gui/MainWindow.ui +++ b/src/gui/MainWindow.ui @@ -231,14 +231,6 @@ &Recent Databases - - - &Import - - - - - &Export @@ -266,7 +258,7 @@ - + @@ -1271,6 +1263,19 @@ Toggle Allow Screen Capture + + + 1Password 1PUX... + + + Import a 1Password 1PUX file + + + + + Import… + + diff --git a/src/gui/OpVaultOpenWidget.cpp b/src/gui/OpVaultOpenWidget.cpp deleted file mode 100644 index cae569cf2..000000000 --- a/src/gui/OpVaultOpenWidget.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2019 KeePassXC Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 or (at your option) - * version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "OpVaultOpenWidget.h" - -#include "core/Database.h" -#include "format/OpVaultReader.h" -#include "ui_DatabaseOpenWidget.h" - -OpVaultOpenWidget::OpVaultOpenWidget(QWidget* parent) - : DatabaseOpenWidget(parent) -{ - m_ui->labelHeadline->setText("Import 1Password Database"); -} - -void OpVaultOpenWidget::openDatabase() -{ - OpVaultReader reader; - - QString password; - password = m_ui->editPassword->text(); - - QDir opVaultDir(m_filename); - - QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - m_db.reset(reader.readDatabase(opVaultDir, password)); - QApplication::restoreOverrideCursor(); - - if (m_db) { - emit dialogFinished(true); - } else { - m_ui->messageWidget->showMessage(tr("Read Database did not produce an instance\n%1").arg(reader.errorString()), - MessageWidget::Error); - m_ui->editPassword->clear(); - } -} diff --git a/src/gui/PasswordWidget.h b/src/gui/PasswordWidget.h index 0014b696f..d803b1f81 100644 --- a/src/gui/PasswordWidget.h +++ b/src/gui/PasswordWidget.h @@ -33,6 +33,7 @@ class PasswordWidget : public QWidget { Q_OBJECT + Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged USER true) public: explicit PasswordWidget(QWidget* parent = nullptr); ~PasswordWidget() override; diff --git a/src/gui/TotpDialog.h b/src/gui/TotpDialog.h index 1782c2de8..d64549759 100644 --- a/src/gui/TotpDialog.h +++ b/src/gui/TotpDialog.h @@ -19,6 +19,8 @@ #ifndef KEEPASSX_TOTPDIALOG_H #define KEEPASSX_TOTPDIALOG_H +#include + #include "core/Database.h" #include "gui/DatabaseWidget.h" diff --git a/src/gui/TotpExportSettingsDialog.cpp b/src/gui/TotpExportSettingsDialog.cpp index b60657e40..f018ed9b7 100644 --- a/src/gui/TotpExportSettingsDialog.cpp +++ b/src/gui/TotpExportSettingsDialog.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include diff --git a/src/gui/TotpExportSettingsDialog.h b/src/gui/TotpExportSettingsDialog.h index 7a807cd0c..c36836f1a 100644 --- a/src/gui/TotpExportSettingsDialog.h +++ b/src/gui/TotpExportSettingsDialog.h @@ -18,6 +18,8 @@ #ifndef KEEPASSX_TotpExportSettingsDialog_H #define KEEPASSX_TotpExportSettingsDialog_H +#include + #include "core/Database.h" #include "gui/DatabaseWidget.h" diff --git a/src/gui/TotpSetupDialog.h b/src/gui/TotpSetupDialog.h index 9781b3954..3822f119f 100644 --- a/src/gui/TotpSetupDialog.h +++ b/src/gui/TotpSetupDialog.h @@ -19,6 +19,8 @@ #ifndef KEEPASSX_SETUPTOTPDIALOG_H #define KEEPASSX_SETUPTOTPDIALOG_H +#include + #include "core/Database.h" #include "gui/DatabaseWidget.h" diff --git a/src/gui/WelcomeWidget.cpp b/src/gui/WelcomeWidget.cpp index 916719c9d..d20dc2b7d 100644 --- a/src/gui/WelcomeWidget.cpp +++ b/src/gui/WelcomeWidget.cpp @@ -37,14 +37,15 @@ WelcomeWidget::WelcomeWidget(QWidget* parent) m_ui->welcomeLabel->setFont(welcomeLabelFont); m_ui->iconLabel->setPixmap(icons()->applicationIcon().pixmap(64)); + m_ui->buttonNewDatabase->setIcon(icons()->icon("document-new")); + m_ui->buttonOpenDatabase->setIcon(icons()->icon("document-open")); + m_ui->buttonImport->setIcon(icons()->icon("document-import")); refreshLastDatabases(); connect(m_ui->buttonNewDatabase, SIGNAL(clicked()), SIGNAL(newDatabase())); connect(m_ui->buttonOpenDatabase, SIGNAL(clicked()), SIGNAL(openDatabase())); - connect(m_ui->buttonImportKeePass1, SIGNAL(clicked()), SIGNAL(importKeePass1Database())); - connect(m_ui->buttonImportOpVault, SIGNAL(clicked()), SIGNAL(importOpVaultDatabase())); - connect(m_ui->buttonImportCSV, SIGNAL(clicked()), SIGNAL(importCsv())); + connect(m_ui->buttonImport, SIGNAL(clicked()), SIGNAL(importFile())); connect(m_ui->recentListWidget, SIGNAL(itemActivated(QListWidgetItem*)), this, diff --git a/src/gui/WelcomeWidget.h b/src/gui/WelcomeWidget.h index 675882340..ed92c7b4b 100644 --- a/src/gui/WelcomeWidget.h +++ b/src/gui/WelcomeWidget.h @@ -39,9 +39,7 @@ signals: void newDatabase(); void openDatabase(); void openDatabaseFile(QString); - void importKeePass1Database(); - void importOpVaultDatabase(); - void importCsv(); + void importFile(); protected: void keyPressEvent(QKeyEvent* event) override; diff --git a/src/gui/WelcomeWidget.ui b/src/gui/WelcomeWidget.ui index 8b72df840..7a753e010 100644 --- a/src/gui/WelcomeWidget.ui +++ b/src/gui/WelcomeWidget.ui @@ -70,6 +70,22 @@ + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + @@ -103,40 +119,26 @@ - - - - Create new database - - - - - - - Open existing database - - - - + - Import from KeePass 1 + Create Database - + - Import from 1Password + Open Database - + - Import from CSV + Import File @@ -148,12 +150,12 @@ Qt::Vertical - QSizePolicy::Minimum + QSizePolicy::Fixed 0 - 5 + 20 @@ -193,11 +195,7 @@ - buttonNewDatabase - buttonOpenDatabase - buttonImportKeePass1 - buttonImportOpVault - buttonImportCSV + buttonImport recentListWidget diff --git a/src/gui/csvImport/CsvImportWidget.cpp b/src/gui/csvImport/CsvImportWidget.cpp index 56743bd96..be66c50e0 100644 --- a/src/gui/csvImport/CsvImportWidget.cpp +++ b/src/gui/csvImport/CsvImportWidget.cpp @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 2016 Enrico Mariotti * Copyright (C) 2017 KeePassXC Team * @@ -19,38 +19,69 @@ #include "CsvImportWidget.h" #include "ui_CsvImportWidget.h" +#include "core/Clock.h" +#include "core/Database.h" +#include "core/Group.h" +#include "core/Totp.h" +#include "format/CsvParser.h" +#include "format/KeePass2Writer.h" +#include "gui/csvImport/CsvParserModel.h" + #include -#include "core/Clock.h" -#include "core/Totp.h" -#include "format/KeePass2Writer.h" -#include "gui/MessageBox.h" +namespace +{ + // Extract group names from nested path and return the last group created + Group* createGroupStructure(Database* db, const QString& groupPath) + { + auto group = db->rootGroup(); + if (!group || groupPath.isEmpty()) { + return group; + } -// I wanted to make the CSV import GUI future-proof, so if one day you need a new field, -// all you have to do is add a field to m_columnHeader, and the GUI will follow: -// dynamic generation of comboBoxes, labels, placement and so on. Try it for immense fun! + auto nameList = groupPath.split("/", QString::SkipEmptyParts); + // Skip over first group name if root + if (nameList.first().compare("root", Qt::CaseInsensitive)) { + nameList.removeFirst(); + } + + for (const auto& name : qAsConst(nameList)) { + auto child = group->findChildByName(name); + if (!child) { + auto newGroup = new Group(); + newGroup->setUuid(QUuid::createUuid()); + newGroup->setName(name); + newGroup->setParent(group); + group = newGroup; + } else { + group = child; + } + } + return group; + } +} // namespace CsvImportWidget::CsvImportWidget(QWidget* parent) : QWidget(parent) , m_ui(new Ui::CsvImportWidget()) , m_parserModel(new CsvParserModel(this)) , m_comboModel(new QStringListModel(this)) - , m_columnHeader(QStringList() << QObject::tr("Group") << QObject::tr("Title") << QObject::tr("Username") - << QObject::tr("Password") << QObject::tr("URL") << QObject::tr("Notes") - << QObject::tr("TOTP") << QObject::tr("Icon") << QObject::tr("Last Modified") - << QObject::tr("Created")) - , m_fieldSeparatorList(QStringList() << "," - << ";" - << "-" - << ":" - << "." - << "\t") { m_ui->setupUi(this); m_ui->tableViewFields->setSelectionMode(QAbstractItemView::NoSelection); m_ui->tableViewFields->setFocusPolicy(Qt::NoFocus); - m_ui->messageWidget->setHidden(true); + + m_columnHeader << QObject::tr("Group") << QObject::tr("Title") << QObject::tr("Username") << QObject::tr("Password") + << QObject::tr("URL") << QObject::tr("Notes") << QObject::tr("TOTP") << QObject::tr("Icon") + << QObject::tr("Last Modified") << QObject::tr("Created"); + + m_fieldSeparatorList << "," + << ";" + << "-" + << ":" + << "." + << "\t"; m_combos << m_ui->groupCombo << m_ui->titleCombo << m_ui->usernameCombo << m_ui->passwordCombo << m_ui->urlCombo << m_ui->notesCombo << m_ui->totpCombo << m_ui->iconCombo << m_ui->lastModifiedCombo << m_ui->createdCombo; @@ -70,15 +101,12 @@ CsvImportWidget::CsvImportWidget(QWidget* parent) connect(m_ui->comboBoxFieldSeparator, SIGNAL(currentIndexChanged(int)), SLOT(parse())); connect(m_ui->checkBoxBackslash, SIGNAL(toggled(bool)), SLOT(parse())); connect(m_ui->checkBoxFieldNames, SIGNAL(toggled(bool)), SLOT(updatePreview())); - - connect(m_ui->buttonBox, SIGNAL(accepted()), this, SLOT(writeDatabase())); - connect(m_ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject())); } void CsvImportWidget::comboChanged(int index) { // this line is the one that actually updates GUI table - m_parserModel->mapColumns(index, m_combos.indexOf(qobject_cast(sender()))); + m_parserModel->mapColumns(index - 1, m_combos.indexOf(qobject_cast(sender()))); updateTableview(); } @@ -92,68 +120,81 @@ CsvImportWidget::~CsvImportWidget() = default; void CsvImportWidget::configParser() { - m_parserModel->setBackslashSyntax(m_ui->checkBoxBackslash->isChecked()); - m_parserModel->setComment(m_ui->comboBoxComment->currentText().at(0)); - m_parserModel->setTextQualifier(m_ui->comboBoxTextQualifier->currentText().at(0)); - m_parserModel->setCodec(m_ui->comboBoxCodec->currentText()); - m_parserModel->setFieldSeparator(m_fieldSeparatorList.at(m_ui->comboBoxFieldSeparator->currentIndex()).at(0)); + auto parser = m_parserModel->parser(); + parser->setBackslashSyntax(m_ui->checkBoxBackslash->isChecked()); + parser->setComment(m_ui->comboBoxComment->currentText().at(0)); + parser->setTextQualifier(m_ui->comboBoxTextQualifier->currentText().at(0)); + parser->setCodec(m_ui->comboBoxCodec->currentText()); + parser->setFieldSeparator(m_fieldSeparatorList.at(m_ui->comboBoxFieldSeparator->currentIndex()).at(0)); } void CsvImportWidget::updateTableview() { - m_ui->tableViewFields->resizeRowsToContents(); - m_ui->tableViewFields->resizeColumnsToContents(); + if (!m_buildingPreview) { + m_ui->tableViewFields->resizeRowsToContents(); + m_ui->tableViewFields->resizeColumnsToContents(); - for (int c = 0; c < m_ui->tableViewFields->horizontalHeader()->count(); ++c) { - m_ui->tableViewFields->horizontalHeader()->setSectionResizeMode(c, QHeaderView::Stretch); + for (int c = 0; c < m_ui->tableViewFields->horizontalHeader()->count(); ++c) { + m_ui->tableViewFields->horizontalHeader()->setSectionResizeMode(c, QHeaderView::Stretch); + } } } void CsvImportWidget::updatePreview() { - int minSkip = 0; - if (m_ui->checkBoxFieldNames->isChecked()) { - minSkip = 1; - } + m_buildingPreview = true; + + int minSkip = m_ui->checkBoxFieldNames->isChecked() ? 1 : 0; m_ui->labelSizeRowsCols->setText(m_parserModel->getFileInfo()); m_ui->spinBoxSkip->setRange(minSkip, qMax(minSkip, m_parserModel->rowCount() - 1)); m_ui->spinBoxSkip->setValue(minSkip); - QStringList list(tr("Not Present")); - for (int i = 1; i < m_parserModel->getCsvCols(); ++i) { + QStringList csvColumns(tr("Not Present")); + auto parser = m_parserModel->parser(); + for (int i = 0; i < parser->getCsvCols(); ++i) { if (m_ui->checkBoxFieldNames->isChecked()) { - auto columnName = m_parserModel->getCsvTable().at(0).at(i); + auto columnName = parser->getCsvTable().at(0).at(i); if (columnName.isEmpty()) { - list << QString(tr("Column %1").arg(i)); + csvColumns << QString(tr("Column %1").arg(i)); } else { - list << columnName; + csvColumns << columnName; } } else { - list << QString(tr("Column %1").arg(i)); + csvColumns << QString(tr("Column %1").arg(i)); } } - m_comboModel->setStringList(list); + m_comboModel->setStringList(csvColumns); - int j = 1; - for (QComboBox* b : m_combos) { - if (j < m_parserModel->getCsvCols()) { - b->setCurrentIndex(j); - } else { - b->setCurrentIndex(0); + // Try to match named columns to the combo boxes + for (int i = 0; i < m_columnHeader.size(); ++i) { + if (i >= m_combos.size()) { + // This should not happen, it is a programming error otherwise + Q_ASSERT(false); + break; + } + + bool found = false; + for (int j = 0; j < csvColumns.size(); ++j) { + if (m_columnHeader.at(i).compare(csvColumns.at(j), Qt::CaseInsensitive) == 0) { + m_combos.at(i)->setCurrentIndex(j); + found = true; + break; + } + } + // Named column not found, default to "Not Present" + if (!found) { + m_combos.at(i)->setCurrentIndex(0); } - ++j; } + + m_buildingPreview = false; + updateTableview(); } -void CsvImportWidget::load(const QString& filename, Database* const db) +void CsvImportWidget::load(const QString& filename) { - // QApplication::processEvents(); - m_db = db; + m_filename = filename; m_parserModel->setFilename(filename); - m_ui->labelFilename->setText(filename); - Group* group = m_db->rootGroup(); - group->setUuid(QUuid::createUuid()); - group->setNotes(tr("Imported from CSV file").append("\n").append(tr("Original data: ")) + filename); parse(); } @@ -161,42 +202,33 @@ void CsvImportWidget::parse() { configParser(); QApplication::setOverrideCursor(Qt::WaitCursor); - // QApplication::processEvents(); + QApplication::processEvents(); bool good = m_parserModel->parse(); updatePreview(); QApplication::restoreOverrideCursor(); if (!good) { - m_ui->messageWidget->showMessage(tr("Error(s) detected in CSV file!").append("\n").append(formatStatusText()), - MessageWidget::Warning); - } else { - m_ui->messageWidget->setHidden(true); + emit message(tr("Failed to parse CSV file: %1").arg(formatStatusText())); } } -QString CsvImportWidget::formatStatusText() const +QSharedPointer CsvImportWidget::buildDatabase() { - QString text = m_parserModel->getStatus(); - int items = text.count('\n'); - if (items > 2) { - return text.section('\n', 0, 1).append("\n").append(tr("[%n more message(s) skipped]", "", items - 2)); - } - if (items == 1) { - text.append(QString("\n")); - } - return text; -} + auto db = QSharedPointer::create(); + db->rootGroup()->setNotes(tr("Imported from CSV file: %1").arg(m_filename)); -void CsvImportWidget::writeDatabase() -{ - setRootGroup(); for (int r = 0; r < m_parserModel->rowCount(); ++r) { // use validity of second column as a GO/NOGO for all others fields - if (not m_parserModel->data(m_parserModel->index(r, 1)).isValid()) { + if (!m_parserModel->data(m_parserModel->index(r, 1)).isValid()) { continue; } + auto group = createGroupStructure(db.data(), m_parserModel->data(m_parserModel->index(r, 0)).toString()); + if (!group) { + continue; + } + auto entry = new Entry(); entry->setUuid(QUuid::createUuid()); - entry->setGroup(splitGroups(m_parserModel->data(m_parserModel->index(r, 0)).toString())); + entry->setGroup(group); entry->setTitle(m_parserModel->data(m_parserModel->index(r, 1)).toString()); entry->setUsername(m_parserModel->data(m_parserModel->index(r, 2)).toString()); entry->setPassword(m_parserModel->data(m_parserModel->index(r, 3)).toString()); @@ -255,99 +287,19 @@ void CsvImportWidget::writeDatabase() } entry->setTimeInfo(timeInfo); } - QBuffer buffer; - buffer.open(QBuffer::ReadWrite); - KeePass2Writer writer; - writer.writeDatabase(&buffer, m_db); - if (writer.hasError()) { - MessageBox::warning(this, - tr("Error"), - tr("CSV import: writer has errors:\n%1").arg(writer.errorString()), - MessageBox::Ok, - MessageBox::Ok); - } - emit editFinished(true); + return db; } -void CsvImportWidget::setRootGroup() +QString CsvImportWidget::formatStatusText() const { - QString groupLabel; - QStringList groupList; - bool is_root = false; - bool is_empty = false; - bool is_label = false; - - for (int r = 0; r < m_parserModel->rowCount(); ++r) { - // use validity of second column as a GO/NOGO for all others fields - if (not m_parserModel->data(m_parserModel->index(r, 1)).isValid()) { - continue; - } - groupLabel = m_parserModel->data(m_parserModel->index(r, 0)).toString(); - // check if group name is either "root", "" (empty) or some other label - groupList = groupLabel.split("/", QString::SkipEmptyParts); - if (groupList.isEmpty()) { - is_empty = true; - } else if (not groupList.first().compare("Root", Qt::CaseSensitive)) { - is_root = true; - } else if (not groupLabel.compare("")) { - is_empty = true; - } else { - is_label = true; - } - - groupList.clear(); + QString text = m_parserModel->parser()->getStatus(); + int items = text.count('\n'); + if (items > 2) { + return text.section('\n', 0, 1).append("\n").append(tr("[%n more message(s) skipped]", "", items - 2)); } - - if ((is_empty and is_root) or (is_label and not is_empty and is_root)) { - m_db->rootGroup()->setName("CSV IMPORTED"); - } else { - m_db->rootGroup()->setName("Root"); + if (items == 1) { + text.append(QString("\n")); } -} - -Group* CsvImportWidget::splitGroups(const QString& label) -{ - // extract group names from nested path provided in "label" - Group* current = m_db->rootGroup(); - if (label.isEmpty()) { - return current; - } - - QStringList groupList = label.split("/", QString::SkipEmptyParts); - // avoid the creation of a subgroup with the same name as Root - if (m_db->rootGroup()->name() == "Root" && groupList.first() == "Root") { - groupList.removeFirst(); - } - - for (const QString& groupName : groupList) { - Group* children = hasChildren(current, groupName); - if (children == nullptr) { - auto brandNew = new Group(); - brandNew->setParent(current); - brandNew->setName(groupName); - brandNew->setUuid(QUuid::createUuid()); - current = brandNew; - } else { - Q_ASSERT(children != nullptr); - current = children; - } - } - return current; -} - -Group* CsvImportWidget::hasChildren(Group* current, const QString& groupName) -{ - // returns the group whose name is "groupName" and is child of "current" group - for (Group* group : current->children()) { - if (group->name() == groupName) { - return group; - } - } - return nullptr; -} - -void CsvImportWidget::reject() -{ - emit editFinished(false); + return text; } diff --git a/src/gui/csvImport/CsvImportWidget.h b/src/gui/csvImport/CsvImportWidget.h index 2f09c7b13..c428d7200 100644 --- a/src/gui/csvImport/CsvImportWidget.h +++ b/src/gui/csvImport/CsvImportWidget.h @@ -19,12 +19,13 @@ #ifndef KEEPASSX_CSVIMPORTWIDGET_H #define KEEPASSX_CSVIMPORTWIDGET_H -#include +#include +#include -#include "core/Metadata.h" -#include "gui/csvImport/CsvParserModel.h" - -class QStringListModel; +class CsvParserModel; +class Database; +class Group; +class QComboBox; namespace Ui { @@ -38,35 +39,35 @@ class CsvImportWidget : public QWidget public: explicit CsvImportWidget(QWidget* parent = nullptr); ~CsvImportWidget() override; - void load(const QString& filename, Database* const db); + + void load(const QString& filename); + QSharedPointer buildDatabase(); signals: - void editFinished(bool accepted); + void message(QString msg); private slots: void parse(); void comboChanged(int index); void skippedChanged(int rows); - void writeDatabase(); void updatePreview(); - void setRootGroup(); - void reject(); private: - Q_DISABLE_COPY(CsvImportWidget) - const QScopedPointer m_ui; - CsvParserModel* const m_parserModel; - QStringListModel* const m_comboModel; - QList m_combos; - Database* m_db; - - const QStringList m_columnHeader; - QStringList m_fieldSeparatorList; void configParser(); void updateTableview(); - Group* splitGroups(const QString& label); - Group* hasChildren(Group* current, const QString& groupName); QString formatStatusText() const; + + QScopedPointer m_ui; + + CsvParserModel* m_parserModel; + QStringListModel* m_comboModel; + QList m_combos; + QStringList m_columnHeader; + QStringList m_fieldSeparatorList; + QString m_filename; + bool m_buildingPreview = false; + + Q_DISABLE_COPY(CsvImportWidget) }; #endif // KEEPASSX_CSVIMPORTWIDGET_H diff --git a/src/gui/csvImport/CsvImportWidget.ui b/src/gui/csvImport/CsvImportWidget.ui index 7a5627d98..cd7af9816 100644 --- a/src/gui/csvImport/CsvImportWidget.ui +++ b/src/gui/csvImport/CsvImportWidget.ui @@ -6,763 +6,677 @@ 0 0 - 788 - 530 + 820 + 523 + + 0 + + + 0 + + + 0 + + + 0 + - - - - - - Qt::ScrollBarAlwaysOff - - - true - - - - - 0 - 0 - 753 - 615 - - - - - - - - 11 - 75 - true - - - - Import CSV fields - - - - - - - - - filename - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - size, rows, columns - - - - - - - - - - - - 75 - true - - - - Column Association - - - - - - - - - - - - 50 - false - - - - Password - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 2 - - - - - - - - 50 - false - - - - Username - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 2 - - - - - - - - - - - - - - 50 - false - - - - Title - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 2 - - - - - - - - - - - 50 - false - - - - Group - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 2 - - - - - - - - 50 - false - - - - URL - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 2 - - - - - - - - - - - 50 - false - - - - Notes - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 2 - - - - - - - - - - - 50 - false - - - - TOTP - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 2 - - - - - - - - - - - - - - 50 - false - - - - Created - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 2 - - - - - - - - 50 - false - - - - Last Modified - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 2 - - - - - - - - - - - 50 - false - - - - Icon - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 2 - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - 75 - true - - - - Encoding - - - - - - - 50 - false - - - - Codec - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 50 - false - - - - Codec - - - false - - - UTF-8 - - - - UTF-8 - - - - - Windows-1252 - - - - - UTF-16 - - - - - UTF-16LE - - - - - - - - - 50 - false - - - - Text is qualified by - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 50 - false - - - - Text qualification - - - false - - - " - - - - " - - - - - ' - - - - - : - - - - - . - - - - - | - - - - - - - - - 50 - false - - - - Fields are separated by - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 50 - false - - - - Field separation - - - false - - - , - - - - , - - - - - ; - - - - - - - - - - - : - - - - - . - - - - - TAB (\t) - - - - - - - - - 50 - false - - - - Comments start with - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 50 - false - - - - Comments start with - - - false - - - # - - - - # - - - - - ; - - - - - : - - - - - @ - - - - - - - - - 50 - false - - - - Header lines skipped - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - 50 - false - - - - Number of header lines to discard - - - - - - - Qt::Horizontal - - - - 122 - 20 - - - - - - - - - - - 50 - false - - - - First line has field names - - - - - - - - 50 - false - - - - Consider '\' an escape character - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - 75 - true - - - - Preview - - - false - - + + + + + + 75 + true + + + + Column Association + + + + + + + 50 + false + + + + Icon + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + + 50 + false + + + + TOTP + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + + + + + 50 + false + + + + Notes + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + + 50 + false + + + + Title + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + + + + + + + + + + + + + + 50 + false + + + + First line has field names + + + true + + + + + + + + + + + + + + 50 + false + + + + Password + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + + 50 + false + + + + Group + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + + + + + 50 + false + + + + Username + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + + 50 + false + + + + URL + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + + + + + 50 + false + + + + Created + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + + + + + 50 + false + + + + Last Modified + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 2 + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 6 + 20 + + + + + + + + + + + + 75 + true + + + + Encoding + + + + + + + 50 + false + + + + Codec + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 50 + false + + + + Codec + + + false + + + UTF-8 + - - - - 0 - 0 - - - - - 0 - 300 - - - - - 50 - false - - - - CSV import preview - - - false - - - true - - + + UTF-8 + - - - - - - + + + Windows-1252 + + + + + UTF-16 + + + + + UTF-16LE + + + + + + + + + 50 + false + + + + Text is qualified by + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 50 + false + + + + Text qualification + + + false + + + " + + + + " + + + + + ' + + + + + : + + + + + . + + + + + | + + + + + + + + + 50 + false + + + + Fields are separated by + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 50 + false + + + + Field separation + + + false + + + , + + + + , + + + + + ; + + + + + - + + + + + : + + + + + . + + + + + TAB (\t) + + + + + + + + + 50 + false + + + + Comments start with + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 50 + false + + + + Comments start with + + + false + + + # + + + + # + + + + + ; + + + + + : + + + + + @ + + + + + + + + + 50 + false + + + + Header lines skipped + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 50 + false + + + + Number of header lines to discard + + + + + + + + 50 + false + + + + Consider '\' an escape character + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + 75 + true + - + + Preview + + false + + + 3 + + + 0 + + + + + + 50 + false + + + + size, rows, columns + + + + + + + + 0 + 0 + + + + + 800 + 300 + + + + + 50 + false + + + + CSV import preview + + + false + + + true + + + + - - - MessageWidget - QWidget -

gui/MessageWidget.h
- 1 - - - scrollArea - groupCombo - titleCombo - usernameCombo - passwordCombo - urlCombo - notesCombo - totpCombo - iconCombo - lastModifiedCombo - createdCombo comboBoxCodec comboBoxTextQualifier comboBoxFieldSeparator comboBoxComment - spinBoxSkip - checkBoxFieldNames - checkBoxBackslash tableViewFields diff --git a/src/gui/csvImport/CsvImportWizard.cpp b/src/gui/csvImport/CsvImportWizard.cpp deleted file mode 100644 index d0856023e..000000000 --- a/src/gui/csvImport/CsvImportWizard.cpp +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2016 Enrico Mariotti - * Copyright (C) 2017 KeePassXC Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 or (at your option) - * version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "CsvImportWizard.h" - -#include - -CsvImportWizard::CsvImportWizard(QWidget* parent) - : DialogyWidget(parent) -{ - m_layout = new QGridLayout(this); - m_layout->addWidget(m_parse = new CsvImportWidget(this), 0, 0); - - connect(m_parse, SIGNAL(editFinished(bool)), this, SLOT(parseFinished(bool))); -} - -CsvImportWizard::~CsvImportWizard() = default; - -void CsvImportWizard::load(const QString& filename, Database* database) -{ - m_db = database; - m_parse->load(filename, database); -} - -void CsvImportWizard::parseFinished(bool accepted) -{ - emit importFinished(accepted); -} diff --git a/src/gui/csvImport/CsvImportWizard.h b/src/gui/csvImport/CsvImportWizard.h deleted file mode 100644 index 084d8794d..000000000 --- a/src/gui/csvImport/CsvImportWizard.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2016 Enrico Mariotti - * Copyright (C) 2017 KeePassXC Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 or (at your option) - * version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef KEEPASSX_CSVIMPORTWIZARD_H -#define KEEPASSX_CSVIMPORTWIZARD_H - -#include "CsvImportWidget.h" - -#include "gui/DialogyWidget.h" - -class QGridLayout; - -class CsvImportWidget; - -class CsvImportWizard : public DialogyWidget -{ - Q_OBJECT - -public: - explicit CsvImportWizard(QWidget* parent = nullptr); - ~CsvImportWizard() override; - void load(const QString& filename, Database* database); - -signals: - void importFinished(bool accepted); - -private slots: - void parseFinished(bool accepted); - -private: - QPointer m_db; - CsvImportWidget* m_parse; - QGridLayout* m_layout; -}; - -#endif // KEEPASSX_CSVIMPORTWIZARD_H diff --git a/src/gui/csvImport/CsvParserModel.cpp b/src/gui/csvImport/CsvParserModel.cpp index 45675d0c4..eb59157d3 100644 --- a/src/gui/csvImport/CsvParserModel.cpp +++ b/src/gui/csvImport/CsvParserModel.cpp @@ -18,16 +18,25 @@ #include "CsvParserModel.h" +#include "core/Tools.h" +#include "format/CsvParser.h" + #include CsvParserModel::CsvParserModel(QObject* parent) : QAbstractTableModel(parent) + , m_parser(new CsvParser()) , m_skipped(0) { } CsvParserModel::~CsvParserModel() = default; +CsvParser* CsvParserModel::parser() +{ + return m_parser; +} + void CsvParserModel::setFilename(const QString& filename) { m_filename = filename; @@ -35,11 +44,10 @@ void CsvParserModel::setFilename(const QString& filename) QString CsvParserModel::getFileInfo() { - QString a(tr("%1, %2, %3", "file info: bytes, rows, columns") - .arg(tr("%n byte(s)", nullptr, getFileSize()), - tr("%n row(s)", nullptr, getCsvRows()), - tr("%n column(s)", nullptr, qMax(0, getCsvCols() - 1)))); - return a; + return QString("%1, %2, %3") + .arg(Tools::humanReadableFileSize(m_parser->getFileSize()), + tr("%n row(s)", "CSV row count", m_parser->getCsvRows()), + tr("%n column(s)", "CSV column count", qMax(0, m_parser->getCsvCols() - 1))); } bool CsvParserModel::parse() @@ -47,37 +55,28 @@ bool CsvParserModel::parse() bool r; beginResetModel(); m_columnMap.clear(); - if (CsvParser::isFileLoaded()) { - r = CsvParser::reparse(); + if (m_parser->isFileLoaded()) { + r = m_parser->reparse(); } else { QFile csv(m_filename); - r = CsvParser::parse(&csv); + r = m_parser->parse(&csv); } for (int i = 0; i < columnCount(); ++i) { m_columnMap.insert(i, 0); } - addEmptyColumn(); endResetModel(); return r; } -void CsvParserModel::addEmptyColumn() -{ - for (int i = 0; i < m_table.size(); ++i) { - CsvRow r = m_table.at(i); - r.prepend(QString("")); - m_table.replace(i, r); - } -} - void CsvParserModel::mapColumns(int csvColumn, int dbColumn) { - if ((csvColumn < 0) || (dbColumn < 0)) { + if (dbColumn < 0 || dbColumn >= m_columnMap.size()) { return; } beginResetModel(); - if (csvColumn >= getCsvCols()) { - m_columnMap[dbColumn] = 0; // map to the empty column + if (csvColumn < 0 || csvColumn >= m_parser->getCsvCols()) { + // This indicates a blank cell + m_columnMap[dbColumn] = -1; } else { m_columnMap[dbColumn] = csvColumn; } @@ -103,7 +102,7 @@ int CsvParserModel::rowCount(const QModelIndex& parent) const if (parent.isValid()) { return 0; } - return getCsvRows(); + return m_parser->getCsvRows(); } int CsvParserModel::columnCount(const QModelIndex& parent) const @@ -116,11 +115,14 @@ int CsvParserModel::columnCount(const QModelIndex& parent) const QVariant CsvParserModel::data(const QModelIndex& index, int role) const { - if ((index.column() >= m_columnHeader.size()) || (index.row() + m_skipped >= rowCount()) || !index.isValid()) { + if (index.column() >= m_columnHeader.size() || index.row() + m_skipped >= rowCount() || !index.isValid()) { return {}; } if (role == Qt::DisplayRole) { - return m_table.at(index.row() + m_skipped).at(m_columnMap[index.column()]); + auto column = m_columnMap[index.column()]; + if (column >= 0) { + return m_parser->getCsvTable().at(index.row() + m_skipped).at(column); + } } return {}; } @@ -129,15 +131,13 @@ QVariant CsvParserModel::headerData(int section, Qt::Orientation orientation, in { if (role == Qt::DisplayRole) { if (orientation == Qt::Horizontal) { - if ((section < 0) || (section >= m_columnHeader.size())) { - return {}; + if (section >= 0 && section < m_columnHeader.size()) { + return m_columnHeader.at(section); } - return m_columnHeader.at(section); } else if (orientation == Qt::Vertical) { - if (section + m_skipped >= rowCount()) { - return {}; + if (section + m_skipped < rowCount()) { + return QString::number(section + 1); } - return QString::number(section + 1); } } return {}; diff --git a/src/gui/csvImport/CsvParserModel.h b/src/gui/csvImport/CsvParserModel.h index aec430958..2717b826d 100644 --- a/src/gui/csvImport/CsvParserModel.h +++ b/src/gui/csvImport/CsvParserModel.h @@ -21,20 +21,22 @@ #include -#include "core/Group.h" -#include "format/CsvParser.h" +class CsvParser; -class CsvParserModel : public QAbstractTableModel, public CsvParser +class CsvParserModel : public QAbstractTableModel { Q_OBJECT public: explicit CsvParserModel(QObject* parent = nullptr); ~CsvParserModel() override; + void setFilename(const QString& filename); QString getFileInfo(); bool parse(); + CsvParser* parser(); + void setHeaderLabels(const QStringList& labels); void mapColumns(int csvColumn, int dbColumn); @@ -47,12 +49,12 @@ public slots: void setSkippedRows(int skipped); private: + CsvParser* m_parser; int m_skipped; QString m_filename; QStringList m_columnHeader; // first column of model must be empty (aka combobox row "Not present in CSV file") void addEmptyColumn(); - // mapping CSV columns to keepassx columns QMap m_columnMap; }; diff --git a/src/gui/tag/TagsEdit.cpp b/src/gui/tag/TagsEdit.cpp index 6a8becbd0..bd4dabb57 100644 --- a/src/gui/tag/TagsEdit.cpp +++ b/src/gui/tag/TagsEdit.cpp @@ -24,6 +24,7 @@ #include "TagsEdit.h" #include "gui/MainWindow.h" +#include #include #include #include diff --git a/src/gui/wizard/ImportWizard.cpp b/src/gui/wizard/ImportWizard.cpp new file mode 100644 index 000000000..05fdbfe38 --- /dev/null +++ b/src/gui/wizard/ImportWizard.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2018 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ImportWizard.h" +#include "ImportWizardPageReview.h" +#include "ImportWizardPageSelect.h" + +#include "core/Global.h" +#include "core/Group.h" + +#include +#include + +ImportWizard::ImportWizard(QWidget* parent) + : QWizard(parent) + , m_pageSelect(new ImportWizardPageSelect) + , m_pageReview(new ImportWizardPageReview) +{ + setWizardStyle(MacStyle); + setOption(HaveHelpButton, false); + setOption(NoDefaultButton, false); // Needed for macOS + + addPage(m_pageSelect.data()); + addPage(m_pageReview.data()); + + setWindowTitle(tr("Import Wizard")); + + Q_INIT_RESOURCE(wizard); + setPixmap(BackgroundPixmap, QPixmap(":/wizard/background-pixmap.png")); + + // Fix MacStyle QWizard page frame too bright in dark mode (QTBUG-70346, QTBUG-71696) + QPalette defaultPalette; + auto windowColor = defaultPalette.color(QPalette::Window); + windowColor.setAlpha(153); + auto baseColor = defaultPalette.color(QPalette::Base); + baseColor.setAlpha(153); + + auto* pageFrame = findChildren()[0]; + auto framePalette = pageFrame->palette(); + framePalette.setBrush(QPalette::Window, windowColor.lighter(120)); + framePalette.setBrush(QPalette::Base, baseColor.lighter(120)); + pageFrame->setPalette(framePalette); +} + +ImportWizard::~ImportWizard() +{ +} + +bool ImportWizard::validateCurrentPage() +{ + bool ret = QWizard::validateCurrentPage(); + if (ret && currentPage() == m_pageReview) { + m_db = m_pageReview->database(); + } + return ret; +} + +QPair ImportWizard::importInto() +{ + auto list = field("ImportInto").toList(); + if (list.size() >= 2) { + return qMakePair(QUuid(list[0].toString()), QUuid(list[1].toString())); + } + return {}; +} + +QSharedPointer ImportWizard::database() +{ + return m_db; +} diff --git a/src/gui/wizard/ImportWizard.h b/src/gui/wizard/ImportWizard.h new file mode 100644 index 000000000..b7e9de68d --- /dev/null +++ b/src/gui/wizard/ImportWizard.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2018 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_IMPORTWIZARD_H +#define KEEPASSXC_IMPORTWIZARD_H + +#include +#include + +class Database; +class ImportWizardPageSelect; +class ImportWizardPageReview; + +/** + * Setup wizard for importing a file into a database. + */ +class ImportWizard : public QWizard +{ + Q_OBJECT + +public: + explicit ImportWizard(QWidget* parent = nullptr); + ~ImportWizard() override; + + bool validateCurrentPage() override; + + QSharedPointer database(); + QPair importInto(); + + enum ImportType + { + IMPORT_NONE = 0, + IMPORT_CSV, + IMPORT_OPVAULT, + IMPORT_OPUX, + IMPORT_BITWARDEN, + IMPORT_KEEPASS1 + }; + +private: + QSharedPointer m_db; + QPointer m_pageSelect; + QPointer m_pageReview; +}; + +#endif // KEEPASSXC_IMPORTWIZARD_H diff --git a/src/gui/wizard/ImportWizardPageReview.cpp b/src/gui/wizard/ImportWizardPageReview.cpp new file mode 100644 index 000000000..2cb56791b --- /dev/null +++ b/src/gui/wizard/ImportWizardPageReview.cpp @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ImportWizardPageReview.h" +#include "ui_ImportWizardPageReview.h" + +#include "core/Database.h" +#include "core/Group.h" +#include "format/BitwardenReader.h" +#include "format/KeePass1Reader.h" +#include "format/OPUXReader.h" +#include "format/OpVaultReader.h" +#include "gui/csvImport/CsvImportWidget.h" +#include "gui/wizard/ImportWizard.h" + +#include +#include +#include +#include + +ImportWizardPageReview::ImportWizardPageReview(QWidget* parent) + : QWizardPage(parent) + , m_ui(new Ui::ImportWizardPageReview) +{ +} + +ImportWizardPageReview::~ImportWizardPageReview() +{ +} + +void ImportWizardPageReview::initializePage() +{ + m_db.reset(); + + // Reset the widget in case we changed the import type + for (auto child : children()) { + delete child; + } + m_ui->setupUi(this); + + auto filename = field("ImportFile").toString(); + m_ui->filenameLabel->setText(filename); + + m_ui->messageWidget->hideMessage(); + m_ui->messageWidget->setAnimate(false); + m_ui->messageWidget->setCloseButtonVisible(false); + + auto importType = field("ImportType").toInt(); + switch (importType) { + case ImportWizard::IMPORT_CSV: + setupCsvImport(filename); + break; + case ImportWizard::IMPORT_OPVAULT: + m_db = importOPVault(filename, field("ImportPassword").toString()); + setupDatabasePreview(); + break; + case ImportWizard::IMPORT_OPUX: + m_db = importOPUX(filename); + setupDatabasePreview(); + break; + case ImportWizard::IMPORT_KEEPASS1: + m_db = importKeePass1(filename, field("ImportPassword").toString(), field("ImportKeyFile").toString()); + setupDatabasePreview(); + break; + case ImportWizard::IMPORT_BITWARDEN: + m_db = importBitwarden(filename, field("ImportPassword").toString()); + setupDatabasePreview(); + break; + default: + break; + } +} + +bool ImportWizardPageReview::validatePage() +{ + if (m_csvWidget && field("ImportType").toInt() == ImportWizard::IMPORT_CSV) { + m_db = m_csvWidget->buildDatabase(); + } + return !m_db.isNull(); +} + +QSharedPointer ImportWizardPageReview::database() +{ + return m_db; +} + +void ImportWizardPageReview::setupCsvImport(const QString& filename) +{ + // No need for this label with CSV + m_ui->previewLabel->hide(); + + m_csvWidget = new CsvImportWidget(); + connect(m_csvWidget, &CsvImportWidget::message, m_ui->messageWidget, [this](QString message) { + m_ui->messageWidget->showMessage(message, KMessageWidget::Error, -1); + }); + + m_csvWidget->load(filename); + + // Qt does not automatically resize a QScrollWidget in a QWizard... + m_ui->scrollAreaContents->layout()->addWidget(m_csvWidget); + m_ui->scrollArea->setMinimumSize(m_csvWidget->width() + 50, m_csvWidget->height() + 100); +} + +void ImportWizardPageReview::setupDatabasePreview() +{ + if (!m_db) { + m_ui->scrollArea->setVisible(false); + return; + } + + auto entryList = m_db->rootGroup()->entriesRecursive(); + m_ui->previewLabel->setText(tr("Entry count: %1").arg(entryList.count())); + + QStringList headerLabels({tr("Group"), tr("Title"), tr("Username"), tr("Password"), tr("Url")}); + + auto tableWidget = new QTableWidget(entryList.count(), headerLabels.count()); + tableWidget->setHorizontalHeaderLabels(headerLabels); + + int row = 0; + for (auto entry : entryList) { + QList items({new QTableWidgetItem(entry->group()->name()), + new QTableWidgetItem(entry->title()), + new QTableWidgetItem(entry->username()), + new QTableWidgetItem(entry->password()), + new QTableWidgetItem(entry->url())}); + int column = 0; + for (auto item : items) { + tableWidget->setItem(row, column++, item); + } + ++row; + } + + tableWidget->setSortingEnabled(true); + tableWidget->setSelectionMode(QTableWidget::NoSelection); + tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); + tableWidget->setWordWrap(true); + tableWidget->horizontalHeader()->setMaximumSectionSize(200); + tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + tableWidget->horizontalHeader()->setStretchLastSection(true); + + m_ui->scrollAreaContents->layout()->addWidget(tableWidget); +} + +QSharedPointer ImportWizardPageReview::importOPUX(const QString& filename) +{ + OPUXReader reader; + auto db = reader.convert(filename); + if (reader.hasError()) { + m_ui->messageWidget->showMessage(reader.errorString(), KMessageWidget::Error, -1); + } + return db; +} + +QSharedPointer ImportWizardPageReview::importBitwarden(const QString& filename, const QString& password) +{ + BitwardenReader reader; + auto db = reader.convert(filename, password); + if (reader.hasError()) { + m_ui->messageWidget->showMessage(reader.errorString(), KMessageWidget::Error, -1); + } + return db; +} + +QSharedPointer ImportWizardPageReview::importOPVault(const QString& filename, const QString& password) +{ + OpVaultReader reader; + QDir opVault(filename); + auto db = reader.convert(opVault, password); + if (reader.hasError()) { + m_ui->messageWidget->showMessage(reader.errorString(), KMessageWidget::Error, -1); + } + return db; +} + +QSharedPointer +ImportWizardPageReview::importKeePass1(const QString& filename, const QString& password, const QString& keyfile) +{ + KeePass1Reader reader; + + // TODO: Handle case of empty password? + + auto db = reader.readDatabase(filename, password, keyfile); + if (reader.hasError()) { + m_ui->messageWidget->showMessage(reader.errorString(), KMessageWidget::Error, -1); + } + + return db; +} diff --git a/src/gui/wizard/ImportWizardPageReview.h b/src/gui/wizard/ImportWizardPageReview.h new file mode 100644 index 000000000..87f501c85 --- /dev/null +++ b/src/gui/wizard/ImportWizardPageReview.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_IMPORTWIZARDPAGEREVIEW_H +#define KEEPASSXC_IMPORTWIZARDPAGEREVIEW_H + +#include +#include + +class CsvImportWidget; +class Database; +namespace Ui +{ + class ImportWizardPageReview; +}; + +class ImportWizardPageReview : public QWizardPage +{ + Q_OBJECT + +public: + explicit ImportWizardPageReview(QWidget* parent = nullptr); + Q_DISABLE_COPY(ImportWizardPageReview) + ~ImportWizardPageReview() override; + + void initializePage() override; + bool validatePage() override; + + QSharedPointer database(); + +private: + void setupCsvImport(const QString& filename); + QSharedPointer importOPUX(const QString& filename); + QSharedPointer importBitwarden(const QString& filename, const QString& password); + QSharedPointer importOPVault(const QString& filename, const QString& password); + QSharedPointer importKeePass1(const QString& filename, const QString& password, const QString& keyfile); + + void setupDatabasePreview(); + + QScopedPointer m_ui; + + QSharedPointer m_db; + QPointer m_csvWidget; +}; + +#endif diff --git a/src/gui/wizard/ImportWizardPageReview.ui b/src/gui/wizard/ImportWizardPageReview.ui new file mode 100644 index 000000000..6872ec4ea --- /dev/null +++ b/src/gui/wizard/ImportWizardPageReview.ui @@ -0,0 +1,95 @@ + + + ImportWizardPageReview + + + + 0 + 0 + 518 + 334 + + + + WizardPage + + + + + + + + + + 500 + 300 + + + + Qt::ScrollBarAlwaysOff + + + QAbstractScrollArea::AdjustToContentsOnFirstShow + + + true + + + + + 0 + 0 + 498 + 298 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 75 + true + + + + filename + + + + + + + Entry count: %1 + + + + + + + + + + + + MessageWidget + QWidget +
gui/MessageWidget.h
+ 1 +
+
+ + +
diff --git a/src/gui/wizard/ImportWizardPageSelect.cpp b/src/gui/wizard/ImportWizardPageSelect.cpp new file mode 100644 index 000000000..7bca1a39a --- /dev/null +++ b/src/gui/wizard/ImportWizardPageSelect.cpp @@ -0,0 +1,236 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "ImportWizardPageSelect.h" +#include "ui_ImportWizardPageSelect.h" + +#include "ImportWizard.h" + +#include "gui/DatabaseWidget.h" +#include "gui/FileDialog.h" +#include "gui/Icons.h" +#include "gui/MainWindow.h" + +ImportWizardPageSelect::ImportWizardPageSelect(QWidget* parent) + : QWizardPage(parent) + , m_ui(new Ui::ImportWizardPageSelect()) +{ + m_ui->setupUi(this); + + new QListWidgetItem(icons()->icon("csv"), tr("Comma Separated Values (.csv)"), m_ui->importTypeList); + new QListWidgetItem(icons()->icon("onepassword"), tr("1Password Export (.1pux)"), m_ui->importTypeList); + new QListWidgetItem(icons()->icon("onepassword"), tr("1Password Vault (.opvault)"), m_ui->importTypeList); + new QListWidgetItem(icons()->icon("bitwarden"), tr("Bitwarden (.json)"), m_ui->importTypeList); + new QListWidgetItem(icons()->icon("object-locked"), tr("KeePass 1 Database (.kdb)"), m_ui->importTypeList); + + m_ui->importTypeList->item(0)->setData(Qt::UserRole, ImportWizard::IMPORT_CSV); + m_ui->importTypeList->item(1)->setData(Qt::UserRole, ImportWizard::IMPORT_OPUX); + m_ui->importTypeList->item(2)->setData(Qt::UserRole, ImportWizard::IMPORT_OPVAULT); + m_ui->importTypeList->item(3)->setData(Qt::UserRole, ImportWizard::IMPORT_BITWARDEN); + m_ui->importTypeList->item(4)->setData(Qt::UserRole, ImportWizard::IMPORT_KEEPASS1); + + connect(m_ui->importTypeList, &QListWidget::currentItemChanged, this, &ImportWizardPageSelect::itemSelected); + m_ui->importTypeList->setCurrentRow(0); + + connect(m_ui->importFileButton, &QAbstractButton::clicked, this, &ImportWizardPageSelect::chooseImportFile); + connect(m_ui->keyFileButton, &QAbstractButton::clicked, this, &ImportWizardPageSelect::chooseKeyFile); + connect(m_ui->existingDatabaseRadio, &QRadioButton::toggled, this, [this](bool state) { + m_ui->existingDatabaseChoice->setEnabled(state); + }); + + updateDatabaseChoices(); + + registerField("ImportType", this); + registerField("ImportFile*", m_ui->importFileEdit); + registerField("ImportInto", m_ui->importIntoLabel); + registerField("ImportPassword", m_ui->passwordEdit, "text", "textChanged"); + registerField("ImportKeyFile", m_ui->keyFileEdit); +} + +ImportWizardPageSelect::~ImportWizardPageSelect() +{ +} + +void ImportWizardPageSelect::initializePage() +{ + setField("ImportType", m_ui->importTypeList->currentItem()->data(Qt::UserRole).toInt()); + adjustSize(); +} + +bool ImportWizardPageSelect::validatePage() +{ + if (m_ui->existingDatabaseRadio->isChecked()) { + if (m_ui->existingDatabaseChoice->currentIndex() == -1) { + return false; + } + setField("ImportInto", m_ui->existingDatabaseChoice->currentData()); + } else { + setField("ImportInto", {}); + } + + return true; +} + +void ImportWizardPageSelect::itemSelected(QListWidgetItem* current, QListWidgetItem* previous) +{ + Q_UNUSED(previous) + + if (!current) { + setCredentialState(false); + return; + } + + m_ui->importFileEdit->clear(); + m_ui->passwordEdit->clear(); + m_ui->keyFileEdit->clear(); + + auto type = current->data(Qt::UserRole).toInt(); + setField("ImportType", type); + switch (type) { + // Unencrypted types + case ImportWizard::IMPORT_CSV: + case ImportWizard::IMPORT_OPUX: + setCredentialState(false); + break; + // Password may be required + case ImportWizard::IMPORT_BITWARDEN: + case ImportWizard::IMPORT_OPVAULT: + setCredentialState(true); + break; + // Password and/or Key File may be required + case ImportWizard::IMPORT_KEEPASS1: + setCredentialState(true, true); + break; + default: + Q_ASSERT(false); + } +} + +void ImportWizardPageSelect::updateDatabaseChoices() const +{ + m_ui->existingDatabaseChoice->clear(); + auto mainWindow = getMainWindow(); + if (mainWindow) { + for (auto dbWidget : mainWindow->getOpenDatabases()) { + // Skip over locked databases + if (dbWidget->isLocked()) { + continue; + } + + // Enable the selection of an existing database + m_ui->existingDatabaseRadio->setEnabled(true); + m_ui->existingDatabaseRadio->setToolTip(""); + + // Add a separator between databases + if (m_ui->existingDatabaseChoice->count() > 0) { + m_ui->existingDatabaseChoice->insertSeparator(m_ui->existingDatabaseChoice->count()); + } + + // Add the root group as a special line item + auto db = dbWidget->database(); + m_ui->existingDatabaseChoice->addItem( + QString("%1 (%2)").arg(dbWidget->displayName(), db->rootGroup()->name()), + QList() << db->uuid() << db->rootGroup()->uuid()); + + if (dbWidget->isVisible()) { + m_ui->existingDatabaseChoice->setCurrentIndex(m_ui->existingDatabaseChoice->count() - 1); + } + + // Add remaining groups + for (const auto& group : db->rootGroup()->groupsRecursive(false)) { + if (!group->isRecycled()) { + auto path = group->hierarchy(); + path.removeFirst(); + m_ui->existingDatabaseChoice->addItem(QString(" / %1").arg(path.join(" / ")), + QList() << db->uuid() << group->uuid()); + } + } + } + } +} + +void ImportWizardPageSelect::chooseImportFile() +{ + QString file; +#ifndef Q_OS_MACOS + // OPVault is a folder except on macOS + if (field("ImportType").toInt() == ImportWizard::IMPORT_OPVAULT) { + file = fileDialog()->getExistingDirectory(this, tr("Open OPVault"), QDir::homePath()); + } else { +#endif + file = fileDialog()->getOpenFileName(this, tr("Select import file"), QDir::homePath(), importFileFilter()); +#ifndef Q_OS_MACOS + } +#endif + + if (!file.isEmpty()) { + m_ui->importFileEdit->setText(file); + } +} + +void ImportWizardPageSelect::chooseKeyFile() +{ + auto filter = QString("%1 (*);;%2 (*.keyx; *.key)").arg(tr("All files"), tr("Key files")); + auto file = fileDialog()->getOpenFileName(this, tr("Select key file"), QDir::homePath(), filter); + if (!file.isEmpty()) { + m_ui->keyFileEdit->setText(file); + } +} + +void ImportWizardPageSelect::setCredentialState(bool passwordEnabled, bool keyFileEnable) +{ + bool passwordStateChanged = m_ui->passwordLabel->isVisible() != passwordEnabled; + m_ui->passwordLabel->setVisible(passwordEnabled); + m_ui->passwordEdit->setVisible(passwordEnabled); + + bool keyFileStateChanged = m_ui->keyFileLabel->isVisible() != keyFileEnable; + m_ui->keyFileLabel->setVisible(keyFileEnable); + m_ui->keyFileEdit->setVisible(keyFileEnable); + m_ui->keyFileButton->setVisible(keyFileEnable); + + // Workaround Qt bug where the wizard window is not updated when the internal layout changes + if (window()) { + int height = window()->height(); + if (passwordStateChanged) { + auto diff = m_ui->passwordEdit->height() + m_ui->inputFields->layout()->spacing(); + height += passwordEnabled ? diff : -diff; + } + if (keyFileStateChanged) { + auto diff = m_ui->keyFileEdit->height() + m_ui->inputFields->layout()->spacing(); + height += keyFileEnable ? diff : -diff; + } + window()->resize(window()->width(), height); + } +} + +QString ImportWizardPageSelect::importFileFilter() +{ + switch (field("ImportType").toInt()) { + case ImportWizard::IMPORT_CSV: + return QString("%1 (*.csv);;%2 (*)").arg(tr("Comma Separated Values"), tr("All files")); + case ImportWizard::IMPORT_OPUX: + return QString("%1 (*.1pux)").arg(tr("1Password Export")); + case ImportWizard::IMPORT_BITWARDEN: + return QString("%1 (*.json)").arg(tr("Bitwarden JSON Export")); + case ImportWizard::IMPORT_OPVAULT: + return QString("%1 (*.opvault)").arg(tr("1Password Vault")); + case ImportWizard::IMPORT_KEEPASS1: + return QString("%1 (*.kdb)").arg(tr("KeePass1 Database")); + default: + return {}; + } +} diff --git a/src/gui/wizard/ImportWizardPageSelect.h b/src/gui/wizard/ImportWizardPageSelect.h new file mode 100644 index 000000000..029865a56 --- /dev/null +++ b/src/gui/wizard/ImportWizardPageSelect.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2023 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_IMPORTWIZARDPAGESELECT_H +#define KEEPASSXC_IMPORTWIZARDPAGESELECT_H + +#include +#include + +class QListWidgetItem; + +namespace Ui +{ + class ImportWizardPageSelect; +} + +class ImportWizardPageSelect : public QWizardPage +{ + Q_OBJECT + +public: + explicit ImportWizardPageSelect(QWidget* parent = nullptr); + Q_DISABLE_COPY(ImportWizardPageSelect) + ~ImportWizardPageSelect() override; + + void initializePage() override; + bool validatePage() override; + +private slots: + void itemSelected(QListWidgetItem* current, QListWidgetItem* previous); + void chooseImportFile(); + void chooseKeyFile(); + void updateDatabaseChoices() const; + +private: + QString importFileFilter(); + void setCredentialState(bool passwordEnabled, bool keyFileEnable = false); + + QScopedPointer m_ui; +}; + +#endif diff --git a/src/gui/wizard/ImportWizardPageSelect.ui b/src/gui/wizard/ImportWizardPageSelect.ui new file mode 100644 index 000000000..6a7c8adad --- /dev/null +++ b/src/gui/wizard/ImportWizardPageSelect.ui @@ -0,0 +1,276 @@ + + + ImportWizardPageSelect + + + + 0 + 0 + 500 + 388 + + + + Form + + + Import File Selection + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 500 + 125 + + + + QAbstractScrollArea::AdjustToContents + + + QAbstractItemView::NoEditTriggers + + + true + + + QAbstractItemView::SelectRows + + + Qt::ElideNone + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + + + + 0 + 0 + + + + + 400 + 0 + + + + + QLayout::SetMinimumSize + + + + + Import File: + + + + + + + + + + + + Browse… + + + + + + + + + Password: + + + + + + + + + + Key File: + + + + + + + + + + + + Browse… + + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 15 + + + + + + + + Import Into: + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + + + + + 0 + 0 + + + + + 0 + 60 + + + + + + + + QLayout::SetMinimumSize + + + 6 + + + 6 + + + 6 + + + 6 + + + + + New Database + + + true + + + + + + + + + false + + + No unlocked databases available + + + Existing Database: + + + + + + + false + + + + + + + + + + + + + + + Qt::Vertical + + + QSizePolicy::MinimumExpanding + + + + 20 + 40 + + + + + + + + + PasswordWidget + QWidget +
gui/PasswordWidget.h
+ 1 +
+
+ + +
diff --git a/src/keeshare/CMakeLists.txt b/src/keeshare/CMakeLists.txt index 3adf272ad..5f7a39658 100644 --- a/src/keeshare/CMakeLists.txt +++ b/src/keeshare/CMakeLists.txt @@ -13,8 +13,6 @@ if(WITH_XC_KEESHARE) ShareObserver.cpp ) - find_package(Minizip REQUIRED) - add_library(keeshare STATIC ${keeshare_SOURCES}) target_link_libraries(keeshare PUBLIC Qt5::Core Qt5::Widgets ${BOTAN_LIBRARIES} ${ZLIB_LIBRARIES} PRIVATE ${MINIZIP_LIBRARIES}) include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index aaf985c2f..4b26d38bc 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -142,7 +142,7 @@ add_unit_test(NAME testdeletedobjects SOURCES TestDeletedObjects.cpp add_unit_test(NAME testkeepass1reader SOURCES TestKeePass1Reader.cpp LIBS ${TEST_LIBRARIES}) -add_unit_test(NAME testopvaultreader SOURCES TestOpVaultReader.cpp +add_unit_test(NAME testimports SOURCES TestImports.cpp LIBS ${TEST_LIBRARIES}) if(WITH_XC_NETWORKING) diff --git a/tests/TestImports.cpp b/tests/TestImports.cpp new file mode 100644 index 000000000..a809cc3ed --- /dev/null +++ b/tests/TestImports.cpp @@ -0,0 +1,267 @@ +/* + * Copyright (C) 2022 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "TestImports.h" + +#include "config-keepassx-tests.h" +#include "core/Group.h" +#include "core/Metadata.h" +#include "core/Totp.h" +#include "crypto/Crypto.h" +#include "format/BitwardenReader.h" +#include "format/OPUXReader.h" +#include "format/OpVaultReader.h" + +#include +#include +#include + +QTEST_GUILESS_MAIN(TestImports) + +void TestImports::initTestCase() +{ + QVERIFY(Crypto::init()); +} + +void TestImports::testOPUX() +{ + auto opuxPath = QStringLiteral("%1/%2").arg(KEEPASSX_TEST_DATA_DIR, QStringLiteral("/1PasswordExport.1pux")); + + OPUXReader reader; + auto db = reader.convert(opuxPath); + QVERIFY2(!reader.hasError(), qPrintable(reader.errorString())); + QVERIFY(db); + + // Confirm specific entry details are valid + auto entry = db->rootGroup()->findEntryByPath("/Personal/Login"); + QVERIFY(entry); + QCOMPARE(entry->title(), QStringLiteral("Login")); + QCOMPARE(entry->username(), QStringLiteral("team@keepassxc.org")); + QCOMPARE(entry->password(), QStringLiteral("password")); + QCOMPARE(entry->url(), QStringLiteral("https://keepassxc.org")); + QCOMPARE(entry->notes(), QStringLiteral("Note to self")); + // Check extra URL's + QCOMPARE(entry->attribute("KP2A_URL_1"), QStringLiteral("https://twitter.com")); + // Check TOTP + QVERIFY(entry->hasTotp()); + QVERIFY(!entry->attribute("otp_1").isEmpty()); + // Check tags + QVERIFY(entry->tagList().contains("Favorite")); + QVERIFY(entry->tagList().contains("website")); + + // Check attachments + entry = db->rootGroup()->findEntryByPath("/Personal/KeePassXC Logo"); + auto attachments = entry->attachments(); + QCOMPARE(attachments->keys().count(), 1); + QCOMPARE(attachments->keys()[0], QString("keepassxc.png")); + + // Confirm advanced attributes + // NOTE: 1PUX does not support an explicit expiration field + entry = db->rootGroup()->findEntryByPath("/Personal/Credit Card"); + QVERIFY(entry); + auto tmpl = QString("Credit Card Fields_%1"); + auto attr = entry->attributes(); + QCOMPARE(attr->value(tmpl.arg("cardholder name")), QStringLiteral("KeePassXC")); + QCOMPARE(attr->value(tmpl.arg("expiry date")), QStringLiteral("202206")); + QCOMPARE(attr->value(tmpl.arg("verification number")), QStringLiteral("123")); + QVERIFY(attr->isProtected(tmpl.arg("verification number"))); + + // Confirm address fields + entry = db->rootGroup()->findEntryByPath("/Personal/Identity"); + QVERIFY(entry); + attr = entry->attributes(); + QCOMPARE(attr->value("Address_address"), QStringLiteral("123 Avenue Rd\nBoston, MA 12345\nus")); + + // Check archived entries + entry = db->rootGroup()->findEntryByPath("/Personal/Login Archived"); + QVERIFY(entry); + QVERIFY(entry->tagList().contains("Archived")); + + // Check vault to group structure + entry = db->rootGroup()->findEntryByPath("/Shared/Bank Account"); + QVERIFY(entry); + // Check custom group icon + QVERIFY(!entry->group()->iconUuid().isNull()); +} + +void TestImports::testOPVault() +{ + auto opVaultPath = QStringLiteral("%1/%2").arg(KEEPASSX_TEST_DATA_DIR, QStringLiteral("/keepassxc.opvault")); + + auto categories = QStringList({QStringLiteral("Login"), + QStringLiteral("Credit Card"), + QStringLiteral("Secure Note"), + QStringLiteral("Identity"), + QStringLiteral("Password"), + QStringLiteral("Tombstone"), + QStringLiteral("Software License"), + QStringLiteral("Bank Account"), + QStringLiteral("Database"), + QStringLiteral("Driver License"), + QStringLiteral("Outdoor License"), + QStringLiteral("Membership"), + QStringLiteral("Passport"), + QStringLiteral("Rewards"), + QStringLiteral("SSN"), + QStringLiteral("Router"), + QStringLiteral("Server"), + QStringLiteral("Email")}); + + QDir opVaultDir(opVaultPath); + + OpVaultReader reader; + auto db = reader.convert(opVaultDir, "a"); + QVERIFY2(!reader.hasError(), qPrintable(reader.errorString())); + QVERIFY(db); + + // Confirm specific entry details are valid + auto entry = db->rootGroup()->findEntryByPath("/Login/KeePassXC"); + QVERIFY(entry); + QCOMPARE(entry->title(), QStringLiteral("KeePassXC")); + QCOMPARE(entry->username(), QStringLiteral("keepassxc")); + QCOMPARE(entry->password(), QStringLiteral("opvault")); + QCOMPARE(entry->url(), QStringLiteral("https://www.keepassxc.org")); + QCOMPARE(entry->notes(), QStringLiteral("KeePassXC Account")); + // Check extra URL's + QCOMPARE(entry->attribute("KP2A_URL_1"), QStringLiteral("https://snapshot.keepassxc.org")); + // Check TOTP + QVERIFY(entry->hasTotp()); + // Check attachments + auto attachments = entry->attachments(); + QCOMPARE(attachments->keys().count(), 1); + QCOMPARE(*attachments->values().begin(), QByteArray("attachment")); + + // Confirm expired entries + entry = db->rootGroup()->findEntryByPath("/Login/Expired Login"); + QVERIFY(entry->isExpired()); + + // Confirm advanced attributes + entry = db->rootGroup()->findEntryByPath("/Credit Card/My Credit Card"); + QVERIFY(entry); + auto attr = entry->attributes(); + QCOMPARE(attr->value("cardholder name"), QStringLiteral("Team KeePassXC")); + QVERIFY(!attr->value("valid from").isEmpty()); + QCOMPARE(attr->value("Additional Details_PIN"), QStringLiteral("1234")); + QVERIFY(attr->isProtected("Additional Details_PIN")); + + // Confirm address fields + entry = db->rootGroup()->findEntryByPath("/Identity/Team KeePassXC"); + QVERIFY(entry); + attr = entry->attributes(); + QCOMPARE(attr->value("address_street"), QStringLiteral("123 Password Lane")); + + // Confirm complex passwords + entry = db->rootGroup()->findEntryByPath("/Password/Complex Password"); + QVERIFY(entry); + QCOMPARE(entry->password(), QStringLiteral("HfgcHjEL}iO}^3N!?*cv~O:9GJZQ0>oC")); + QVERIFY(entry->hasTotp()); + auto totpSettings = entry->totpSettings(); + QCOMPARE(totpSettings->digits, static_cast(8)); + QCOMPARE(totpSettings->step, static_cast(45)); + + // Add another OTP to this entry to confirm it doesn't overwrite the existing one + auto field = QJsonObject::fromVariantMap({{"n", "TOTP_SETTINGS"}, {"v", "otpauth://test.url?digits=6"}}); + reader.fillFromSectionField(entry, "", field); + QVERIFY(entry->hasTotp()); + totpSettings = entry->totpSettings(); + QCOMPARE(totpSettings->digits, static_cast(8)); + QCOMPARE(totpSettings->step, static_cast(45)); + QVERIFY(entry->attributes()->contains("otp_1")); + + // Confirm trashed entries are sent to the recycle bin + auto recycleBin = db->metadata()->recycleBin(); + QVERIFY(recycleBin); + QVERIFY(!recycleBin->isEmpty()); + QVERIFY(recycleBin->findEntryByPath("Trashed Password")); + + // Confirm created groups align with category names + for (const auto group : db->rootGroup()->children()) { + if (group == recycleBin) { + continue; + } + QVERIFY2(categories.contains(group->name()), + qPrintable(QStringLiteral("Invalid group name: %1").arg(group->name()))); + // Confirm each group is not empty + QVERIFY2(!group->isEmpty(), qPrintable(QStringLiteral("Group %1 is empty").arg(group->name()))); + } +} + +void TestImports::testBitwarden() +{ + auto bitwardenPath = QStringLiteral("%1/%2").arg(KEEPASSX_TEST_DATA_DIR, QStringLiteral("/bitwarden_export.json")); + + BitwardenReader reader; + auto db = reader.convert(bitwardenPath); + QVERIFY2(!reader.hasError(), qPrintable(reader.errorString())); + QVERIFY(db); + + // Confirm Login fields + auto entry = db->rootGroup()->findEntryByPath("/My Folder/Login Name"); + QVERIFY(entry); + QCOMPARE(entry->title(), QStringLiteral("Login Name")); + QCOMPARE(entry->username(), QStringLiteral("myusername@gmail.com")); + QCOMPARE(entry->password(), QStringLiteral("mypassword")); + QCOMPARE(entry->url(), QStringLiteral("https://mail.google.com")); + QCOMPARE(entry->notes(), QStringLiteral("1st line of note text\n2nd Line of note text")); + // Check extra URL's + QCOMPARE(entry->attribute("KP2A_URL_1"), QStringLiteral("https://google.com")); + QCOMPARE(entry->attribute("KP2A_URL_2"), QStringLiteral("https://gmail.com")); + // Check TOTP + QVERIFY(entry->hasTotp()); + // NOTE: Bitwarden does not export attachments + // NOTE: Bitwarden does not export expiration dates + + // Confirm Identity fields + entry = db->rootGroup()->findEntryByPath("/My Folder/My Identity"); + QVERIFY(entry); + auto attr = entry->attributes(); + // NOTE: The extra spaces are deliberate to test unmodified ingest of data + QCOMPARE(attr->value("identity_address"), + QStringLiteral(" 1 North Calle Cesar Chavez \nSanta Barbara, CA 93103\nUnited States ")); + QCOMPARE(attr->value("identity_name"), QStringLiteral("Mrs Jane A Doe")); + QCOMPARE(attr->value("identity_ssn"), QStringLiteral("123-12-1234")); + QVERIFY(attr->isProtected("identity_ssn")); + + // Confirm Secure Note + entry = db->rootGroup()->findEntryByPath("/My Folder/My Secure Note"); + QVERIFY(entry); + QCOMPARE(entry->notes(), + QStringLiteral("1st line of secure note\n2nd line of secure note\n3rd line of secure note")); + + // Confirm Credit Card + entry = db->rootGroup()->findEntryByPath("/Second Folder/Card Name"); + QVERIFY(entry); + attr = entry->attributes(); + QCOMPARE(attr->value("card_cardholderName"), QStringLiteral("Jane Doe")); + QCOMPARE(attr->value("card_number"), QStringLiteral("1234567891011121")); + QCOMPARE(attr->value("card_code"), QStringLiteral("123")); + QVERIFY(attr->isProtected("card_code")); +} + +void TestImports::testBitwardenEncrypted() +{ + // We already tested the parser so just test that decryption works properly + auto bitwardenPath = + QStringLiteral("%1/%2").arg(KEEPASSX_TEST_DATA_DIR, QStringLiteral("/bitwarden_encrypted_export.json")); + + BitwardenReader reader; + auto db = reader.convert(bitwardenPath, "a"); + if (reader.hasError()) { + QFAIL(qPrintable(reader.errorString())); + } + QVERIFY(db); +} diff --git a/src/gui/KeePass1OpenWidget.h b/tests/TestImports.h similarity index 64% rename from src/gui/KeePass1OpenWidget.h rename to tests/TestImports.h index 203b78632..2e00de9a6 100644 --- a/src/gui/KeePass1OpenWidget.h +++ b/tests/TestImports.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012 Felix Geyer + * Copyright (C) 2022 KeePassXC Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,20 +15,21 @@ * along with this program. If not, see . */ -#ifndef KEEPASSX_KEEPASS1OPENWIDGET_H -#define KEEPASSX_KEEPASS1OPENWIDGET_H +#ifndef TEST_IMPORTS_H +#define TEST_IMPORTS_H -#include "gui/DatabaseOpenWidget.h" +#include -class KeePass1OpenWidget : public DatabaseOpenWidget +class TestImports : public QObject { Q_OBJECT -public: - explicit KeePass1OpenWidget(QWidget* parent = nullptr); - -protected: - void openDatabase() override; +private slots: + void initTestCase(); + void testOPUX(); + void testOPVault(); + void testBitwarden(); + void testBitwardenEncrypted(); }; -#endif // KEEPASSX_KEEPASS1OPENWIDGET_H +#endif /* TEST_IMPORTS_H */ diff --git a/tests/TestOpVaultReader.cpp b/tests/TestOpVaultReader.cpp deleted file mode 100644 index 4899d335f..000000000 --- a/tests/TestOpVaultReader.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2019 KeePassXC Team - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 or (at your option) - * version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "TestOpVaultReader.h" - -#include "config-keepassx-tests.h" -#include "core/Group.h" -#include "core/Metadata.h" -#include "core/Totp.h" -#include "crypto/Crypto.h" -#include "format/OpVaultReader.h" - -#include -#include -#include -#include - -QTEST_GUILESS_MAIN(TestOpVaultReader) - -void TestOpVaultReader::initTestCase() -{ - QVERIFY(Crypto::init()); - - m_opVaultPath = QStringLiteral("%1/%2").arg(KEEPASSX_TEST_DATA_DIR, QStringLiteral("/keepassxc.opvault")); - - m_categories = QStringList({QStringLiteral("Login"), - QStringLiteral("Credit Card"), - QStringLiteral("Secure Note"), - QStringLiteral("Identity"), - QStringLiteral("Password"), - QStringLiteral("Tombstone"), - QStringLiteral("Software License"), - QStringLiteral("Bank Account"), - QStringLiteral("Database"), - QStringLiteral("Driver License"), - QStringLiteral("Outdoor License"), - QStringLiteral("Membership"), - QStringLiteral("Passport"), - QStringLiteral("Rewards"), - QStringLiteral("SSN"), - QStringLiteral("Router"), - QStringLiteral("Server"), - QStringLiteral("Email")}); -} - -void TestOpVaultReader::testReadIntoDatabase() -{ - QDir opVaultDir(m_opVaultPath); - - OpVaultReader reader; - QScopedPointer db(reader.readDatabase(opVaultDir, "a")); - QVERIFY(db); - QVERIFY2(!reader.hasError(), qPrintable(reader.errorString())); - - // Confirm specific entry details are valid - auto entry = db->rootGroup()->findEntryByPath("/Login/KeePassXC"); - QVERIFY(entry); - QCOMPARE(entry->title(), QStringLiteral("KeePassXC")); - QCOMPARE(entry->username(), QStringLiteral("keepassxc")); - QCOMPARE(entry->password(), QStringLiteral("opvault")); - QCOMPARE(entry->url(), QStringLiteral("https://www.keepassxc.org")); - QCOMPARE(entry->notes(), QStringLiteral("KeePassXC Account")); - // Check extra URL's - QCOMPARE(entry->attribute("KP2A_URL_1"), QStringLiteral("https://snapshot.keepassxc.org")); - // Check TOTP - QVERIFY(entry->hasTotp()); - // Check attachments - auto attachments = entry->attachments(); - QCOMPARE(attachments->keys().count(), 1); - QCOMPARE(*attachments->values().begin(), QByteArray("attachment")); - - // Confirm expired entries - entry = db->rootGroup()->findEntryByPath("/Login/Expired Login"); - QVERIFY(entry->isExpired()); - - // Confirm advanced attributes - entry = db->rootGroup()->findEntryByPath("/Credit Card/My Credit Card"); - QVERIFY(entry); - auto attr = entry->attributes(); - QCOMPARE(attr->value("cardholder name"), QStringLiteral("Team KeePassXC")); - QVERIFY(!attr->value("valid from").isEmpty()); - QCOMPARE(attr->value("Additional Details_PIN"), QStringLiteral("1234")); - QVERIFY(attr->isProtected("Additional Details_PIN")); - - // Confirm address fields - entry = db->rootGroup()->findEntryByPath("/Identity/Team KeePassXC"); - QVERIFY(entry); - attr = entry->attributes(); - QCOMPARE(attr->value("address_street"), QStringLiteral("123 Password Lane")); - - // Confirm complex passwords - entry = db->rootGroup()->findEntryByPath("/Password/Complex Password"); - QVERIFY(entry); - QCOMPARE(entry->password(), QStringLiteral("HfgcHjEL}iO}^3N!?*cv~O:9GJZQ0>oC")); - QVERIFY(entry->hasTotp()); - auto totpSettings = entry->totpSettings(); - QCOMPARE(totpSettings->digits, static_cast(8)); - QCOMPARE(totpSettings->step, static_cast(45)); - - // Add another OTP to this entry to confirm it doesn't overwrite the existing one - auto field = QJsonObject::fromVariantMap({{"n", "TOTP_SETTINGS"}, {"v", "otpauth://test.url?digits=6"}}); - reader.fillFromSectionField(entry, "", field); - QVERIFY(entry->hasTotp()); - totpSettings = entry->totpSettings(); - QCOMPARE(totpSettings->digits, static_cast(8)); - QCOMPARE(totpSettings->step, static_cast(45)); - QVERIFY(entry->attributes()->contains("otp_1")); - - // Confirm trashed entries are sent to the recycle bin - auto recycleBin = db->metadata()->recycleBin(); - QVERIFY(recycleBin); - QVERIFY(!recycleBin->isEmpty()); - QVERIFY(recycleBin->findEntryByPath("Trashed Password")); - - // Confirm created groups align with category names - for (const auto group : db->rootGroup()->children()) { - if (group == recycleBin) { - continue; - } - QVERIFY2(m_categories.contains(group->name()), - qPrintable(QStringLiteral("Invalid group name: %1").arg(group->name()))); - // Confirm each group is not empty - QVERIFY2(!group->isEmpty(), qPrintable(QStringLiteral("Group %1 is empty").arg(group->name()))); - } -} diff --git a/tests/data/1PasswordExport.1pux b/tests/data/1PasswordExport.1pux new file mode 100644 index 0000000000000000000000000000000000000000..509d7d07b79726eb648ec263d1fbc9c46f58b529 GIT binary patch literal 31621 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 KcnqI^w*DJ^V%cQ? literal 0 HcmV?d00001 diff --git a/tests/data/bitwarden_encrypted_export.json b/tests/data/bitwarden_encrypted_export.json new file mode 100644 index 000000000..0f759686c --- /dev/null +++ b/tests/data/bitwarden_encrypted_export.json @@ -0,0 +1,11 @@ +{ + "encrypted": true, + "passwordProtected": true, + "salt": "jxJdzv853aLmu0y/mCgSxg==", + "kdfType": 0, + "kdfIterations": 100000, + "kdfMemory": null, + "kdfParallelism": null, + "encKeyValidation_DO_NOT_EDIT": "2.6O5+RkqPRTCxGIjEIyqukQ==|J7Ks4QhjfOyt7qMU82XEuJoGw0GpQabv0vGerKC+YjSQWmaqbbyMDgba78vyRvSU|f0nwbY+JRc2KfkU6mY0dmiKNiDb00A0CngpF4TEEM0c=", + "data": "2.OA/bDI14kq+642rwmWYWxg==|216xw4kCZbqhVifzikzvzqLY2Er35tiYo+gl+hgf9dmLrPMf5vYcFgMe8IdTHXZCdUEuyEdpQeoAwGT8zG8d9GcwdKKOktccl04lE39Cb6XqKEr1PA3d4R8iPYTpeeFSm/cFLQlod5iymUkW4wxHTSIVn9KO/y0F8LWyKX7XxAdCEJykatSoUcC9SmFTPxEtR7BBgfkLTCgSZ9AUE0suKoYIUR6sJSlDq3IHP/09T8w0bbahBkRzevj5+JXawxn1DvBld00bVzo6GgrGojHz+VNa/crpLSaPqyR/IlD66+bS1DdIZ4UBODpZVZTxNKbWd7mPhkCcHF+NchCb47MR442dVQD9QjXk8q7E3SoK76JkYdOZsd3FIH8fZNdYTSOZsvLOYans74RyX1qCD5w3QVaR1cwRYD+kwCe0eFlHmzCLCx3IAuTfH1QdXvIvqaevYKikuKE8tfaAhrPJ2N4MHoKyxdF801jqslZdWrUrZvWsovdBZhp2siQZiWpd/fteJTSpy19sJ+J49+4SYEAfYe3lbz2K7ypKia8duffnV4+eh5tsK24MkExHO3ZQzQVkQdsX6eeFJmdqK4wONunSgnXIDti5rw/bWNtjVvAYiDMX+DNULML/opp9TPZUvrTgFhMsFFwbVzIjTxwE/PS9w+lD3etP195QkD717F87dClpkIrvm+UfQrQwCgDxOQ9PTPcUBVugq9MEflsiSn4NjCXdjWL1siSgxm2eJQ3k0OKJoN5bUInwG9i9njLh5fjxc4aiuvOOGAkqgX/mr3MxuuV8luKWRy884Reu8DdnZq6Vdq+yHgs7o9Ipxrtr8t85yBeU90yqyJrtmwDgEJiLK0TpJ1bY9ZwnqhYrtJGRrzxWrfvAGcJzEsWJ98aq9T+r/CnnsInyRTyptOgmsjmPlw0rTZ8//KI2afwRQRL+yIZ4817T+DekyF18QnYD607njiJb5igEy9MzYw04osr9yyQikheyuPDvD2UnGgGYdy04sHKVNgt0/xtzsJvxhsmy0mXknRcajExsKe6wH1jzTq6IxWo+08+5lnMmr05gtE8Y6HN2nsOAVdGU6x26MQVI|ASjBD0/F6Z61WSWc++RXhA6iQv8AziJO+/EXrj7GSVY=" +} \ No newline at end of file diff --git a/tests/data/bitwarden_export.json b/tests/data/bitwarden_export.json new file mode 100644 index 000000000..7d6a5de21 --- /dev/null +++ b/tests/data/bitwarden_export.json @@ -0,0 +1,180 @@ +{ + "folders": [ + { + "id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", + "name": "My Folder" + }, + { + "id": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy", + "name": "Second Folder" + } + ], + "items": [ + { + "id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaa", + "organizationId": null, + "folderId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", + "type": 2, + "name": "My Secure Note", + "notes": "1st line of secure note\n2nd line of secure note\n3rd line of secure note", + "favorite": false, + "fields": [ + { + "name": "Text Field", + "value": "text-field-value", + "type": 0 + }, + { + "name": "Hidden Field", + "value": "hidden-field-value", + "type": 1 + }, + { + "name": "Boolean Field", + "value": "false", + "type": 2 + } + ], + "secureNote": { + "type": 0 + }, + "collectionIds": [ + null + ] + }, + { + "id": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", + "organizationId": null, + "folderId": "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy", + "type": 3, + "name": "Card Name", + "notes": "1st line of note text\n2nd line of note text", + "favorite": false, + "fields": [ + { + "name": "Text Field", + "value": "text-field-value", + "type": 0 + }, + { + "name": "Hidden Field", + "value": "hidden-field-value", + "type": 1 + }, + { + "name": "Boolean Field", + "value": "false", + "type": 2 + } + ], + "card": { + "cardholderName": "Jane Doe", + "brand": "Visa", + "number": "1234567891011121", + "expMonth": "10", + "expYear": "2021", + "code": "123" + }, + "collectionIds": [ + null + ] + }, + { + "id": "cccccccc-cccc-cccc-cccc-cccccccccccc", + "organizationId": null, + "folderId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", + "type": 4, + "name": "My Identity", + "notes": "1st line of a note\n2nd line of a note", + "favorite": false, + "fields": [ + { + "name": "Text Field", + "value": "text-field-value", + "type": 0 + }, + { + "name": "Hidden Field", + "value": "hidden-field-value", + "type": 1 + }, + { + "name": "Boolean Field", + "value": "true", + "type": 2 + } + ], + "identity": { + "title": "Mrs", + "firstName": "Jane", + "middleName": "A", + "lastName": "Doe", + "address1": " 1 North Calle Cesar Chavez ", + "address2": null, + "address3": null, + "city": "Santa Barbara", + "state": "CA", + "postalCode": "93103", + "country": "United States ", + "company": "My Employer", + "email": "myemail@gmail.com", + "phone": "123-123-1234", + "ssn": "123-12-1234", + "username": "myusername", + "passportNumber": "123456789", + "licenseNumber": "123456789" + }, + "collectionIds": [ + null + ] + }, + { + "id": "dddddddd-dddd-dddd-dddd-dddddddddddd", + "organizationId": null, + "folderId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", + "type": 1, + "name": "Login Name", + "notes": "1st line of note text\n2nd Line of note text", + "favorite": true, + "fields": [ + { + "name": "Text Field", + "value": "text-field-value", + "type": 0 + }, + { + "name": "Hidden Field", + "value": "hidden-field-value", + "type": 1 + }, + { + "name": "Boolean Field", + "value": "true", + "type": 2 + } + ], + "login": { + "uris": [ + { + "match": null, + "uri": "https://mail.google.com" + }, + { + "match": null, + "uri": "https://google.com" + }, + { + "match": null, + "uri": "https://gmail.com" + } + ], + "username": "myusername@gmail.com", + "password": "mypassword", + "totp": "otpauth://totp/Google:myusername%40gmail.com?secret=DFDFDEF%3D&period=30&digits=6&issuer=Google" + }, + "collectionIds": [ + null + ] + } + ] +} diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp index fc5edbc99..5aa459ffa 100644 --- a/tests/gui/TestGui.cpp +++ b/tests/gui/TestGui.cpp @@ -1640,28 +1640,6 @@ void TestGui::testDatabaseSettings() config()->set(Config::AutoSaveAfterEveryChange, false); } -void TestGui::testKeePass1Import() -{ - fileDialog()->setNextFileName(QString(KEEPASSX_TEST_DATA_DIR).append("/basic.kdb")); - triggerAction("actionImportKeePass1"); - - auto* keepass1OpenWidget = m_tabWidget->currentDatabaseWidget()->findChild("keepass1OpenWidget"); - auto* editPassword = - keepass1OpenWidget->findChild("editPassword")->findChild("passwordEdit"); - QVERIFY(editPassword); - - QTest::keyClicks(editPassword, "masterpw"); - QTest::keyClick(editPassword, Qt::Key_Enter); - - QTRY_COMPARE(m_tabWidget->count(), 2); - QTRY_COMPARE(m_tabWidget->tabText(m_tabWidget->currentIndex()), QString("basic [New Database]*")); - - // Close the KeePass1 Database - MessageBox::setNextAnswer(MessageBox::No); - triggerAction("actionDatabaseClose"); - QApplication::processEvents(); -} - void TestGui::testDatabaseLocking() { QString origDbName = m_tabWidget->tabText(0); diff --git a/tests/gui/TestGui.h b/tests/gui/TestGui.h index 057dfb3c2..c74783ded 100644 --- a/tests/gui/TestGui.h +++ b/tests/gui/TestGui.h @@ -61,7 +61,6 @@ private slots: void testSaveBackupPath(); void testSaveBackupPath_data(); void testDatabaseSettings(); - void testKeePass1Import(); void testDatabaseLocking(); void testDragAndDropKdbxFiles(); void testSortGroups();