mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-10-01 01:26:01 -04:00
Feature : clip command (#578)
This commit is contained in:
parent
6c050c55d9
commit
a2e82dc883
@ -14,6 +14,8 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
set(cli_SOURCES
|
set(cli_SOURCES
|
||||||
|
Clip.cpp
|
||||||
|
Clip.h
|
||||||
EntropyMeter.cpp
|
EntropyMeter.cpp
|
||||||
EntropyMeter.h
|
EntropyMeter.h
|
||||||
Extract.cpp
|
Extract.cpp
|
||||||
|
73
src/cli/Clip.cpp
Normal file
73
src/cli/Clip.cpp
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 KeePassXC Team
|
||||||
|
*
|
||||||
|
* 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 <cstdlib>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "Clip.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QClipboard>
|
||||||
|
#include <QCommandLineParser>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QTextStream>
|
||||||
|
|
||||||
|
#include "core/Database.h"
|
||||||
|
#include "core/Entry.h"
|
||||||
|
#include "core/Group.h"
|
||||||
|
#include "gui/Clipboard.h"
|
||||||
|
#include "keys/CompositeKey.h"
|
||||||
|
|
||||||
|
int Clip::execute(int argc, char** argv)
|
||||||
|
{
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
QTextStream out(stdout);
|
||||||
|
|
||||||
|
QCommandLineParser parser;
|
||||||
|
parser.setApplicationDescription(QCoreApplication::translate("main", "Copy a password to the clipboard"));
|
||||||
|
parser.addPositionalArgument("database", QCoreApplication::translate("main", "Path of the database."));
|
||||||
|
parser.addPositionalArgument("entry", QCoreApplication::translate("main", "Name of the entry to clip."));
|
||||||
|
parser.process(app);
|
||||||
|
|
||||||
|
const QStringList args = parser.positionalArguments();
|
||||||
|
if (args.size() != 2) {
|
||||||
|
parser.showHelp();
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
out << "Insert the database password\n> ";
|
||||||
|
out.flush();
|
||||||
|
|
||||||
|
static QTextStream inputTextStream(stdin, QIODevice::ReadOnly);
|
||||||
|
QString line = inputTextStream.readLine();
|
||||||
|
CompositeKey key = CompositeKey::readFromLine(line);
|
||||||
|
|
||||||
|
Database* db = Database::openDatabaseFile(args.at(0), key);
|
||||||
|
if (!db) {
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString entryId = args.at(1);
|
||||||
|
Entry* entry = db->rootGroup()->findEntry(entryId);
|
||||||
|
if (!entry) {
|
||||||
|
qCritical("Entry %s not found.", qPrintable(entryId));
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Clipboard::instance()->setText(entry->password());
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
27
src/cli/Clip.h
Normal file
27
src/cli/Clip.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 KeePassXC Team
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 or (at your option)
|
||||||
|
* version 3 of the License.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef KEEPASSXC_CLIP_H
|
||||||
|
#define KEEPASSXC_CLIP_H
|
||||||
|
|
||||||
|
class Clip
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static int execute(int argc, char** argv);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // KEEPASSXC_CLIP_H
|
@ -30,14 +30,14 @@
|
|||||||
#include "format/KeePass2Reader.h"
|
#include "format/KeePass2Reader.h"
|
||||||
#include "keys/CompositeKey.h"
|
#include "keys/CompositeKey.h"
|
||||||
|
|
||||||
int Extract::execute(int argc, char **argv)
|
int Extract::execute(int argc, char** argv)
|
||||||
{
|
{
|
||||||
QCoreApplication app(argc, argv);
|
QCoreApplication app(argc, argv);
|
||||||
QTextStream out(stdout);
|
QTextStream out(stdout);
|
||||||
|
|
||||||
QCommandLineParser parser;
|
QCommandLineParser parser;
|
||||||
parser.setApplicationDescription(QCoreApplication::translate("main",
|
parser.setApplicationDescription(
|
||||||
"Extract and print the content of a database."));
|
QCoreApplication::translate("main", "Extract and print the content of a database."));
|
||||||
parser.addPositionalArgument("database", QCoreApplication::translate("main", "Path of the database to extract."));
|
parser.addPositionalArgument("database", QCoreApplication::translate("main", "Path of the database to extract."));
|
||||||
parser.process(app);
|
parser.process(app);
|
||||||
|
|
||||||
@ -75,8 +75,7 @@ int Extract::execute(int argc, char **argv)
|
|||||||
if (reader.hasError()) {
|
if (reader.hasError()) {
|
||||||
if (xmlData.isEmpty()) {
|
if (xmlData.isEmpty()) {
|
||||||
qCritical("Error while reading the database:\n%s", qPrintable(reader.errorString()));
|
qCritical("Error while reading the database:\n%s", qPrintable(reader.errorString()));
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
qWarning("Error while parsing the database:\n%s\n", qPrintable(reader.errorString()));
|
qWarning("Error while parsing the database:\n%s\n", qPrintable(reader.errorString()));
|
||||||
}
|
}
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
|
@ -30,7 +30,8 @@
|
|||||||
#include "core/Group.h"
|
#include "core/Group.h"
|
||||||
#include "keys/CompositeKey.h"
|
#include "keys/CompositeKey.h"
|
||||||
|
|
||||||
void printGroup(Group* group, QString baseName, int depth) {
|
void printGroup(Group* group, QString baseName, int depth)
|
||||||
|
{
|
||||||
|
|
||||||
QTextStream out(stdout);
|
QTextStream out(stdout);
|
||||||
|
|
||||||
@ -52,17 +53,15 @@ void printGroup(Group* group, QString baseName, int depth) {
|
|||||||
for (Group* innerGroup : group->children()) {
|
for (Group* innerGroup : group->children()) {
|
||||||
printGroup(innerGroup, groupName, depth + 1);
|
printGroup(innerGroup, groupName, depth + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int List::execute(int argc, char **argv)
|
int List::execute(int argc, char** argv)
|
||||||
{
|
{
|
||||||
QCoreApplication app(argc, argv);
|
QCoreApplication app(argc, argv);
|
||||||
QTextStream out(stdout);
|
QTextStream out(stdout);
|
||||||
|
|
||||||
QCommandLineParser parser;
|
QCommandLineParser parser;
|
||||||
parser.setApplicationDescription(QCoreApplication::translate("main",
|
parser.setApplicationDescription(QCoreApplication::translate("main", "List database entries."));
|
||||||
"List database entries."));
|
|
||||||
parser.addPositionalArgument("database", QCoreApplication::translate("main", "Path of the database."));
|
parser.addPositionalArgument("database", QCoreApplication::translate("main", "Path of the database."));
|
||||||
parser.process(app);
|
parser.process(app);
|
||||||
|
|
||||||
|
@ -37,10 +37,14 @@ int Merge::execute(int argc, char** argv)
|
|||||||
|
|
||||||
QCommandLineParser parser;
|
QCommandLineParser parser;
|
||||||
parser.setApplicationDescription(QCoreApplication::translate("main", "Merge two databases."));
|
parser.setApplicationDescription(QCoreApplication::translate("main", "Merge two databases."));
|
||||||
parser.addPositionalArgument("database1", QCoreApplication::translate("main", "Path of the database to merge into."));
|
parser.addPositionalArgument("database1",
|
||||||
parser.addPositionalArgument("database2", QCoreApplication::translate("main", "Path of the database to merge from."));
|
QCoreApplication::translate("main", "Path of the database to merge into."));
|
||||||
|
parser.addPositionalArgument("database2",
|
||||||
|
QCoreApplication::translate("main", "Path of the database to merge from."));
|
||||||
|
|
||||||
QCommandLineOption samePasswordOption(QStringList() << "s" << "same-password",
|
QCommandLineOption samePasswordOption(
|
||||||
|
QStringList() << "s"
|
||||||
|
<< "same-password",
|
||||||
QCoreApplication::translate("main", "Use the same password for both database files."));
|
QCoreApplication::translate("main", "Use the same password for both database files."));
|
||||||
|
|
||||||
parser.addOption(samePasswordOption);
|
parser.addOption(samePasswordOption);
|
||||||
@ -62,15 +66,13 @@ int Merge::execute(int argc, char** argv)
|
|||||||
CompositeKey key2;
|
CompositeKey key2;
|
||||||
if (parser.isSet("same-password")) {
|
if (parser.isSet("same-password")) {
|
||||||
key2 = *key1.clone();
|
key2 = *key1.clone();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
out << "Insert the second database password\n> ";
|
out << "Insert the second database password\n> ";
|
||||||
out.flush();
|
out.flush();
|
||||||
QString line2 = inputTextStream.readLine();
|
QString line2 = inputTextStream.readLine();
|
||||||
key2 = CompositeKey::readFromLine(line2);
|
key2 = CompositeKey::readFromLine(line2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Database* db1 = Database::openDatabaseFile(args.at(0), key1);
|
Database* db1 = Database::openDatabaseFile(args.at(0), key1);
|
||||||
if (db1 == nullptr) {
|
if (db1 == nullptr) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
@ -104,5 +106,4 @@ int Merge::execute(int argc, char** argv)
|
|||||||
|
|
||||||
out << "Successfully merged the database files.\n";
|
out << "Successfully merged the database files.\n";
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,16 +30,15 @@
|
|||||||
#include "core/Group.h"
|
#include "core/Group.h"
|
||||||
#include "keys/CompositeKey.h"
|
#include "keys/CompositeKey.h"
|
||||||
|
|
||||||
int Show::execute(int argc, char **argv)
|
int Show::execute(int argc, char** argv)
|
||||||
{
|
{
|
||||||
QCoreApplication app(argc, argv);
|
QCoreApplication app(argc, argv);
|
||||||
QTextStream out(stdout);
|
QTextStream out(stdout);
|
||||||
|
|
||||||
QCommandLineParser parser;
|
QCommandLineParser parser;
|
||||||
parser.setApplicationDescription(QCoreApplication::translate("main",
|
parser.setApplicationDescription(QCoreApplication::translate("main", "Show a password."));
|
||||||
"Show a password."));
|
|
||||||
parser.addPositionalArgument("database", QCoreApplication::translate("main", "Path of the database."));
|
parser.addPositionalArgument("database", QCoreApplication::translate("main", "Path of the database."));
|
||||||
parser.addPositionalArgument("uuid", QCoreApplication::translate("main", "Uuid of the entry to show"));
|
parser.addPositionalArgument("entry", QCoreApplication::translate("main", "Name of the entry to show."));
|
||||||
parser.process(app);
|
parser.process(app);
|
||||||
|
|
||||||
const QStringList args = parser.positionalArguments();
|
const QStringList args = parser.positionalArguments();
|
||||||
@ -60,10 +59,10 @@ int Show::execute(int argc, char **argv)
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Uuid uuid = Uuid::fromHex(args.at(1));
|
QString entryId = args.at(1);
|
||||||
Entry* entry = db->resolveEntry(uuid);
|
Entry* entry = db->rootGroup()->findEntry(entryId);
|
||||||
if (entry == nullptr) {
|
if (!entry) {
|
||||||
qCritical("No entry found with uuid %s", qPrintable(uuid.toHex()));
|
qCritical("Entry %s not found.", qPrintable(entryId));
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|
||||||
|
#include <cli/Clip.h>
|
||||||
#include <cli/EntropyMeter.h>
|
#include <cli/EntropyMeter.h>
|
||||||
#include <cli/Extract.h>
|
#include <cli/Extract.h>
|
||||||
#include <cli/List.h>
|
#include <cli/List.h>
|
||||||
@ -35,7 +36,7 @@
|
|||||||
#include <sanitizer/lsan_interface.h>
|
#include <sanitizer/lsan_interface.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
#ifdef QT_NO_DEBUG
|
#ifdef QT_NO_DEBUG
|
||||||
Tools::disableCoreDumps();
|
Tools::disableCoreDumps();
|
||||||
@ -53,6 +54,7 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
QString description("KeePassXC command line interface.");
|
QString description("KeePassXC command line interface.");
|
||||||
description = description.append(QString("\n\nAvailable commands:"));
|
description = description.append(QString("\n\nAvailable commands:"));
|
||||||
|
description = description.append(QString("\n clip\t\tCopy a password to the clipboard."));
|
||||||
description = description.append(QString("\n extract\tExtract and print the content of a database."));
|
description = description.append(QString("\n extract\tExtract and print the content of a database."));
|
||||||
description = description.append(QString("\n entropy-meter\tCalculate password entropy."));
|
description = description.append(QString("\n entropy-meter\tCalculate password entropy."));
|
||||||
description = description.append(QString("\n list\t\tList database entries."));
|
description = description.append(QString("\n list\t\tList database entries."));
|
||||||
@ -82,7 +84,10 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
int exitCode = EXIT_FAILURE;
|
int exitCode = EXIT_FAILURE;
|
||||||
|
|
||||||
if (commandName == "entropy-meter") {
|
if (commandName == "clip") {
|
||||||
|
argv[0] = const_cast<char*>("keepassxc-cli clip");
|
||||||
|
exitCode = Clip::execute(argc, argv);
|
||||||
|
} else if (commandName == "entropy-meter") {
|
||||||
argv[0] = const_cast<char*>("keepassxc-cli entropy-meter");
|
argv[0] = const_cast<char*>("keepassxc-cli entropy-meter");
|
||||||
exitCode = EntropyMeter::execute(argc, argv);
|
exitCode = EntropyMeter::execute(argc, argv);
|
||||||
} else if (commandName == "extract") {
|
} else if (commandName == "extract") {
|
||||||
@ -110,5 +115,4 @@ int main(int argc, char **argv)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
return exitCode;
|
return exitCode;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -367,7 +367,7 @@ void Database::startModifiedTimer()
|
|||||||
m_timer->start(150);
|
m_timer->start(150);
|
||||||
}
|
}
|
||||||
|
|
||||||
const CompositeKey & Database::key() const
|
const CompositeKey& Database::key() const
|
||||||
{
|
{
|
||||||
return m_data.key;
|
return m_data.key;
|
||||||
}
|
}
|
||||||
|
@ -483,7 +483,24 @@ QList<Entry*> Group::entriesRecursive(bool includeHistoryItems) const
|
|||||||
return entryList;
|
return entryList;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entry* Group::findEntry(const Uuid& uuid)
|
Entry* Group::findEntry(QString entryId)
|
||||||
|
{
|
||||||
|
Q_ASSERT(!entryId.isEmpty());
|
||||||
|
Q_ASSERT(!entryId.isNull());
|
||||||
|
|
||||||
|
if (Uuid::isUuid(entryId)) {
|
||||||
|
Uuid entryUuid = Uuid::fromHex(entryId);
|
||||||
|
for (Entry* entry : entriesRecursive(false)) {
|
||||||
|
if (entry->uuid() == entryUuid) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return findEntryByPath(entryId);
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry* Group::findEntryByUuid(const Uuid& uuid)
|
||||||
{
|
{
|
||||||
Q_ASSERT(!uuid.isNull());
|
Q_ASSERT(!uuid.isNull());
|
||||||
for (Entry* entry : asConst(m_entries)) {
|
for (Entry* entry : asConst(m_entries)) {
|
||||||
@ -495,6 +512,29 @@ Entry* Group::findEntry(const Uuid& uuid)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Entry* Group::findEntryByPath(QString entryPath, QString basePath)
|
||||||
|
{
|
||||||
|
|
||||||
|
Q_ASSERT(!entryPath.isEmpty());
|
||||||
|
Q_ASSERT(!entryPath.isNull());
|
||||||
|
|
||||||
|
for (Entry* entry : asConst(m_entries)) {
|
||||||
|
QString currentEntryPath = basePath + entry->title();
|
||||||
|
if (entryPath == currentEntryPath) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Group* group : asConst(m_children)) {
|
||||||
|
Entry* entry = group->findEntryByPath(entryPath, basePath + group->name() + QString("/"));
|
||||||
|
if (entry != nullptr) {
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
QList<const Group*> Group::groupsRecursive(bool includeSelf) const
|
QList<const Group*> Group::groupsRecursive(bool includeSelf) const
|
||||||
{
|
{
|
||||||
QList<const Group*> groupList;
|
QList<const Group*> groupList;
|
||||||
@ -551,10 +591,10 @@ void Group::merge(const Group* other)
|
|||||||
const QList<Entry*> dbEntries = other->entries();
|
const QList<Entry*> dbEntries = other->entries();
|
||||||
for (Entry* entry : dbEntries) {
|
for (Entry* entry : dbEntries) {
|
||||||
// entries are searched by uuid
|
// entries are searched by uuid
|
||||||
if (!findEntry(entry->uuid())) {
|
if (!findEntryByUuid(entry->uuid())) {
|
||||||
entry->clone(Entry::CloneNoFlags)->setGroup(this);
|
entry->clone(Entry::CloneNoFlags)->setGroup(this);
|
||||||
} else {
|
} else {
|
||||||
resolveConflict(findEntry(entry->uuid()), entry);
|
resolveConflict(findEntryByUuid(entry->uuid()), entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +78,9 @@ public:
|
|||||||
static const int DefaultIconNumber;
|
static const int DefaultIconNumber;
|
||||||
static const int RecycleBinIconNumber;
|
static const int RecycleBinIconNumber;
|
||||||
|
|
||||||
Entry* findEntry(const Uuid& uuid);
|
Entry* findEntry(QString entryId);
|
||||||
|
Entry* findEntryByUuid(const Uuid& uuid);
|
||||||
|
Entry* findEntryByPath(QString entryPath, QString basePath = QString(""));
|
||||||
Group* findChildByName(const QString& name);
|
Group* findChildByName(const QString& name);
|
||||||
void setUuid(const Uuid& uuid);
|
void setUuid(const Uuid& uuid);
|
||||||
void setName(const QString& name);
|
void setName(const QString& name);
|
||||||
|
@ -22,6 +22,8 @@
|
|||||||
#include "crypto/Random.h"
|
#include "crypto/Random.h"
|
||||||
|
|
||||||
const int Uuid::Length = 16;
|
const int Uuid::Length = 16;
|
||||||
|
const QRegExp Uuid::HexRegExp = QRegExp(QString("^[0-9A-F]{%1}$").arg(QString::number(Uuid::Length * 2)),
|
||||||
|
Qt::CaseInsensitive);
|
||||||
|
|
||||||
Uuid::Uuid()
|
Uuid::Uuid()
|
||||||
: m_data(Length, 0)
|
: m_data(Length, 0)
|
||||||
@ -115,3 +117,8 @@ QDataStream& operator>>(QDataStream& stream, Uuid& uuid)
|
|||||||
|
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Uuid::isUuid(const QString& uuid)
|
||||||
|
{
|
||||||
|
return Uuid::HexRegExp.exactMatch(uuid);
|
||||||
|
}
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include <QByteArray>
|
#include <QByteArray>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QRegExp>
|
||||||
|
|
||||||
class Uuid
|
class Uuid
|
||||||
{
|
{
|
||||||
@ -36,8 +37,10 @@ public:
|
|||||||
bool operator==(const Uuid& other) const;
|
bool operator==(const Uuid& other) const;
|
||||||
bool operator!=(const Uuid& other) const;
|
bool operator!=(const Uuid& other) const;
|
||||||
static const int Length;
|
static const int Length;
|
||||||
|
static const QRegExp HexRegExp;
|
||||||
static Uuid fromBase64(const QString& str);
|
static Uuid fromBase64(const QString& str);
|
||||||
static Uuid fromHex(const QString& str);
|
static Uuid fromHex(const QString& str);
|
||||||
|
static bool isUuid(const QString& str);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QByteArray m_data;
|
QByteArray m_data;
|
||||||
|
@ -567,3 +567,55 @@ Database* TestGroup::createMergeTestDatabase()
|
|||||||
|
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TestGroup::testFindEntry()
|
||||||
|
{
|
||||||
|
Database* db = new Database();
|
||||||
|
|
||||||
|
Entry* entry1 = new Entry();
|
||||||
|
entry1->setTitle(QString("entry1"));
|
||||||
|
entry1->setGroup(db->rootGroup());
|
||||||
|
entry1->setUuid(Uuid::random());
|
||||||
|
|
||||||
|
Group* group1 = new Group();
|
||||||
|
group1->setName("group1");
|
||||||
|
|
||||||
|
Entry* entry2 = new Entry();
|
||||||
|
|
||||||
|
entry2->setTitle(QString("entry2"));
|
||||||
|
entry2->setGroup(group1);
|
||||||
|
entry2->setUuid(Uuid::random());
|
||||||
|
|
||||||
|
group1->setParent(db->rootGroup());
|
||||||
|
|
||||||
|
Entry* entry;
|
||||||
|
|
||||||
|
entry = db->rootGroup()->findEntry(entry1->uuid().toHex());
|
||||||
|
QVERIFY(entry != nullptr);
|
||||||
|
QCOMPARE(entry->title(), QString("entry1"));
|
||||||
|
|
||||||
|
entry = db->rootGroup()->findEntry(QString("entry1"));
|
||||||
|
QVERIFY(entry != nullptr);
|
||||||
|
QCOMPARE(entry->title(), QString("entry1"));
|
||||||
|
|
||||||
|
entry = db->rootGroup()->findEntry(entry2->uuid().toHex());
|
||||||
|
QVERIFY(entry != nullptr);
|
||||||
|
QCOMPARE(entry->title(), QString("entry2"));
|
||||||
|
|
||||||
|
entry = db->rootGroup()->findEntry(QString("group1/entry2"));
|
||||||
|
QVERIFY(entry != nullptr);
|
||||||
|
QCOMPARE(entry->title(), QString("entry2"));
|
||||||
|
|
||||||
|
entry = db->rootGroup()->findEntry(QString("invalid/path/to/entry2"));
|
||||||
|
QVERIFY(entry == nullptr);
|
||||||
|
|
||||||
|
// A valid UUID that does not exist in this database.
|
||||||
|
entry = db->rootGroup()->findEntry(QString("febfb01ebcdf9dbd90a3f1579dc75281"));
|
||||||
|
QVERIFY(entry == nullptr);
|
||||||
|
|
||||||
|
// An invalid UUID.
|
||||||
|
entry = db->rootGroup()->findEntry(QString("febfb01ebcdf9dbd90a3f1579dc"));
|
||||||
|
QVERIFY(entry == nullptr);
|
||||||
|
|
||||||
|
delete db;
|
||||||
|
}
|
||||||
|
@ -38,6 +38,7 @@ private slots:
|
|||||||
void testMergeConflict();
|
void testMergeConflict();
|
||||||
void testMergeDatabase();
|
void testMergeDatabase();
|
||||||
void testMergeConflictKeepBoth();
|
void testMergeConflictKeepBoth();
|
||||||
|
void testFindEntry();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Database* createMergeTestDatabase();
|
Database* createMergeTestDatabase();
|
||||||
|
Loading…
Reference in New Issue
Block a user