Replace Optional with QVariant

This commit is contained in:
Adolfo E. García 2017-10-20 16:55:02 -06:00 committed by Janek Bevendorff
parent 905e104ba2
commit 24f560aaa2
6 changed files with 54 additions and 120 deletions

View File

@ -61,7 +61,6 @@ set(keepassx_SOURCES
core/Uuid.cpp core/Uuid.cpp
core/Base32.h core/Base32.h
core/Base32.cpp core/Base32.cpp
core/Optional.h
cli/PasswordInput.cpp cli/PasswordInput.cpp
cli/PasswordInput.h cli/PasswordInput.h
crypto/Crypto.cpp crypto/Crypto.cpp

View File

@ -40,14 +40,14 @@ constexpr quint8 ASCII_a = static_cast<quint8>('a');
constexpr quint8 ASCII_z = static_cast<quint8>('z'); constexpr quint8 ASCII_z = static_cast<quint8>('z');
constexpr quint8 ASCII_EQ = static_cast<quint8>('='); constexpr quint8 ASCII_EQ = static_cast<quint8>('=');
Optional<QByteArray> Base32::decode(const QByteArray& encodedData) QVariant Base32::decode(const QByteArray& encodedData)
{ {
if (encodedData.size() <= 0) { if (encodedData.size() <= 0) {
return Optional<QByteArray>(""); return QVariant::fromValue(QByteArray(""));
} }
if (encodedData.size() % 8 != 0) { if (encodedData.size() % 8 != 0) {
return Optional<QByteArray>(); return QVariant();
} }
int nPads = 0; int nPads = 0;
@ -114,7 +114,7 @@ Optional<QByteArray> Base32::decode(const QByteArray& encodedData)
continue; continue;
} else { } else {
// illegal character // illegal character
return Optional<QByteArray>(); return QVariant();
} }
} }
} }
@ -132,7 +132,7 @@ Optional<QByteArray> Base32::decode(const QByteArray& encodedData)
} }
} }
return Optional<QByteArray>(data); return QVariant::fromValue(data);
} }
QByteArray Base32::encode(const QByteArray& data) QByteArray Base32::encode(const QByteArray& data)

View File

