Remove obsolete database repair feature

This commit is contained in:
Weslly 2018-09-22 12:00:24 -03:00 committed by Jonathan White
parent d4112fe2bf
commit 44c9469221
13 changed files with 4 additions and 391 deletions

View File

@ -85,7 +85,6 @@ set(keepassx_SOURCES
format/KeePass1Reader.cpp
format/KeePass2.cpp
format/KeePass2RandomStream.cpp
format/KeePass2Repair.cpp
format/KdbxReader.cpp
format/KdbxWriter.cpp
format/KdbxXmlReader.cpp
@ -102,7 +101,6 @@ set(keepassx_SOURCES
gui/Clipboard.cpp
gui/CloneDialog.cpp
gui/DatabaseOpenWidget.cpp
gui/DatabaseRepairWidget.cpp
gui/DatabaseTabWidget.cpp
gui/DatabaseWidget.cpp
gui/DatabaseWidgetStateSync.cpp
@ -113,7 +111,6 @@ set(keepassx_SOURCES
gui/EditWidgetIcons.cpp
gui/EditWidgetProperties.cpp
gui/FileDialog.cpp
gui/masterkey/KeyComponentWidget.cpp
gui/Font.cpp
gui/IconModels.cpp
gui/KeePass1OpenWidget.cpp
@ -150,16 +147,17 @@ set(keepassx_SOURCES
gui/group/EditGroupWidget.cpp
gui/group/GroupModel.cpp
gui/group/GroupView.cpp
gui/masterkey/KeyComponentWidget.cpp
gui/masterkey/PasswordEditWidget.cpp
gui/masterkey/YubiKeyEditWidget.cpp
gui/masterkey/KeyFileEditWidget.cpp
gui/settings/SettingsWidget.cpp
gui/dbsettings/DatabaseSettingsWidget.cpp
gui/dbsettings/DatabaseSettingsDialog.cpp
gui/dbsettings/DatabaseSettingsWidgetGeneral.cpp
gui/dbsettings/DatabaseSettingsWidgetMetaDataSimple.cpp
gui/dbsettings/DatabaseSettingsWidgetMetaDataSimple.cpp
gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp
gui/dbsettings/DatabaseSettingsWidgetMasterKey.cpp
gui/dbsettings/DatabaseSettingsWidgetMasterKey.cpp
gui/settings/SettingsWidget.cpp
gui/wizard/NewDatabaseWizard.cpp
gui/wizard/NewDatabaseWizardPage.cpp
gui/wizard/NewDatabaseWizardPageMetaData.cpp

View File

@ -120,11 +120,6 @@ QByteArray KdbxReader::xmlData() const
return m_xmlData;
}
QByteArray KdbxReader::streamKey() const
{
return m_protectedStreamKey;
}
KeePass2::ProtectedStreamAlgo KdbxReader::protectedStreamAlgo() const
{
return m_irsAlgo;

View File

@ -48,7 +48,6 @@ public:
bool saveXml() const;
void setSaveXml(bool save);
QByteArray xmlData() const;
QByteArray streamKey() const;
KeePass2::ProtectedStreamAlgo protectedStreamAlgo() const;
protected:

View File

@ -1,102 +0,0 @@
/*
* Copyright (C) 2016 Felix Geyer <debfx@fobos.de>
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "KeePass2Repair.h"
#include <QBuffer>
#include "core/Group.h"
#include "format/Kdbx4Reader.h"
#include "format/KdbxXmlReader.h"
#include "format/KeePass2.h"
#include "format/KeePass2RandomStream.h"
#include "format/KeePass2Reader.h"
KeePass2Repair::RepairOutcome KeePass2Repair::repairDatabase(QIODevice* device, QSharedPointer<const CompositeKey> key)
{
m_errorStr.clear();
KeePass2Reader reader;
reader.setSaveXml(true);
QScopedPointer<Database> db(reader.readDatabase(device, key, true));
if (!reader.hasError()) {
return qMakePair(NothingTodo, nullptr);
}
QByteArray xmlData = reader.reader()->xmlData();
if (!db || xmlData.isEmpty()) {
m_errorStr = reader.errorString();
return qMakePair(UnableToOpen, nullptr);
}
bool repairAction = false;
QString xmlStart = QString::fromLatin1(xmlData.constData(), qMin(100, xmlData.size()));
QRegExp encodingRegExp("encoding=\"([^\"]+)\"", Qt::CaseInsensitive, QRegExp::RegExp2);
if (encodingRegExp.indexIn(xmlStart) != -1) {
if (encodingRegExp.cap(1).compare("utf-8", Qt::CaseInsensitive) != 0
&& encodingRegExp.cap(1).compare("utf8", Qt::CaseInsensitive) != 0) {
// database is not utf-8 encoded, we don't support repairing that
return qMakePair(RepairFailed, nullptr);
}
}
// try to fix broken databases because of bug #392
for (int i = (xmlData.size() - 1); i >= 0; i--) {
auto ch = static_cast<quint8>(xmlData.at(i));
if (ch < 0x20 && ch != 0x09 && ch != 0x0A && ch != 0x0D) {
xmlData.remove(i, 1);
repairAction = true;
}
}
if (!repairAction) {
// we were unable to find the problem
return qMakePair(RepairFailed, nullptr);
}
KeePass2RandomStream randomStream(reader.reader()->protectedStreamAlgo());
randomStream.init(reader.reader()->streamKey());
bool hasError;
QBuffer buffer(&xmlData);
buffer.open(QIODevice::ReadOnly);
if ((reader.version() & KeePass2::FILE_VERSION_CRITICAL_MASK) < KeePass2::FILE_VERSION_4) {
KdbxXmlReader xmlReader(KeePass2::FILE_VERSION_3_1);
xmlReader.readDatabase(&buffer, db.data(), &randomStream);
hasError = xmlReader.hasError();
} else {
auto reader4 = reader.reader().staticCast<Kdbx4Reader>();
QHash<QString, QByteArray> pool = reader4->binaryPool();
KdbxXmlReader xmlReader(KeePass2::FILE_VERSION_4, pool);
xmlReader.readDatabase(&buffer, db.data(), &randomStream);
hasError = xmlReader.hasError();
}
if (hasError) {
return qMakePair(RepairFailed, nullptr);
} else {
return qMakePair(RepairSuccess, db.take());
}
}
QString KeePass2Repair::errorString() const
{
return m_errorStr;
}

View File

@ -1,50 +0,0 @@
/*
* Copyright (C) 2016 Felix Geyer <debfx@fobos.de>
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSX_KEEPASS2REPAIR_H
#define KEEPASSX_KEEPASS2REPAIR_H
#include <QCoreApplication>
#include <QIODevice>
#include <QPair>
#include "core/Database.h"
#include "keys/CompositeKey.h"
class KeePass2Repair
{
Q_DECLARE_TR_FUNCTIONS(KeePass2Repair)
public:
enum RepairResult
{
NothingTodo,
UnableToOpen,
RepairSuccess,
RepairFailed
};
using RepairOutcome = QPair<RepairResult, Database*>;
RepairOutcome repairDatabase(QIODevice* device, QSharedPointer<const CompositeKey> key);
QString errorString() const;
private:
QString m_errorStr;
};
#endif // KEEPASSX_KEEPASS2REPAIR_H

View File

@ -1,107 +0,0 @@
/*
* Copyright (C) 2016 Felix Geyer <debfx@fobos.de>
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#include "DatabaseRepairWidget.h"
#include <QFile>
#include <QFileInfo>
#include "core/Database.h"
#include "core/Metadata.h"
#include "format/KeePass2Repair.h"
#include "gui/MessageBox.h"
#include "keys/FileKey.h"
#include "keys/PasswordKey.h"
#include "ui_DatabaseOpenWidget.h"
DatabaseRepairWidget::DatabaseRepairWidget(QWidget* parent)
: DatabaseOpenWidget(parent)
{
m_ui->labelHeadline->setText(tr("Repair database"));
connect(this, SIGNAL(editFinished(bool)), this, SLOT(processEditFinished(bool)));
}
void DatabaseRepairWidget::openDatabase()
{
auto masterKey = QSharedPointer<CompositeKey>::create();
if (m_ui->checkPassword->isChecked()) {
masterKey->addKey(QSharedPointer<PasswordKey>::create(m_ui->editPassword->text()));
}
if (m_ui->checkKeyFile->isChecked()) {
auto key = QSharedPointer<FileKey>::create();
QString keyFilename = m_ui->comboKeyFile->currentText();
QString errorMsg;
if (!key->load(keyFilename, &errorMsg)) {
MessageBox::warning(this, tr("Error"), tr("Can't open key file:\n%1").arg(errorMsg));
emit editFinished(false);
return;
}
masterKey->addKey(key);
}
KeePass2Repair repair;
QFile file(m_filename);
if (!file.open(QIODevice::ReadOnly)) {
MessageBox::warning(
this, tr("Error"), tr("Unable to open the database.").append("\n").append(file.errorString()));
emit editFinished(false);
return;
}
if (m_db) {
delete m_db;
}
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
auto repairOutcome = repair.repairDatabase(&file, masterKey);
KeePass2Repair::RepairResult repairResult = repairOutcome.first;
QApplication::restoreOverrideCursor();
switch (repairResult) {
case KeePass2Repair::NothingTodo:
MessageBox::information(this, tr("Error"), tr("Database opened fine. Nothing to do."));
emit editFinished(false);
return;
case KeePass2Repair::UnableToOpen:
MessageBox::warning(
this, tr("Error"), tr("Unable to open the database.").append("\n").append(repair.errorString()));
emit editFinished(false);
return;
case KeePass2Repair::RepairSuccess:
m_db = repairOutcome.second;
MessageBox::warning(
this, tr("Success"), tr("The database has been successfully repaired\nYou can now save it."));
emit editFinished(true);
return;
case KeePass2Repair::RepairFailed:
MessageBox::warning(this, tr("Error"), tr("Unable to repair the database."));
emit editFinished(false);
return;
}
}
void DatabaseRepairWidget::processEditFinished(bool result)
{
if (result) {
emit success();
} else {
emit error();
}
}

View File

@ -1,41 +0,0 @@
/*
* Copyright (C) 2016 Felix Geyer <debfx@fobos.de>
*
* 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 <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSX_DATABASEREPAIRWIDGET_H
#define KEEPASSX_DATABASEREPAIRWIDGET_H
#include "gui/DatabaseOpenWidget.h"
class DatabaseRepairWidget : public DatabaseOpenWidget
{
Q_OBJECT
public:
explicit DatabaseRepairWidget(QWidget* parent = nullptr);
signals:
void success();
void error();
protected:
void openDatabase() override;
private slots:
void processEditFinished(bool result);
};
#endif // KEEPASSX_DATABASEREPAIRWIDGET_H

View File

@ -32,12 +32,8 @@
#include "core/FilePath.h"
#include "core/InactivityTimer.h"
#include "core/Metadata.h"
#include "format/KeePass2Writer.h"
#include "gui/AboutDialog.h"
#include "gui/DatabaseRepairWidget.h"
#include "gui/DatabaseWidget.h"
#include "gui/FileDialog.h"
#include "gui/MessageBox.h"
#include "gui/SearchWidget.h"
#ifdef WITH_XC_SSHAGENT
@ -278,7 +274,6 @@ MainWindow::MainWindow()
connect(m_ui->actionChangeDatabaseSettings, SIGNAL(triggered()), m_ui->tabWidget, SLOT(changeDatabaseSettings()));
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->actionRepairDatabase, SIGNAL(triggered()), this, SLOT(repairDatabase()));
connect(m_ui->actionExportCsv, SIGNAL(triggered()), m_ui->tabWidget, SLOT(exportToCsv()));
connect(m_ui->actionLockDatabases, SIGNAL(triggered()), m_ui->tabWidget, SLOT(lockDatabases()));
connect(m_ui->actionQuit, SIGNAL(triggered()), SLOT(appExit()));
@ -448,7 +443,6 @@ void MainWindow::setMenuActionState(DatabaseWidget::Mode mode)
m_ui->actionDatabaseOpen->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
m_ui->menuRecentDatabases->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
m_ui->menuImport->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
m_ui->actionRepairDatabase->setEnabled(inDatabaseTabWidgetOrWelcomeWidget);
m_ui->actionLockDatabases->setEnabled(m_ui->tabWidget->hasLockableDatabases());
@ -963,39 +957,6 @@ void MainWindow::forgetTouchIDAfterInactivity()
#endif
}
void MainWindow::repairDatabase()
{
QString filter = QString("%1 (*.kdbx);;%2 (*)").arg(tr("KeePass 2 Database"), tr("All files"));
QString fileName = fileDialog()->getOpenFileName(this, tr("Open database"), QString(), filter);
if (fileName.isEmpty()) {
return;
}
QScopedPointer<QDialog> dialog(new QDialog(this));
DatabaseRepairWidget* dbRepairWidget = new DatabaseRepairWidget(dialog.data());
connect(dbRepairWidget, SIGNAL(success()), dialog.data(), SLOT(accept()));
connect(dbRepairWidget, SIGNAL(error()), dialog.data(), SLOT(reject()));
dbRepairWidget->load(fileName);
if (dialog->exec() == QDialog::Accepted && dbRepairWidget->database()) {
QString saveFileName = fileDialog()->getSaveFileName(this,
tr("Save repaired database"),
QString(),
tr("KeePass 2 Database").append(" (*.kdbx)"),
nullptr,
0,
"kdbx");
if (!saveFileName.isEmpty()) {
KeePass2Writer writer;
writer.writeDatabase(saveFileName, dbRepairWidget->database());
if (writer.hasError()) {
displayGlobalMessage(tr("Writing the database failed.").append("\n").append(writer.errorString()),
MessageWidget::Error);
}
}
}
}
bool MainWindow::isTrayIconEnabled() const
{
return config()->get("GUI/ShowTrayIcon").toBool() && QSystemTrayIcon::isSystemTrayAvailable();

View File

@ -107,7 +107,6 @@ private slots:
void toggleWindow();
void lockDatabasesAfterInactivity();
void forgetTouchIDAfterInactivity();
void repairDatabase();
void hideTabMessage();
void handleScreenLock();
void showErrorMessage(const QString& message);

View File

@ -215,7 +215,6 @@
<addaction name="actionDatabaseMerge"/>
<addaction name="menuImport"/>
<addaction name="actionExportCsv"/>
<addaction name="actionRepairDatabase"/>
<addaction name="separator"/>
<addaction name="actionQuit"/>
</widget>
@ -576,11 +575,6 @@
<string>Import CSV file...</string>
</property>
</action>
<action name="actionRepairDatabase">
<property name="text">
<string>Re&amp;pair database...</string>
</property>
</action>
<action name="actionEntryTotp">
<property name="text">
<string>Show TOTP</string>

View File

@ -24,7 +24,6 @@
#include "format/KdbxXmlWriter.h"
#include "format/KeePass2.h"
#include "format/KeePass2Reader.h"
#include "format/KeePass2Repair.h"
#include "format/KeePass2Writer.h"
#include "keys/PasswordKey.h"
@ -181,34 +180,3 @@ void TestKdbx3::testBrokenHeaderHash()
QVERIFY(!db.data());
QVERIFY(reader.hasError());
}
void TestKdbx3::testKdbxRepair()
{
QString brokenDbFilename = QString(KEEPASSX_TEST_DATA_DIR).append("/bug392.kdbx");
// master password = test
// entry username: testuser\x10\x20AC
// entry password: testpw
auto key = QSharedPointer<CompositeKey>::create();
key->addKey(QSharedPointer<PasswordKey>::create("test"));
// test that we can't open the broken database
bool hasError;
QString errorString;
QScopedPointer<Database> dbBroken;
readKdbx(brokenDbFilename, key, dbBroken, hasError, errorString);
QVERIFY(!dbBroken.data());
QVERIFY(hasError);
// test if we can repair the database
KeePass2Repair repair;
QFile file(brokenDbFilename);
file.open(QIODevice::ReadOnly);
auto result = repair.repairDatabase(&file, key);
QCOMPARE(result.first, KeePass2Repair::RepairSuccess);
QScopedPointer<Database> dbRepaired(result.second);
QVERIFY(dbRepaired);
QCOMPARE(dbRepaired->rootGroup()->entries().size(), 1);
QCOMPARE(dbRepaired->rootGroup()->entries().at(0)->username(), QString("testuser").append(QChar(0x20AC)));
QCOMPARE(dbRepaired->rootGroup()->entries().at(0)->password(), QString("testpw"));
}

View File

@ -30,7 +30,6 @@ private slots:
void testProtectedStrings();
void testBrokenHeaderHash();
void testFormat300();
void testKdbxRepair();
protected:
void initTestCaseImpl() override;

Binary file not shown.