mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-10-01 01:26:01 -04:00
parent
79b15e2ac6
commit
65f2790170
@ -19,11 +19,13 @@
|
||||
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QTextCodec>
|
||||
#include <QtGui/QImage>
|
||||
|
||||
#include "core/Database.h"
|
||||
#include "core/Endian.h"
|
||||
#include "core/Entry.h"
|
||||
#include "core/Group.h"
|
||||
#include "core/Metadata.h"
|
||||
#include "crypto/CryptoHash.h"
|
||||
#include "format/KeePass1.h"
|
||||
#include "keys/CompositeKey.h"
|
||||
@ -170,9 +172,7 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor
|
||||
|
||||
Q_FOREACH (Entry* entry, entries) {
|
||||
if (isMetaStream(entry)) {
|
||||
if (!parseMetaStream(entry)) {
|
||||
return 0;
|
||||
}
|
||||
parseMetaStream(entry);
|
||||
|
||||
delete entry;
|
||||
}
|
||||
@ -189,12 +189,10 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor
|
||||
group->setUpdateTimeinfo(true);
|
||||
}
|
||||
|
||||
Q_FOREACH (Entry* entry, entries) {
|
||||
Q_FOREACH (Entry* entry, m_db->rootGroup()->entriesRecursive()) {
|
||||
entry->setUpdateTimeinfo(true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return db.take();
|
||||
}
|
||||
|
||||
@ -607,7 +605,7 @@ bool KeePass1Reader::constructGroupTree(const QList<Group*> groups)
|
||||
else {
|
||||
for (int j = (i - 1); j >= 0; j--) {
|
||||
if (m_groupLevels.value(groups[j]) < level) {
|
||||
if ((m_groupLevels.value(groups[j]) - level) != 1) {
|
||||
if ((level - m_groupLevels.value(groups[j])) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -625,9 +623,127 @@ bool KeePass1Reader::constructGroupTree(const QList<Group*> groups)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KeePass1Reader::parseMetaStream(const Entry* entry)
|
||||
void KeePass1Reader::parseMetaStream(const Entry* entry)
|
||||
{
|
||||
// TODO: implement
|
||||
QByteArray data = entry->attachments()->value("bin-stream");
|
||||
|
||||
if (entry->notes() == "KPX_GROUP_TREE_STATE") {
|
||||
if (!parseGroupTreeState(data)) {
|
||||
qWarning("Unable to parse group tree state metastream.");
|
||||
}
|
||||
}
|
||||
else if (entry->notes() == "KPX_CUSTOM_ICONS_4") {
|
||||
if (!parseCustomIcons4(data)) {
|
||||
qWarning("Unable to parse custom icons metastream.");
|
||||
}
|
||||
}
|
||||
else {
|
||||
qWarning("Ignoring unknown metastream \"%s\".", entry->notes().toLocal8Bit().constData());
|
||||
}
|
||||
}
|
||||
|
||||
bool KeePass1Reader::parseGroupTreeState(const QByteArray& data)
|
||||
{
|
||||
if (data.size() < 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
quint32 num = Endian::bytesToUInt32(data.mid(pos, 4), KeePass1::BYTEORDER);
|
||||
pos += 4;
|
||||
|
||||
if ((data.size() - 4) != (num * 5)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (quint32 i = 0; i < num; i++) {
|
||||
quint32 groupId = Endian::bytesToUInt32(data.mid(pos, 4), KeePass1::BYTEORDER);
|
||||
pos += 4;
|
||||
|
||||
bool expanded = data.at(pos);
|
||||
pos += 1;
|
||||
|
||||
if (m_groupIds.contains(groupId)) {
|
||||
m_groupIds[groupId]->setExpanded(expanded);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool KeePass1Reader::parseCustomIcons4(const QByteArray& data)
|
||||
{
|
||||
if (data.size() < 12) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int pos = 0;
|
||||
|
||||
quint32 numIcons = Endian::bytesToUInt32(data.mid(pos, 4), KeePass1::BYTEORDER);
|
||||
pos += 4;
|
||||
|
||||
quint32 numEntries = Endian::bytesToUInt32(data.mid(pos, 4), KeePass1::BYTEORDER);
|
||||
pos += 4;
|
||||
|
||||
quint32 numGroups = Endian::bytesToUInt32(data.mid(pos, 4), KeePass1::BYTEORDER);
|
||||
pos += 4;
|
||||
|
||||
QList<Uuid> iconUuids;
|
||||
|
||||
for (quint32 i = 0; i < numIcons; i++) {
|
||||
if (data.size() < (pos + 4)) {
|
||||
return false;
|
||||
}
|
||||
quint32 iconSize = Endian::bytesToUInt32(data.mid(pos, 4), KeePass1::BYTEORDER);
|
||||
pos += 4;
|
||||
|
||||
if (data.size() < (pos + iconSize)) {
|
||||
return false;
|
||||
}
|
||||
QImage icon = QImage::fromData(data.mid(pos, iconSize));
|
||||
pos += iconSize;
|
||||
|
||||
if (icon.width() != 16 || icon.height() != 16) {
|
||||
icon = icon.scaled(16, 16);
|
||||
}
|
||||
|
||||
Uuid uuid = Uuid::random();
|
||||
iconUuids.append(uuid);
|
||||
m_db->metadata()->addCustomIcon(uuid, icon);
|
||||
}
|
||||
|
||||
if (data.size() < (pos + numEntries * 20)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (quint32 i = 0; i < numEntries; i++) {
|
||||
QByteArray entryUuid = data.mid(pos, 16);
|
||||
pos += 16;
|
||||
|
||||
int iconId = Endian::bytesToUInt32(data.mid(pos, 4), KeePass1::BYTEORDER);
|
||||
pos += 4;
|
||||
|
||||
if (m_entryUuids.contains(entryUuid) && (iconId < iconUuids.size())) {
|
||||
m_entryUuids[entryUuid]->setIcon(iconUuids[iconId]);
|
||||
}
|
||||
}
|
||||
|
||||
if (data.size() < (pos + numGroups * 8)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (quint32 i = 0; i < numGroups; i++) {
|
||||
quint32 groupId = Endian::bytesToUInt32(data.mid(pos, 4), KeePass1::BYTEORDER);
|
||||
pos += 4;
|
||||
|
||||
int iconId = Endian::bytesToUInt32(data.mid(pos, 4), KeePass1::BYTEORDER);
|
||||
pos += 4;
|
||||
|
||||
if (m_groupIds.contains(groupId) && (iconId < iconUuids.size())) {
|
||||
m_groupIds[groupId]->setIcon(iconUuids[iconId]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,9 @@ private:
|
||||
Group* readGroup(QIODevice* cipherStream);
|
||||
Entry* readEntry(QIODevice* cipherStream);
|
||||
bool constructGroupTree(const QList<Group*> groups);
|
||||
bool parseMetaStream(const Entry* entry);
|
||||
void parseMetaStream(const Entry* entry);
|
||||
bool parseGroupTreeState(const QByteArray& data);
|
||||
bool parseCustomIcons4(const QByteArray& data);
|
||||
void raiseError(const QString& str);
|
||||
static QDateTime dateFromPackedStruct(const QByteArray& data);
|
||||
static bool isMetaStream(const Entry* entry);
|
||||
|
@ -24,29 +24,31 @@
|
||||
#include "core/Database.h"
|
||||
#include "core/Entry.h"
|
||||
#include "core/Group.h"
|
||||
#include "core/Metadata.h"
|
||||
#include "crypto/Crypto.h"
|
||||
#include "format/KeePass1Reader.h"
|
||||
|
||||
void TestKeePass1Reader::initTestCase()
|
||||
{
|
||||
Crypto::init();
|
||||
|
||||
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/basic.kdb");
|
||||
|
||||
KeePass1Reader reader;
|
||||
m_db = reader.readDatabase(filename, "masterpw", QByteArray());
|
||||
QVERIFY(m_db);
|
||||
QVERIFY(!reader.hasError());
|
||||
}
|
||||
|
||||
void TestKeePass1Reader::testBasic()
|
||||
{
|
||||
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/basic.kdb");
|
||||
QCOMPARE(m_db->rootGroup()->children().size(), 2);
|
||||
|
||||
KeePass1Reader reader;
|
||||
Database* db = reader.readDatabase(filename, "masterpw", QByteArray());
|
||||
QVERIFY(db);
|
||||
QVERIFY(!reader.hasError());
|
||||
|
||||
QCOMPARE(db->rootGroup()->children().size(), 2);
|
||||
|
||||
Group* group1 = db->rootGroup()->children().at(0);
|
||||
Group* group1 = m_db->rootGroup()->children().at(0);
|
||||
QCOMPARE(group1->name(), QString("Internet"));
|
||||
QCOMPARE(group1->iconNumber(), 1);
|
||||
QCOMPARE(group1->children().size(), 2);
|
||||
QCOMPARE(group1->entries().size(), 2);
|
||||
QCOMPARE(group1->iconNumber(), 1);
|
||||
|
||||
Entry* entry11 = group1->entries().at(0);
|
||||
QCOMPARE(entry11->title(), QString("Test entry"));
|
||||
@ -71,12 +73,58 @@ void TestKeePass1Reader::testBasic()
|
||||
QVERIFY(!entry12->timeInfo().expires());
|
||||
QCOMPARE(entry12->attachments()->keys().size(), 0);
|
||||
|
||||
Group* group2 = db->rootGroup()->children().at(1);
|
||||
QCOMPARE(group2->name(), QString("eMail"));
|
||||
QCOMPARE(group2->iconNumber(), 19);
|
||||
QCOMPARE(group2->entries().size(), 0);
|
||||
Group* group11 = group1->children().at(0);
|
||||
QCOMPARE(group11->name(), QString("Subgroup 1"));
|
||||
QCOMPARE(group11->children().size(), 1);
|
||||
|
||||
delete db;
|
||||
Group* group111 = group11->children().at(0);
|
||||
QCOMPARE(group111->name(), QString("Unexpanded"));
|
||||
QCOMPARE(group111->children().size(), 1);
|
||||
|
||||
Group* group1111 = group111->children().at(0);
|
||||
QCOMPARE(group1111->name(), QString("abc"));
|
||||
QCOMPARE(group1111->children().size(), 0);
|
||||
|
||||
Group* group12 = group1->children().at(1);
|
||||
QCOMPARE(group12->name(), QString("Subgroup 2"));
|
||||
QCOMPARE(group12->children().size(), 0);
|
||||
|
||||
Group* group2 = m_db->rootGroup()->children().at(1);
|
||||
QCOMPARE(group2->name(), QString("eMail"));
|
||||
QCOMPARE(group2->entries().size(), 1);
|
||||
QCOMPARE(group2->iconNumber(), 19);
|
||||
}
|
||||
|
||||
void TestKeePass1Reader::testCustomIcons()
|
||||
{
|
||||
QCOMPARE(m_db->metadata()->customIcons().size(), 1);
|
||||
|
||||
Entry* entry = m_db->rootGroup()->children().at(1)->entries().first();
|
||||
|
||||
QCOMPARE(entry->icon().width(), 16);
|
||||
QCOMPARE(entry->icon().height(), 16);
|
||||
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
QRgb rgb = entry->icon().pixel(x, y);
|
||||
QCOMPARE(qRed(rgb), 8);
|
||||
QCOMPARE(qGreen(rgb), 160);
|
||||
QCOMPARE(qBlue(rgb), 60);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TestKeePass1Reader::testGroupExpanded()
|
||||
{
|
||||
QCOMPARE(m_db->rootGroup()->children().at(0)->isExpanded(), true);
|
||||
QCOMPARE(m_db->rootGroup()->children().at(0)->children().at(0)->isExpanded(), true);
|
||||
QCOMPARE(m_db->rootGroup()->children().at(0)->children().at(0)->children().at(0)->isExpanded(),
|
||||
false);
|
||||
}
|
||||
|
||||
void TestKeePass1Reader::cleanupTestCase()
|
||||
{
|
||||
delete m_db;
|
||||
}
|
||||
|
||||
QDateTime TestKeePass1Reader::genDT(int year, int month, int day, int hour, int min)
|
||||
|
@ -21,6 +21,8 @@
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QtCore/QObject>
|
||||
|
||||
class Database;
|
||||
|
||||
class TestKeePass1Reader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -28,9 +30,14 @@ class TestKeePass1Reader : public QObject
|
||||
private Q_SLOTS:
|
||||
void initTestCase();
|
||||
void testBasic();
|
||||
void testCustomIcons();
|
||||
void testGroupExpanded();
|
||||
void cleanupTestCase();
|
||||
|
||||
private:
|
||||
static QDateTime genDT(int year, int month, int day, int hour, int min);
|
||||
|
||||
Database* m_db;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_TESTKEEPASS1READER_H
|
||||
|
Binary file not shown.
Loading…
Reference in New Issue
Block a user