Fixed bug in FileWatcher, improved unsafe sharing

BulkFileWatcher didn't recognize added files in observed directory

Improved UI for unsecured sharing only (hide certificate ui, added
warnings and adjusted indicators)
This commit is contained in:
Christian Kieschnick 2019-01-03 17:50:36 +01:00
parent d4c391deb2
commit 2e18388825
12 changed files with 319 additions and 166 deletions

View file

@ -182,28 +182,28 @@ void BulkFileWatcher::handleFileChanged(const QString& path)
void BulkFileWatcher::handleDirectoryChanged(const QString& path) void BulkFileWatcher::handleDirectoryChanged(const QString& path)
{ {
qDebug("Directory changed %s", qPrintable(path)); qDebug("Directory changed %s", qPrintable(path));
const QFileInfo directory(path); const QFileInfo directoryInfo(path);
const QMap<QString, bool>& watchedFiles = m_watchedFilesInDirectory[directory.absolutePath()]; const QMap<QString, bool>& watchedFiles = m_watchedFilesInDirectory[directoryInfo.absoluteFilePath()];
for (const QString& file : watchedFiles.keys()) { for (const QString& filename : watchedFiles.keys()) {
const QFileInfo info(file); const QFileInfo fileInfo(filename);
const bool existed = watchedFiles[info.absoluteFilePath()]; const bool existed = watchedFiles[fileInfo.absoluteFilePath()];
if (!info.exists() && existed) { if (!fileInfo.exists() && existed) {
qDebug("Remove watch file %s", qPrintable(info.absoluteFilePath())); qDebug("Remove watch file %s", qPrintable(fileInfo.absoluteFilePath()));
m_fileWatcher.removePath(info.absolutePath()); m_fileWatcher.removePath(fileInfo.absolutePath());
emit fileRemoved(info.absoluteFilePath()); emit fileRemoved(fileInfo.absoluteFilePath());
} }
if (!existed && info.exists()) { if (!existed && fileInfo.exists()) {
qDebug("Add watch file %s", qPrintable(info.absoluteFilePath())); qDebug("Add watch file %s", qPrintable(fileInfo.absoluteFilePath()));
m_fileWatcher.addPath(info.absolutePath()); m_fileWatcher.addPath(fileInfo.absolutePath());
emit fileCreated(info.absoluteFilePath()); emit fileCreated(fileInfo.absoluteFilePath());
} }
if (existed && info.exists()) { if (existed && fileInfo.exists()) {
qDebug("Refresh watch file %s", qPrintable(info.absoluteFilePath())); qDebug("Refresh watch file %s", qPrintable(fileInfo.absoluteFilePath()));
m_fileWatcher.removePath(info.absolutePath()); m_fileWatcher.removePath(fileInfo.absolutePath());
m_fileWatcher.addPath(info.absolutePath()); m_fileWatcher.addPath(fileInfo.absolutePath());
emit fileChanged(info.absoluteFilePath()); emit fileChanged(fileInfo.absoluteFilePath());
} }
m_watchedFilesInDirectory[info.absolutePath()][info.absoluteFilePath()] = info.exists(); m_watchedFilesInDirectory[fileInfo.absolutePath()][fileInfo.absoluteFilePath()] = fileInfo.exists();
} }
} }

View file

