keepassxc/src/format/KeePass2XmlReader.cpp

943 lines
26 KiB
C++
Raw Normal View History

2010-08-07 09:10:44 -04:00
/*
* Copyright (C) 2010 Felix Geyer <debfx@fobos.de>
*
* 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 "KeePass2XmlReader.h"
2010-08-07 09:10:44 -04:00
#include <QtCore/QBuffer>
2010-08-07 09:10:44 -04:00
#include <QtCore/QFile>
#include "core/Database.h"
2010-09-22 18:21:36 -04:00
#include "core/DatabaseIcons.h"
2011-07-08 07:57:02 -04:00
#include "core/Group.h"
#include "core/Metadata.h"
#include "core/Tools.h"
#include "format/KeePass2RandomStream.h"
#include "streams/QtIOCompressor"
KeePass2XmlReader::KeePass2XmlReader()
: m_randomStream(0)
, m_db(0)
, m_meta(0)
2010-08-07 09:10:44 -04:00
{
}
void KeePass2XmlReader::readDatabase(QIODevice* device, Database* db, KeePass2RandomStream* randomStream)
2010-08-07 09:10:44 -04:00
{
m_xml.clear();
m_xml.setDevice(device);
m_db = db;
m_meta = m_db->metadata();
2012-04-11 09:57:11 -04:00
m_meta->setUpdateDatetime(false);
m_randomStream = randomStream;
2010-08-07 09:10:44 -04:00
m_tmpParent = new Group();
2010-08-07 09:10:44 -04:00
if (!m_xml.error() && m_xml.readNextStartElement()) {
2010-08-07 09:10:44 -04:00
if (m_xml.name() == "KeePassFile") {
parseKeePassFile();
}
}
if (!m_xml.error()) {
if (!m_tmpParent->children().isEmpty()) {
qWarning("KeePass2XmlReader::readDatabase: found %d invalid group reference(s)",
m_tmpParent->children().size());
}
if (!m_tmpParent->entries().isEmpty()) {
qWarning("KeePass2XmlReader::readDatabase: found %d invalid entry reference(s)",
m_tmpParent->children().size());
}
}
QSet<QString> poolKeys = m_binaryPool.keys().toSet();
QSet<QString> entryKeys = m_binaryMap.keys().toSet();
QSet<QString> unmappedKeys = entryKeys - poolKeys;
QSet<QString> unusedKeys = poolKeys - entryKeys;
if (!unmappedKeys.isEmpty()) {
raiseError(17);
}
if (!m_xml.error()) {
Q_FOREACH (const QString& key, unusedKeys) {
qWarning("KeePass2XmlReader::readDatabase: found unused key \"%s\"", qPrintable(key));
}
}
QHash<QString, QPair<Entry*, QString> >::const_iterator i;
for (i = m_binaryMap.constBegin(); i != m_binaryMap.constEnd(); ++i) {
const QPair<Entry*, QString>& target = i.value();
target.first->attachments()->set(target.second, m_binaryPool[i.key()]);
}
2012-04-11 09:57:11 -04:00
m_meta->setUpdateDatetime(true);
2012-04-23 11:02:09 -04:00
QHash<Uuid, Group*>::const_iterator iGroup;
for (iGroup = m_groups.constBegin(); iGroup != m_groups.constEnd(); ++iGroup) {
iGroup.value()->setUpdateTimeinfo(true);
2012-04-11 12:00:28 -04:00
}
2012-04-11 09:57:11 -04:00
QHash<Uuid, Entry*>::const_iterator iEntry;
for (iEntry = m_entries.constBegin(); iEntry != m_entries.constEnd(); ++iEntry) {
iEntry.value()->setUpdateTimeinfo(true);
Q_FOREACH (Entry* histEntry, iEntry.value()->historyItems()) {
histEntry->setUpdateTimeinfo(true);
}
2012-04-11 13:51:54 -04:00
}
2010-08-13 12:08:06 -04:00
delete m_tmpParent;
}
2010-08-13 12:08:06 -04:00
Database* KeePass2XmlReader::readDatabase(QIODevice* device)
{
Database* db = new Database();
readDatabase(device, db);
return db;
}
Database* KeePass2XmlReader::readDatabase(const QString& filename)
{
QFile file(filename);
file.open(QIODevice::ReadOnly);
return readDatabase(&file);
}
bool KeePass2XmlReader::hasError()
{
return m_xml.hasError();
2010-08-07 09:10:44 -04:00
}
QString KeePass2XmlReader::errorString()
2010-08-13 12:08:06 -04:00
{
return QString("%1\nLine %2, column %3")
.arg(m_xml.errorString())
.arg(m_xml.lineNumber())
.arg(m_xml.columnNumber());
}
void KeePass2XmlReader::parseKeePassFile()
2010-08-07 09:10:44 -04:00
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "KeePassFile");
while (!m_xml.error() && m_xml.readNextStartElement()) {
2010-08-07 09:10:44 -04:00
if (m_xml.name() == "Meta") {
parseMeta();
}
else if (m_xml.name() == "Root") {
parseRoot();
}
else {
2010-08-13 12:08:06 -04:00
skipCurrentElement();
2010-08-07 09:10:44 -04:00
}
}
}
void KeePass2XmlReader::parseMeta()
2010-08-07 09:10:44 -04:00
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Meta");
while (!m_xml.error() && m_xml.readNextStartElement()) {
2010-08-07 09:10:44 -04:00
if (m_xml.name() == "Generator") {
m_meta->setGenerator(readString());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "DatabaseName") {
m_meta->setName(readString());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "DatabaseNameChanged") {
m_meta->setNameChanged(readDateTime());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "DatabaseDescription") {
m_meta->setDescription(readString());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "DatabaseDescriptionChanged") {
m_meta->setDescriptionChanged(readDateTime());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "DefaultUserName") {
m_meta->setDefaultUserName(readString());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "DefaultUserNameChanged") {
m_meta->setDefaultUserNameChanged(readDateTime());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "MaintenanceHistoryDays") {
m_meta->setMaintenanceHistoryDays(readNumber());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "Color") {
m_meta->setColor(readColor());
}
else if (m_xml.name() == "MasterKeyChanged") {
m_meta->setMasterKeyChanged(readDateTime());
}
else if (m_xml.name() == "MasterKeyChangeRec") {
m_meta->setMasterKeyChangeRec(readNumber());
}
else if (m_xml.name() == "MasterKeyChangeForce") {
m_meta->setMasterKeyChangeForce(readNumber());
}
2010-08-07 09:10:44 -04:00
else if (m_xml.name() == "MemoryProtection") {
parseMemoryProtection();
}
else if (m_xml.name() == "CustomIcons") {
parseCustomIcons();
}
else if (m_xml.name() == "RecycleBinEnabled") {
m_meta->setRecycleBinEnabled(readBool());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "RecycleBinUUID") {
2010-08-13 12:08:06 -04:00
m_meta->setRecycleBin(getGroup(readUuid()));
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "RecycleBinChanged") {
m_meta->setRecycleBinChanged(readDateTime());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "EntryTemplatesGroup") {
2010-08-13 12:08:06 -04:00
m_meta->setEntryTemplatesGroup(getGroup(readUuid()));
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "EntryTemplatesGroupChanged") {
m_meta->setEntryTemplatesGroupChanged(readDateTime());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "LastSelectedGroup") {
2010-08-13 12:08:06 -04:00
m_meta->setLastSelectedGroup(getGroup(readUuid()));
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "LastTopVisibleGroup") {
2010-08-13 12:08:06 -04:00
m_meta->setLastTopVisibleGroup(getGroup(readUuid()));
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "HistoryMaxItems") {
int value = readNumber();
if (value >= -1) {
m_meta->setHistoryMaxItems(value);
}
else {
raiseError(18);
}
}
else if (m_xml.name() == "HistoryMaxSize") {
int value = readNumber();
if (value >= -1) {
m_meta->setHistoryMaxSize(value);
}
else {
raiseError(19);
}
}
else if (m_xml.name() == "Binaries") {
parseBinaries();
}
2010-08-07 09:10:44 -04:00
else if (m_xml.name() == "CustomData") {
parseCustomData();
}
else {
2010-08-13 12:08:06 -04:00
skipCurrentElement();
2010-08-07 09:10:44 -04:00
}
}
}
void KeePass2XmlReader::parseMemoryProtection()
2010-08-07 09:10:44 -04:00
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "MemoryProtection");
while (!m_xml.error() && m_xml.readNextStartElement()) {
2010-08-07 09:10:44 -04:00
if (m_xml.name() == "ProtectTitle") {
m_meta->setProtectTitle(readBool());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "ProtectUserName") {
m_meta->setProtectUsername(readBool());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "ProtectPassword") {
m_meta->setProtectPassword(readBool());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "ProtectURL") {
m_meta->setProtectUrl(readBool());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "ProtectNotes") {
m_meta->setProtectNotes(readBool());
2010-08-07 09:10:44 -04:00
}
/*else if (m_xml.name() == "AutoEnableVisualHiding") {
m_meta->setAutoEnableVisualHiding(readBool());
}*/
2010-08-07 09:10:44 -04:00
else {
2010-08-13 12:08:06 -04:00
skipCurrentElement();
2010-08-07 09:10:44 -04:00
}
}
}
void KeePass2XmlReader::parseCustomIcons()
2010-08-07 09:10:44 -04:00
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "CustomIcons");
while (!m_xml.error() && m_xml.readNextStartElement()) {
2010-08-07 09:10:44 -04:00
if (m_xml.name() == "Icon") {
parseIcon();
}
else {
2010-08-13 12:08:06 -04:00
skipCurrentElement();
2010-08-07 09:10:44 -04:00
}
}
}
void KeePass2XmlReader::parseIcon()
2010-08-07 09:10:44 -04:00
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Icon");
Uuid uuid;
while (!m_xml.error() && m_xml.readNextStartElement()) {
2010-08-07 09:10:44 -04:00
if (m_xml.name() == "UUID") {
uuid = readUuid();
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "Data") {
QImage icon;
icon.loadFromData(readBinary());
m_meta->addCustomIcon(uuid, icon);
2010-08-07 09:10:44 -04:00
}
else {
2010-08-13 12:08:06 -04:00
skipCurrentElement();
2010-08-07 09:10:44 -04:00
}
}
}
void KeePass2XmlReader::parseBinaries()
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Binaries");
while (!m_xml.error() && m_xml.readNextStartElement()) {
if (m_xml.name() == "Binary") {
QXmlStreamAttributes attr = m_xml.attributes();
QString id = attr.value("ID").toString();
QByteArray data;
if (attr.value("Compressed").compare("True", Qt::CaseInsensitive) == 0) {
data = readCompressedBinary();
}
else {
data = readBinary();
}
if (m_binaryPool.contains(id)) {
qWarning("KeePass2XmlReader::parseBinaries: overwriting binary item \"%s\"",
qPrintable(id));
}
m_binaryPool.insert(id, data);
}
else {
skipCurrentElement();
}
}
}
void KeePass2XmlReader::parseCustomData()
2010-08-07 09:10:44 -04:00
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "CustomData");
2010-08-13 12:08:06 -04:00
while (!m_xml.error() && m_xml.readNextStartElement()) {
if (m_xml.name() == "Item") {
parseCustomDataItem();
}
else {
skipCurrentElement();
}
}
}
void KeePass2XmlReader::parseCustomDataItem()
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Item");
QString key;
while (!m_xml.error() && m_xml.readNextStartElement()) {
if (m_xml.name() == "Key") {
key = readString();
}
else if (m_xml.name() == "Value") {
m_meta->addCustomField(key, readString());
}
else {
skipCurrentElement();
}
2010-08-13 12:08:06 -04:00
}
2010-08-07 09:10:44 -04:00
}
void KeePass2XmlReader::parseRoot()
2010-08-07 09:10:44 -04:00
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Root");
while (!m_xml.error() && m_xml.readNextStartElement()) {
2010-08-07 09:10:44 -04:00
if (m_xml.name() == "Group") {
Group* rootGroup = parseGroup();
2010-08-12 15:43:57 -04:00
if (rootGroup) {
Group* oldRoot = m_db->rootGroup();
2011-07-08 07:57:02 -04:00
m_db->setRootGroup(rootGroup);
delete oldRoot;
}
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "DeletedObjects") {
parseDeletedObjects();
2010-08-07 09:10:44 -04:00
}
else {
2010-08-13 12:08:06 -04:00
skipCurrentElement();
2010-08-07 09:10:44 -04:00
}
}
}
Group* KeePass2XmlReader::parseGroup()
2010-08-07 09:10:44 -04:00
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Group");
Group* group = 0;
while (!m_xml.error() && m_xml.readNextStartElement()) {
2010-08-07 09:10:44 -04:00
if (m_xml.name() == "UUID") {
Uuid uuid = readUuid();
if (uuid.isNull()) {
raiseError(1);
}
else {
2010-08-13 12:08:06 -04:00
group = getGroup(uuid);
}
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "Name") {
group->setName(readString());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "Notes") {
group->setNotes(readString());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "IconID") {
int iconId = readNumber();
2010-08-14 06:24:35 -04:00
if (iconId < 0) {
raiseError(2);
2010-08-14 06:24:35 -04:00
}
else {
if (iconId >= databaseIcons()->iconCount()) {
2010-09-22 18:21:36 -04:00
qWarning("KeePass2XmlReader::parseGroup: icon id \"%d\" not supported", iconId);
}
group->setIcon(iconId);
2010-08-14 06:24:35 -04:00
}
}
else if (m_xml.name() == "CustomIconUUID") {
Uuid uuid = readUuid();
if (!uuid.isNull()) {
group->setIcon(uuid);
}
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "Times") {
group->setTimeInfo(parseTimes());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "IsExpanded") {
group->setExpanded(readBool());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "DefaultAutoTypeSequence") {
group->setDefaultAutoTypeSequence(readString());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "EnableAutoType") {
QString str = readString();
if (str.compare("null", Qt::CaseInsensitive) == 0) {
group->setAutoTypeEnabled(Group::Inherit);
}
else if (str.compare("true", Qt::CaseInsensitive) == 0) {
group->setAutoTypeEnabled(Group::Enable);
}
else if (str.compare("false", Qt::CaseInsensitive) == 0) {
group->setAutoTypeEnabled(Group::Disable);
}
else {
raiseError(3);
}
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "EnableSearching") {
QString str = readString();
if (str.compare("null", Qt::CaseInsensitive) == 0) {
group->setSearchingEnabled(Group::Inherit);
}
else if (str.compare("true", Qt::CaseInsensitive) == 0) {
group->setSearchingEnabled(Group::Enable);
}
else if (str.compare("false", Qt::CaseInsensitive) == 0) {
group->setSearchingEnabled(Group::Disable);
}
else {
raiseError(4);
}
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "LastTopVisibleEntry") {
2010-08-13 12:08:06 -04:00
group->setLastTopVisibleEntry(getEntry(readUuid()));
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "Group") {
Group* newGroup = parseGroup();
if (newGroup) {
newGroup->setParent(group);
}
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "Entry") {
Entry* newEntry = parseEntry(false);
if (newEntry) {
newEntry->setGroup(group);
}
2010-08-07 09:10:44 -04:00
}
else {
2010-08-13 12:08:06 -04:00
skipCurrentElement();
2010-08-07 09:10:44 -04:00
}
}
return group;
2010-08-07 09:10:44 -04:00
}
void KeePass2XmlReader::parseDeletedObjects()
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "DeletedObjects");
while (!m_xml.error() && m_xml.readNextStartElement()) {
if (m_xml.name() == "DeletedObject") {
parseDeletedObject();
}
else {
skipCurrentElement();
}
}
}
void KeePass2XmlReader::parseDeletedObject()
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "DeletedObject");
DeletedObject delObj;
while (!m_xml.error() && m_xml.readNextStartElement()) {
if (m_xml.name() == "UUID") {
Uuid uuid = readUuid();
if (uuid.isNull()) {
raiseError(5);
}
else {
delObj.uuid = uuid;
}
}
else if (m_xml.name() == "DeletionTime") {
delObj.deletionTime = readDateTime();
}
else {
skipCurrentElement();
}
}
m_db->addDeletedObject(delObj);
}
Entry* KeePass2XmlReader::parseEntry(bool history)
2010-08-07 09:10:44 -04:00
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Entry");
Entry* entry = 0;
while (!m_xml.error() && m_xml.readNextStartElement()) {
2010-08-07 09:10:44 -04:00
if (m_xml.name() == "UUID") {
Uuid uuid = readUuid();
if (uuid.isNull()) {
raiseError(6);
}
else {
if (history) {
entry = new Entry();
entry->setUpdateTimeinfo(false);
entry->setUuid(uuid);
}
else {
entry = getEntry(uuid);
}
}
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "IconID") {
int iconId = readNumber();
2010-08-14 06:24:35 -04:00
if (iconId < 0) {
raiseError(7);
2010-08-14 06:24:35 -04:00
}
else {
entry->setIcon(iconId);
2010-08-14 06:24:35 -04:00
}
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "CustomIconUUID") {
Uuid uuid = readUuid();
2010-09-19 15:22:24 -04:00
if (!uuid.isNull()) {
entry->setIcon(uuid);
2010-09-19 15:22:24 -04:00
}
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "ForegroundColor") {
entry->setForegroundColor(readColor());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "BackgroundColor") {
entry->setBackgroundColor(readColor());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "OverrideURL") {
entry->setOverrideUrl(readString());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "Tags") {
entry->setTags(readString());
}
2010-08-07 09:10:44 -04:00
else if (m_xml.name() == "Times") {
entry->setTimeInfo(parseTimes());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "String") {
parseEntryString(entry);
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "Binary") {
parseEntryBinary(entry);
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "AutoType") {
parseAutoType(entry);
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "History") {
if (history) {
raiseError(8);
}
else {
parseEntryHistory(entry);
}
2010-08-07 09:10:44 -04:00
}
else {
2010-08-13 12:08:06 -04:00
skipCurrentElement();
2010-08-07 09:10:44 -04:00
}
}
2010-08-13 12:08:06 -04:00
return entry;
2010-08-07 09:10:44 -04:00
}
2012-05-02 11:04:03 -04:00
void KeePass2XmlReader::parseEntryString(Entry* entry)
2010-08-07 09:10:44 -04:00
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "String");
QString key;
while (!m_xml.error() && m_xml.readNextStartElement()) {
2010-08-07 09:10:44 -04:00
if (m_xml.name() == "Key") {
key = readString();
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "Value") {
QXmlStreamAttributes attr = m_xml.attributes();
QString value = readString();
bool isProtected = attr.value("Protected") == "True";
bool protectInMemory = attr.value("ProtectInMemory") == "True";
if (isProtected && !value.isEmpty()) {
if (m_randomStream) {
value = m_randomStream->process(QByteArray::fromBase64(value.toAscii()));
}
else {
raiseError(9);
}
}
entry->attributes()->set(key, value, isProtected || protectInMemory);
2010-08-07 09:10:44 -04:00
}
else {
2010-08-13 12:08:06 -04:00
skipCurrentElement();
2010-08-07 09:10:44 -04:00
}
}
}
2012-05-02 11:04:03 -04:00
void KeePass2XmlReader::parseEntryBinary(Entry* entry)
2010-08-07 09:10:44 -04:00
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Binary");
QString key;
while (!m_xml.error() && m_xml.readNextStartElement()) {
2010-08-07 09:10:44 -04:00
if (m_xml.name() == "Key") {
key = readString();
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "Value") {
QXmlStreamAttributes attr = m_xml.attributes();
if (attr.hasAttribute("Ref")) {
m_binaryMap.insertMulti(attr.value("Ref").toString(), qMakePair(entry, key));
m_xml.skipCurrentElement();
}
else {
// format compatbility
QByteArray value = readBinary();
bool isProtected = attr.hasAttribute("Protected")
&& (attr.value("Protected") == "True");
if (isProtected && !value.isEmpty()) {
m_randomStream->processInPlace(value);
}
entry->attachments()->set(key, value);
}
2010-08-07 09:10:44 -04:00
}
else {
2010-08-13 12:08:06 -04:00
skipCurrentElement();
2010-08-07 09:10:44 -04:00
}
}
}
void KeePass2XmlReader::parseAutoType(Entry* entry)
2010-08-07 09:10:44 -04:00
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "AutoType");
while (!m_xml.error() && m_xml.readNextStartElement()) {
2010-08-07 09:10:44 -04:00
if (m_xml.name() == "Enabled") {
entry->setAutoTypeEnabled(readBool());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "DataTransferObfuscation") {
entry->setAutoTypeObfuscation(readNumber());
}
else if (m_xml.name() == "DefaultSequence") {
entry->setDefaultAutoTypeSequence(readString());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "Association") {
parseAutoTypeAssoc(entry);
2010-08-07 09:10:44 -04:00
}
else {
2010-08-13 12:08:06 -04:00
skipCurrentElement();
2010-08-07 09:10:44 -04:00
}
}
}
2012-05-02 11:04:03 -04:00
void KeePass2XmlReader::parseAutoTypeAssoc(Entry* entry)
2010-08-07 09:10:44 -04:00
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Association");
AutoTypeAssociation assoc;
while (!m_xml.error() && m_xml.readNextStartElement()) {
2010-08-07 09:10:44 -04:00
if (m_xml.name() == "Window") {
assoc.window = readString();
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "KeystrokeSequence") {
assoc.sequence = readString();
entry->addAutoTypeAssociation(assoc);
2010-08-07 09:10:44 -04:00
}
else {
2010-08-13 12:08:06 -04:00
skipCurrentElement();
2010-08-07 09:10:44 -04:00
}
}
}
void KeePass2XmlReader::parseEntryHistory(Entry* entry)
2010-08-07 09:10:44 -04:00
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "History");
while (!m_xml.error() && m_xml.readNextStartElement()) {
2010-08-07 09:10:44 -04:00
if (m_xml.name() == "Entry") {
Entry* historyItem = parseEntry(true);
entry->addHistoryItem(historyItem);
2010-08-07 09:10:44 -04:00
}
else {
2010-08-13 12:08:06 -04:00
skipCurrentElement();
2010-08-07 09:10:44 -04:00
}
}
}
TimeInfo KeePass2XmlReader::parseTimes()
2010-08-07 09:10:44 -04:00
{
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "Times");
TimeInfo timeInfo;
while (!m_xml.error() && m_xml.readNextStartElement()) {
2010-08-07 09:10:44 -04:00
if (m_xml.name() == "LastModificationTime") {
timeInfo.setLastModificationTime(readDateTime());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "CreationTime") {
timeInfo.setCreationTime(readDateTime());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "LastAccessTime") {
timeInfo.setLastAccessTime(readDateTime());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "ExpiryTime") {
timeInfo.setExpiryTime(readDateTime());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "Expires") {
timeInfo.setExpires(readBool());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "UsageCount") {
timeInfo.setUsageCount(readNumber());
2010-08-07 09:10:44 -04:00
}
else if (m_xml.name() == "LocationChanged") {
timeInfo.setLocationChanged(readDateTime());
2010-08-07 09:10:44 -04:00
}
else {
2010-08-13 12:08:06 -04:00
skipCurrentElement();
2010-08-07 09:10:44 -04:00
}
}
return timeInfo;
2010-08-07 09:10:44 -04:00
}
QString KeePass2XmlReader::readString()
2010-08-07 09:10:44 -04:00
{
return m_xml.readElementText();
}
bool KeePass2XmlReader::readBool()
2010-08-07 09:10:44 -04:00
{
QString str = readString();
if (str.compare("True", Qt::CaseInsensitive) == 0) {
2010-08-07 09:10:44 -04:00
return true;
}
else if (str.compare("False", Qt::CaseInsensitive) == 0) {
2010-08-07 09:10:44 -04:00
return false;
}
else {
raiseError(10);
2010-08-13 12:08:06 -04:00
return false;
2010-08-07 09:10:44 -04:00
}
}
QDateTime KeePass2XmlReader::readDateTime()
2010-08-07 09:10:44 -04:00
{
QString str = readString();
QDateTime dt = QDateTime::fromString(str, Qt::ISODate);
if (!dt.isValid()) {
raiseError(11);
2010-08-07 09:10:44 -04:00
}
return dt;
}
QColor KeePass2XmlReader::readColor()
2010-08-07 09:10:44 -04:00
{
QString colorStr = readString();
2010-08-13 12:08:06 -04:00
if (colorStr.isEmpty()) {
return QColor();
}
if (colorStr.length() != 7 || colorStr[0] != '#') {
raiseError(12);
return QColor();
}
QColor color;
2012-04-18 16:08:22 -04:00
for (int i = 0; i <= 2; i++) {
QString rgbPartStr = colorStr.mid(1 + 2*i, 2);
bool ok;
2010-08-13 12:08:06 -04:00
int rgbPart = rgbPartStr.toInt(&ok, 16);
if (!ok || rgbPart > 255) {
raiseError(13);
return QColor();
}
if (i == 0) {
color.setRed(rgbPart);
}
else if (i == 1) {
color.setGreen(rgbPart);
}
else {
color.setBlue(rgbPart);
}
}
return color;
}
int KeePass2XmlReader::readNumber()
{
bool ok;
int result = readString().toInt(&ok);
if (!ok) {
raiseError(14);
}
return result;
2010-08-07 09:10:44 -04:00
}
Uuid KeePass2XmlReader::readUuid()
2010-08-07 09:10:44 -04:00
{
QByteArray uuidBin = readBinary();
2012-05-14 13:10:42 -04:00
if (uuidBin.length() != Uuid::Length) {
raiseError(15);
return Uuid();
}
else {
2010-08-13 12:08:06 -04:00
return Uuid(uuidBin);
}
2010-08-07 09:10:44 -04:00
}
QByteArray KeePass2XmlReader::readBinary()
2010-08-07 09:10:44 -04:00
{
return QByteArray::fromBase64(readString().toAscii());
}
QByteArray KeePass2XmlReader::readCompressedBinary()
{
QByteArray rawData = readBinary();
QBuffer buffer(&rawData);
buffer.open(QIODevice::ReadOnly);
QtIOCompressor compressor(&buffer);
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
compressor.open(QIODevice::ReadOnly);
QByteArray result;
if (!Tools::readAllFromDevice(&compressor, result)) {
raiseError(16);
}
return result;
}
Group* KeePass2XmlReader::getGroup(const Uuid& uuid)
{
2010-08-13 12:08:06 -04:00
if (uuid.isNull()) {
return 0;
}
if (m_groups.contains(uuid)) {
return m_groups.value(uuid);
}
else {
Group* group = new Group();
group->setUpdateTimeinfo(false);
group->setUuid(uuid);
group->setParent(m_tmpParent);
m_groups.insert(uuid, group);
return group;
}
}
Entry* KeePass2XmlReader::getEntry(const Uuid& uuid)
{
2010-08-13 12:08:06 -04:00
if (uuid.isNull()) {
return 0;
}
if (m_entries.contains(uuid)) {
return m_entries.value(uuid);
}
else {
Entry* entry = new Entry();
entry->setUpdateTimeinfo(false);
entry->setUuid(uuid);
entry->setGroup(m_tmpParent);
m_entries.insert(uuid, entry);
return entry;
}
}
void KeePass2XmlReader::raiseError(int internalNumber)
{
m_xml.raiseError(tr("Invalid database file (error no %1).").arg(QString::number(internalNumber)));
2010-08-07 09:10:44 -04:00
}
2010-08-13 12:08:06 -04:00
void KeePass2XmlReader::skipCurrentElement()
2010-08-13 12:08:06 -04:00
{
2010-09-22 18:21:36 -04:00
qWarning("KeePass2XmlReader::skipCurrentElement: skip element \"%s\"", qPrintable(m_xml.name().toString()));
2010-08-13 12:08:06 -04:00
m_xml.skipCurrentElement();
}