2018-10-01 10:26:24 -04:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2018 KeePassXC Team <team@keepassxc.org>
|
|
|
|
*
|
|
|
|
* 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 "KeeShare.h"
|
|
|
|
#include "core/Config.h"
|
|
|
|
#include "core/CustomData.h"
|
|
|
|
#include "core/Database.h"
|
|
|
|
#include "core/DatabaseIcons.h"
|
|
|
|
#include "core/Group.h"
|
|
|
|
#include "core/Metadata.h"
|
|
|
|
#include "crypto/ssh/OpenSSHKey.h"
|
|
|
|
#include "keeshare/ShareObserver.h"
|
|
|
|
#include "keeshare/Signature.h"
|
|
|
|
|
|
|
|
#include <QMessageBox>
|
|
|
|
#include <QPainter>
|
|
|
|
#include <QPushButton>
|
|
|
|
|
|
|
|
namespace
|
|
|
|
{
|
2019-01-18 21:53:02 -05:00
|
|
|
static const QString KeeShare_Reference("KeeShare/Reference");
|
|
|
|
static const QString KeeShare_Own("KeeShare/Settings.own");
|
|
|
|
static const QString KeeShare_Foreign("KeeShare/Settings.foreign");
|
|
|
|
static const QString KeeShare_Active("KeeShare/Settings.active");
|
|
|
|
} // namespace
|
2018-10-01 10:26:24 -04:00
|
|
|
|
|
|
|
KeeShare* KeeShare::m_instance = nullptr;
|
|
|
|
|
|
|
|
KeeShare* KeeShare::instance()
|
|
|
|
{
|
|
|
|
if (!m_instance) {
|
|
|
|
qFatal("Race condition: instance wanted before it was initialized, this is a bug.");
|
|
|
|
}
|
|
|
|
|
|
|
|
return m_instance;
|
|
|
|
}
|
|
|
|
|
2018-12-19 17:52:12 -05:00
|
|
|
KeeShare::KeeShare(QObject* parent)
|
|
|
|
: QObject(parent)
|
|
|
|
{
|
|
|
|
connect(config(), SIGNAL(changed(QString)), SLOT(handleSettingsChanged(QString)));
|
|
|
|
}
|
|
|
|
|
2018-10-01 10:26:24 -04:00
|
|
|
void KeeShare::init(QObject* parent)
|
|
|
|
{
|
|
|
|
Q_ASSERT(!m_instance);
|
|
|
|
m_instance = new KeeShare(parent);
|
|
|
|
}
|
|
|
|
|
|
|
|
KeeShareSettings::Own KeeShare::own()
|
|
|
|
{
|
|
|
|
return KeeShareSettings::Own::deserialize(config()->get(KeeShare_Own).toString());
|
|
|
|
}
|
|
|
|
|
|
|
|
KeeShareSettings::Active KeeShare::active()
|
|
|
|
{
|
|
|
|
return KeeShareSettings::Active::deserialize(config()->get(KeeShare_Active).toString());
|
|
|
|
}
|
|
|
|
|
|
|
|
KeeShareSettings::Foreign KeeShare::foreign()
|
|
|
|
{
|
|
|
|
return KeeShareSettings::Foreign::deserialize(config()->get(KeeShare_Foreign).toString());
|
|
|
|
}
|
|
|
|
|
|
|
|
void KeeShare::setForeign(const KeeShareSettings::Foreign& foreign)
|
|
|
|
{
|
|
|
|
config()->set(KeeShare_Foreign, KeeShareSettings::Foreign::serialize(foreign));
|
|
|
|
}
|
|
|
|
|
|
|
|
void KeeShare::setActive(const KeeShareSettings::Active& active)
|
|
|
|
{
|
|
|
|
config()->set(KeeShare_Active, KeeShareSettings::Active::serialize(active));
|
|
|
|
}
|
|
|
|
|
|
|
|
void KeeShare::setOwn(const KeeShareSettings::Own& own)
|
|
|
|
{
|
|
|
|
config()->set(KeeShare_Own, KeeShareSettings::Own::serialize(own));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KeeShare::isShared(const Group* group)
|
|
|
|
{
|
|
|
|
return group->customData()->contains(KeeShare_Reference);
|
|
|
|
}
|
|
|
|
|
|
|
|
KeeShareSettings::Reference KeeShare::referenceOf(const Group* group)
|
|
|
|
{
|
|
|
|
static const KeeShareSettings::Reference s_emptyReference;
|
|
|
|
const CustomData* customData = group->customData();
|
|
|
|
if (!customData->contains(KeeShare_Reference)) {
|
|
|
|
return s_emptyReference;
|
|
|
|
}
|
|
|
|
const auto encoded = customData->value(KeeShare_Reference);
|
|
|
|
const auto serialized = QString::fromUtf8(QByteArray::fromBase64(encoded.toLatin1()));
|
|
|
|
KeeShareSettings::Reference reference = KeeShareSettings::Reference::deserialize(serialized);
|
|
|
|
if (reference.isNull()) {
|
|
|
|
qWarning("Invalid sharing reference detected - sharing disabled");
|
|
|
|
return s_emptyReference;
|
|
|
|
}
|
|
|
|
return reference;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KeeShare::setReferenceTo(Group* group, const KeeShareSettings::Reference& reference)
|
|
|
|
{
|
|
|
|
CustomData* customData = group->customData();
|
|
|
|
if (reference.isNull()) {
|
|
|
|
customData->remove(KeeShare_Reference);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const auto serialized = KeeShareSettings::Reference::serialize(reference);
|
|
|
|
const auto encoded = serialized.toUtf8().toBase64();
|
|
|
|
customData->set(KeeShare_Reference, encoded);
|
|
|
|
}
|
|
|
|
|
2019-01-03 17:50:36 +01:00
|
|
|
bool KeeShare::isEnabled(const Group* group)
|
|
|
|
{
|
|
|
|
const auto reference = KeeShare::referenceOf(group);
|
|
|
|
#if !defined(WITH_XC_KEESHARE_SECURE)
|
2019-01-18 21:53:02 -05:00
|
|
|
if (reference.path.endsWith(signedContainerFileType(), Qt::CaseInsensitive)) {
|
|
|
|
return false;
|
2019-01-03 17:50:36 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if !defined(WITH_XC_KEESHARE_INSECURE)
|
2019-01-18 21:53:02 -05:00
|
|
|
if (reference.path.endsWith(unsignedContainerFileType(), Qt::CaseInsensitive)) {
|
|
|
|
return false;
|
2019-01-03 17:50:36 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
const auto active = KeeShare::active();
|
|
|
|
return (reference.isImporting() && active.in) || (reference.isExporting() && active.out);
|
|
|
|
}
|
|
|
|
|
2018-10-01 10:26:24 -04:00
|
|
|
QPixmap KeeShare::indicatorBadge(const Group* group, QPixmap pixmap)
|
|
|
|
{
|
|
|
|
if (!isShared(group)) {
|
|
|
|
return pixmap;
|
|
|
|
}
|
2019-01-03 17:50:36 +01:00
|
|
|
const QPixmap badge = isEnabled(group) ? databaseIcons()->iconPixmap(DatabaseIcons::SharedIconIndex)
|
|
|
|
: databaseIcons()->iconPixmap(DatabaseIcons::UnsharedIconIndex);
|
2018-10-01 10:26:24 -04:00
|
|
|
QImage canvas = pixmap.toImage();
|
|
|
|
const QRectF target(canvas.width() * 0.4, canvas.height() * 0.4, canvas.width() * 0.6, canvas.height() * 0.6);
|
|
|
|
QPainter painter(&canvas);
|
|
|
|
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
|
|
|
painter.drawPixmap(target, badge, badge.rect());
|
|
|
|
pixmap.convertFromImage(canvas);
|
|
|
|
return pixmap;
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KeeShare::referenceTypeLabel(const KeeShareSettings::Reference& reference)
|
|
|
|
{
|
|
|
|
switch (reference.type) {
|
|
|
|
case KeeShareSettings::Inactive:
|
|
|
|
return tr("Disabled share");
|
|
|
|
case KeeShareSettings::ImportFrom:
|
|
|
|
return tr("Import from");
|
|
|
|
case KeeShareSettings::ExportTo:
|
|
|
|
return tr("Export to");
|
|
|
|
case KeeShareSettings::SynchronizeWith:
|
|
|
|
return tr("Synchronize with");
|
|
|
|
}
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
|
|
|
QString KeeShare::indicatorSuffix(const Group* group, const QString& text)
|
|
|
|
{
|
|
|
|
// we not adjust the display name for now - it's just an alternative to the icon
|
|
|
|
Q_UNUSED(group);
|
|
|
|
return text;
|
|
|
|
}
|
|
|
|
|
2018-12-18 22:28:56 -05:00
|
|
|
void KeeShare::connectDatabase(QSharedPointer<Database> newDb, QSharedPointer<Database> oldDb)
|
2018-10-01 10:26:24 -04:00
|
|
|
{
|
2018-12-19 17:52:12 -05:00
|
|
|
if (oldDb && m_observersByDatabase.contains(oldDb->uuid())) {
|
|
|
|
QPointer<ShareObserver> observer = m_observersByDatabase.take(oldDb->uuid());
|
2018-10-01 10:26:24 -04:00
|
|
|
if (observer) {
|
|
|
|
delete observer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-19 17:52:12 -05:00
|
|
|
if (newDb && !m_observersByDatabase.contains(newDb->uuid())) {
|
2018-12-18 22:28:56 -05:00
|
|
|
QPointer<ShareObserver> observer(new ShareObserver(newDb, this));
|
2018-12-19 17:52:12 -05:00
|
|
|
m_observersByDatabase[newDb->uuid()] = observer;
|
2018-10-01 10:26:24 -04:00
|
|
|
connect(observer.data(),
|
|
|
|
SIGNAL(sharingMessage(QString, MessageWidget::MessageType)),
|
2018-12-19 17:52:12 -05:00
|
|
|
SIGNAL(sharingMessage(QString, MessageWidget::MessageType)));
|
2018-10-01 10:26:24 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-18 21:53:02 -05:00
|
|
|
const QString& KeeShare::signedContainerFileType()
|
2019-01-03 08:46:32 +01:00
|
|
|
{
|
|
|
|
static const QString filetype("kdbx.share");
|
|
|
|
return filetype;
|
|
|
|
}
|
|
|
|
|
2019-01-18 21:53:02 -05:00
|
|
|
const QString& KeeShare::unsignedContainerFileType()
|
2019-01-03 08:46:32 +01:00
|
|
|
{
|
|
|
|
static const QString filetype("kdbx");
|
|
|
|
return filetype;
|
|
|
|
}
|
|
|
|
|
2018-10-01 10:26:24 -04:00
|
|
|
void KeeShare::handleSettingsChanged(const QString& key)
|
|
|
|
{
|
|
|
|
if (key == KeeShare_Active) {
|
|
|
|
emit activeChanged();
|
|
|
|
}
|
|
|
|
}
|