@ -24,15 +24,15 @@
#ifndef BASE32_H #ifndef BASE32_H
#define BASE32_H #define BASE32_H
#include "Optional.h"
#include <QByteArray> #include <QByteArray>
#include <QVariant>
#include <QtCore/qglobal.h> #include <QtCore/qglobal.h>
class Base32 class Base32
{ {
public: public:
Base32() = default; Base32() = default;
Q_REQUIRED_RESULT static Optional<QByteArray> decode(const QByteArray&); Q_REQUIRED_RESULT static QVariant decode(const QByteArray&);
Q_REQUIRED_RESULT static QByteArray encode(const QByteArray&); Q_REQUIRED_RESULT static QByteArray encode(const QByteArray&);
Q_REQUIRED_RESULT static QByteArray addPadding(const QByteArray&); Q_REQUIRED_RESULT static QByteArray addPadding(const QByteArray&);
Q_REQUIRED_RESULT static QByteArray removePadding(const QByteArray&); Q_REQUIRED_RESULT static QByteArray removePadding(const QByteArray&);

View File

@ -1,86 +0,0 @@
/*
* 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 OPTIONAL_H
#define OPTIONAL_H
/*
* This utility class is for providing basic support for an option type.
* It can be replaced by std::optional (C++17) or
* std::experimental::optional (C++11) when they become fully supported
* by all the main compiler toolchains.
*/
template <typename T> class Optional
{
public:
// None
Optional()
: m_hasValue(false)
, m_value(){};
// Some T
Optional(const T& value)
: m_hasValue(true)
, m_value(value){};
// Copy
Optional(const Optional& other)
: m_hasValue(other.m_hasValue)
, m_value(other.m_value){};
const Optional& operator=(const Optional& other)
{
m_hasValue = other.m_hasValue;
m_value = other.m_value;
return *this;
}
bool operator==(const Optional& other) const
{
if (m_hasValue)
return other.m_hasValue && m_value == other.m_value;
else
return !other.m_hasValue;
}
bool operator!=(const Optional& other) const
{
return !(*this == other);
}
bool hasValue() const
{
return m_hasValue;
}
T valueOr(const T& other) const
{
return m_hasValue ? m_value : other;
}
Optional static makeOptional(const T& value)
{
return Optional(value);
}
private:
bool m_hasValue;
T m_value;
};
#endif // OPTIONAL_H

View File

@ -24,6 +24,7 @@
#include <QRegExp> #include <QRegExp>
#include <QUrl> #include <QUrl>
#include <QUrlQuery> #include <QUrlQuery>
#include <QVariant>
#include <QtEndian> #include <QtEndian>
#include <cmath> #include <cmath>
@ -98,13 +99,13 @@ QString QTotp::generateTotp(const QByteArray key,
{ {
quint64 current = qToBigEndian(time / step); quint64 current = qToBigEndian(time / step);
Optional<QByteArray> secret = Base32::decode(Base32::sanitizeInput(key)); QVariant secret = Base32::decode(Base32::sanitizeInput(key));
if (!secret.hasValue()) { if (secret.isNull()) {
return "Invalid TOTP secret key"; return "Invalid TOTP secret key";
} }
QMessageAuthenticationCode code(QCryptographicHash::Sha1); QMessageAuthenticationCode code(QCryptographicHash::Sha1);
code.setKey(secret.valueOr("")); code.setKey(secret.toByteArray());
code.addData(QByteArray(reinterpret_cast<char*>(&current), sizeof(current))); code.addData(QByteArray(reinterpret_cast<char*>(&current), sizeof(current)));
QByteArray hmac = code.result(); QByteArray hmac = code.result();

View File

@ -25,86 +25,102 @@ void TestBase32::testDecode()
{ {
// 3 quanta, all upper case + padding // 3 quanta, all upper case + padding
QByteArray encodedData = "JBSWY3DPEB3W64TMMQXC4LQ="; QByteArray encodedData = "JBSWY3DPEB3W64TMMQXC4LQ=";
auto data = Base32::decode(encodedData); QVariant data = Base32::decode(encodedData);
QCOMPARE(QString::fromLatin1(data.valueOr("ERROR")), QString("Hello world...")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("Hello world..."));
// 4 quanta, all upper case // 4 quanta, all upper case
encodedData = "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ"; encodedData = "GEZDGNBVGY3TQOJQGEZDGNBVGY3TQOJQ";
data = Base32::decode(encodedData); data = Base32::decode(encodedData);
QCOMPARE(QString::fromLatin1(data.valueOr("ERROR")), QString("12345678901234567890")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("12345678901234567890"));
// 4 quanta, all lower case // 4 quanta, all lower case
encodedData = "gezdgnbvgy3tqojqgezdgnbvgy3tqojq"; encodedData = "gezdgnbvgy3tqojqgezdgnbvgy3tqojq";
data = Base32::decode(encodedData); data = Base32::decode(encodedData);
QCOMPARE(QString::fromLatin1(data.valueOr("ERROR")), QString("12345678901234567890")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("12345678901234567890"));
// 4 quanta, mixed upper and lower case // 4 quanta, mixed upper and lower case
encodedData = "Gezdgnbvgy3tQojqgezdGnbvgy3tQojQ"; encodedData = "Gezdgnbvgy3tQojqgezdGnbvgy3tQojQ";
data = Base32::decode(encodedData); data = Base32::decode(encodedData);
QCOMPARE(QString::fromLatin1(data.valueOr("ERROR")), QString("12345678901234567890")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("12345678901234567890"));
// 1 pad characters // 1 pad characters
encodedData = "ORSXG5A="; encodedData = "ORSXG5A=";
data = Base32::decode(encodedData); data = Base32::decode(encodedData);
QCOMPARE(QString::fromLatin1(data.valueOr("ERROR")), QString("test")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("test"));
// 3 pad characters // 3 pad characters
encodedData = "L5PV6==="; encodedData = "L5PV6===";
data = Base32::decode(encodedData); data = Base32::decode(encodedData);
QCOMPARE(QString::fromLatin1(data.valueOr("ERROR")), QString("___")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("___"));
// 4 pad characters // 4 pad characters
encodedData = "MZXW6IDCMFZA===="; encodedData = "MZXW6IDCMFZA====";
data = Base32::decode(encodedData); data = Base32::decode(encodedData);
QCOMPARE(QString::fromLatin1(data.valueOr("ERROR")), QString("foo bar")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("foo bar"));
// six pad characters // six pad characters
encodedData = "MZXW6YTBOI======"; encodedData = "MZXW6YTBOI======";
data = Base32::decode(encodedData); data = Base32::decode(encodedData);
QCOMPARE(QString::fromLatin1(data.valueOr("ERROR")), QString("foobar")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("foobar"));
encodedData = "IA======"; encodedData = "IA======";
data = Base32::decode(encodedData); data = Base32::decode(encodedData);
QCOMPARE(QString::fromLatin1(data.valueOr("ERROR")), QString("@")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("@"));
// error: illegal character // error: illegal character
encodedData = "1MZXW6YTBOI====="; encodedData = "1MZXW6YTBOI=====";
data = Base32::decode(encodedData); data = Base32::decode(encodedData);
QCOMPARE(QString::fromLatin1(data.valueOr("ERROR")), QString("ERROR")); QVERIFY(data.isNull());
// error: missing pad character // error: missing pad character
encodedData = "MZXW6YTBOI====="; encodedData = "MZXW6YTBOI=====";
data = Base32::decode(encodedData); data = Base32::decode(encodedData);
QCOMPARE(QString::fromLatin1(data.valueOr("ERROR")), QString("ERROR")); QVERIFY(data.isNull());
// RFC 4648 test vectors // RFC 4648 test vectors
encodedData = ""; encodedData = "";
data = Base32::decode(encodedData); data = Base32::decode(encodedData);
QCOMPARE(QString::fromLatin1(data.valueOr("ERROR")), QString("")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString(""));
encodedData = "MY======"; encodedData = "MY======";
data = Base32::decode(encodedData); data = Base32::decode(encodedData);
QCOMPARE(QString::fromLatin1(data.valueOr("ERROR")), QString("f")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("f"));
encodedData = "MZXQ===="; encodedData = "MZXQ====";
data = Base32::decode(encodedData); data = Base32::decode(encodedData);
QCOMPARE(QString::fromLatin1(data.valueOr("ERROR")), QString("fo")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("fo"));
encodedData = "MZXW6==="; encodedData = "MZXW6===";
data = Base32::decode(encodedData); data = Base32::decode(encodedData);
QCOMPARE(QString::fromLatin1(data.valueOr("ERROR")), QString("foo")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("foo"));
encodedData = "MZXW6YQ="; encodedData = "MZXW6YQ=";
data = Base32::decode(encodedData); data = Base32::decode(encodedData);
QCOMPARE(QString::fromLatin1(data.valueOr("ERROR")), QString("foob")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("foob"));
encodedData = "MZXW6YTB"; encodedData = "MZXW6YTB";
data = Base32::decode(encodedData); data = Base32::decode(encodedData);
QCOMPARE(QString::fromLatin1(data.valueOr("ERROR")), QString("fooba")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("fooba"));
encodedData = "MZXW6YTBOI======"; encodedData = "MZXW6YTBOI======";
data = Base32::decode(encodedData); data = Base32::decode(encodedData);
QCOMPARE(QString::fromLatin1(data.valueOr("ERROR")), QString("foobar")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("foobar"));
} }
void TestBase32::testEncode() void TestBase32::testEncode()
@ -258,21 +274,25 @@ void TestBase32::testSanitizeInput()
// sanitize input (white space + missing padding) // sanitize input (white space + missing padding)
QByteArray encodedData = "JBSW Y3DP EB3W 64TM MQXC 4LQA"; QByteArray encodedData = "JBSW Y3DP EB3W 64TM MQXC 4LQA";
auto data = Base32::decode(Base32::sanitizeInput(encodedData)); auto data = Base32::decode(Base32::sanitizeInput(encodedData));
QCOMPARE(QString::fromLatin1(data.valueOr("ERRROR")), QString("Hello world...")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("Hello world..."));
// sanitize input (typo + missing padding) // sanitize input (typo + missing padding)
encodedData = "J8SWY3DPE83W64TMMQXC4LQA"; encodedData = "J8SWY3DPE83W64TMMQXC4LQA";
data = Base32::decode(Base32::sanitizeInput(encodedData)); data = Base32::decode(Base32::sanitizeInput(encodedData));
QCOMPARE(QString::fromLatin1(data.valueOr("ERRROR")), QString("Hello world...")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("Hello world..."));
// sanitize input (other illegal characters) // sanitize input (other illegal characters)
encodedData = "J8SWY3D[PE83W64TMMQ]XC!4LQA"; encodedData = "J8SWY3D[PE83W64TMMQ]XC!4LQA";
data = Base32::decode(Base32::sanitizeInput(encodedData)); data = Base32::decode(Base32::sanitizeInput(encodedData));
QCOMPARE(QString::fromLatin1(data.valueOr("ERRROR")), QString("Hello world...")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("Hello world..."));
// sanitize input (NUL character) // sanitize input (NUL character)
encodedData = "J8SWY3DPE83W64TMMQXC4LQA"; encodedData = "J8SWY3DPE83W64TMMQXC4LQA";
encodedData.insert(3, '\0'); encodedData.insert(3, '\0');
data = Base32::decode(Base32::sanitizeInput(encodedData)); data = Base32::decode(Base32::sanitizeInput(encodedData));
QCOMPARE(QString::fromLatin1(data.valueOr("ERRROR")), QString("Hello world...")); QVERIFY(!data.isNull());
QCOMPARE(data.toString(), QString("Hello world..."));
} }