File indexing completed on 2024-05-12 05:52:46
0001 /* 0002 * SPDX-License-Identifier: GPL-3.0-or-later 0003 * SPDX-FileCopyrightText: 2020 Johan Ouwerkerk <jm.ouwerkerk@gmail.com> 0004 */ 0005 #include "account/actions_p.h" 0006 0007 #include "../test-utils/secret.h" 0008 #include "../../test-utils/spy.h" 0009 0010 #include <QSignalSpy> 0011 #include <QTest> 0012 0013 class ComputeTotpTest: public QObject 0014 { 0015 Q_OBJECT 0016 private Q_SLOTS: 0017 void initTestCase(void); 0018 void testDefaults(void); 0019 void testDefaults_data(void); 0020 private: 0021 accounts::AccountSecret m_secret; 0022 }; 0023 0024 // RFC test vector uses the key: 12345678901234567890 0025 static QByteArray rfcSecret("12345678901234567890"); 0026 0027 // the RFC test vector consists of 6-character tokens 0028 static uint tokenLength = 6; 0029 0030 // the default TOTP timestep is 30s 0031 static uint timeStep = 30; 0032 0033 // the default TOTP epoch is the Unix epoch 0034 static QDateTime epoch = QDateTime::fromMSecsSinceEpoch(0); 0035 0036 void ComputeTotpTest::initTestCase(void) 0037 { 0038 QVERIFY2(test::useDummyPassword(&m_secret), "should be able to set up the master key"); 0039 } 0040 0041 void ComputeTotpTest::testDefaults(void) 0042 { 0043 QFETCH(qint64, counter); 0044 std::function<qint64(void)> clock([counter](void) -> qint64 { 0045 return counter * timeStep * 1000; 0046 }); 0047 0048 0049 0050 std::optional<secrets::EncryptedSecret> tokenSecret = test::encrypt(&m_secret, rfcSecret); 0051 QVERIFY2(tokenSecret, "should be able to encrypt the token secret"); 0052 0053 accounts::ComputeTotp uut(&m_secret, *tokenSecret, tokenLength, epoch, timeStep, accounts::Account::Hash::Sha1, clock); 0054 QSignalSpy tokenGenerated(&uut, &accounts::ComputeTotp::otp); 0055 QSignalSpy jobFinished(&uut, &accounts::ComputeTotp::finished); 0056 0057 uut.run(); 0058 0059 QVERIFY2(test::signal_eventually_emitted_once(tokenGenerated), "token should be generated by now"); 0060 QVERIFY2(test::signal_eventually_emitted_once(jobFinished), "job should be finished by now"); 0061 0062 QTEST(tokenGenerated.at(0).at(0).toString(), "rfc-test-vector"); 0063 QCOMPARE(tokenGenerated.at(0).at(2).toDateTime(), QDateTime::fromMSecsSinceEpoch(timeStep * 1000 * (counter + 1))); // from 0064 QCOMPARE(tokenGenerated.at(0).at(3).toDateTime(), QDateTime::fromMSecsSinceEpoch(timeStep * 1000 * (counter + 2))); // until 0065 } 0066 0067 static void define_test_case(int k, const char *expected) 0068 { 0069 0070 QByteArray output(expected, tokenLength); 0071 QTest::newRow(qPrintable(QStringLiteral("RFC 4226 test vector, # time steps = %1").arg(k))) << (qint64) k << QString::fromLocal8Bit(output); 0072 } 0073 0074 void ComputeTotpTest::testDefaults_data(void) 0075 { 0076 static const char * corpus[10] { 0077 "755224", 0078 "287082", 0079 "359152", 0080 "969429", 0081 "338314", 0082 "254676", 0083 "287922", 0084 "162583", 0085 "399871", 0086 "520489" 0087 }; 0088 0089 QTest::addColumn<qint64>("counter"); 0090 QTest::addColumn<QString>("rfc-test-vector"); 0091 0092 for (int k = 0; k < 10; ++k) { 0093 define_test_case(k, corpus[k]); 0094 } 0095 } 0096 0097 QTEST_MAIN(ComputeTotpTest) 0098 0099 #include "compute-totp.moc"