From b6d9c2e48683bef9a7e8d9c96ea146880447449e Mon Sep 17 00:00:00 2001 From: Felix Geyer Date: Thu, 19 Jul 2012 23:21:12 +0200 Subject: [PATCH] Import Auto-Type associations in KeePass1Reader. --- src/format/KeePass1Reader.cpp | 64 +++++++++++++++++++++++++++++++++- src/format/KeePass1Reader.h | 1 + tests/TestKeePass1Reader.cpp | 30 ++++++++++++++++ tests/TestKeePass1Reader.h | 1 + tests/data/basic.kdb | Bin 1836 -> 2476 bytes 5 files changed, 95 insertions(+), 1 deletion(-) diff --git a/src/format/KeePass1Reader.cpp b/src/format/KeePass1Reader.cpp index 73ea564da..94f237e11 100644 --- a/src/format/KeePass1Reader.cpp +++ b/src/format/KeePass1Reader.cpp @@ -567,7 +567,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream) entry->setPassword(QString::fromUtf8(fieldData.constData())); break; case 0x0008: - entry->setNotes(QString::fromUtf8(fieldData.constData())); + parseNotes(QString::fromUtf8(fieldData.constData()), entry.data()); break; case 0x0009: { @@ -636,6 +636,68 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream) return entry.take(); } +void KeePass1Reader::parseNotes(const QString& rawNotes, Entry* entry) +{ + QRegExp sequenceRegexp("Auto-Type(?:-(\\d+))?: (.+)", Qt::CaseInsensitive, QRegExp::RegExp2); + QRegExp windowRegexp("Auto-Type-Window(?:-(\\d+))?: (.+)", Qt::CaseInsensitive, QRegExp::RegExp2); + QHash sequences; + QMap windows; + + QStringList notes; + + bool lastLineAutoType = false; + Q_FOREACH (QString line, rawNotes.split("\n")) { + line.remove("\r"); + + if (sequenceRegexp.exactMatch(line)) { + if (sequenceRegexp.cap(1).isEmpty()) { + entry->setDefaultAutoTypeSequence(sequenceRegexp.cap(2)); + } + else { + sequences[sequenceRegexp.cap(1).toInt()] = sequenceRegexp.cap(2); + } + + lastLineAutoType = true; + } + else if (windowRegexp.exactMatch(line)) { + int nr; + if (windowRegexp.cap(1).isEmpty()) { + nr = -1; // special number that matches no other sequence + } + else { + nr = windowRegexp.cap(1).toInt(); + } + + windows[nr].append(windowRegexp.cap(2)); + + lastLineAutoType = true; + } + else { + // don't add empty lines following a removed auto-type line + if (!lastLineAutoType || !line.isEmpty()) { + notes.append(line); + } + lastLineAutoType = false; + } + } + + entry->setNotes(notes.join("\n")); + + QMapIterator i(windows); + while (i.hasNext()) { + i.next(); + + QString sequence = sequences.value(i.key()); + + Q_FOREACH (const QString& window, i.value()) { + AutoTypeAssociations::Association assoc; + assoc.window = window; + assoc.sequence = sequence; + entry->autoTypeAssociations()->add(assoc); + } + } +} + bool KeePass1Reader::constructGroupTree(const QList groups) { for (int i = 0; i < groups.size(); i++) { diff --git a/src/format/KeePass1Reader.h b/src/format/KeePass1Reader.h index 3375c100e..643587484 100644 --- a/src/format/KeePass1Reader.h +++ b/src/format/KeePass1Reader.h @@ -57,6 +57,7 @@ private: bool verifyKey(SymmetricCipherStream* cipherStream); Group* readGroup(QIODevice* cipherStream); Entry* readEntry(QIODevice* cipherStream); + void parseNotes(const QString& rawNotes, Entry* entry); bool constructGroupTree(const QList groups); void parseMetaStream(const Entry* entry); bool parseGroupTreeState(const QByteArray& data); diff --git a/tests/TestKeePass1Reader.cpp b/tests/TestKeePass1Reader.cpp index b15e8a032..a7e1114fe 100644 --- a/tests/TestKeePass1Reader.cpp +++ b/tests/TestKeePass1Reader.cpp @@ -139,6 +139,36 @@ void TestKeePass1Reader::testGroupExpanded() false); } +void TestKeePass1Reader::testAutoType() +{ + Group* group = m_db->rootGroup()->children().at(0)->children().at(0); + QCOMPARE(group->entries().size(), 2); + + Entry* entry1 = group->entries().at(0); + QCOMPARE(entry1->notes(), QString("last line")); + QCOMPARE(entry1->defaultAutoTypeSequence(), QString("{USERNAME}{ENTER}")); + QCOMPARE(entry1->autoTypeAssociations()->size(), 5); + QCOMPARE(entry1->autoTypeAssociations()->get(0).sequence, QString("")); + QCOMPARE(entry1->autoTypeAssociations()->get(0).window, QString("a window")); + QCOMPARE(entry1->autoTypeAssociations()->get(1).sequence, QString("")); + QCOMPARE(entry1->autoTypeAssociations()->get(1).window, QString("a second window")); + QCOMPARE(entry1->autoTypeAssociations()->get(2).sequence, QString("{PASSWORD}{ENTER}")); + QCOMPARE(entry1->autoTypeAssociations()->get(2).window, QString("Window Nr 1a")); + QCOMPARE(entry1->autoTypeAssociations()->get(3).sequence, QString("{PASSWORD}{ENTER}")); + QCOMPARE(entry1->autoTypeAssociations()->get(3).window, QString("Window Nr 1b")); + QCOMPARE(entry1->autoTypeAssociations()->get(4).sequence, QString("")); + QCOMPARE(entry1->autoTypeAssociations()->get(4).window, QString("Window 2")); + + Entry* entry2 = group->entries().at(1); + QCOMPARE(entry2->notes(), QString("start line\nend line")); + QCOMPARE(entry2->defaultAutoTypeSequence(), QString("")); + QCOMPARE(entry2->autoTypeAssociations()->size(), 2); + QCOMPARE(entry2->autoTypeAssociations()->get(0).sequence, QString("")); + QCOMPARE(entry2->autoTypeAssociations()->get(0).window, QString("Main Window")); + QCOMPARE(entry2->autoTypeAssociations()->get(1).sequence, QString("")); + QCOMPARE(entry2->autoTypeAssociations()->get(1).window, QString("Test Window")); +} + void TestKeePass1Reader::testFileKey() { QFETCH(QString, type); diff --git a/tests/TestKeePass1Reader.h b/tests/TestKeePass1Reader.h index a4fc8a0e5..4088d9f02 100644 --- a/tests/TestKeePass1Reader.h +++ b/tests/TestKeePass1Reader.h @@ -33,6 +33,7 @@ private Q_SLOTS: void testMasterKey(); void testCustomIcons(); void testGroupExpanded(); + void testAutoType(); void testFileKey(); void testFileKey_data(); void testCompositeKey(); diff --git a/tests/data/basic.kdb b/tests/data/basic.kdb index b0daacabcec4972da2852da366ef81c466173f54..16968bafa995144a3d842ce26483f6e9c39a444c 100644 GIT binary patch delta 2467 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 Mu4I#ORZ!0YC@?pP;Q#;t