mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-01-28 15:27:18 -05:00
Support KeePass format 3.00 (used by KeePass2 >= 2.15).
Closes #6 Attachments are now stored in a pool under Metadata instead of in entries. The protected flag of attachments isn't supported anymore. New metadata attributes: color, historyMaxItems and historyMaxSize. Dropped metadata attribute: autoEnableVisualHiding.
This commit is contained in:
parent
e8ac70120b
commit
8acd6f74d8
@ -32,12 +32,7 @@ QByteArray EntryAttachments::value(const QString& key) const
|
|||||||
return m_attachments.value(key);
|
return m_attachments.value(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EntryAttachments::isProtected(const QString& key) const
|
void EntryAttachments::set(const QString& key, const QByteArray& value)
|
||||||
{
|
|
||||||
return m_protectedAttachments.contains(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
void EntryAttachments::set(const QString& key, const QByteArray& value, bool protect)
|
|
||||||
{
|
{
|
||||||
bool emitModified = false;
|
bool emitModified = false;
|
||||||
bool addAttachment = !m_attachments.contains(key);
|
bool addAttachment = !m_attachments.contains(key);
|
||||||
@ -51,17 +46,6 @@ void EntryAttachments::set(const QString& key, const QByteArray& value, bool pro
|
|||||||
emitModified = true;
|
emitModified = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (protect != m_protectedAttachments.contains(key)) {
|
|
||||||
if (protect) {
|
|
||||||
m_protectedAttachments.insert(key);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
m_protectedAttachments.remove(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
emitModified = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (addAttachment) {
|
if (addAttachment) {
|
||||||
Q_EMIT added(key);
|
Q_EMIT added(key);
|
||||||
}
|
}
|
||||||
@ -84,7 +68,6 @@ void EntryAttachments::remove(const QString& key)
|
|||||||
Q_EMIT aboutToBeRemoved(key);
|
Q_EMIT aboutToBeRemoved(key);
|
||||||
|
|
||||||
m_attachments.remove(key);
|
m_attachments.remove(key);
|
||||||
m_protectedAttachments.remove(key);
|
|
||||||
|
|
||||||
Q_EMIT removed(key);
|
Q_EMIT removed(key);
|
||||||
Q_EMIT modified();
|
Q_EMIT modified();
|
||||||
@ -96,13 +79,9 @@ void EntryAttachments::copyFrom(const EntryAttachments* other)
|
|||||||
Q_EMIT aboutToBeReset();
|
Q_EMIT aboutToBeReset();
|
||||||
|
|
||||||
m_attachments.clear();
|
m_attachments.clear();
|
||||||
m_protectedAttachments.clear();
|
|
||||||
|
|
||||||
Q_FOREACH (const QString& key, other->keys()) {
|
Q_FOREACH (const QString& key, other->keys()) {
|
||||||
m_attachments.insert(key, other->value(key));
|
m_attachments.insert(key, other->value(key));
|
||||||
if (other->isProtected(key)) {
|
|
||||||
m_protectedAttachments.insert(key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Q_EMIT reset();
|
Q_EMIT reset();
|
||||||
@ -119,7 +98,6 @@ void EntryAttachments::clear()
|
|||||||
Q_EMIT aboutToBeReset();
|
Q_EMIT aboutToBeReset();
|
||||||
|
|
||||||
m_attachments.clear();
|
m_attachments.clear();
|
||||||
m_protectedAttachments.clear();
|
|
||||||
|
|
||||||
Q_EMIT reset();
|
Q_EMIT reset();
|
||||||
Q_EMIT modified();
|
Q_EMIT modified();
|
||||||
@ -127,5 +105,5 @@ void EntryAttachments::clear()
|
|||||||
|
|
||||||
bool EntryAttachments::operator!=(const EntryAttachments& other) const
|
bool EntryAttachments::operator!=(const EntryAttachments& other) const
|
||||||
{
|
{
|
||||||
return m_attachments != other.m_attachments || m_protectedAttachments != other.m_protectedAttachments;
|
return m_attachments != other.m_attachments;
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,7 @@ public:
|
|||||||
explicit EntryAttachments(QObject* parent = 0);
|
explicit EntryAttachments(QObject* parent = 0);
|
||||||
QList<QString> keys() const;
|
QList<QString> keys() const;
|
||||||
QByteArray value(const QString& key) const;
|
QByteArray value(const QString& key) const;
|
||||||
bool isProtected(const QString& key) const;
|
void set(const QString& key, const QByteArray& value);
|
||||||
void set(const QString& key, const QByteArray& value, bool protect = false);
|
|
||||||
void remove(const QString& key);
|
void remove(const QString& key);
|
||||||
void copyFrom(const EntryAttachments* other);
|
void copyFrom(const EntryAttachments* other);
|
||||||
void clear();
|
void clear();
|
||||||
@ -48,7 +47,6 @@ Q_SIGNALS:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QMap<QString, QByteArray> m_attachments;
|
QMap<QString, QByteArray> m_attachments;
|
||||||
QSet<QString> m_protectedAttachments;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSX_ENTRYATTACHMENTS_H
|
#endif // KEEPASSX_ENTRYATTACHMENTS_H
|
||||||
|
@ -305,6 +305,25 @@ const QList<Entry*>& Group::entries() const
|
|||||||
return m_entries;
|
return m_entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<Entry*> Group::entriesRecursive(bool includeHistoryItems)
|
||||||
|
{
|
||||||
|
QList<Entry*> entryList;
|
||||||
|
|
||||||
|
entryList.append(m_entries);
|
||||||
|
|
||||||
|
if (includeHistoryItems) {
|
||||||
|
Q_FOREACH (Entry* entry, m_entries) {
|
||||||
|
entryList.append(entry->historyItems());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_FOREACH (Group* group, m_children) {
|
||||||
|
entryList.append(group->entriesRecursive(includeHistoryItems));
|
||||||
|
}
|
||||||
|
|
||||||
|
return entryList;
|
||||||
|
}
|
||||||
|
|
||||||
void Group::addEntry(Entry *entry)
|
void Group::addEntry(Entry *entry)
|
||||||
{
|
{
|
||||||
Q_ASSERT(entry);
|
Q_ASSERT(entry);
|
||||||
|
@ -74,6 +74,7 @@ public:
|
|||||||
const QList<Group*>& children() const;
|
const QList<Group*>& children() const;
|
||||||
QList<Entry*> entries();
|
QList<Entry*> entries();
|
||||||
const QList<Entry*>& entries() const;
|
const QList<Entry*>& entries() const;
|
||||||
|
QList<Entry*> entriesRecursive(bool includeHistoryItems = false);
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void dataChanged(Group* group);
|
void dataChanged(Group* group);
|
||||||
|
@ -34,6 +34,8 @@ Metadata::Metadata(Database* parent)
|
|||||||
m_recycleBinEnabled = true;
|
m_recycleBinEnabled = true;
|
||||||
m_masterKeyChangeRec = -1;
|
m_masterKeyChangeRec = -1;
|
||||||
m_masterKeyChangeForce = -1;
|
m_masterKeyChangeForce = -1;
|
||||||
|
m_historyMaxItems = 10;
|
||||||
|
m_historyMaxSize = 6291456;
|
||||||
|
|
||||||
QDateTime now = QDateTime::currentDateTimeUtc();
|
QDateTime now = QDateTime::currentDateTimeUtc();
|
||||||
m_nameChanged = now;
|
m_nameChanged = now;
|
||||||
@ -48,7 +50,7 @@ Metadata::Metadata(Database* parent)
|
|||||||
m_protectPassword = true;
|
m_protectPassword = true;
|
||||||
m_protectUrl = false;
|
m_protectUrl = false;
|
||||||
m_protectNotes = false;
|
m_protectNotes = false;
|
||||||
m_autoEnableVisualHiding = false;
|
// m_autoEnableVisualHiding = false;
|
||||||
|
|
||||||
m_updateDatetime = true;
|
m_updateDatetime = true;
|
||||||
}
|
}
|
||||||
@ -122,6 +124,11 @@ int Metadata::maintenanceHistoryDays() const
|
|||||||
return m_maintenanceHistoryDays;
|
return m_maintenanceHistoryDays;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QColor Metadata::color() const
|
||||||
|
{
|
||||||
|
return m_color;
|
||||||
|
}
|
||||||
|
|
||||||
bool Metadata::protectTitle() const
|
bool Metadata::protectTitle() const
|
||||||
{
|
{
|
||||||
return m_protectTitle;
|
return m_protectTitle;
|
||||||
@ -147,10 +154,10 @@ bool Metadata::protectNotes() const
|
|||||||
return m_protectNotes;
|
return m_protectNotes;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Metadata::autoEnableVisualHiding() const
|
/*bool Metadata::autoEnableVisualHiding() const
|
||||||
{
|
{
|
||||||
return m_autoEnableVisualHiding;
|
return m_autoEnableVisualHiding;
|
||||||
}
|
}*/
|
||||||
|
|
||||||
QImage Metadata::customIcon(const Uuid& uuid) const
|
QImage Metadata::customIcon(const Uuid& uuid) const
|
||||||
{
|
{
|
||||||
@ -217,6 +224,16 @@ int Metadata::masterKeyChangeForce() const
|
|||||||
return m_masterKeyChangeForce;
|
return m_masterKeyChangeForce;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Metadata::historyMaxItems() const
|
||||||
|
{
|
||||||
|
return m_historyMaxItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Metadata::historyMaxSize() const
|
||||||
|
{
|
||||||
|
return m_historyMaxSize;
|
||||||
|
}
|
||||||
|
|
||||||
QHash<QString, QString> Metadata::customFields() const
|
QHash<QString, QString> Metadata::customFields() const
|
||||||
{
|
{
|
||||||
return m_customFields;
|
return m_customFields;
|
||||||
@ -264,6 +281,11 @@ void Metadata::setMaintenanceHistoryDays(int value)
|
|||||||
set(m_maintenanceHistoryDays, value);
|
set(m_maintenanceHistoryDays, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Metadata::setColor(const QColor& value)
|
||||||
|
{
|
||||||
|
set(m_color, value);
|
||||||
|
}
|
||||||
|
|
||||||
void Metadata::setProtectTitle(bool value)
|
void Metadata::setProtectTitle(bool value)
|
||||||
{
|
{
|
||||||
set(m_protectTitle, value);
|
set(m_protectTitle, value);
|
||||||
@ -289,10 +311,10 @@ void Metadata::setProtectNotes(bool value)
|
|||||||
set(m_protectNotes, value);
|
set(m_protectNotes, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Metadata::setAutoEnableVisualHiding(bool value)
|
/*void Metadata::setAutoEnableVisualHiding(bool value)
|
||||||
{
|
{
|
||||||
set(m_autoEnableVisualHiding, value);
|
set(m_autoEnableVisualHiding, value);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
void Metadata::addCustomIcon(const Uuid& uuid, const QImage& icon)
|
void Metadata::addCustomIcon(const Uuid& uuid, const QImage& icon)
|
||||||
{
|
{
|
||||||
@ -362,6 +384,16 @@ void Metadata::setMasterKeyChangeForce(int value)
|
|||||||
set(m_masterKeyChangeForce, value);
|
set(m_masterKeyChangeForce, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Metadata::setHistoryMaxItems(int value)
|
||||||
|
{
|
||||||
|
set(m_historyMaxItems, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Metadata::setHistoryMaxSize(int value)
|
||||||
|
{
|
||||||
|
set(m_historyMaxSize, value);
|
||||||
|
}
|
||||||
|
|
||||||
void Metadata::addCustomField(const QString& key, const QString& value)
|
void Metadata::addCustomField(const QString& key, const QString& value)
|
||||||
{
|
{
|
||||||
Q_ASSERT(!m_customFields.contains(key));
|
Q_ASSERT(!m_customFields.contains(key));
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include <QtCore/QDateTime>
|
#include <QtCore/QDateTime>
|
||||||
#include <QtCore/QHash>
|
#include <QtCore/QHash>
|
||||||
|
#include <QtGui/QColor>
|
||||||
#include <QtGui/QImage>
|
#include <QtGui/QImage>
|
||||||
|
|
||||||
#include "core/Uuid.h"
|
#include "core/Uuid.h"
|
||||||
@ -42,12 +43,13 @@ public:
|
|||||||
QString defaultUserName() const;
|
QString defaultUserName() const;
|
||||||
QDateTime defaultUserNameChanged() const;
|
QDateTime defaultUserNameChanged() const;
|
||||||
int maintenanceHistoryDays() const;
|
int maintenanceHistoryDays() const;
|
||||||
|
QColor color() const;
|
||||||
bool protectTitle() const;
|
bool protectTitle() const;
|
||||||
bool protectUsername() const;
|
bool protectUsername() const;
|
||||||
bool protectPassword() const;
|
bool protectPassword() const;
|
||||||
bool protectUrl() const;
|
bool protectUrl() const;
|
||||||
bool protectNotes() const;
|
bool protectNotes() const;
|
||||||
bool autoEnableVisualHiding() const;
|
// bool autoEnableVisualHiding() const;
|
||||||
QImage customIcon(const Uuid& uuid) const;
|
QImage customIcon(const Uuid& uuid) const;
|
||||||
QHash<Uuid, QImage> customIcons() const;
|
QHash<Uuid, QImage> customIcons() const;
|
||||||
bool recycleBinEnabled() const;
|
bool recycleBinEnabled() const;
|
||||||
@ -61,6 +63,8 @@ public:
|
|||||||
QDateTime masterKeyChanged() const;
|
QDateTime masterKeyChanged() const;
|
||||||
int masterKeyChangeRec() const;
|
int masterKeyChangeRec() const;
|
||||||
int masterKeyChangeForce() const;
|
int masterKeyChangeForce() const;
|
||||||
|
int historyMaxItems() const;
|
||||||
|
int historyMaxSize() const;
|
||||||
QHash<QString, QString> customFields() const;
|
QHash<QString, QString> customFields() const;
|
||||||
|
|
||||||
void setGenerator(const QString& value);
|
void setGenerator(const QString& value);
|
||||||
@ -71,12 +75,13 @@ public:
|
|||||||
void setDefaultUserName(const QString& value);
|
void setDefaultUserName(const QString& value);
|
||||||
void setDefaultUserNameChanged(const QDateTime& value);
|
void setDefaultUserNameChanged(const QDateTime& value);
|
||||||
void setMaintenanceHistoryDays(int value);
|
void setMaintenanceHistoryDays(int value);
|
||||||
|
void setColor(const QColor& value);
|
||||||
void setProtectTitle(bool value);
|
void setProtectTitle(bool value);
|
||||||
void setProtectUsername(bool value);
|
void setProtectUsername(bool value);
|
||||||
void setProtectPassword(bool value);
|
void setProtectPassword(bool value);
|
||||||
void setProtectUrl(bool value);
|
void setProtectUrl(bool value);
|
||||||
void setProtectNotes(bool value);
|
void setProtectNotes(bool value);
|
||||||
void setAutoEnableVisualHiding(bool value);
|
// void setAutoEnableVisualHiding(bool value);
|
||||||
void addCustomIcon(const Uuid& uuid, const QImage& icon);
|
void addCustomIcon(const Uuid& uuid, const QImage& icon);
|
||||||
void removeCustomIcon(const Uuid& uuid);
|
void removeCustomIcon(const Uuid& uuid);
|
||||||
void setRecycleBinEnabled(bool value);
|
void setRecycleBinEnabled(bool value);
|
||||||
@ -89,6 +94,8 @@ public:
|
|||||||
void setMasterKeyChanged(const QDateTime& value);
|
void setMasterKeyChanged(const QDateTime& value);
|
||||||
void setMasterKeyChangeRec(int value);
|
void setMasterKeyChangeRec(int value);
|
||||||
void setMasterKeyChangeForce(int value);
|
void setMasterKeyChangeForce(int value);
|
||||||
|
void setHistoryMaxItems(int value);
|
||||||
|
void setHistoryMaxSize(int value);
|
||||||
void addCustomField(const QString& key, const QString& value);
|
void addCustomField(const QString& key, const QString& value);
|
||||||
void removeCustomField(const QString& key);
|
void removeCustomField(const QString& key);
|
||||||
void setUpdateDatetime(bool value);
|
void setUpdateDatetime(bool value);
|
||||||
@ -111,13 +118,14 @@ private:
|
|||||||
QString m_defaultUserName;
|
QString m_defaultUserName;
|
||||||
QDateTime m_defaultUserNameChanged;
|
QDateTime m_defaultUserNameChanged;
|
||||||
int m_maintenanceHistoryDays;
|
int m_maintenanceHistoryDays;
|
||||||
|
QColor m_color;
|
||||||
|
|
||||||
bool m_protectTitle;
|
bool m_protectTitle;
|
||||||
bool m_protectUsername;
|
bool m_protectUsername;
|
||||||
bool m_protectPassword;
|
bool m_protectPassword;
|
||||||
bool m_protectUrl;
|
bool m_protectUrl;
|
||||||
bool m_protectNotes;
|
bool m_protectNotes;
|
||||||
bool m_autoEnableVisualHiding;
|
// bool m_autoEnableVisualHiding;
|
||||||
|
|
||||||
QHash<Uuid, QImage> m_customIcons;
|
QHash<Uuid, QImage> m_customIcons;
|
||||||
|
|
||||||
@ -132,6 +140,8 @@ private:
|
|||||||
QDateTime m_masterKeyChanged;
|
QDateTime m_masterKeyChanged;
|
||||||
int m_masterKeyChangeRec;
|
int m_masterKeyChangeRec;
|
||||||
int m_masterKeyChangeForce;
|
int m_masterKeyChangeForce;
|
||||||
|
int m_historyMaxItems;
|
||||||
|
int m_historyMaxSize;
|
||||||
|
|
||||||
QHash<QString, QString> m_customFields;
|
QHash<QString, QString> m_customFields;
|
||||||
|
|
||||||
|
@ -26,7 +26,8 @@ namespace KeePass2
|
|||||||
{
|
{
|
||||||
const quint32 SIGNATURE_1 = 0x9AA2D903;
|
const quint32 SIGNATURE_1 = 0x9AA2D903;
|
||||||
const quint32 SIGNATURE_2 = 0xB54BFB67;
|
const quint32 SIGNATURE_2 = 0xB54BFB67;
|
||||||
const quint32 FILE_VERSION = 0x00020000;
|
const quint32 FILE_VERSION = 0x00030000;
|
||||||
|
const quint32 FILE_VERSION_MIN = 0x00020000;
|
||||||
const quint32 FILE_VERSION_CRITICAL_MASK = 0xFFFF0000;
|
const quint32 FILE_VERSION_CRITICAL_MASK = 0xFFFF0000;
|
||||||
|
|
||||||
const QSysInfo::Endian BYTEORDER = QSysInfo::LittleEndian;
|
const QSysInfo::Endian BYTEORDER = QSysInfo::LittleEndian;
|
||||||
|
@ -60,9 +60,8 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
|
|||||||
}
|
}
|
||||||
|
|
||||||
quint32 version = Endian::readUInt32(m_device, KeePass2::BYTEORDER, &ok) & KeePass2::FILE_VERSION_CRITICAL_MASK;
|
quint32 version = Endian::readUInt32(m_device, KeePass2::BYTEORDER, &ok) & KeePass2::FILE_VERSION_CRITICAL_MASK;
|
||||||
quint32 expectedVersion = KeePass2::FILE_VERSION & KeePass2::FILE_VERSION_CRITICAL_MASK;
|
quint32 maxVersion = KeePass2::FILE_VERSION & KeePass2::FILE_VERSION_CRITICAL_MASK;
|
||||||
// TODO do we support old Kdbx versions?
|
if (!ok || (version < KeePass2::FILE_VERSION_MIN) || (version > maxVersion)) {
|
||||||
if (!ok || (version != expectedVersion)) {
|
|
||||||
raiseError(tr("Unsupported KeePass database version."));
|
raiseError(tr("Unsupported KeePass database version."));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "KeePass2XmlReader.h"
|
#include "KeePass2XmlReader.h"
|
||||||
|
|
||||||
|
#include <QtCore/QBuffer>
|
||||||
#include <QtCore/QFile>
|
#include <QtCore/QFile>
|
||||||
|
|
||||||
#include "core/Database.h"
|
#include "core/Database.h"
|
||||||
@ -24,6 +25,7 @@
|
|||||||
#include "core/Group.h"
|
#include "core/Group.h"
|
||||||
#include "core/Metadata.h"
|
#include "core/Metadata.h"
|
||||||
#include "format/KeePass2RandomStream.h"
|
#include "format/KeePass2RandomStream.h"
|
||||||
|
#include "streams/QtIOCompressor"
|
||||||
|
|
||||||
KeePass2XmlReader::KeePass2XmlReader()
|
KeePass2XmlReader::KeePass2XmlReader()
|
||||||
: m_randomStream(0)
|
: m_randomStream(0)
|
||||||
@ -63,6 +65,27 @@ void KeePass2XmlReader::readDatabase(QIODevice* device, Database* db, KeePass2Ra
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
QPair<Entry*, QString> target = i.value();
|
||||||
|
target.first->attachments()->set(target.second, m_binaryPool[i.key()]);
|
||||||
|
}
|
||||||
|
|
||||||
m_meta->setUpdateDatetime(true);
|
m_meta->setUpdateDatetime(true);
|
||||||
Q_FOREACH (Group* group, m_groups) {
|
Q_FOREACH (Group* group, m_groups) {
|
||||||
group->setUpdateTimeinfo(true);
|
group->setUpdateTimeinfo(true);
|
||||||
@ -151,6 +174,9 @@ void KeePass2XmlReader::parseMeta()
|
|||||||
else if (m_xml.name() == "MaintenanceHistoryDays") {
|
else if (m_xml.name() == "MaintenanceHistoryDays") {
|
||||||
m_meta->setMaintenanceHistoryDays(readNumber());
|
m_meta->setMaintenanceHistoryDays(readNumber());
|
||||||
}
|
}
|
||||||
|
else if (m_xml.name() == "Color") {
|
||||||
|
m_meta->setColor(readColor());
|
||||||
|
}
|
||||||
else if (m_xml.name() == "MasterKeyChanged") {
|
else if (m_xml.name() == "MasterKeyChanged") {
|
||||||
m_meta->setMasterKeyChanged(readDateTime());
|
m_meta->setMasterKeyChanged(readDateTime());
|
||||||
}
|
}
|
||||||
@ -187,6 +213,15 @@ void KeePass2XmlReader::parseMeta()
|
|||||||
else if (m_xml.name() == "LastTopVisibleGroup") {
|
else if (m_xml.name() == "LastTopVisibleGroup") {
|
||||||
m_meta->setLastTopVisibleGroup(getGroup(readUuid()));
|
m_meta->setLastTopVisibleGroup(getGroup(readUuid()));
|
||||||
}
|
}
|
||||||
|
else if (m_xml.name() == "HistoryMaxItems") {
|
||||||
|
m_meta->setHistoryMaxItems(readNumber());
|
||||||
|
}
|
||||||
|
else if (m_xml.name() == "HistoryMaxSize") {
|
||||||
|
m_meta->setHistoryMaxSize(readNumber());
|
||||||
|
}
|
||||||
|
else if (m_xml.name() == "Binaries") {
|
||||||
|
parseBinaries();
|
||||||
|
}
|
||||||
else if (m_xml.name() == "CustomData") {
|
else if (m_xml.name() == "CustomData") {
|
||||||
parseCustomData();
|
parseCustomData();
|
||||||
}
|
}
|
||||||
@ -216,9 +251,9 @@ void KeePass2XmlReader::parseMemoryProtection()
|
|||||||
else if (m_xml.name() == "ProtectNotes") {
|
else if (m_xml.name() == "ProtectNotes") {
|
||||||
m_meta->setProtectNotes(readBool());
|
m_meta->setProtectNotes(readBool());
|
||||||
}
|
}
|
||||||
else if (m_xml.name() == "AutoEnableVisualHiding") {
|
/*else if (m_xml.name() == "AutoEnableVisualHiding") {
|
||||||
m_meta->setAutoEnableVisualHiding(readBool());
|
m_meta->setAutoEnableVisualHiding(readBool());
|
||||||
}
|
}*/
|
||||||
else {
|
else {
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
}
|
}
|
||||||
@ -259,6 +294,37 @@ void KeePass2XmlReader::parseIcon()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
void KeePass2XmlReader::parseCustomData()
|
||||||
{
|
{
|
||||||
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "CustomData");
|
Q_ASSERT(m_xml.isStartElement() && m_xml.name() == "CustomData");
|
||||||
@ -547,7 +613,8 @@ void KeePass2XmlReader::parseEntryString(Entry *entry)
|
|||||||
QXmlStreamAttributes attr = m_xml.attributes();
|
QXmlStreamAttributes attr = m_xml.attributes();
|
||||||
QString value = readString();
|
QString value = readString();
|
||||||
|
|
||||||
bool isProtected = attr.hasAttribute("Protected") && (attr.value("Protected") == "True");
|
bool isProtected = attr.value("Protected") == "True";
|
||||||
|
bool protectInMemory = attr.value("ProtectInMemory") == "True";
|
||||||
|
|
||||||
if (isProtected && !value.isEmpty()) {
|
if (isProtected && !value.isEmpty()) {
|
||||||
if (m_randomStream) {
|
if (m_randomStream) {
|
||||||
@ -558,7 +625,7 @@ void KeePass2XmlReader::parseEntryString(Entry *entry)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->attributes()->set(key, value, isProtected);
|
entry->attributes()->set(key, value, isProtected || protectInMemory);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
@ -576,16 +643,24 @@ void KeePass2XmlReader::parseEntryBinary(Entry *entry)
|
|||||||
key = readString();
|
key = readString();
|
||||||
}
|
}
|
||||||
else if (m_xml.name() == "Value") {
|
else if (m_xml.name() == "Value") {
|
||||||
QByteArray value = readBinary();
|
|
||||||
QXmlStreamAttributes attr = m_xml.attributes();
|
QXmlStreamAttributes attr = m_xml.attributes();
|
||||||
|
|
||||||
bool isProtected = attr.hasAttribute("Protected") && (attr.value("Protected") == "True");
|
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()) {
|
if (isProtected && !value.isEmpty()) {
|
||||||
m_randomStream->processInPlace(value);
|
m_randomStream->processInPlace(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
entry->attachments()->set(key, value, isProtected);
|
entry->attachments()->set(key, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
skipCurrentElement();
|
skipCurrentElement();
|
||||||
@ -782,6 +857,38 @@ QByteArray KeePass2XmlReader::readBinary()
|
|||||||
return QByteArray::fromBase64(readString().toAscii());
|
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;
|
||||||
|
qint64 readBytes = 0;
|
||||||
|
qint64 readResult;
|
||||||
|
do {
|
||||||
|
result.resize(result.size() + 16384);
|
||||||
|
readResult = compressor.read(result.data() + readBytes, result.size() - readBytes);
|
||||||
|
if (readResult > 0) {
|
||||||
|
readBytes += readResult;
|
||||||
|
}
|
||||||
|
} while (readResult > 0);
|
||||||
|
|
||||||
|
if (readResult == -1) {
|
||||||
|
raiseError(16);
|
||||||
|
return QByteArray();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result.resize(static_cast<int>(readBytes));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Group* KeePass2XmlReader::getGroup(const Uuid& uuid)
|
Group* KeePass2XmlReader::getGroup(const Uuid& uuid)
|
||||||
{
|
{
|
||||||
if (uuid.isNull()) {
|
if (uuid.isNull()) {
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
#include <QtCore/QCoreApplication>
|
#include <QtCore/QCoreApplication>
|
||||||
#include <QtCore/QDateTime>
|
#include <QtCore/QDateTime>
|
||||||
|
#include <QtCore/QHash>
|
||||||
|
#include <QtCore/QPair>
|
||||||
#include <QtCore/QXmlStreamReader>
|
#include <QtCore/QXmlStreamReader>
|
||||||
#include <QtGui/QColor>
|
#include <QtGui/QColor>
|
||||||
|
|
||||||
@ -51,6 +53,7 @@ private:
|
|||||||
void parseMemoryProtection();
|
void parseMemoryProtection();
|
||||||
void parseCustomIcons();
|
void parseCustomIcons();
|
||||||
void parseIcon();
|
void parseIcon();
|
||||||
|
void parseBinaries();
|
||||||
void parseCustomData();
|
void parseCustomData();
|
||||||
void parseCustomDataItem();
|
void parseCustomDataItem();
|
||||||
void parseRoot();
|
void parseRoot();
|
||||||
@ -72,6 +75,7 @@ private:
|
|||||||
int readNumber();
|
int readNumber();
|
||||||
Uuid readUuid();
|
Uuid readUuid();
|
||||||
QByteArray readBinary();
|
QByteArray readBinary();
|
||||||
|
QByteArray readCompressedBinary();
|
||||||
|
|
||||||
Group* getGroup(const Uuid& uuid);
|
Group* getGroup(const Uuid& uuid);
|
||||||
Entry* getEntry(const Uuid& uuid);
|
Entry* getEntry(const Uuid& uuid);
|
||||||
@ -85,6 +89,8 @@ private:
|
|||||||
Group* m_tmpParent;
|
Group* m_tmpParent;
|
||||||
QList<Group*> m_groups;
|
QList<Group*> m_groups;
|
||||||
QList<Entry*> m_entries;
|
QList<Entry*> m_entries;
|
||||||
|
QHash<QString, QByteArray> m_binaryPool;
|
||||||
|
QHash<QString, QPair<Entry*, QString> > m_binaryMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSX_KEEPASS2XMLREADER_H
|
#endif // KEEPASSX_KEEPASS2XMLREADER_H
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include "core/Metadata.h"
|
#include "core/Metadata.h"
|
||||||
#include "format/KeePass2RandomStream.h"
|
#include "format/KeePass2RandomStream.h"
|
||||||
|
#include "streams/QtIOCompressor"
|
||||||
|
|
||||||
KeePass2XmlWriter::KeePass2XmlWriter()
|
KeePass2XmlWriter::KeePass2XmlWriter()
|
||||||
: m_db(0)
|
: m_db(0)
|
||||||
@ -39,6 +40,8 @@ void KeePass2XmlWriter::writeDatabase(QIODevice* device, Database* db, KeePass2R
|
|||||||
m_meta = db->metadata();
|
m_meta = db->metadata();
|
||||||
m_randomStream = randomStream;
|
m_randomStream = randomStream;
|
||||||
|
|
||||||
|
generateIdMap();
|
||||||
|
|
||||||
m_xml.setDevice(device);
|
m_xml.setDevice(device);
|
||||||
|
|
||||||
m_xml.writeStartDocument("1.0", true);
|
m_xml.writeStartDocument("1.0", true);
|
||||||
@ -60,6 +63,21 @@ void KeePass2XmlWriter::writeDatabase(const QString& filename, Database* db, Kee
|
|||||||
writeDatabase(&file, db, randomStream);
|
writeDatabase(&file, db, randomStream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KeePass2XmlWriter::generateIdMap()
|
||||||
|
{
|
||||||
|
QList<Entry*> allEntries = m_db->rootGroup()->entriesRecursive(true);
|
||||||
|
int nextId = 0;
|
||||||
|
|
||||||
|
Q_FOREACH (Entry* entry, allEntries) {
|
||||||
|
Q_FOREACH (const QString& key, entry->attachments()->keys()) {
|
||||||
|
QByteArray data = entry->attachments()->value(key);
|
||||||
|
if (!m_idMap.contains(data)) {
|
||||||
|
m_idMap.insert(data, nextId++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void KeePass2XmlWriter::writeMetadata()
|
void KeePass2XmlWriter::writeMetadata()
|
||||||
{
|
{
|
||||||
m_xml.writeStartElement("Meta");
|
m_xml.writeStartElement("Meta");
|
||||||
@ -72,6 +90,7 @@ void KeePass2XmlWriter::writeMetadata()
|
|||||||
writeString("DefaultUserName", m_meta->defaultUserName());
|
writeString("DefaultUserName", m_meta->defaultUserName());
|
||||||
writeDateTime("DefaultUserNameChanged", m_meta->defaultUserNameChanged());
|
writeDateTime("DefaultUserNameChanged", m_meta->defaultUserNameChanged());
|
||||||
writeNumber("MaintenanceHistoryDays", m_meta->maintenanceHistoryDays());
|
writeNumber("MaintenanceHistoryDays", m_meta->maintenanceHistoryDays());
|
||||||
|
writeColor("Color", m_meta->color());
|
||||||
writeDateTime("MasterKeyChanged", m_meta->masterKeyChanged());
|
writeDateTime("MasterKeyChanged", m_meta->masterKeyChanged());
|
||||||
writeNumber("MasterKeyChangeRec", m_meta->masterKeyChangeRec());
|
writeNumber("MasterKeyChangeRec", m_meta->masterKeyChangeRec());
|
||||||
writeNumber("MasterKeyChangeForce", m_meta->masterKeyChangeForce());
|
writeNumber("MasterKeyChangeForce", m_meta->masterKeyChangeForce());
|
||||||
@ -84,6 +103,9 @@ void KeePass2XmlWriter::writeMetadata()
|
|||||||
writeDateTime("EntryTemplatesGroupChanged", m_meta->entryTemplatesGroupChanged());
|
writeDateTime("EntryTemplatesGroupChanged", m_meta->entryTemplatesGroupChanged());
|
||||||
writeUuid("LastSelectedGroup", m_meta->lastSelectedGroup());
|
writeUuid("LastSelectedGroup", m_meta->lastSelectedGroup());
|
||||||
writeUuid("LastTopVisibleGroup", m_meta->lastTopVisibleGroup());
|
writeUuid("LastTopVisibleGroup", m_meta->lastTopVisibleGroup());
|
||||||
|
writeNumber("HistoryMaxItems", m_meta->historyMaxItems());
|
||||||
|
writeNumber("HistoryMaxSize", m_meta->historyMaxSize());
|
||||||
|
writeBinaries();
|
||||||
writeCustomData();
|
writeCustomData();
|
||||||
|
|
||||||
m_xml.writeEndElement();
|
m_xml.writeEndElement();
|
||||||
@ -98,7 +120,7 @@ void KeePass2XmlWriter::writeMemoryProtection()
|
|||||||
writeBool("ProtectPassword", m_meta->protectPassword());
|
writeBool("ProtectPassword", m_meta->protectPassword());
|
||||||
writeBool("ProtectURL", m_meta->protectUrl());
|
writeBool("ProtectURL", m_meta->protectUrl());
|
||||||
writeBool("ProtectNotes", m_meta->protectNotes());
|
writeBool("ProtectNotes", m_meta->protectNotes());
|
||||||
writeBool("AutoEnableVisualHiding", m_meta->autoEnableVisualHiding());
|
// writeBool("AutoEnableVisualHiding", m_meta->autoEnableVisualHiding());
|
||||||
|
|
||||||
m_xml.writeEndElement();
|
m_xml.writeEndElement();
|
||||||
}
|
}
|
||||||
@ -132,6 +154,43 @@ void KeePass2XmlWriter::writeIcon(const Uuid& uuid, const QImage& icon)
|
|||||||
m_xml.writeEndElement();
|
m_xml.writeEndElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void KeePass2XmlWriter::writeBinaries()
|
||||||
|
{
|
||||||
|
m_xml.writeStartElement("Binaries");
|
||||||
|
|
||||||
|
QHash<QByteArray, int>::const_iterator i;
|
||||||
|
for (i = m_idMap.constBegin(); i != m_idMap.constEnd(); ++i) {
|
||||||
|
m_xml.writeStartElement("Binary");
|
||||||
|
|
||||||
|
m_xml.writeAttribute("ID", QString::number(i.value()));
|
||||||
|
|
||||||
|
if (m_db->compressionAlgo() == Database::CompressionGZip) {
|
||||||
|
m_xml.writeAttribute("Compressed", "True");
|
||||||
|
|
||||||
|
QBuffer buffer;
|
||||||
|
buffer.open(QIODevice::ReadWrite);
|
||||||
|
|
||||||
|
QtIOCompressor compressor(&buffer);
|
||||||
|
compressor.setStreamFormat(QtIOCompressor::GzipFormat);
|
||||||
|
compressor.open(QIODevice::WriteOnly);
|
||||||
|
|
||||||
|
qint64 bytesWritten = compressor.write(i.key());
|
||||||
|
Q_ASSERT(bytesWritten == i.key().size());
|
||||||
|
compressor.close();
|
||||||
|
|
||||||
|
buffer.seek(0);
|
||||||
|
m_xml.writeCharacters(QString::fromAscii(buffer.readAll().toBase64()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_xml.writeCharacters(QString::fromAscii(i.key().toBase64()));
|
||||||
|
}
|
||||||
|
|
||||||
|
m_xml.writeEndElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_xml.writeEndElement();
|
||||||
|
}
|
||||||
|
|
||||||
void KeePass2XmlWriter::writeCustomData()
|
void KeePass2XmlWriter::writeCustomData()
|
||||||
{
|
{
|
||||||
m_xml.writeStartElement("CustomData");
|
m_xml.writeStartElement("CustomData");
|
||||||
@ -262,8 +321,7 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry)
|
|||||||
((key == "Password") && m_meta->protectPassword()) ||
|
((key == "Password") && m_meta->protectPassword()) ||
|
||||||
((key == "URL") && m_meta->protectUrl()) ||
|
((key == "URL") && m_meta->protectUrl()) ||
|
||||||
((key == "Notes") && m_meta->protectNotes()) ||
|
((key == "Notes") && m_meta->protectNotes()) ||
|
||||||
entry->attributes()->isProtected(key) ) &&
|
entry->attributes()->isProtected(key) );
|
||||||
m_randomStream;
|
|
||||||
|
|
||||||
writeString("Key", key);
|
writeString("Key", key);
|
||||||
|
|
||||||
@ -271,10 +329,16 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry)
|
|||||||
QString value;
|
QString value;
|
||||||
|
|
||||||
if (protect) {
|
if (protect) {
|
||||||
|
if (m_randomStream) {
|
||||||
m_xml.writeAttribute("Protected", "True");
|
m_xml.writeAttribute("Protected", "True");
|
||||||
QByteArray rawData = m_randomStream->process(entry->attributes()->value(key).toUtf8());
|
QByteArray rawData = m_randomStream->process(entry->attributes()->value(key).toUtf8());
|
||||||
value = QString::fromAscii(rawData.toBase64());
|
value = QString::fromAscii(rawData.toBase64());
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
m_xml.writeAttribute("ProtectInMemory", "True");
|
||||||
|
value = entry->attributes()->value(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
value = entry->attributes()->value(key);
|
value = entry->attributes()->value(key);
|
||||||
}
|
}
|
||||||
@ -288,23 +352,10 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry)
|
|||||||
Q_FOREACH (const QString& key, entry->attachments()->keys()) {
|
Q_FOREACH (const QString& key, entry->attachments()->keys()) {
|
||||||
m_xml.writeStartElement("Binary");
|
m_xml.writeStartElement("Binary");
|
||||||
|
|
||||||
bool protect = entry->attachments()->isProtected(key) && m_randomStream;
|
|
||||||
|
|
||||||
writeString("Key", key);
|
writeString("Key", key);
|
||||||
|
|
||||||
m_xml.writeStartElement("Value");
|
m_xml.writeStartElement("Value");
|
||||||
QString value;
|
m_xml.writeAttribute("Ref", QString::number(m_idMap[entry->attachments()->value(key)]));
|
||||||
|
|
||||||
if (protect) {
|
|
||||||
m_xml.writeAttribute("Protected", "True");
|
|
||||||
QByteArray rawData = m_randomStream->process(entry->attachments()->value(key));
|
|
||||||
value = QString::fromAscii(rawData.toBase64());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
value = entry->attachments()->value(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_xml.writeCharacters(value);
|
|
||||||
m_xml.writeEndElement();
|
m_xml.writeEndElement();
|
||||||
|
|
||||||
m_xml.writeEndElement();
|
m_xml.writeEndElement();
|
||||||
|
@ -43,10 +43,13 @@ public:
|
|||||||
QString errorString();
|
QString errorString();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void generateIdMap();
|
||||||
|
|
||||||
void writeMetadata();
|
void writeMetadata();
|
||||||
void writeMemoryProtection();
|
void writeMemoryProtection();
|
||||||
void writeCustomIcons();
|
void writeCustomIcons();
|
||||||
void writeIcon(const Uuid& uuid, const QImage& icon);
|
void writeIcon(const Uuid& uuid, const QImage& icon);
|
||||||
|
void writeBinaries();
|
||||||
void writeCustomData();
|
void writeCustomData();
|
||||||
void writeCustomDataItem(const QString& key, const QString& value);
|
void writeCustomDataItem(const QString& key, const QString& value);
|
||||||
void writeRoot();
|
void writeRoot();
|
||||||
@ -75,6 +78,7 @@ private:
|
|||||||
Database* m_db;
|
Database* m_db;
|
||||||
Metadata* m_meta;
|
Metadata* m_meta;
|
||||||
KeePass2RandomStream* m_randomStream;
|
KeePass2RandomStream* m_randomStream;
|
||||||
|
QHash<QByteArray, int> m_idMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSX_KEEPASS2XMLWRITER_H
|
#endif // KEEPASSX_KEEPASS2XMLWRITER_H
|
||||||
|
@ -82,8 +82,6 @@ void TestKeePass2Reader::testProtectedStrings()
|
|||||||
QCOMPARE(entry->attributes()->value("TestProtected"), QString("ABC"));
|
QCOMPARE(entry->attributes()->value("TestProtected"), QString("ABC"));
|
||||||
QCOMPARE(entry->attributes()->value("TestUnprotected"), QString("DEF"));
|
QCOMPARE(entry->attributes()->value("TestUnprotected"), QString("DEF"));
|
||||||
|
|
||||||
QVERIFY(!db->metadata()->protectTitle());
|
|
||||||
QVERIFY(db->metadata()->protectUsername());
|
|
||||||
QVERIFY(db->metadata()->protectPassword());
|
QVERIFY(db->metadata()->protectPassword());
|
||||||
QVERIFY(entry->attributes()->isProtected("TestProtected"));
|
QVERIFY(entry->attributes()->isProtected("TestProtected"));
|
||||||
QVERIFY(!entry->attributes()->isProtected("TestUnprotected"));
|
QVERIFY(!entry->attributes()->isProtected("TestUnprotected"));
|
||||||
@ -92,4 +90,36 @@ void TestKeePass2Reader::testProtectedStrings()
|
|||||||
delete reader;
|
delete reader;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestKeePass2Reader::testFormat200()
|
||||||
|
{
|
||||||
|
QString filename = QString(KEEPASSX_TEST_DATA_DIR).append("/Format200.kdbx");
|
||||||
|
CompositeKey key;
|
||||||
|
key.addKey(PasswordKey("a"));
|
||||||
|
KeePass2Reader* reader = new KeePass2Reader();
|
||||||
|
Database* db = reader->readDatabase(filename, key);
|
||||||
|
QVERIFY(db);
|
||||||
|
QVERIFY(!reader->hasError());
|
||||||
|
|
||||||
|
QCOMPARE(db->rootGroup()->name(), QString("Format200"));
|
||||||
|
QVERIFY(!db->metadata()->protectTitle());
|
||||||
|
QVERIFY(db->metadata()->protectUsername());
|
||||||
|
QVERIFY(!db->metadata()->protectPassword());
|
||||||
|
QVERIFY(db->metadata()->protectUrl());
|
||||||
|
QVERIFY(!db->metadata()->protectNotes());
|
||||||
|
|
||||||
|
QCOMPARE(db->rootGroup()->entries().size(), 1);
|
||||||
|
Entry* entry = db->rootGroup()->entries().at(0);
|
||||||
|
|
||||||
|
QCOMPARE(entry->title(), QString("Sample Entry"));
|
||||||
|
QCOMPARE(entry->username(), QString("User Name"));
|
||||||
|
QCOMPARE(entry->attachments()->keys().size(), 2);
|
||||||
|
QCOMPARE(entry->attachments()->value("myattach.txt"), QByteArray("abcdefghijk"));
|
||||||
|
QCOMPARE(entry->attachments()->value("test.txt"), QByteArray("this is a test"));
|
||||||
|
|
||||||
|
QCOMPARE(entry->historyItems().size(), 2);
|
||||||
|
QCOMPARE(entry->historyItems().at(0)->attachments()->keys().size(), 0);
|
||||||
|
QCOMPARE(entry->historyItems().at(1)->attachments()->keys().size(), 1);
|
||||||
|
QCOMPARE(entry->historyItems().at(1)->attachments()->value("myattach.txt"), QByteArray("abcdefghijk"));
|
||||||
|
}
|
||||||
|
|
||||||
KEEPASSX_QTEST_CORE_MAIN(TestKeePass2Reader)
|
KEEPASSX_QTEST_CORE_MAIN(TestKeePass2Reader)
|
||||||
|
@ -29,6 +29,7 @@ private Q_SLOTS:
|
|||||||
void testNonAscii();
|
void testNonAscii();
|
||||||
void testCompressed();
|
void testCompressed();
|
||||||
void testProtectedStrings();
|
void testProtectedStrings();
|
||||||
|
void testFormat200();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSX_TESTKEEPASS2READER_H
|
#endif // KEEPASSX_TESTKEEPASS2READER_H
|
||||||
|
@ -46,6 +46,8 @@ void TestKeePass2Writer::initTestCase()
|
|||||||
entry->setUuid(Uuid::random());
|
entry->setUuid(Uuid::random());
|
||||||
entry->attributes()->set("test", "protectedTest", true);
|
entry->attributes()->set("test", "protectedTest", true);
|
||||||
QVERIFY(entry->attributes()->isProtected("test"));
|
QVERIFY(entry->attributes()->isProtected("test"));
|
||||||
|
entry->attachments()->set("myattach.txt", QByteArray("this is an attachment"));
|
||||||
|
entry->attachments()->set("aaa.txt", QByteArray("also an attachment"));
|
||||||
entry->setGroup(group);
|
entry->setGroup(group);
|
||||||
Group* groupNew = new Group();
|
Group* groupNew = new Group();
|
||||||
groupNew->setUuid(Uuid::random());
|
groupNew->setUuid(Uuid::random());
|
||||||
@ -83,4 +85,12 @@ void TestKeePass2Writer::testProtectedAttributes()
|
|||||||
QCOMPARE(entry->attributes()->isProtected("test"), true);
|
QCOMPARE(entry->attributes()->isProtected("test"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestKeePass2Writer::testAttachments()
|
||||||
|
{
|
||||||
|
Entry* entry = m_dbTest->rootGroup()->entries().at(0);
|
||||||
|
QCOMPARE(entry->attachments()->keys().size(), 2);
|
||||||
|
QCOMPARE(entry->attachments()->value("myattach.txt"), QByteArray("this is an attachment"));
|
||||||
|
QCOMPARE(entry->attachments()->value("aaa.txt"), QByteArray("also an attachment"));
|
||||||
|
}
|
||||||
|
|
||||||
KEEPASSX_QTEST_CORE_MAIN(TestKeePass2Writer)
|
KEEPASSX_QTEST_CORE_MAIN(TestKeePass2Writer)
|
||||||
|
@ -30,6 +30,7 @@ private Q_SLOTS:
|
|||||||
void initTestCase();
|
void initTestCase();
|
||||||
void testBasic();
|
void testBasic();
|
||||||
void testProtectedAttributes();
|
void testProtectedAttributes();
|
||||||
|
void testAttachments();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Database* m_dbOrg;
|
Database* m_dbOrg;
|
||||||
|
@ -84,12 +84,15 @@ void TestKeePass2XmlReader::testMetadata()
|
|||||||
QCOMPARE(m_db->metadata()->defaultUserName(), QString("DEFUSERNAME"));
|
QCOMPARE(m_db->metadata()->defaultUserName(), QString("DEFUSERNAME"));
|
||||||
QCOMPARE(m_db->metadata()->defaultUserNameChanged(), genDT(2010, 8, 8, 17, 27, 45));
|
QCOMPARE(m_db->metadata()->defaultUserNameChanged(), genDT(2010, 8, 8, 17, 27, 45));
|
||||||
QCOMPARE(m_db->metadata()->maintenanceHistoryDays(), 127);
|
QCOMPARE(m_db->metadata()->maintenanceHistoryDays(), 127);
|
||||||
|
QCOMPARE(m_db->metadata()->color(), QColor(0xff, 0xef, 0x00));
|
||||||
|
QCOMPARE(m_db->metadata()->masterKeyChanged(), genDT(2012, 4, 5, 17, 9, 34));
|
||||||
|
QCOMPARE(m_db->metadata()->masterKeyChangeRec(), 101);
|
||||||
|
QCOMPARE(m_db->metadata()->masterKeyChangeForce(), -1);
|
||||||
QCOMPARE(m_db->metadata()->protectTitle(), false);
|
QCOMPARE(m_db->metadata()->protectTitle(), false);
|
||||||
QCOMPARE(m_db->metadata()->protectUsername(), true);
|
QCOMPARE(m_db->metadata()->protectUsername(), true);
|
||||||
QCOMPARE(m_db->metadata()->protectPassword(), false);
|
QCOMPARE(m_db->metadata()->protectPassword(), false);
|
||||||
QCOMPARE(m_db->metadata()->protectUrl(), true);
|
QCOMPARE(m_db->metadata()->protectUrl(), true);
|
||||||
QCOMPARE(m_db->metadata()->protectNotes(), false);
|
QCOMPARE(m_db->metadata()->protectNotes(), false);
|
||||||
QCOMPARE(m_db->metadata()->autoEnableVisualHiding(), false);
|
|
||||||
QCOMPARE(m_db->metadata()->recycleBinEnabled(), true);
|
QCOMPARE(m_db->metadata()->recycleBinEnabled(), true);
|
||||||
QVERIFY(m_db->metadata()->recycleBin() != 0);
|
QVERIFY(m_db->metadata()->recycleBin() != 0);
|
||||||
QCOMPARE(m_db->metadata()->recycleBin()->name(), QString("Recycle Bin"));
|
QCOMPARE(m_db->metadata()->recycleBin()->name(), QString("Recycle Bin"));
|
||||||
@ -99,6 +102,8 @@ void TestKeePass2XmlReader::testMetadata()
|
|||||||
QVERIFY(m_db->metadata()->lastSelectedGroup() != 0);
|
QVERIFY(m_db->metadata()->lastSelectedGroup() != 0);
|
||||||
QCOMPARE(m_db->metadata()->lastSelectedGroup()->name(), QString("NewDatabase"));
|
QCOMPARE(m_db->metadata()->lastSelectedGroup()->name(), QString("NewDatabase"));
|
||||||
QVERIFY(m_db->metadata()->lastTopVisibleGroup() == m_db->metadata()->lastSelectedGroup());
|
QVERIFY(m_db->metadata()->lastTopVisibleGroup() == m_db->metadata()->lastSelectedGroup());
|
||||||
|
QCOMPARE(m_db->metadata()->historyMaxItems(), -1);
|
||||||
|
QCOMPARE(m_db->metadata()->historyMaxSize(), 5242880);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestKeePass2XmlReader::testCustomIcons()
|
void TestKeePass2XmlReader::testCustomIcons()
|
||||||
@ -199,11 +204,13 @@ void TestKeePass2XmlReader::testEntry1()
|
|||||||
const Entry* entry = m_db->rootGroup()->entries().at(0);
|
const Entry* entry = m_db->rootGroup()->entries().at(0);
|
||||||
|
|
||||||
QCOMPARE(entry->uuid().toBase64(), QString("+wSUOv6qf0OzW8/ZHAs2sA=="));
|
QCOMPARE(entry->uuid().toBase64(), QString("+wSUOv6qf0OzW8/ZHAs2sA=="));
|
||||||
|
QCOMPARE(entry->historyItems().size(), 2);
|
||||||
QCOMPARE(entry->iconNumber(), 0);
|
QCOMPARE(entry->iconNumber(), 0);
|
||||||
QCOMPARE(entry->iconUuid(), Uuid());
|
QCOMPARE(entry->iconUuid(), Uuid());
|
||||||
QVERIFY(!entry->foregroundColor().isValid());
|
QVERIFY(!entry->foregroundColor().isValid());
|
||||||
QVERIFY(!entry->backgroundColor().isValid());
|
QVERIFY(!entry->backgroundColor().isValid());
|
||||||
QCOMPARE(entry->overrideUrl(), QString(""));
|
QCOMPARE(entry->overrideUrl(), QString(""));
|
||||||
|
QCOMPARE(entry->tags(), QString("a b c"));
|
||||||
|
|
||||||
const TimeInfo ti = entry->timeInfo();
|
const TimeInfo ti = entry->timeInfo();
|
||||||
QCOMPARE(ti.lastModificationTime(), genDT(2010, 8, 25, 16, 19, 25));
|
QCOMPARE(ti.lastModificationTime(), genDT(2010, 8, 25, 16, 19, 25));
|
||||||
@ -216,14 +223,19 @@ void TestKeePass2XmlReader::testEntry1()
|
|||||||
|
|
||||||
QList<QString> attrs = entry->attributes()->keys();
|
QList<QString> attrs = entry->attributes()->keys();
|
||||||
QCOMPARE(entry->attributes()->value("Notes"), QString("Notes"));
|
QCOMPARE(entry->attributes()->value("Notes"), QString("Notes"));
|
||||||
|
QVERIFY(!entry->attributes()->isProtected("Notes"));
|
||||||
QVERIFY(attrs.removeOne("Notes"));
|
QVERIFY(attrs.removeOne("Notes"));
|
||||||
QCOMPARE(entry->attributes()->value("Password"), QString("Password"));
|
QCOMPARE(entry->attributes()->value("Password"), QString("Password"));
|
||||||
|
QVERIFY(!entry->attributes()->isProtected("Password"));
|
||||||
QVERIFY(attrs.removeOne("Password"));
|
QVERIFY(attrs.removeOne("Password"));
|
||||||
QCOMPARE(entry->attributes()->value("Title"), QString("Sample Entry 1"));
|
QCOMPARE(entry->attributes()->value("Title"), QString("Sample Entry 1"));
|
||||||
|
QVERIFY(!entry->attributes()->isProtected("Title"));
|
||||||
QVERIFY(attrs.removeOne("Title"));
|
QVERIFY(attrs.removeOne("Title"));
|
||||||
QCOMPARE(entry->attributes()->value("URL"), QString(""));
|
QCOMPARE(entry->attributes()->value("URL"), QString(""));
|
||||||
|
QVERIFY(entry->attributes()->isProtected("URL"));
|
||||||
QVERIFY(attrs.removeOne("URL"));
|
QVERIFY(attrs.removeOne("URL"));
|
||||||
QCOMPARE(entry->attributes()->value("UserName"), QString("User Name"));
|
QCOMPARE(entry->attributes()->value("UserName"), QString("User Name"));
|
||||||
|
QVERIFY(entry->attributes()->isProtected("UserName"));
|
||||||
QVERIFY(attrs.removeOne("UserName"));
|
QVERIFY(attrs.removeOne("UserName"));
|
||||||
QVERIFY(attrs.isEmpty());
|
QVERIFY(attrs.isEmpty());
|
||||||
|
|
||||||
@ -233,7 +245,13 @@ void TestKeePass2XmlReader::testEntry1()
|
|||||||
QCOMPARE(entry->password(), entry->attributes()->value("Password"));
|
QCOMPARE(entry->password(), entry->attributes()->value("Password"));
|
||||||
QCOMPARE(entry->notes(), entry->attributes()->value("Notes"));
|
QCOMPARE(entry->notes(), entry->attributes()->value("Notes"));
|
||||||
|
|
||||||
QCOMPARE(entry->attachments()->keys().size(), 0);
|
QCOMPARE(entry->attachments()->keys().size(), 1);
|
||||||
|
QCOMPARE(entry->attachments()->value("myattach.txt"), QByteArray("abcdefghijk"));
|
||||||
|
QCOMPARE(entry->historyItems().at(0)->attachments()->keys().size(), 1);
|
||||||
|
QCOMPARE(entry->historyItems().at(0)->attachments()->value("myattach.txt"), QByteArray("0123456789"));
|
||||||
|
QCOMPARE(entry->historyItems().at(1)->attachments()->keys().size(), 1);
|
||||||
|
QCOMPARE(entry->historyItems().at(1)->attachments()->value("myattach.txt"), QByteArray("abcdefghijk"));
|
||||||
|
|
||||||
QCOMPARE(entry->autoTypeEnabled(), false);
|
QCOMPARE(entry->autoTypeEnabled(), false);
|
||||||
QCOMPARE(entry->autoTypeObfuscation(), 0);
|
QCOMPARE(entry->autoTypeObfuscation(), 0);
|
||||||
QCOMPARE(entry->defaultAutoTypeSequence(), QString(""));
|
QCOMPARE(entry->defaultAutoTypeSequence(), QString(""));
|
||||||
@ -254,6 +272,7 @@ void TestKeePass2XmlReader::testEntry2()
|
|||||||
QCOMPARE(entry->foregroundColor(), QColor(255, 0, 0));
|
QCOMPARE(entry->foregroundColor(), QColor(255, 0, 0));
|
||||||
QCOMPARE(entry->backgroundColor(), QColor(255, 255, 0));
|
QCOMPARE(entry->backgroundColor(), QColor(255, 255, 0));
|
||||||
QCOMPARE(entry->overrideUrl(), QString("http://override.net/"));
|
QCOMPARE(entry->overrideUrl(), QString("http://override.net/"));
|
||||||
|
QCOMPARE(entry->tags(), QString(""));
|
||||||
|
|
||||||
const TimeInfo ti = entry->timeInfo();
|
const TimeInfo ti = entry->timeInfo();
|
||||||
QCOMPARE(ti.usageCount(), 7);
|
QCOMPARE(ti.usageCount(), 7);
|
||||||
@ -276,7 +295,7 @@ void TestKeePass2XmlReader::testEntry2()
|
|||||||
QVERIFY(attrs.isEmpty());
|
QVERIFY(attrs.isEmpty());
|
||||||
|
|
||||||
QCOMPARE(entry->attachments()->keys().size(), 1);
|
QCOMPARE(entry->attachments()->keys().size(), 1);
|
||||||
QCOMPARE(QString(entry->attachments()->value("testattach.txt")), QString("42"));
|
QCOMPARE(QString(entry->attachments()->value("myattach.txt")), QString("abcdefghijk"));
|
||||||
|
|
||||||
QCOMPARE(entry->autoTypeEnabled(), true);
|
QCOMPARE(entry->autoTypeEnabled(), true);
|
||||||
QCOMPARE(entry->autoTypeObfuscation(), 1);
|
QCOMPARE(entry->autoTypeObfuscation(), 1);
|
||||||
|
Binary file not shown.
BIN
tests/data/Format200.kdbx
Normal file
BIN
tests/data/Format200.kdbx
Normal file
Binary file not shown.
@ -9,13 +9,16 @@
|
|||||||
<DefaultUserName>DEFUSERNAME</DefaultUserName>
|
<DefaultUserName>DEFUSERNAME</DefaultUserName>
|
||||||
<DefaultUserNameChanged>2010-08-08T17:27:45Z</DefaultUserNameChanged>
|
<DefaultUserNameChanged>2010-08-08T17:27:45Z</DefaultUserNameChanged>
|
||||||
<MaintenanceHistoryDays>127</MaintenanceHistoryDays>
|
<MaintenanceHistoryDays>127</MaintenanceHistoryDays>
|
||||||
|
<Color>#FFEF00</Color>
|
||||||
|
<MasterKeyChanged>2012-04-05T17:09:34Z</MasterKeyChanged>
|
||||||
|
<MasterKeyChangeRec>101</MasterKeyChangeRec>
|
||||||
|
<MasterKeyChangeForce>-1</MasterKeyChangeForce>
|
||||||
<MemoryProtection>
|
<MemoryProtection>
|
||||||
<ProtectTitle>False</ProtectTitle>
|
<ProtectTitle>False</ProtectTitle>
|
||||||
<ProtectUserName>True</ProtectUserName>
|
<ProtectUserName>True</ProtectUserName>
|
||||||
<ProtectPassword>False</ProtectPassword>
|
<ProtectPassword>False</ProtectPassword>
|
||||||
<ProtectURL>True</ProtectURL>
|
<ProtectURL>True</ProtectURL>
|
||||||
<ProtectNotes>False</ProtectNotes>
|
<ProtectNotes>False</ProtectNotes>
|
||||||
<AutoEnableVisualHiding>False</AutoEnableVisualHiding>
|
|
||||||
</MemoryProtection>
|
</MemoryProtection>
|
||||||
<CustomIcons>
|
<CustomIcons>
|
||||||
<Icon>
|
<Icon>
|
||||||
@ -30,6 +33,12 @@
|
|||||||
<EntryTemplatesGroupChanged>2010-08-08T17:24:19Z</EntryTemplatesGroupChanged>
|
<EntryTemplatesGroupChanged>2010-08-08T17:24:19Z</EntryTemplatesGroupChanged>
|
||||||
<LastSelectedGroup>lmU+9n0aeESKZvcEze+bRg==</LastSelectedGroup>
|
<LastSelectedGroup>lmU+9n0aeESKZvcEze+bRg==</LastSelectedGroup>
|
||||||
<LastTopVisibleGroup>lmU+9n0aeESKZvcEze+bRg==</LastTopVisibleGroup>
|
<LastTopVisibleGroup>lmU+9n0aeESKZvcEze+bRg==</LastTopVisibleGroup>
|
||||||
|
<HistoryMaxItems>-1</HistoryMaxItems>
|
||||||
|
<HistoryMaxSize>5242880</HistoryMaxSize>
|
||||||
|
<Binaries>
|
||||||
|
<Binary ID="0" Compressed="True">H4sIAAAAAAAEAO29B2AcSZYlJi9tynt/SvVK1+B0oQiAYBMk2JBAEOzBiM3mkuwdaUcjKasqgcplVmVdZhZAzO2dvPfee++999577733ujudTif33/8/XGZkAWz2zkrayZ4hgKrIHz9+fB8/InZ29+7t3//0wcHD/wfGx4SmCgAAAA==</Binary>
|
||||||
|
<Binary ID="1" Compressed="True">H4sIAAAAAAAEAO29B2AcSZYlJi9tynt/SvVK1+B0oQiAYBMk2JBAEOzBiM3mkuwdaUcjKasqgcplVmVdZhZAzO2dvPfee++999577733ujudTif33/8/XGZkAWz2zkrayZ4hgKrIHz9+fB8/IrLJdJafX8yLn377/wCfD1fOCwAAAA==</Binary>
|
||||||
|
</Binaries>
|
||||||
<CustomData>
|
<CustomData>
|
||||||
<Item>
|
<Item>
|
||||||
<Key>A Sample Test Key</Key>
|
<Key>A Sample Test Key</Key>
|
||||||
@ -67,6 +76,7 @@
|
|||||||
<ForegroundColor />
|
<ForegroundColor />
|
||||||
<BackgroundColor />
|
<BackgroundColor />
|
||||||
<OverrideURL />
|
<OverrideURL />
|
||||||
|
<Tags>a b c</Tags>
|
||||||
<Times>
|
<Times>
|
||||||
<LastModificationTime>2010-08-25T16:19:25Z</LastModificationTime>
|
<LastModificationTime>2010-08-25T16:19:25Z</LastModificationTime>
|
||||||
<CreationTime>2010-08-25T16:13:54Z</CreationTime>
|
<CreationTime>2010-08-25T16:13:54Z</CreationTime>
|
||||||
@ -90,12 +100,16 @@
|
|||||||
</String>
|
</String>
|
||||||
<String>
|
<String>
|
||||||
<Key>URL</Key>
|
<Key>URL</Key>
|
||||||
<Value />
|
<Value ProtectInMemory="True" />
|
||||||
</String>
|
</String>
|
||||||
<String>
|
<String>
|
||||||
<Key>UserName</Key>
|
<Key>UserName</Key>
|
||||||
<Value>User Name</Value>
|
<Value ProtectInMemory="True">User Name</Value>
|
||||||
</String>
|
</String>
|
||||||
|
<Binary>
|
||||||
|
<Key>myattach.txt</Key>
|
||||||
|
<Value Ref="1" />
|
||||||
|
</Binary>
|
||||||
<AutoType>
|
<AutoType>
|
||||||
<Enabled>False</Enabled>
|
<Enabled>False</Enabled>
|
||||||
<DataTransferObfuscation>0</DataTransferObfuscation>
|
<DataTransferObfuscation>0</DataTransferObfuscation>
|
||||||
@ -111,6 +125,7 @@
|
|||||||
<ForegroundColor />
|
<ForegroundColor />
|
||||||
<BackgroundColor />
|
<BackgroundColor />
|
||||||
<OverrideURL />
|
<OverrideURL />
|
||||||
|
<Tags />
|
||||||
<Times>
|
<Times>
|
||||||
<LastModificationTime>2010-08-25T16:13:54Z</LastModificationTime>
|
<LastModificationTime>2010-08-25T16:13:54Z</LastModificationTime>
|
||||||
<CreationTime>2010-08-25T16:13:54Z</CreationTime>
|
<CreationTime>2010-08-25T16:13:54Z</CreationTime>
|
||||||
@ -140,6 +155,10 @@
|
|||||||
<Key>UserName</Key>
|
<Key>UserName</Key>
|
||||||
<Value>User Name</Value>
|
<Value>User Name</Value>
|
||||||
</String>
|
</String>
|
||||||
|
<Binary>
|
||||||
|
<Key>myattach.txt</Key>
|
||||||
|
<Value Ref="0" />
|
||||||
|
</Binary>
|
||||||
<AutoType>
|
<AutoType>
|
||||||
<Enabled>True</Enabled>
|
<Enabled>True</Enabled>
|
||||||
<DataTransferObfuscation>0</DataTransferObfuscation>
|
<DataTransferObfuscation>0</DataTransferObfuscation>
|
||||||
@ -155,6 +174,7 @@
|
|||||||
<ForegroundColor />
|
<ForegroundColor />
|
||||||
<BackgroundColor />
|
<BackgroundColor />
|
||||||
<OverrideURL />
|
<OverrideURL />
|
||||||
|
<Tags />
|
||||||
<Times>
|
<Times>
|
||||||
<LastModificationTime>2010-08-25T16:15:43Z</LastModificationTime>
|
<LastModificationTime>2010-08-25T16:15:43Z</LastModificationTime>
|
||||||
<CreationTime>2010-08-25T16:13:54Z</CreationTime>
|
<CreationTime>2010-08-25T16:13:54Z</CreationTime>
|
||||||
@ -184,6 +204,10 @@
|
|||||||
<Key>UserName</Key>
|
<Key>UserName</Key>
|
||||||
<Value>User Name</Value>
|
<Value>User Name</Value>
|
||||||
</String>
|
</String>
|
||||||
|
<Binary>
|
||||||
|
<Key>myattach.txt</Key>
|
||||||
|
<Value Ref="1" />
|
||||||
|
</Binary>
|
||||||
<AutoType>
|
<AutoType>
|
||||||
<Enabled>True</Enabled>
|
<Enabled>True</Enabled>
|
||||||
<DataTransferObfuscation>0</DataTransferObfuscation>
|
<DataTransferObfuscation>0</DataTransferObfuscation>
|
||||||
@ -202,6 +226,7 @@
|
|||||||
<ForegroundColor>#FF0000</ForegroundColor>
|
<ForegroundColor>#FF0000</ForegroundColor>
|
||||||
<BackgroundColor>#FFFF00</BackgroundColor>
|
<BackgroundColor>#FFFF00</BackgroundColor>
|
||||||
<OverrideURL>http://override.net/</OverrideURL>
|
<OverrideURL>http://override.net/</OverrideURL>
|
||||||
|
<Tags />
|
||||||
<Times>
|
<Times>
|
||||||
<LastModificationTime>2010-08-25T16:20:24Z</LastModificationTime>
|
<LastModificationTime>2010-08-25T16:20:24Z</LastModificationTime>
|
||||||
<CreationTime>2010-08-25T16:15:45Z</CreationTime>
|
<CreationTime>2010-08-25T16:15:45Z</CreationTime>
|
||||||
@ -233,15 +258,15 @@
|
|||||||
</String>
|
</String>
|
||||||
<String>
|
<String>
|
||||||
<Key>URL</Key>
|
<Key>URL</Key>
|
||||||
<Value>http://www.keepassx.org/</Value>
|
<Value ProtectInMemory="True">http://www.keepassx.org/</Value>
|
||||||
</String>
|
</String>
|
||||||
<String>
|
<String>
|
||||||
<Key>UserName</Key>
|
<Key>UserName</Key>
|
||||||
<Value>notDEFUSERNAME</Value>
|
<Value ProtectInMemory="True">notDEFUSERNAME</Value>
|
||||||
</String>
|
</String>
|
||||||
<Binary>
|
<Binary>
|
||||||
<Key>testattach.txt</Key>
|
<Key>myattach.txt</Key>
|
||||||
<Value>NDI=</Value>
|
<Value Ref="1" />
|
||||||
</Binary>
|
</Binary>
|
||||||
<AutoType>
|
<AutoType>
|
||||||
<Enabled>True</Enabled>
|
<Enabled>True</Enabled>
|
||||||
@ -322,6 +347,7 @@
|
|||||||
<ForegroundColor />
|
<ForegroundColor />
|
||||||
<BackgroundColor />
|
<BackgroundColor />
|
||||||
<OverrideURL />
|
<OverrideURL />
|
||||||
|
<Tags />
|
||||||
<Times>
|
<Times>
|
||||||
<LastModificationTime>2010-08-25T16:21:15Z</LastModificationTime>
|
<LastModificationTime>2010-08-25T16:21:15Z</LastModificationTime>
|
||||||
<CreationTime>2010-08-25T16:20:45Z</CreationTime>
|
<CreationTime>2010-08-25T16:20:45Z</CreationTime>
|
||||||
@ -384,6 +410,7 @@
|
|||||||
<ForegroundColor />
|
<ForegroundColor />
|
||||||
<BackgroundColor />
|
<BackgroundColor />
|
||||||
<OverrideURL />
|
<OverrideURL />
|
||||||
|
<Tags />
|
||||||
<Times>
|
<Times>
|
||||||
<LastModificationTime>2010-08-25T16:20:32Z</LastModificationTime>
|
<LastModificationTime>2010-08-25T16:20:32Z</LastModificationTime>
|
||||||
<CreationTime>2010-08-25T16:20:27Z</CreationTime>
|
<CreationTime>2010-08-25T16:20:27Z</CreationTime>
|
||||||
|
Binary file not shown.
1
tests/data/NonAscii.kdbx.key
Normal file
1
tests/data/NonAscii.kdbx.key
Normal file
@ -0,0 +1 @@
|
|||||||
|
Δöض
|
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user