diff options
author | Jonathan White <support@dmapps.us> | 2019-06-25 01:03:42 +0300 |
---|---|---|
committer | Jonathan White <support@dmapps.us> | 2019-06-25 22:37:40 +0300 |
commit | 0e0cba653f2648842d90ceef957f52f9ec851f86 (patch) | |
tree | 790e7982c797e812f3e70bd8c5496e7762af1eb5 /tests | |
parent | bb2d7bca5a5de675d6ee1f4ec4c4f868229da47a (diff) |
CLI: add 'analyze' subcommand for offline HIBP breach checks
This new subcommand checks all passwords in the given database against a given list of SHA-1 password hashes. Such lists are available from the "Have I Been Pwned" project at https://haveibeenpwned.com/Passwords.
Note that this support offline checking only. The HIBP project also provides a web API for checking specific hash ranges; this is not currently supported.
Diffstat (limited to 'tests')
-rw-r--r-- | tests/CMakeLists.txt | 3 | ||||
-rw-r--r-- | tests/TestCli.cpp | 21 | ||||
-rw-r--r-- | tests/TestCli.h | 6 | ||||
-rw-r--r-- | tests/TestEntry.cpp | 26 | ||||
-rw-r--r-- | tests/TestEntry.h | 1 | ||||
-rw-r--r-- | tests/TestHibp.cpp | 125 | ||||
-rw-r--r-- | tests/TestHibp.h | 42 | ||||
-rw-r--r-- | tests/data/hibp.txt | 5 |
8 files changed, 227 insertions, 2 deletions
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 6d2867bb6..d76fd3fc5 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -193,6 +193,9 @@ add_unit_test(NAME testpasswordgenerator SOURCES TestPasswordGenerator.cpp add_unit_test(NAME testpassphrasegenerator SOURCES TestPassphraseGenerator.cpp LIBS ${TEST_LIBRARIES}) +add_unit_test(NAME testhibp SOURCES TestHibp.cpp + LIBS ${TEST_LIBRARIES}) + add_unit_test(NAME testtotp SOURCES TestTotp.cpp LIBS ${TEST_LIBRARIES}) diff --git a/tests/TestCli.cpp b/tests/TestCli.cpp index a7bb067c8..d65a7af6c 100644 --- a/tests/TestCli.cpp +++ b/tests/TestCli.cpp @@ -32,6 +32,7 @@ #include "format/KeePass2.h" #include "cli/Add.h" +#include "cli/Analyze.h" #include "cli/Clip.h" #include "cli/Command.h" #include "cli/Create.h" @@ -51,6 +52,7 @@ #include <QFile> #include <QFuture> #include <QSet> +#include <QTextStream> #include <QtConcurrent> #include <cstdio> @@ -160,8 +162,9 @@ QSharedPointer<Database> TestCli::readTestDatabase() const void TestCli::testCommand() { - QCOMPARE(Command::getCommands().size(), 13); + QCOMPARE(Command::getCommands().size(), 14); QVERIFY(Command::getCommand("add")); + QVERIFY(Command::getCommand("analyze")); QVERIFY(Command::getCommand("clip")); QVERIFY(Command::getCommand("create")); QVERIFY(Command::getCommand("diceware")); @@ -239,6 +242,22 @@ void TestCli::testAdd() QCOMPARE(entry->password(), QString("newpassword")); } +void TestCli::testAnalyze() +{ + Analyze analyzeCmd; + QVERIFY(!analyzeCmd.name.isEmpty()); + QVERIFY(analyzeCmd.getDescriptionLine().contains(analyzeCmd.name)); + + const QString hibpPath = QString(KEEPASSX_TEST_DATA_DIR).append("/hibp.txt"); + + Utils::Test::setNextPassword("a"); + analyzeCmd.execute({"analyze", "--hibp", hibpPath, m_dbFile->fileName()}); + m_stdoutFile->reset(); + m_stdoutFile->readLine(); // skip password prompt + auto output = m_stdoutFile->readAll(); + QVERIFY(output.contains("Sample Entry") && output.contains("123")); +} + bool isTOTP(const QString& value) { QString val = value.trimmed(); diff --git a/tests/TestCli.h b/tests/TestCli.h index cd8ebacfb..dcc84c2e3 100644 --- a/tests/TestCli.h +++ b/tests/TestCli.h @@ -21,11 +21,14 @@ #include "core/Database.h" #include "util/TemporaryFile.h" +#include <QByteArray> #include <QFile> #include <QScopedPointer> +#include <QSharedPointer> #include <QTemporaryFile> #include <QTest> -#include <QTextStream> + +#include <stdio.h> class TestCli : public QObject { @@ -42,6 +45,7 @@ private slots: void testCommand(); void testAdd(); + void testAnalyze(); void testClip(); void testCreate(); void testDiceware(); diff --git a/tests/TestEntry.cpp b/tests/TestEntry.cpp index c174e798d..5552549fe 100644 --- a/tests/TestEntry.cpp +++ b/tests/TestEntry.cpp @@ -21,6 +21,7 @@ #include "TestEntry.h" #include "TestGlobal.h" #include "core/Clock.h" +#include "core/Metadata.h" #include "crypto/Crypto.h" QTEST_GUILESS_MAIN(TestEntry) @@ -561,3 +562,28 @@ void TestEntry::testResolveClonedEntry() QCOMPARE(cclone4->resolveMultiplePlaceholders(cclone4->username()), original->username()); QCOMPARE(cclone4->resolveMultiplePlaceholders(cclone4->password()), original->password()); } + +void TestEntry::testIsRecycled() +{ + Entry* entry = new Entry(); + QVERIFY(!entry->isRecycled()); + + Database db; + Group* root = db.rootGroup(); + QVERIFY(root); + entry->setGroup(root); + QVERIFY(!entry->isRecycled()); + + QVERIFY(db.metadata()->recycleBinEnabled()); + db.recycleEntry(entry); + QVERIFY(entry->isRecycled()); + + Group* group1 = new Group(); + group1->setParent(root); + + Entry* entry1 = new Entry(); + entry1->setGroup(group1); + QVERIFY(!entry1->isRecycled()); + db.recycleGroup(group1); + QVERIFY(entry1->isRecycled()); +} diff --git a/tests/TestEntry.h b/tests/TestEntry.h index 7c2350861..ff0cfe07f 100644 --- a/tests/TestEntry.h +++ b/tests/TestEntry.h @@ -37,6 +37,7 @@ private slots: void testResolveReferencePlaceholders(); void testResolveNonIdPlaceholdersToUuid(); void testResolveClonedEntry(); + void testIsRecycled(); }; #endif // KEEPASSX_TESTENTRY_H diff --git a/tests/TestHibp.cpp b/tests/TestHibp.cpp new file mode 100644 index 000000000..f1682bccd --- /dev/null +++ b/tests/TestHibp.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2019 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 "TestHibp.h" + +#include "config-keepassx-tests.h" + +#include "core/Database.h" +#include "core/Entry.h" +#include "core/Group.h" +#include "core/HibpOffline.h" +#include "crypto/Crypto.h" + +#include <QBuffer> +#include <QByteArray> +#include <QFile> +#include <QList> +#include <QTest> + +QTEST_GUILESS_MAIN(TestHibp) + +const char* TEST_HIBP_CONTENTS = "0BEEC7B5EA3F0FDBC95D0DD47F3C5BC275DA8A33:123\n" // SHA-1 of "foo" + "62cdb7020ff920e5aa642c3d4066950dd1f01f4d:456\n"; // SHA-1 of "bar" + +const char* TEST_BAD_HIBP_CONTENTS = "barf:nope\n"; + +void TestHibp::initTestCase() +{ + QVERIFY(Crypto::init()); +} + +void TestHibp::init() +{ + m_db.reset(new Database()); +} + +void TestHibp::testBadHibpFormat() +{ + QByteArray hibpContents(TEST_BAD_HIBP_CONTENTS); + QBuffer hibpBuffer(&hibpContents); + QVERIFY(hibpBuffer.open(QIODevice::ReadOnly)); + + QList<QPair<const Entry*, int>> findings; + QString error; + QVERIFY(!HibpOffline::report(m_db, hibpBuffer, findings, &error)); + QVERIFY(!error.isEmpty()); + QCOMPARE(findings.size(), 0); +} + +void TestHibp::testEmpty() +{ + QByteArray hibpContents(TEST_HIBP_CONTENTS); + QBuffer hibpBuffer(&hibpContents); + QVERIFY(hibpBuffer.open(QIODevice::ReadOnly)); + + QList<QPair<const Entry*, int>> findings; + QString error; + QVERIFY(HibpOffline::report(m_db, hibpBuffer, findings, &error)); + QCOMPARE(error, QString()); + QCOMPARE(findings.size(), 0); +} + +void TestHibp::testIoError() +{ + QBuffer hibpBuffer; + // hibpBuffer has not been opened, so reading will cause I/O error + + QList<QPair<const Entry*, int>> findings; + QString error; + QVERIFY(!HibpOffline::report(m_db, hibpBuffer, findings, &error)); + QVERIFY(!error.isEmpty()); + QCOMPARE(findings.size(), 0); +} + +void TestHibp::testPwned() +{ + QByteArray hibpContents(TEST_HIBP_CONTENTS); + QBuffer hibpBuffer(&hibpContents); + QVERIFY(hibpBuffer.open(QIODevice::ReadOnly)); + + Group* root = m_db->rootGroup(); + + Entry* entry1 = new Entry(); + entry1->setPassword("foo"); + entry1->setGroup(root); + + Entry* entry2 = new Entry(); + entry2->setPassword("xyz"); + entry2->setGroup(root); + + Entry* entry3 = new Entry(); + entry3->setPassword("foo"); + m_db->recycleEntry(entry3); + + Group* group1 = new Group(); + group1->setParent(root); + + Entry* entry4 = new Entry(); + entry4->setPassword("bar"); + entry4->setGroup(group1); + + QList<QPair<const Entry*, int>> findings; + QString error; + QVERIFY(HibpOffline::report(m_db, hibpBuffer, findings, &error)); + QCOMPARE(error, QString()); + QCOMPARE(findings.size(), 2); + QCOMPARE(findings[0].first, entry1); + QCOMPARE(findings[0].second, 123); + QCOMPARE(findings[1].first, entry4); + QCOMPARE(findings[1].second, 456); +} diff --git a/tests/TestHibp.h b/tests/TestHibp.h new file mode 100644 index 000000000..18ec3fb9e --- /dev/null +++ b/tests/TestHibp.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2019 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 KEEPASSXC_TESTHIBP_H +#define KEEPASSXC_TESTHIBP_H + +#include <QObject> +#include <QSharedPointer> + +class Database; + +class TestHibp : public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void init(); + void testBadHibpFormat(); + void testEmpty(); + void testIoError(); + void testPwned(); + +private: + QSharedPointer<Database> m_db; +}; + +#endif // KEEPASSXC_TESTHIBP_H diff --git a/tests/data/hibp.txt b/tests/data/hibp.txt new file mode 100644 index 000000000..6b48666d7 --- /dev/null +++ b/tests/data/hibp.txt @@ -0,0 +1,5 @@ +000000005AD76BD555C1D6D771DE417A4B87E4B4:4
+00000000A8DAE4228F821FB418F59826079BF368:2
+8BE3C943B1609FFFBFC51AAD666D0A04ADF83C9D:123
+00000000DD7F2A1C68A35673713783CA390C9E93:630
+00000001E225B908BAC31C56DB04D892E47536E0:5
|