@ -114,7 +114,9 @@ QString FileDialog::getFileName(QWidget* parent,
dialog.selectFile(defaultName); dialog.selectFile(defaultName);
} }
dialog.setOptions(options); dialog.setOptions(options);
if (!defaultExtension.isEmpty()) {
dialog.setDefaultSuffix(defaultExtension); dialog.setDefaultSuffix(defaultExtension);
}
dialog.setLabelText(QFileDialog::Accept, QFileDialog::tr("Select")); dialog.setLabelText(QFileDialog::Accept, QFileDialog::tr("Select"));
QStringList results; QStringList results;
if (dialog.exec()) { if (dialog.exec()) {

View file

@ -57,7 +57,7 @@ void DatabaseSettingsWidgetKeeShare::loadSettings(QSharedPointer<Database> db)
QStringList hierarchy = group->hierarchy(); QStringList hierarchy = group->hierarchy();
hierarchy.removeFirst(); hierarchy.removeFirst();
QList<QStandardItem*> row = QList<QStandardItem*>(); QList<QStandardItem*> row = QList<QStandardItem*>();
row << new QStandardItem(hierarchy.join(" > ")); row << new QStandardItem(hierarchy.join(tr(" > ", "Breadcrumb separator")));
row << new QStandardItem(KeeShare::referenceTypeLabel(reference)); row << new QStandardItem(KeeShare::referenceTypeLabel(reference));
row << new QStandardItem(reference.path); row << new QStandardItem(reference.path);
m_referencesModel->appendRow(row); m_referencesModel->appendRow(row);

View file

@ -125,15 +125,29 @@ void KeeShare::setReferenceTo(Group* group, const KeeShareSettings::Reference& r
customData->set(KeeShare_Reference, encoded); customData->set(KeeShare_Reference, encoded);
} }
bool KeeShare::isEnabled(const Group* group)
{
const auto reference = KeeShare::referenceOf(group);
#if !defined(WITH_XC_KEESHARE_SECURE)
if (reference.path.endsWith(secureContainerFileType(), Qt::CaseInsensitive)){
return false;
}
#endif
#if !defined(WITH_XC_KEESHARE_INSECURE)
if (reference.path.endsWith(insecureContainerFileType(), Qt::CaseInsensitive)){
return false;
}
#endif
const auto active = KeeShare::active();
return (reference.isImporting() && active.in) || (reference.isExporting() && active.out);
}
QPixmap KeeShare::indicatorBadge(const Group* group, QPixmap pixmap) QPixmap KeeShare::indicatorBadge(const Group* group, QPixmap pixmap)
{ {
if (!isShared(group)) { if (!isShared(group)) {
return pixmap; return pixmap;
} }
const auto reference = KeeShare::referenceOf(group); const QPixmap badge = isEnabled(group) ? databaseIcons()->iconPixmap(DatabaseIcons::SharedIconIndex)
const auto active = KeeShare::active();
const bool enabled = (reference.isImporting() && active.in) || (reference.isExporting() && active.out);
const QPixmap badge = enabled ? databaseIcons()->iconPixmap(DatabaseIcons::SharedIconIndex)
: databaseIcons()->iconPixmap(DatabaseIcons::UnsharedIconIndex); : databaseIcons()->iconPixmap(DatabaseIcons::UnsharedIconIndex);
QImage canvas = pixmap.toImage(); QImage canvas = pixmap.toImage();
const QRectF target(canvas.width() * 0.4, canvas.height() * 0.4, canvas.width() * 0.6, canvas.height() * 0.6); const QRectF target(canvas.width() * 0.4, canvas.height() * 0.4, canvas.width() * 0.6, canvas.height() * 0.6);

View file

@ -41,6 +41,7 @@ public:
static QPixmap indicatorBadge(const Group* group, QPixmap pixmap); static QPixmap indicatorBadge(const Group* group, QPixmap pixmap);
static bool isShared(const Group* group); static bool isShared(const Group* group);
static bool isEnabled(const Group *group);
static KeeShareSettings::Own own(); static KeeShareSettings::Own own();
static KeeShareSettings::Active active(); static KeeShareSettings::Active active();

View file

@ -32,10 +32,9 @@ namespace KeeShareSettings
{ {
namespace namespace
{ {
Certificate packCertificate(const OpenSSHKey& key, bool verified, const QString& signer) Certificate packCertificate(const OpenSSHKey& key, const QString& signer)
{ {
KeeShareSettings::Certificate extracted; KeeShareSettings::Certificate extracted;
extracted.trusted = verified;
extracted.signer = signer; extracted.signer = signer;
Q_ASSERT(key.type() == "ssh-rsa"); Q_ASSERT(key.type() == "ssh-rsa");
extracted.key = OpenSSHKey::serializeToBinary(OpenSSHKey::Public, key); extracted.key = OpenSSHKey::serializeToBinary(OpenSSHKey::Public, key);
@ -108,9 +107,6 @@ namespace KeeShareSettings
writer.writeStartElement("Signer"); writer.writeStartElement("Signer");
writer.writeCharacters(certificate.signer); writer.writeCharacters(certificate.signer);
writer.writeEndElement(); writer.writeEndElement();
writer.writeStartElement("Trusted");
writer.writeCharacters(certificate.trusted ? "True" : "False");
writer.writeEndElement();
writer.writeStartElement("Key"); writer.writeStartElement("Key");
writer.writeCharacters(certificate.key.toBase64()); writer.writeCharacters(certificate.key.toBase64());
writer.writeEndElement(); writer.writeEndElement();
@ -118,7 +114,7 @@ namespace KeeShareSettings
bool Certificate::operator==(const Certificate& other) const bool Certificate::operator==(const Certificate& other) const
{ {
return trusted == other.trusted && key == other.key && signer == other.signer; return key == other.key && signer == other.signer;
} }
bool Certificate::operator!=(const Certificate& other) const bool Certificate::operator!=(const Certificate& other) const
@ -128,7 +124,7 @@ namespace KeeShareSettings
bool Certificate::isNull() const bool Certificate::isNull() const
{ {
return !trusted && key.isEmpty() && signer.isEmpty(); return key.isEmpty() && signer.isEmpty();
} }
QString Certificate::fingerprint() const QString Certificate::fingerprint() const
@ -158,8 +154,6 @@ namespace KeeShareSettings
while (!reader.error() && reader.readNextStartElement()) { while (!reader.error() && reader.readNextStartElement()) {
if (reader.name() == "Signer") { if (reader.name() == "Signer") {
certificate.signer = reader.readElementText(); certificate.signer = reader.readElementText();
} else if (reader.name() == "Trusted") {
certificate.trusted = reader.readElementText() == "True";
} else if (reader.name() == "Key") { } else if (reader.name() == "Key") {
certificate.key = QByteArray::fromBase64(reader.readElementText().toLatin1()); certificate.key = QByteArray::fromBase64(reader.readElementText().toLatin1());
} }
@ -217,7 +211,7 @@ namespace KeeShareSettings
Own own; Own own;
own.key = packKey(key); own.key = packKey(key);
const QString name = qgetenv("USER"); // + "@" + QHostInfo::localHostName(); const QString name = qgetenv("USER"); // + "@" + QHostInfo::localHostName();
own.certificate = packCertificate(key, true, name); own.certificate = packCertificate(key, name);
return own; return own;
} }
@ -301,13 +295,39 @@ namespace KeeShareSettings
return own; return own;
} }
bool ScopedCertificate::operator==(const ScopedCertificate &other) const
{
return trusted == other.trusted && path == other.path && certificate == other.certificate;
}
bool ScopedCertificate::operator!=(const ScopedCertificate &other) const
{
return !operator==(other);
}
void ScopedCertificate::serialize(QXmlStreamWriter& writer, const ScopedCertificate& scopedCertificate)
{
writer.writeAttribute("Path", scopedCertificate.path);
writer.writeAttribute("Trusted", scopedCertificate.trusted ? "True" : "False");
Certificate::serialize(writer, scopedCertificate.certificate);
}
ScopedCertificate ScopedCertificate::deserialize(QXmlStreamReader &reader)
{
ScopedCertificate scopedCertificate;
scopedCertificate.path = reader.attributes().value("Path").toString();
scopedCertificate.trusted = reader.attributes().value("Trusted") == "True";
scopedCertificate.certificate = Certificate::deserialize(reader);
return scopedCertificate;
}
QString Foreign::serialize(const Foreign& foreign) QString Foreign::serialize(const Foreign& foreign)
{ {
return xmlSerialize([&](QXmlStreamWriter& writer) { return xmlSerialize([&](QXmlStreamWriter& writer) {
writer.writeStartElement("Foreign"); writer.writeStartElement("Foreign");
for (const Certificate& certificate : foreign.certificates) { for (const ScopedCertificate& scopedCertificate : foreign.certificates) {
writer.writeStartElement("Certificate"); writer.writeStartElement("Certificate");
Certificate::serialize(writer, certificate); ScopedCertificate::serialize(writer, scopedCertificate);
writer.writeEndElement(); writer.writeEndElement();
} }
writer.writeEndElement(); writer.writeEndElement();
@ -322,7 +342,7 @@ namespace KeeShareSettings
if (reader.name() == "Foreign") { if (reader.name() == "Foreign") {
while (!reader.error() && reader.readNextStartElement()) { while (!reader.error() && reader.readNextStartElement()) {
if (reader.name() == "Certificate") { if (reader.name() == "Certificate") {
foreign.certificates << Certificate::deserialize(reader); foreign.certificates << ScopedCertificate::deserialize(reader);
} else { } else {
::qWarning() << "Unknown Cerificates element" << reader.name(); ::qWarning() << "Unknown Cerificates element" << reader.name();
reader.skipCurrentElement(); reader.skipCurrentElement();

View file

@ -33,16 +33,10 @@ namespace KeeShareSettings
{ {
QByteArray key; QByteArray key;
QString signer; QString signer;
bool trusted;
bool operator==(const Certificate& other) const; bool operator==(const Certificate& other) const;
bool operator!=(const Certificate& other) const; bool operator!=(const Certificate& other) const;
Certificate()
: trusted(false)
{
}
bool isNull() const; bool isNull() const;
QString fingerprint() const; QString fingerprint() const;
QString publicKey() const; QString publicKey() const;
@ -71,11 +65,13 @@ namespace KeeShareSettings
{ {
bool in; bool in;
bool out; bool out;
Active() Active()
: in(false) : in(false)
, out(false) , out(false)
{ {
} }
bool isNull() const bool isNull() const
{ {
return !in && !out; return !in && !out;
@ -92,6 +88,7 @@ namespace KeeShareSettings
bool operator==(const Own& other) const; bool operator==(const Own& other) const;
bool operator!=(const Own& other) const; bool operator!=(const Own& other) const;
bool isNull() const bool isNull() const
{ {
return key.isNull() && certificate.isNull(); return key.isNull() && certificate.isNull();
@ -102,14 +99,25 @@ namespace KeeShareSettings
static Own generate(); static Own generate();
}; };
struct ScopedCertificate
{
QString path;
Certificate certificate;
bool trusted;
bool operator==(const ScopedCertificate& other) const;
bool operator!=(const ScopedCertificate& other) const;
bool isUnknown() const { return certificate.isNull(); }
bool isKnown() const { return !certificate.isNull(); }
static void serialize(QXmlStreamWriter& writer, const ScopedCertificate& certificate);
static ScopedCertificate deserialize(QXmlStreamReader& reader);
};
struct Foreign struct Foreign
{ {
QList<Certificate> certificates; QList<ScopedCertificate> certificates;
bool isNull() const
{
return certificates.isEmpty();
}
static QString serialize(const Foreign& foreign); static QString serialize(const Foreign& foreign);
static Foreign deserialize(const QString& raw); static Foreign deserialize(const QString& raw);

View file

@ -34,6 +34,11 @@ SettingsWidgetKeeShare::SettingsWidgetKeeShare(QWidget* parent)
{ {
m_ui->setupUi(this); m_ui->setupUi(this);
#if !defined(WITH_XC_KEESHARE_SECURE)
// Setting does not help the user of Version without secure export
m_ui->ownCertificateGroupBox->setVisible(false);
#endif
connect(m_ui->ownCertificateSignerEdit, SIGNAL(textChanged(QString)), SLOT(setVerificationExporter(QString))); connect(m_ui->ownCertificateSignerEdit, SIGNAL(textChanged(QString)), SLOT(setVerificationExporter(QString)));
connect(m_ui->generateOwnCerticateButton, SIGNAL(clicked(bool)), SLOT(generateCertificate())); connect(m_ui->generateOwnCerticateButton, SIGNAL(clicked(bool)), SLOT(generateCertificate()));
@ -65,15 +70,25 @@ void SettingsWidgetKeeShare::loadSettings()
void SettingsWidgetKeeShare::updateForeignCertificates() void SettingsWidgetKeeShare::updateForeignCertificates()
{ {
m_importedCertificateModel.reset(new QStandardItemModel()); m_importedCertificateModel.reset(new QStandardItemModel());
m_importedCertificateModel->setHorizontalHeaderLabels( m_importedCertificateModel->setHorizontalHeaderLabels(QStringList() << tr("Path") << tr("Status")
QStringList() << tr("Signer") << tr("Status") << tr("Fingerprint") << tr("Certificate")); #if defined(WITH_XC_KEESHARE_SECURE)
<< tr("Signer") << tr("Fingerprint") << tr("Certificate")
#endif
);
for (const KeeShareSettings::Certificate& certificate : m_foreign.certificates) { for (const auto& scopedCertificate : m_foreign.certificates) {
QStandardItem* signer = new QStandardItem(certificate.signer); const auto items = QList<QStandardItem*>()
QStandardItem* verified = new QStandardItem(certificate.trusted ? tr("trusted") : tr("untrusted")); << new QStandardItem(scopedCertificate.path)
QStandardItem* fingerprint = new QStandardItem(certificate.fingerprint()); << new QStandardItem(scopedCertificate.trusted ? tr("Trusted") : tr("Untrusted"))
QStandardItem* key = new QStandardItem(certificate.publicKey()); #if defined(WITH_XC_KEESHARE_SECURE)
m_importedCertificateModel->appendRow(QList<QStandardItem*>() << signer << verified << fingerprint << key); << new QStandardItem(scopedCertificate.isKnown()
? scopedCertificate.certificate.signer
: tr("Unknown"))
<< new QStandardItem(scopedCertificate.certificate.fingerprint())
<< new QStandardItem(scopedCertificate.certificate.publicKey())
#endif
;
m_importedCertificateModel->appendRow(items);
} }
m_ui->importedCertificateTableView->setModel(m_importedCertificateModel.data()); m_ui->importedCertificateTableView->setModel(m_importedCertificateModel.data());
@ -124,7 +139,7 @@ void SettingsWidgetKeeShare::importCertificate()
} }
const auto filetype = tr("key.share", "Filetype for KeeShare key"); const auto filetype = tr("key.share", "Filetype for KeeShare key");
const auto filters = QString("%1 (*." + filetype + ");;%2 (*)").arg(tr("KeeShare key file"), tr("All files")); const auto filters = QString("%1 (*." + filetype + ");;%2 (*)").arg(tr("KeeShare key file"), tr("All files"));
QString filename = fileDialog()->getOpenFileName(this, tr("Select path"), defaultDirPath, filters, nullptr, 0); QString filename = fileDialog()->getOpenFileName(this, tr("Select path"), defaultDirPath, filters, nullptr, QFileDialog::Options(0));
if (filename.isEmpty()) { if (filename.isEmpty()) {
return; return;
} }
@ -161,7 +176,7 @@ void SettingsWidgetKeeShare::exportCertificate()
const auto filetype = tr("key.share", "Filetype for KeeShare key"); const auto filetype = tr("key.share", "Filetype for KeeShare key");
const auto filters = QString("%1 (*." + filetype + ");;%2 (*)").arg(tr("KeeShare key file"), tr("All files")); const auto filters = QString("%1 (*." + filetype + ");;%2 (*)").arg(tr("KeeShare key file"), tr("All files"));
QString filename = tr("%1.%2", "Template for KeeShare key file").arg(m_own.certificate.signer).arg(filetype); QString filename = tr("%1.%2", "Template for KeeShare key file").arg(m_own.certificate.signer).arg(filetype);
filename = fileDialog()->getSaveFileName(this, tr("Select path"), defaultDirPath, filters, nullptr, 0, filetype, filename); filename = fileDialog()->getSaveFileName(this, tr("Select path"), defaultDirPath, filters, nullptr, QFileDialog::Options(0), filetype, filename);
if (filename.isEmpty()) { if (filename.isEmpty()) {
return; return;
} }
@ -198,7 +213,7 @@ void SettingsWidgetKeeShare::untrustSelectedCertificates()
void SettingsWidgetKeeShare::removeSelectedCertificates() void SettingsWidgetKeeShare::removeSelectedCertificates()
{ {
QList<KeeShareSettings::Certificate> certificates = m_foreign.certificates; auto certificates = m_foreign.certificates;
const auto* selectionModel = m_ui->importedCertificateTableView->selectionModel(); const auto* selectionModel = m_ui->importedCertificateTableView->selectionModel();
Q_ASSERT(selectionModel); Q_ASSERT(selectionModel);
for (const auto& index : selectionModel->selectedRows()) { for (const auto& index : selectionModel->selectedRows()) {

View file

@ -56,12 +56,12 @@ static const QString KeeShare_Container("container.share.kdbx");
enum Trust enum Trust
{ {
None,
Invalid, Invalid,
Single, Own,
Lasting, UntrustedForever,
Known, UntrustedOnce,
Own TrustedOnce,
TrustedForever,
}; };
bool isOfExportType(const QFileInfo &fileInfo, const QString type) bool isOfExportType(const QFileInfo &fileInfo, const QString type)
@ -72,17 +72,12 @@ bool isOfExportType(const QFileInfo &fileInfo, const QString type)
QPair<Trust, KeeShareSettings::Certificate> check(QByteArray& data, QPair<Trust, KeeShareSettings::Certificate> check(QByteArray& data,
const KeeShareSettings::Reference& reference, const KeeShareSettings::Reference& reference,
const KeeShareSettings::Certificate& ownCertificate, const KeeShareSettings::Certificate& ownCertificate,
const QList<KeeShareSettings::Certificate>& knownCertificates, const QList<KeeShareSettings::ScopedCertificate>& knownCertificates,
const KeeShareSettings::Sign& sign) const KeeShareSettings::Sign& sign)
{ {
if (sign.signature.isEmpty()) { KeeShareSettings::Certificate certificate;
for (const auto& certificate : knownCertificates) { if (!sign.signature.isEmpty()) {
if (certificate.key == certificate.key && certificate.trusted) { certificate = sign.certificate;
return {Known, certificate};
}
}
}
else {
auto key = sign.certificate.sshKey(); auto key = sign.certificate.sshKey();
key.openKey(QString()); key.openKey(QString());
const Signature signer; const Signature signer;
@ -94,43 +89,59 @@ QPair<Trust, KeeShareSettings::Certificate> check(QByteArray& data,
if (ownCertificate.key == sign.certificate.key) { if (ownCertificate.key == sign.certificate.key) {
return {Own, ownCertificate }; return {Own, ownCertificate };
} }
}
for (const auto& certificate : knownCertificates) { enum Scope { Invalid, Global, Local };
if (certificate.key == certificate.key && certificate.trusted) { Scope scope = Invalid;
return {Known, certificate}; bool trusted = false;
for (const auto& scopedCertificate : knownCertificates) {
if (scopedCertificate.certificate.key == certificate.key && scopedCertificate.path == reference.path) {
// Global scope is overwritten by local scope
scope = Global;
trusted = scopedCertificate.trusted;
}
if (scopedCertificate.certificate.key == certificate.key && scopedCertificate.path == reference.path) {
scope = Local;
trusted = scopedCertificate.trusted;
break;
} }
} }
if (scope != Invalid){
// we introduce now scopes if there is a global
return {trusted ? TrustedForever : UntrustedForever, certificate};
} }
QMessageBox warning; QMessageBox warning;
KeeShareSettings::Certificate certificate;
if (sign.signature.isEmpty()){ if (sign.signature.isEmpty()){
warning.setIcon(QMessageBox::Warning); warning.setIcon(QMessageBox::Warning);
warning.setWindowTitle(ShareObserver::tr("Untrustworthy container without signature")); warning.setWindowTitle(ShareObserver::tr("Import from container without signature"));
warning.setText(ShareObserver::tr("We cannot verify the source of the shared container because it is not signed. Do you really want to import %1?").arg(reference.path)); warning.setText(ShareObserver::tr("We cannot verify the source of the shared container because it is not signed. Do you really want to import from %1?")
certificate = KeeShareSettings::Certificate(); .arg(reference.path));
} }
else { else {
warning.setIcon(QMessageBox::Question); warning.setIcon(QMessageBox::Question);
warning.setWindowTitle(ShareObserver::tr("Import from untrustworthy certificate for sharing container")); warning.setWindowTitle(ShareObserver::tr("Import from container with certificate"));
warning.setText(ShareObserver::tr("Do you want to trust %1 with the fingerprint of %2") warning.setText(ShareObserver::tr("Do you want to trust %1 with the fingerprint of %2 from %3")
.arg(sign.certificate.signer) .arg(certificate.signer, certificate.fingerprint(), reference.path));
.arg(sign.certificate.fingerprint()));
certificate = sign.certificate;
} }
auto once = warning.addButton(ShareObserver::tr("Only this time"), QMessageBox::ButtonRole::YesRole); auto untrustedOnce = warning.addButton(ShareObserver::tr("Not this time"), QMessageBox::ButtonRole::NoRole);
auto always = warning.addButton(ShareObserver::tr("Always"), QMessageBox::ButtonRole::YesRole); auto untrustedForever = warning.addButton(ShareObserver::tr("Never"), QMessageBox::ButtonRole::NoRole);
auto abort = warning.addButton(ShareObserver::tr("No"), QMessageBox::ButtonRole::NoRole); auto trustedForever = warning.addButton(ShareObserver::tr("Always"), QMessageBox::ButtonRole::YesRole);
warning.setDefaultButton(abort); auto trustedOnce = warning.addButton(ShareObserver::tr("Just this time"), QMessageBox::ButtonRole::YesRole);
warning.setDefaultButton(untrustedOnce);
warning.exec(); warning.exec();
if (warning.clickedButton() == once){ if (warning.clickedButton() == trustedForever){
return {Single, certificate}; return {TrustedForever, certificate };
} }
if (warning.clickedButton() == always){ if (warning.clickedButton() == trustedOnce){
return {Lasting, certificate}; return {TrustedOnce, certificate};
} }
qWarning("Prevented import due to untrusted certificate of %s", qPrintable(sign.certificate.signer)); if (warning.clickedButton() == untrustedOnce){
return {None, certificate}; return {UntrustedOnce, certificate };
}
if (warning.clickedButton() == untrustedForever){
return {UntrustedForever, certificate };
}
return {UntrustedOnce, certificate };
} }
} // End Namespace } // End Namespace
@ -287,7 +298,7 @@ ShareObserver::Result ShareObserver::importSecureContainerInto(const KeeShareSet
{ {
#if !defined(WITH_XC_KEESHARE_SECURE) #if !defined(WITH_XC_KEESHARE_SECURE)
Q_UNUSED(targetGroup); Q_UNUSED(targetGroup);
return { reference.path, Result::Error, tr("Secured share container are not supported") }; return { reference.path, Result::Warning, tr("Secured share container are not supported - import prevented") };
#else #else
QuaZip zip(reference.path); QuaZip zip(reference.path);
if (!zip.open(QuaZip::mdUnzip)) { if (!zip.open(QuaZip::mdUnzip)) {
@ -332,34 +343,45 @@ ShareObserver::Result ShareObserver::importSecureContainerInto(const KeeShareSet
auto foreign = KeeShare::foreign(); auto foreign = KeeShare::foreign();
auto own = KeeShare::own(); auto own = KeeShare::own();
auto trusted = check(payload, reference, own.certificate, foreign.certificates, sign); auto trust = check(payload, reference, own.certificate, foreign.certificates, sign);
switch (trusted.first) { switch (trust.first) {
case None:
qWarning("Prevent untrusted import");
return {reference.path, Result::Warning, tr("Untrusted import prevented")};
case Invalid: case Invalid:
qCritical("Prevent untrusted import"); qWarning("Prevent untrusted import");
return {reference.path, Result::Error, tr("Untrusted import prevented")}; return {reference.path, Result::Error, tr("Untrusted import prevented")};
case Known: case UntrustedForever:
case Lasting: { case TrustedForever: {
bool found = false; bool found = false;
for (KeeShareSettings::Certificate& knownCertificate : foreign.certificates) { bool trusted = trust.first == TrustedForever;
if (knownCertificate.key == trusted.second.key) { for (KeeShareSettings::ScopedCertificate& scopedCertificate : foreign.certificates) {
knownCertificate.signer = trusted.second.signer; if (scopedCertificate.certificate.key == trust.second.key && scopedCertificate.path == reference.path) {
knownCertificate.trusted = true; scopedCertificate.certificate.signer = trust.second.signer;
scopedCertificate.path = reference.path;
scopedCertificate.trusted = trusted;
found = true; found = true;
} }
} }
if (!found) { if (!found) {
foreign.certificates << trusted.second; foreign.certificates << KeeShareSettings::ScopedCertificate{ reference.path, trust.second, trusted};
// we need to update with the new signer // we need to update with the new signer
KeeShare::setForeign(foreign); KeeShare::setForeign(foreign);
} }
if (trusted) {
qDebug("Synchronize %s %s with %s",
qPrintable(reference.path),
qPrintable(targetGroup->name()),
qPrintable(sourceDb->rootGroup()->name()));
Merger merger(sourceDb->rootGroup(), targetGroup);
merger.setForcedMergeMode(Group::Synchronize);
const bool changed = merger.merge();
if (changed) {
return {reference.path, Result::Success, tr("Successful secured import")};
} }
[[fallthrough]]; }
case Single: // Silent ignore of untrusted import or unchanging import
return {};
}
case TrustedOnce:
case Own: { case Own: {
qDebug("Synchronize %s %s with %s", qDebug("Synchronize %s %s with %s",
qPrintable(reference.path), qPrintable(reference.path),
@ -384,7 +406,7 @@ ShareObserver::Result ShareObserver::importInsecureContainerInto(const KeeShareS
{ {
#if !defined(WITH_XC_KEESHARE_INSECURE) #if !defined(WITH_XC_KEESHARE_INSECURE)
Q_UNUSED(targetGroup); Q_UNUSED(targetGroup);
return {reference.path, Result::Error, tr("Insecured share container are not supported")}; return {reference.path, Result::Warning, tr("Insecured share container are not supported - import prevented")};
#else #else
QFile file(reference.path); QFile file(reference.path);
if (!file.open(QIODevice::ReadOnly)){ if (!file.open(QIODevice::ReadOnly)){
@ -408,26 +430,41 @@ ShareObserver::Result ShareObserver::importInsecureContainerInto(const KeeShareS
auto foreign = KeeShare::foreign(); auto foreign = KeeShare::foreign();
auto own = KeeShare::own(); auto own = KeeShare::own();
static KeeShareSettings::Sign sign; // invalid sign static KeeShareSettings::Sign sign; // invalid sign
auto trusted = check(payload, reference, own.certificate, foreign.certificates, sign); auto trust = check(payload, reference, own.certificate, foreign.certificates, sign);
switch(trusted.first) { switch(trust.first) {
case Known: case UntrustedForever:
case Lasting: { case TrustedForever: {
bool found = false; bool found = false;
for (KeeShareSettings::Certificate& knownCertificate : foreign.certificates) { bool trusted = trust.first == TrustedForever;
if (knownCertificate.key == trusted.second.key) { for (KeeShareSettings::ScopedCertificate& scopedCertificate : foreign.certificates) {
knownCertificate.signer = trusted.second.signer; if (scopedCertificate.certificate.key == trust.second.key && scopedCertificate.path == reference.path) {
knownCertificate.trusted = true; scopedCertificate.certificate.signer = trust.second.signer;
scopedCertificate.path = reference.path;
scopedCertificate.trusted = trusted;
found = true; found = true;
} }
} }
if (!found) { if (!found) {
foreign.certificates << trusted.second; foreign.certificates << KeeShareSettings::ScopedCertificate{ reference.path, trust.second, trusted};
// we need to update with the new signer // we need to update with the new signer
KeeShare::setForeign(foreign); KeeShare::setForeign(foreign);
} }
if (trusted) {
qDebug("Synchronize %s %s with %s",
qPrintable(reference.path),
qPrintable(targetGroup->name()),
qPrintable(sourceDb->rootGroup()->name()));
Merger merger(sourceDb->rootGroup(), targetGroup);
merger.setForcedMergeMode(Group::Synchronize);
const bool changed = merger.merge();
if (changed) {
return {reference.path, Result::Success, tr("Successful secured import")};
} }
[[fallthrough]]; }
case Single: { return {};
}
case TrustedOnce: {
qDebug("Synchronize %s %s with %s", qDebug("Synchronize %s %s with %s",
qPrintable(reference.path), qPrintable(reference.path),
qPrintable(targetGroup->name()), qPrintable(targetGroup->name()),
@ -571,7 +608,7 @@ ShareObserver::Result ShareObserver::exportIntoReferenceSecureContainer(const Ke
{ {
#if !defined(WITH_XC_KEESHARE_SECURE) #if !defined(WITH_XC_KEESHARE_SECURE)
Q_UNUSED(targetDb); Q_UNUSED(targetDb);
return {reference.path, Result::Error, tr("Overwriting secured share container is not supported")}; return {reference.path, Result::Warning, tr("Overwriting secured share container is not supported - export prevented")};
#else #else
QByteArray bytes; QByteArray bytes;
{ {
@ -637,7 +674,7 @@ ShareObserver::Result ShareObserver::exportIntoReferenceInsecureContainer(const
{ {
#if !defined(WITH_XC_KEESHARE_INSECURE) #if !defined(WITH_XC_KEESHARE_INSECURE)
Q_UNUSED(targetDb); Q_UNUSED(targetDb);
return {reference.path, Result::Error, tr("Overwriting secured share container is not supported")}; return {reference.path, Result::Warning, tr("Overwriting secured share container is not supported - export prevented")};
#else #else
QFile file(reference.path); QFile file(reference.path);
const bool fileOpened = file.open(QIODevice::WriteOnly); const bool fileOpened = file.open(QIODevice::WriteOnly);

View file

@ -49,8 +49,8 @@ EditGroupWidgetKeeShare::EditGroupWidgetKeeShare(QWidget* parent)
connect(m_ui->togglePasswordGeneratorButton, SIGNAL(toggled(bool)), SLOT(togglePasswordGeneratorButton(bool))); connect(m_ui->togglePasswordGeneratorButton, SIGNAL(toggled(bool)), SLOT(togglePasswordGeneratorButton(bool)));
connect(m_ui->passwordEdit, SIGNAL(textChanged(QString)), SLOT(selectPassword())); connect(m_ui->passwordEdit, SIGNAL(textChanged(QString)), SLOT(selectPassword()));
connect(m_ui->passwordGenerator, SIGNAL(appliedPassword(QString)), SLOT(setGeneratedPassword(QString))); connect(m_ui->passwordGenerator, SIGNAL(appliedPassword(QString)), SLOT(setGeneratedPassword(QString)));
connect(m_ui->pathEdit, SIGNAL(textChanged(QString)), SLOT(setPath(QString))); connect(m_ui->pathEdit, SIGNAL(editingFinished()), SLOT(selectPath()));
connect(m_ui->pathSelectionButton, SIGNAL(pressed()), SLOT(selectPath())); connect(m_ui->pathSelectionButton, SIGNAL(pressed()), SLOT(launchPathSelectionDialog()));
connect(m_ui->typeComboBox, SIGNAL(currentIndexChanged(int)), SLOT(selectType())); connect(m_ui->typeComboBox, SIGNAL(currentIndexChanged(int)), SLOT(selectType()));
connect(KeeShare::instance(), SIGNAL(activeChanged()), SLOT(showSharingState())); connect(KeeShare::instance(), SIGNAL(activeChanged()), SLOT(showSharingState()));
@ -102,15 +102,40 @@ void EditGroupWidgetKeeShare::showSharingState()
if (!m_temporaryGroup) { if (!m_temporaryGroup) {
return; return;
} }
auto supportedExtensions = QStringList();
#if defined(WITH_XC_KEESHARE_INSECURE)
supportedExtensions << KeeShare::insecureContainerFileType();
#endif
#if defined(WITH_XC_KEESHARE_SECURE)
supportedExtensions << KeeShare::secureContainerFileType();
#endif
const auto reference = KeeShare::referenceOf(m_temporaryGroup);
if (!reference.path.isEmpty()) {
bool supported = false;
for(const auto &extension : supportedExtensions){
if (reference.path.endsWith(extension, Qt::CaseInsensitive)){
supported = true;
break;
}
}
if (!supported) {
m_ui->messageWidget->showMessage(tr("Your KeePassXC version does not support sharing your container type. Please use %1.").arg(supportedExtensions.join(", ")), MessageWidget::Warning);
return;
}
}
const auto active = KeeShare::active(); const auto active = KeeShare::active();
if (!active.in && !active.out) { if (!active.in && !active.out) {
m_ui->messageWidget->showMessage(tr("Database sharing is disabled"), MessageWidget::Information); m_ui->messageWidget->showMessage(tr("Database sharing is disabled"), MessageWidget::Information);
return;
} }
if (active.in && !active.out) { if (active.in && !active.out) {
m_ui->messageWidget->showMessage(tr("Database export is disabled"), MessageWidget::Information); m_ui->messageWidget->showMessage(tr("Database export is disabled"), MessageWidget::Information);
return;
} }
if (!active.in && active.out) { if (!active.in && active.out) {
m_ui->messageWidget->showMessage(tr("Database import is disabled"), MessageWidget::Information); m_ui->messageWidget->showMessage(tr("Database import is disabled"), MessageWidget::Information);
return;
} }
} }
@ -149,17 +174,17 @@ void EditGroupWidgetKeeShare::setGeneratedPassword(const QString& password)
m_ui->togglePasswordGeneratorButton->setChecked(false); m_ui->togglePasswordGeneratorButton->setChecked(false);
} }
void EditGroupWidgetKeeShare::setPath(const QString& path) void EditGroupWidgetKeeShare::selectPath()
{ {
if (!m_temporaryGroup) { if (!m_temporaryGroup) {
return; return;
} }
auto reference = KeeShare::referenceOf(m_temporaryGroup); auto reference = KeeShare::referenceOf(m_temporaryGroup);
reference.path = path; reference.path = m_ui->pathEdit->text();
KeeShare::setReferenceTo(m_temporaryGroup, reference); KeeShare::setReferenceTo(m_temporaryGroup, reference);
} }
void EditGroupWidgetKeeShare::selectPath() void EditGroupWidgetKeeShare::launchPathSelectionDialog()
{ {
if (!m_temporaryGroup) { if (!m_temporaryGroup) {
return; return;
@ -171,20 +196,28 @@ void EditGroupWidgetKeeShare::selectPath()
} }
auto reference = KeeShare::referenceOf(m_temporaryGroup); auto reference = KeeShare::referenceOf(m_temporaryGroup);
QString defaultFiletype = ""; QString defaultFiletype = "";
auto supportedExtensions = QStringList();
auto unsupportedExtensions = QStringList();
auto knownFilters = QStringList() << QString("%1 (*)").arg("All files"); auto knownFilters = QStringList() << QString("%1 (*)").arg("All files");
#if defined(WITH_XC_KEESHARE_INSECURE) #if defined(WITH_XC_KEESHARE_INSECURE)
defaultFiletype = KeeShare::secureContainerFileType(); defaultFiletype = KeeShare::insecureContainerFileType();
supportedExtensions << KeeShare::insecureContainerFileType();
knownFilters.prepend(QString("%1 (*.%2)").arg(tr("KeeShare insecure container"), KeeShare::insecureContainerFileType())); knownFilters.prepend(QString("%1 (*.%2)").arg(tr("KeeShare insecure container"), KeeShare::insecureContainerFileType()));
#else
unsupportedExtensions << KeeShare::insecureContainerFileType();
#endif #endif
#if defined(WITH_XC_KEESHARE_SECURE) #if defined(WITH_XC_KEESHARE_SECURE)
defaultFiletype = KeeShare::secureContainerFileType(); defaultFiletype = KeeShare::secureContainerFileType();
supportedExtensions << KeeShare::secureContainerFileType();
knownFilters.prepend(QString("%1 (*.%2)").arg(tr("KeeShare secure container"), KeeShare::secureContainerFileType())); knownFilters.prepend(QString("%1 (*.%2)").arg(tr("KeeShare secure container"), KeeShare::secureContainerFileType()));
#else
unsupportedExtensions << KeeShare::secureContainerFileType();
#endif #endif
const auto filters = knownFilters.join(";;"); const auto filters = knownFilters.join(";;");
auto filename = reference.path; auto filename = reference.path;
if (filename.isEmpty()) { if (filename.isEmpty()) {
filename = tr("%1.%2", "Template for KeeShare container").arg(m_temporaryGroup->name()).arg(defaultFiletype); filename = m_temporaryGroup->name();
} }
switch (reference.type) { switch (reference.type) {
case KeeShareSettings::ImportFrom: case KeeShareSettings::ImportFrom:
@ -206,6 +239,16 @@ void EditGroupWidgetKeeShare::selectPath()
if (filename.isEmpty()) { if (filename.isEmpty()) {
return; return;
} }
bool validFilename = false;
for(const auto& extension : supportedExtensions + unsupportedExtensions){
if (filename.endsWith(extension, Qt::CaseInsensitive)) {
validFilename = true;
break;
}
}
if (!validFilename){
filename += (!filename.endsWith(".") ? "." : "") + defaultFiletype;
}
m_ui->pathEdit->setText(filename); m_ui->pathEdit->setText(filename);
config()->set("KeeShare/LastShareDir", QFileInfo(filename).absolutePath()); config()->set("KeeShare/LastShareDir", QFileInfo(filename).absolutePath());

View file

@ -46,8 +46,8 @@ private slots:
void update(); void update();
void selectType(); void selectType();
void selectPassword(); void selectPassword();
void launchPathSelectionDialog();
void selectPath(); void selectPath();
void setPath(const QString& path);
void setGeneratedPassword(const QString& password); void setGeneratedPassword(const QString& password);
void togglePasswordGeneratorButton(bool checked); void togglePasswordGeneratorButton(bool checked);

View file

@ -41,7 +41,8 @@ QTEST_GUILESS_MAIN(TestSharing)
Q_DECLARE_METATYPE(KeeShareSettings::Type) Q_DECLARE_METATYPE(KeeShareSettings::Type)
Q_DECLARE_METATYPE(KeeShareSettings::Key) Q_DECLARE_METATYPE(KeeShareSettings::Key)
Q_DECLARE_METATYPE(KeeShareSettings::Certificate) Q_DECLARE_METATYPE(KeeShareSettings::Certificate)
Q_DECLARE_METATYPE(QList<KeeShareSettings::Certificate>) Q_DECLARE_METATYPE(KeeShareSettings::ScopedCertificate)
Q_DECLARE_METATYPE(QList<KeeShareSettings::ScopedCertificate>)
void TestSharing::initTestCase() void TestSharing::initTestCase()
{ {
@ -127,9 +128,9 @@ void TestSharing::testNullObjects()
QVERIFY(xmlActive.isNull()); QVERIFY(xmlActive.isNull());
const KeeShareSettings::Foreign foreign; const KeeShareSettings::Foreign foreign;
QVERIFY(foreign.isNull()); QVERIFY(foreign.certificates.isEmpty());
const KeeShareSettings::Foreign xmlForeign = KeeShareSettings::Foreign::deserialize(empty); const KeeShareSettings::Foreign xmlForeign = KeeShareSettings::Foreign::deserialize(empty);
QVERIFY(xmlForeign.isNull()); QVERIFY(xmlForeign.certificates.isEmpty());
const KeeShareSettings::Reference reference; const KeeShareSettings::Reference reference;
QVERIFY(reference.isNull()); QVERIFY(reference.isNull());
@ -141,28 +142,33 @@ void TestSharing::testCertificateSerialization()
{ {
QFETCH(bool, trusted); QFETCH(bool, trusted);
const OpenSSHKey& key = stubkey(); const OpenSSHKey& key = stubkey();
KeeShareSettings::Certificate original; KeeShareSettings::ScopedCertificate original;
original.key = OpenSSHKey::serializeToBinary(OpenSSHKey::Public, key); original.path = "/path";
original.signer = "Some <!> &#_\"\" weird string"; original.certificate = KeeShareSettings::Certificate
{
OpenSSHKey::serializeToBinary(OpenSSHKey::Public, key),
"Some <!> &#_\"\" weird string"
};
original.trusted = trusted; original.trusted = trusted;
QString buffer; QString buffer;
QXmlStreamWriter writer(&buffer); QXmlStreamWriter writer(&buffer);
writer.writeStartDocument(); writer.writeStartDocument();
writer.writeStartElement("Certificate"); writer.writeStartElement("Certificate");
KeeShareSettings::Certificate::serialize(writer, original); KeeShareSettings::ScopedCertificate::serialize(writer, original);
writer.writeEndElement(); writer.writeEndElement();
writer.writeEndDocument(); writer.writeEndDocument();
QXmlStreamReader reader(buffer); QXmlStreamReader reader(buffer);
reader.readNextStartElement(); reader.readNextStartElement();
QVERIFY(reader.name() == "Certificate"); QVERIFY(reader.name() == "Certificate");
KeeShareSettings::Certificate restored = KeeShareSettings::Certificate::deserialize(reader); KeeShareSettings::ScopedCertificate restored = KeeShareSettings::ScopedCertificate::deserialize(reader);
QCOMPARE(restored.key, original.key); QCOMPARE(restored.certificate.key, original.certificate.key);
QCOMPARE(restored.signer, original.signer); QCOMPARE(restored.certificate.signer, original.certificate.signer);
QCOMPARE(restored.trusted, original.trusted); QCOMPARE(restored.trusted, original.trusted);
QCOMPARE(restored.path, original.path);
QCOMPARE(restored.sshKey().publicParts(), key.publicParts()); QCOMPARE(restored.certificate.sshKey().publicParts(), key.publicParts());
} }
void TestSharing::testCertificateSerialization_data() void TestSharing::testCertificateSerialization_data()
@ -234,7 +240,7 @@ void TestSharing::testSettingsSerialization()
QFETCH(bool, exporting); QFETCH(bool, exporting);
QFETCH(KeeShareSettings::Certificate, ownCertificate); QFETCH(KeeShareSettings::Certificate, ownCertificate);
QFETCH(KeeShareSettings::Key, ownKey); QFETCH(KeeShareSettings::Key, ownKey);
QFETCH(QList<KeeShareSettings::Certificate>, foreignCertificates); QFETCH(QList<KeeShareSettings::ScopedCertificate>, foreignCertificates);
KeeShareSettings::Own originalOwn; KeeShareSettings::Own originalOwn;
KeeShareSettings::Foreign originalForeign; KeeShareSettings::Foreign originalForeign;
@ -257,41 +263,48 @@ void TestSharing::testSettingsSerialization()
QCOMPARE(restoredActive.in, importing); QCOMPARE(restoredActive.in, importing);
QCOMPARE(restoredActive.out, exporting); QCOMPARE(restoredActive.out, exporting);
QCOMPARE(restoredOwn.certificate.key, ownCertificate.key); QCOMPARE(restoredOwn.certificate.key, ownCertificate.key);
QCOMPARE(restoredOwn.certificate.trusted, ownCertificate.trusted);
QCOMPARE(restoredOwn.key.key, ownKey.key); QCOMPARE(restoredOwn.key.key, ownKey.key);
QCOMPARE(restoredForeign.certificates.count(), foreignCertificates.count()); QCOMPARE(restoredForeign.certificates.count(), foreignCertificates.count());
for (int i = 0; i < foreignCertificates.count(); ++i) { for (int i = 0; i < foreignCertificates.count(); ++i) {
QCOMPARE(restoredForeign.certificates[i].key, foreignCertificates[i].key); QCOMPARE(restoredForeign.certificates[i].certificate.key, foreignCertificates[i].certificate.key);
} }
} }
void TestSharing::testSettingsSerialization_data() void TestSharing::testSettingsSerialization_data()
{ {
const OpenSSHKey& sshKey0 = stubkey(0); const OpenSSHKey& sshKey0 = stubkey(0);
KeeShareSettings::Certificate certificate0; KeeShareSettings::ScopedCertificate certificate0;
certificate0.key = OpenSSHKey::serializeToBinary(OpenSSHKey::Public, sshKey0); certificate0.path = "/path/0";
certificate0.signer = "Some <!> &#_\"\" weird string"; certificate0.certificate = KeeShareSettings::Certificate
{
OpenSSHKey::serializeToBinary(OpenSSHKey::Public, sshKey0),
"Some <!> &#_\"\" weird string"
};
certificate0.trusted = true; certificate0.trusted = true;
KeeShareSettings::Key key0; KeeShareSettings::Key key0;
key0.key = OpenSSHKey::serializeToBinary(OpenSSHKey::Private, sshKey0); key0.key = OpenSSHKey::serializeToBinary(OpenSSHKey::Private, sshKey0);
const OpenSSHKey& sshKey1 = stubkey(1); const OpenSSHKey& sshKey1 = stubkey(1);
KeeShareSettings::Certificate certificate1; KeeShareSettings::ScopedCertificate certificate1;
certificate1.key = OpenSSHKey::serializeToBinary(OpenSSHKey::Public, sshKey1); certificate1.path = "/path/1";
certificate1.signer = "Another "; certificate1.certificate = KeeShareSettings::Certificate
certificate1.trusted = true; {
OpenSSHKey::serializeToBinary(OpenSSHKey::Public, sshKey1),
"Another "
};
certificate1.trusted = false;
QTest::addColumn<bool>("importing"); QTest::addColumn<bool>("importing");
QTest::addColumn<bool>("exporting"); QTest::addColumn<bool>("exporting");
QTest::addColumn<KeeShareSettings::Certificate>("ownCertificate"); QTest::addColumn<KeeShareSettings::Certificate>("ownCertificate");
QTest::addColumn<KeeShareSettings::Key>("ownKey"); QTest::addColumn<KeeShareSettings::Key>("ownKey");
QTest::addColumn<QList<KeeShareSettings::Certificate>>("foreignCertificates"); QTest::addColumn<QList<KeeShareSettings::Certificate>>("foreignCertificates");
QTest::newRow("1") << false << false << KeeShareSettings::Certificate() << KeeShareSettings::Key() << QList<KeeShareSettings::Certificate>(); QTest::newRow("1") << false << false << KeeShareSettings::Certificate() << KeeShareSettings::Key() << QList<KeeShareSettings::ScopedCertificate>();
QTest::newRow("2") << true << false << KeeShareSettings::Certificate() << KeeShareSettings::Key() << QList<KeeShareSettings::Certificate>(); QTest::newRow("2") << true << false << KeeShareSettings::Certificate() << KeeShareSettings::Key() << QList<KeeShareSettings::ScopedCertificate>();
QTest::newRow("3") << true << true << KeeShareSettings::Certificate() << KeeShareSettings::Key() << QList<KeeShareSettings::Certificate>({ certificate0, certificate1 }); QTest::newRow("3") << true << true << KeeShareSettings::Certificate() << KeeShareSettings::Key() << QList<KeeShareSettings::ScopedCertificate>({ certificate0, certificate1 });
QTest::newRow("4") << false << true << certificate0 << key0 << QList<KeeShareSettings::Certificate>(); QTest::newRow("4") << false << true << certificate0 << key0 << QList<KeeShareSettings::ScopedCertificate>();
QTest::newRow("5") << false << false << certificate0 << key0 << QList<KeeShareSettings::Certificate>({ certificate1 }); QTest::newRow("5") << false << false << certificate0 << key0 << QList<KeeShareSettings::ScopedCertificate>({ certificate1 });
} }
const OpenSSHKey& TestSharing::stubkey(int index) const OpenSSHKey& TestSharing::stubkey(int index)