From 16f9af908ab36dee98adc7b5bb7fe75aefe0e29f Mon Sep 17 00:00:00 2001 From: Albert Vaca Date: Mon, 30 Nov 2015 10:36:01 -0800 Subject: [PATCH] WIP --- cli/kdeconnect-cli.cpp | 20 +-- core/backends/devicelink.h | 3 +- core/backends/lan/downloadjob.cpp | 30 ++--- core/backends/lan/landevicelink.cpp | 4 +- core/backends/lan/lanlinkprovider.cpp | 17 ++- core/backends/lan/lanlinkprovider.h | 3 +- core/backends/lan/lanpairinghandler.cpp | 122 ++++++++---------- core/backends/lan/lanpairinghandler.h | 12 +- core/backends/lan/uploadjob.cpp | 20 ++- core/backends/lan/uploadjob.h | 4 +- core/backends/loopback/loopbackdevicelink.cpp | 2 +- .../loopback/loopbackpairinghandler.cpp | 36 ++---- .../loopback/loopbackpairinghandler.h | 5 +- core/backends/pairinghandler.cpp | 17 ++- core/backends/pairinghandler.h | 29 +++-- core/daemon.cpp | 12 +- core/daemon.h | 3 - core/device.cpp | 115 +++++++---------- core/device.h | 32 +---- core/kdeconnectconfig.cpp | 7 +- core/kdeconnectconfig.h | 14 +- kcm/kcm.cpp | 2 +- 22 files changed, 212 insertions(+), 297 deletions(-) diff --git a/cli/kdeconnect-cli.cpp b/cli/kdeconnect-cli.cpp index a6387595a..69856cb6a 100644 --- a/cli/kdeconnect-cli.cpp +++ b/cli/kdeconnect-cli.cpp @@ -184,25 +184,9 @@ int main(int argc, char** argv) } } else if(parser.isSet("encryption-info")) { DeviceDbusInterface dev(device); - QDBusPendingReply devReply = dev.certificate(1); // QSsl::Der = 1 + QDBusPendingReply devReply = dev.encryptionInfo(); // QSsl::Der = 1 devReply.waitForFinished(); - if (devReply.value().isEmpty()) { - QTextStream(stderr) << i18n("The other device doesn\'t use a recent version of KDE Connect, using the legacy encryption method.") << endl; - } else { - QByteArray remoteCertificate = QCryptographicHash::hash(devReply.value(), QCryptographicHash::Sha1).toHex(); - for (int i=2 ; i ifaceReply = iface.certificate(1); // QSsl::Der = 1 - ifaceReply.waitForFinished(); - QByteArray myCertificate = QCryptographicHash::hash(ifaceReply.value(), QCryptographicHash::Sha1).toHex(); - for (int i=2 ; i #include "core/networkpackage.h" -#include "pairinghandler.h" +class PairingHandler; class NetworkPackage; class LinkProvider; +class Device; class DeviceLink : public QObject diff --git a/core/backends/lan/downloadjob.cpp b/core/backends/lan/downloadjob.cpp index fd1010355..9b8bd21cc 100644 --- a/core/backends/lan/downloadjob.cpp +++ b/core/backends/lan/downloadjob.cpp @@ -35,18 +35,15 @@ DownloadJob::DownloadJob(const QHostAddress &address, const QVariantMap &transfe mAddress = address; mPort = transferInfo["port"].toInt(); mSocket = QSharedPointer(new QSslSocket); - useSsl = transferInfo.value("useSsl", false).toBool(); // Setting ssl related properties for socket when using ssl - if (useSsl) { - mSocket->setLocalCertificate(KdeConnectConfig::instance()->certificate()); - mSocket->setPrivateKey(KdeConnectConfig::instance()->privateKeyPath()); - mSocket->setProtocol(QSsl::TlsV1_2); - mSocket->setPeerVerifyName(transferInfo.value("deviceId").toString()); - mSocket->setPeerVerifyMode(QSslSocket::VerifyPeer); - mSocket->addCaCertificate(QSslCertificate(KdeConnectConfig::instance()->getTrustedDevice( - transferInfo.value("deviceId").toString()).certificate.toLatin1())); - } + mSocket->setLocalCertificate(KdeConnectConfig::instance()->certificate()); + mSocket->setPrivateKey(KdeConnectConfig::instance()->privateKeyPath()); + mSocket->setProtocol(QSsl::TlsV1_2); + mSocket->setPeerVerifyName(transferInfo.value("deviceId").toString()); + mSocket->setPeerVerifyMode(QSslSocket::VerifyPeer); + mSocket->addCaCertificate(QSslCertificate(KdeConnectConfig::instance()->getDeviceProperty(transferInfo.value("deviceId").toString(),"certificate").toLatin1())); + } DownloadJob::~DownloadJob() @@ -61,14 +58,11 @@ void DownloadJob::start() connect(mSocket.data(), SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(done())); //connect(mSocket.data(), &QAbstractSocket::connected, [=](){ qDebug() << "Connected"; }); - if (useSsl) { - // Cannot use read only, might be due to ssl handshake, getting QIODevice::ReadOnly error and no connection - mSocket->connectToHostEncrypted(mAddress.toString(), mPort, QIODevice::ReadWrite); - mSocket->waitForEncrypted(); - } else { - mSocket->connectToHost(mAddress, mPort, QIODevice::ReadOnly); - mSocket->waitForConnected(); - } + // Cannot use read only, might be due to ssl handshake, getting QIODevice::ReadOnly error and no connection + mSocket->connectToHostEncrypted(mAddress.toString(), mPort, QIODevice::ReadWrite); + mSocket->waitForEncrypted(); +// mSocket->connectToHost(mAddress, mPort, QIODevice::ReadOnly); +// mSocket->waitForConnected(); //mSocket->open(QIODevice::ReadOnly); diff --git a/core/backends/lan/landevicelink.cpp b/core/backends/lan/landevicelink.cpp index 98d67bfb6..f2f6dc5d9 100644 --- a/core/backends/lan/landevicelink.cpp +++ b/core/backends/lan/landevicelink.cpp @@ -57,7 +57,7 @@ void LanDeviceLink::setOnSsl(bool value) PairingHandler* LanDeviceLink::createPairingHandler(Device* device) { - return new LanPairingHandler(device); + return new LanPairingHandler(device->id()); } bool LanDeviceLink::sendPackageEncrypted(QCA::PublicKey& key, NetworkPackage& np) @@ -95,7 +95,7 @@ UploadJob* LanDeviceLink::sendPayload(NetworkPackage& np) transferInfo.insert("useSsl", true); transferInfo.insert("deviceId", deviceId()); } - UploadJob* job = new UploadJob(np.payload(), transferInfo); + UploadJob* job = new UploadJob(np.payload(), deviceId()); job->start(); return job; } diff --git a/core/backends/lan/lanlinkprovider.cpp b/core/backends/lan/lanlinkprovider.cpp index 3bf775298..417250ca9 100644 --- a/core/backends/lan/lanlinkprovider.cpp +++ b/core/backends/lan/lanlinkprovider.cpp @@ -37,7 +37,6 @@ #include "../../daemon.h" #include "landevicelink.h" -#include "lanpairinghandler.h" #include #include #include @@ -187,7 +186,6 @@ void LanLinkProvider::connected() NetworkPackage* receivedPackage = receivedIdentityPackages[socket].np; const QString& deviceId = receivedPackage->get("deviceId"); //qCDebug(KDECONNECT_CORE) << "Connected" << socket->isWritable(); - LanDeviceLink* deviceLink = new LanDeviceLink(deviceId, this, socket, DeviceLink::Remotely); // If network is on ssl, do not believe when they are connected, believe when handshake is completed NetworkPackage np2(""); @@ -210,7 +208,7 @@ void LanLinkProvider::connected() if (isDeviceTrusted) { qDebug() << "Device trusted"; - QString certString = KdeConnectConfig::instance()->getTrustedDevice(deviceId).certificate; + QString certString = KdeConnectConfig::instance()->getDeviceProperty(deviceId, "certificate", QString()); socket->addCaCertificate(QSslCertificate(certString.toLatin1())); socket->setPeerVerifyMode(QSslSocket::VerifyPeer); connect(socket, SIGNAL(sslErrors(QList)), this, SLOT(sslErrors(QList))); @@ -225,7 +223,7 @@ void LanLinkProvider::connected() socket->startServerEncryption(); return; // Return statement prevents from deleting received package, needed in slot "encrypted" } else { - addLink(deviceId, socket, receivedPackage); + addLink(deviceId, socket, receivedPackage, DeviceLink::Remotely); } } else { @@ -256,7 +254,7 @@ void LanLinkProvider::encrypted() receivedPackage->set("certificate", socket->peerCertificate().toPem()); - addLink(deviceId, socket, receivedPackage); + addLink(deviceId, socket, receivedPackage, DeviceLink::Remotely); // Copied from connected slot, now delete received package delete receivedPackage; @@ -355,7 +353,7 @@ void LanLinkProvider::dataReceived() if (isDeviceTrusted) { qDebug() << "Device trusted"; - QString certString = KdeConnectConfig::instance()->getTrustedDevice(deviceId).certificate; + QString certString = KdeConnectConfig::instance()->getDeviceProperty(deviceId, "certificate", QString()); socket->addCaCertificate(QSslCertificate(certString.toLatin1())); socket->setPeerVerifyMode(QSslSocket::VerifyPeer); connect(socket, SIGNAL(sslErrors(QList)), this, SLOT(sslErrors(QList))); @@ -370,7 +368,7 @@ void LanLinkProvider::dataReceived() socket->startClientEncryption(); return; } else { - addLink(deviceId, socket, np); + addLink(deviceId, socket, np, DeviceLink::Locally); } delete np; @@ -420,9 +418,10 @@ void LanLinkProvider::configureSocket(QSslSocket* socket) } -void LanLinkProvider::addLink(QString deviceId, QSslSocket* socket, NetworkPackage* receivedPackage) { +void LanLinkProvider::addLink(const QString& deviceId, QSslSocket* socket, NetworkPackage* receivedPackage, DeviceLink::ConnectionStarted connectionOrigin) +{ - LanDeviceLink* deviceLink = new LanDeviceLink(deviceId, this, socket, DeviceLink::Locally); + LanDeviceLink* deviceLink = new LanDeviceLink(deviceId, this, socket, connectionOrigin); connect(deviceLink, SIGNAL(destroyed(QObject*)), this, SLOT(deviceLinkDestroyed(QObject*))); // Socket disconnection will now be handled by LanDeviceLink diff --git a/core/backends/lan/lanlinkprovider.h b/core/backends/lan/lanlinkprovider.h index c62d998ba..e51183c89 100644 --- a/core/backends/lan/lanlinkprovider.h +++ b/core/backends/lan/lanlinkprovider.h @@ -28,7 +28,6 @@ #include #include "../linkprovider.h" -#include "netaddress.h" #include "server.h" #include "landevicelink.h" @@ -43,7 +42,6 @@ public: QString name() override { return "LanLinkProvider"; } int priority() override { return PRIORITY_HIGH; } - void addLink(QString, QSslSocket*, NetworkPackage*); public Q_SLOTS: virtual void onNetworkChange() override; @@ -63,6 +61,7 @@ private Q_SLOTS: private: static void configureSocket(QSslSocket* socket); void onNetworkConfigurationChanged(const QNetworkConfiguration &config); + void addLink(const QString& deviceId, QSslSocket* socket, NetworkPackage* receivedPackage, DeviceLink::ConnectionStarted connectionOrigin); Server* mServer; QUdpSocket* mUdpServer; diff --git a/core/backends/lan/lanpairinghandler.cpp b/core/backends/lan/lanpairinghandler.cpp index 86bdf4224..c28998e97 100644 --- a/core/backends/lan/lanpairinghandler.cpp +++ b/core/backends/lan/lanpairinghandler.cpp @@ -27,28 +27,28 @@ #include "lanpairinghandler.h" #include "networkpackagetypes.h" -LanPairingHandler::LanPairingHandler(Device* device) - : PairingHandler(device) +LanPairingHandler::LanPairingHandler(const QString& deviceId) + : PairingHandler() + , m_deviceId(deviceId) { m_pairingTimeout.setSingleShot(true); m_pairingTimeout.setInterval(30 * 1000); //30 seconds of timeout connect(&m_pairingTimeout, SIGNAL(timeout()), this, SLOT(pairingTimeout())); - - if (device->isPaired()) { - if (!KdeConnectConfig::instance()->getTrustedDevice(device->id()).publicKey.isNull()) { - m_pairStatus = PairStatus::Paired; - } else { - requestPairing(); // Request pairing if device is paired but public key is not there - } +/* + m_publicKey = KdeConnectConfig::instance()->getDeviceProperty(deviceId, "publicKey", QString()); + m_certificate = KdeConnectConfig::instance()->getDeviceProperty(deviceId, "certificate", QString()); +*/ + if (!m_publicKey.isNull()) { + setPairStatus(PairStatus::Paired); } else { - m_pairStatus = PairStatus::NotPaired; + setPairStatus(PairStatus::NotPaired); } } void LanPairingHandler::createPairPackage(NetworkPackage& np) { - np.set("link", m_deviceLink->name()); + np.set("link", deviceLink()->name()); np.set("pair", true); np.set("publicKey", KdeConnectConfig::instance()->publicKey().toPEM()); } @@ -56,7 +56,7 @@ void LanPairingHandler::createPairPackage(NetworkPackage& np) void LanPairingHandler::packageReceived(const NetworkPackage& np) { - if (np.get("link", m_deviceLink->name()).compare(m_deviceLink->name()) != 0) return; // If this package is not received by my type of link + if (np.get("link", deviceLink()->name()).compare(deviceLink()->name()) != 0) return; // If this package is not received by my type of link m_pairingTimeout.stop(); @@ -64,77 +64,75 @@ void LanPairingHandler::packageReceived(const NetworkPackage& np) if (wantsPair == isPaired()) { // qCDebug(KDECONNECT_CORE) << "Already" << (wantsPair? "paired":"unpaired"); - if (m_pairStatus == PairStatus ::Requested) { - m_pairStatus = PairStatus ::NotPaired; + if (isPairRequested()) { + setPairStatus(PairStatus::NotPaired); Q_EMIT pairingFailed(i18n("Canceled by other peer")); return; - } else if (m_pairStatus == PairStatus ::Paired) { + } else if (isPaired()) { /** * If wants pair is true and is paired is true, this means other device is trying to pair again, might be because it unpaired this device somehow * and we don't know it, unpair it internally */ - Q_EMIT unpairingDone(); + KdeConnectConfig::instance()->removeTrustedDevice(m_deviceId); + setPairStatus(PairingHandler::NotPaired); } } if (wantsPair) { QString keyString = np.get("publicKey"); - m_device->setPublicKey(QCA::RSAPublicKey::fromPEM(keyString)); - bool success = !m_device->publicKey().isNull(); - if (!success) { - if (m_pairStatus == PairStatus ::Requested) { - m_pairStatus = PairStatus::NotPaired; + QString certificateString = np.get("certificate"); + + if (QCA::RSAPublicKey::fromPEM(keyString).isNull()) { + if (isPairRequested()) { + setPairStatus(PairStatus::NotPaired); } Q_EMIT pairingFailed(i18n("Received incorrect key")); return; } - if (m_pairStatus == PairStatus::Requested) { //We started pairing + if (isPairRequested()) { //We started pairing qCDebug(KDECONNECT_CORE) << "Pair answer"; - setAsPaired(); - + KdeConnectConfig::instance()->setDeviceProperty(m_deviceId, "publicKey", keyString); + KdeConnectConfig::instance()->setDeviceProperty(m_deviceId, "certificate", certificateString); + } else { qCDebug(KDECONNECT_CORE) << "Pair request"; - if (m_device->isPaired()) { + if (isPaired()) { acceptPairing(); return; } - Daemon::instance()->requestPairing(m_device); - - m_pairStatus = PairStatus ::RequestedByPeer; + //Daemon::instance()->requestPairing(m_device); + //m_pairStatus = PairStatus::RequestedByPeer; + setPairStatus(PairStatus::RequestedByPeer); } - } else { + } else { //wantsPair == false qCDebug(KDECONNECT_CORE) << "Unpair request"; - PairStatus prevPairStatus = m_pairStatus; - m_pairStatus = PairStatus::NotPaired; - - if (prevPairStatus == PairStatus ::Requested) { + if (isPairRequested()) { Q_EMIT pairingFailed(i18n("Canceled by other peer")); - } else if (prevPairStatus == PairStatus::Paired) { - Q_EMIT (unpairingDone()); } + setPairStatus(PairStatus::NotPaired); } } bool LanPairingHandler::requestPairing() { - switch (m_pairStatus) { + switch (pairStatus()) { case PairStatus::Paired: - Q_EMIT pairingFailed(i18n(m_deviceLink->name().append(" : Already paired").toLatin1().data())); + Q_EMIT pairingFailed(i18n(deviceLink()->name().append(" : Already paired").toLatin1().data())); return false; - case PairStatus ::Requested: - Q_EMIT pairingFailed(i18n(m_deviceLink->name().append(" : Pairing already requested for this device").toLatin1().data())); + case PairStatus::Requested: + Q_EMIT pairingFailed(i18n(deviceLink()->name().append(" : Pairing already requested for this device").toLatin1().data())); return false; - case PairStatus ::RequestedByPeer: - qCDebug(KDECONNECT_CORE) << m_deviceLink->name() << " : Pairing already started by the other end, accepting their request."; + case PairStatus::RequestedByPeer: + qCDebug(KDECONNECT_CORE) << deviceLink()->name() << " : Pairing already started by the other end, accepting their request."; acceptPairing(); return false; case PairStatus::NotPaired: @@ -144,9 +142,9 @@ bool LanPairingHandler::requestPairing() NetworkPackage np(PACKAGE_TYPE_PAIR); createPairPackage(np); bool success; - success = m_deviceLink->sendPackage(np); + success = deviceLink()->sendPackage(np); if (success) { - m_pairStatus = PairStatus::Requested; + setPairStatus(PairStatus::Requested); m_pairingTimeout.start(); } return success; @@ -154,14 +152,13 @@ bool LanPairingHandler::requestPairing() bool LanPairingHandler::acceptPairing() { + m_pairingTimeout.stop(); // Just in case it is started NetworkPackage np(PACKAGE_TYPE_PAIR); createPairPackage(np); bool success; - success = m_deviceLink->sendPackage(np); + success = deviceLink()->sendPackage(np); if (success) { - m_pairStatus = PairStatus::Paired; - setAsPaired(); - Q_EMIT(pairingDone()); + setPairStatus(PairStatus::Paired); } return success; } @@ -170,36 +167,25 @@ void LanPairingHandler::rejectPairing() { NetworkPackage np(PACKAGE_TYPE_PAIR); np.set("pair", false); - np.set("link", m_deviceLink->name()); - m_deviceLink->sendPackage(np); - m_pairStatus = PairStatus::NotPaired; + np.set("link", deviceLink()->name()); + deviceLink()->sendPackage(np); + setPairStatus(PairStatus::NotPaired); } void LanPairingHandler::unpair() { NetworkPackage np(PACKAGE_TYPE_PAIR); np.set("pair", false); - np.set("link", m_deviceLink->name()); - m_deviceLink->sendPackage(np); - m_pairStatus = PairStatus::NotPaired; + np.set("link", deviceLink()->name()); + deviceLink()->sendPackage(np); + setPairStatus(PairStatus::NotPaired); } void LanPairingHandler::pairingTimeout() { NetworkPackage np(PACKAGE_TYPE_PAIR); np.set("pair", false); - np.set("name", m_deviceLink->name()); - m_deviceLink->sendPackage(np); - m_pairStatus = PairStatus::NotPaired; - m_device->pairingTimeout(); // Use signal slot, or this is good ? -} - -void LanPairingHandler::setAsPaired() -{ - KdeConnectConfig::instance()->setDeviceProperty(m_device->id(), "publicKey", m_device->publicKey().toPEM()); - KdeConnectConfig::instance()->setDeviceProperty(m_device->id(), "certificate", QString::fromLatin1(m_device->certificate().toPem())); - - m_pairStatus = PairStatus::Paired; - m_pairingTimeout.stop(); // Just in case it is started - - Q_EMIT(pairingDone()); + np.set("name", deviceLink()->name()); + deviceLink()->sendPackage(np); + setPairStatus(PairStatus::NotPaired); //Will emit the change as well + Q_EMIT pairingFailed(i18n("Timed out")); } diff --git a/core/backends/lan/lanpairinghandler.h b/core/backends/lan/lanpairinghandler.h index 2cc779bbe..d723634a0 100644 --- a/core/backends/lan/lanpairinghandler.h +++ b/core/backends/lan/lanpairinghandler.h @@ -30,7 +30,7 @@ class LanPairingHandler : public PairingHandler { public: - LanPairingHandler(Device* device); + LanPairingHandler(const QString& deviceId); virtual ~LanPairingHandler() { } virtual void createPairPackage(NetworkPackage& np) Q_DECL_OVERRIDE; @@ -40,12 +40,14 @@ public: virtual void rejectPairing() Q_DECL_OVERRIDE; virtual void unpair() Q_DECL_OVERRIDE; -public Q_SLOTS: +private Q_SLOTS: virtual void pairingTimeout(); -private: - virtual void setAsPaired() Q_DECL_OVERRIDE; - +protected: + QTimer m_pairingTimeout; + QString m_deviceId; + QCA::PublicKey m_publicKey; + QSslCertificate m_certificate; }; diff --git a/core/backends/lan/uploadjob.cpp b/core/backends/lan/uploadjob.cpp index d2646f442..f8a10d0bf 100644 --- a/core/backends/lan/uploadjob.cpp +++ b/core/backends/lan/uploadjob.cpp @@ -26,7 +26,7 @@ #include "core_debug.h" -UploadJob::UploadJob(const QSharedPointer& source, const QVariantMap& transferInfo): KJob() +UploadJob::UploadJob(const QSharedPointer& source, const QString& deviceId): KJob() { // TODO: initialize in constructor mInput = source; @@ -35,7 +35,7 @@ UploadJob::UploadJob(const QSharedPointer& source, const QVariantMap& mPort = 0; // We will use this info if link is on ssl, to send encrypted payload - this->mTransferInfo = transferInfo; + this->mDeviceId = deviceId; connect(mInput.data(), SIGNAL(readyRead()), this, SLOT(readyRead())); connect(mInput.data(), SIGNAL(aboutToClose()), this, SLOT(aboutToClose())); @@ -69,15 +69,13 @@ void UploadJob::newConnection() mSocket = server->nextPendingConnection(); connect(mSocket, SIGNAL(disconnected()), mSocket, SLOT(deleteLater())); - if (mTransferInfo.value("useSsl", false).toBool()) { - mSocket->setLocalCertificate(KdeConnectConfig::instance()->certificate()); - mSocket->setPrivateKey(KdeConnectConfig::instance()->privateKeyPath()); - mSocket->setProtocol(QSsl::TlsV1_2); - mSocket->setPeerVerifyName(mTransferInfo.value("deviceId").toString()); - mSocket->addCaCertificate(QSslCertificate(KdeConnectConfig::instance()->getTrustedDevice(mTransferInfo.value("deviceId").toString()).certificate.toLatin1())); - mSocket->startServerEncryption(); - mSocket->waitForEncrypted(); - } + mSocket->setLocalCertificate(KdeConnectConfig::instance()->certificate()); + mSocket->setPrivateKey(KdeConnectConfig::instance()->privateKeyPath()); + mSocket->setProtocol(QSsl::TlsV1_2); + mSocket->setPeerVerifyName(mDeviceId); + mSocket->addCaCertificate(QSslCertificate(KdeConnectConfig::instance()->getDeviceProperty(mDeviceId, "certificate", QString()).toLatin1())); + mSocket->startServerEncryption(); + mSocket->waitForEncrypted(); readyRead(); } diff --git a/core/backends/lan/uploadjob.h b/core/backends/lan/uploadjob.h index 174d176c7..2cb190b5f 100644 --- a/core/backends/lan/uploadjob.h +++ b/core/backends/lan/uploadjob.h @@ -34,7 +34,7 @@ class UploadJob { Q_OBJECT public: - explicit UploadJob(const QSharedPointer& source, const QVariantMap& sslInfo); + explicit UploadJob(const QSharedPointer& source, const QString& deviceId); virtual void start() override; @@ -45,7 +45,7 @@ private: Server* mServer; QSslSocket* mSocket; quint16 mPort; - QVariantMap mTransferInfo; + QString mDeviceId; private Q_SLOTS: void readyRead(); diff --git a/core/backends/loopback/loopbackdevicelink.cpp b/core/backends/loopback/loopbackdevicelink.cpp index 9907196f7..3cb53b516 100644 --- a/core/backends/loopback/loopbackdevicelink.cpp +++ b/core/backends/loopback/loopbackdevicelink.cpp @@ -36,7 +36,7 @@ QString LoopbackDeviceLink::name() PairingHandler* LoopbackDeviceLink::createPairingHandler(Device *device) { - return new LoopbackPairingHandler(device); + return new LoopbackPairingHandler(device->id()); } bool LoopbackDeviceLink::sendPackageEncrypted(QCA::PublicKey& key, NetworkPackage& input) { diff --git a/core/backends/loopback/loopbackpairinghandler.cpp b/core/backends/loopback/loopbackpairinghandler.cpp index 5742bd033..7ff8117a5 100644 --- a/core/backends/loopback/loopbackpairinghandler.cpp +++ b/core/backends/loopback/loopbackpairinghandler.cpp @@ -27,23 +27,23 @@ #include "loopbackpairinghandler.h" #include "networkpackagetypes.h" -LoopbackPairingHandler::LoopbackPairingHandler(Device* device) - : LanPairingHandler(device) +LoopbackPairingHandler::LoopbackPairingHandler(const QString& deviceId) + : LanPairingHandler(deviceId) { -} +} bool LoopbackPairingHandler::requestPairing() { - switch (m_pairStatus) { + switch (pairStatus()) { case PairStatus::Paired: - Q_EMIT pairingFailed(i18n(m_deviceLink->name().append(" : Already paired").toLatin1().data())); + Q_EMIT pairingFailed(deviceLink()->name().append(" : Already paired").toLatin1().data()); return false; case PairStatus ::Requested: - Q_EMIT pairingFailed(i18n(m_deviceLink->name().append(" : Pairing already requested for this device").toLatin1().data())); + Q_EMIT pairingFailed(deviceLink()->name().append(" : Pairing already requested for this device").toLatin1().data()); return false; case PairStatus ::RequestedByPeer: - qCDebug(KDECONNECT_CORE) << m_deviceLink->name() << " : Pairing already started by the other end, accepting their request."; + qCDebug(KDECONNECT_CORE) << deviceLink()->name() << " : Pairing already started by the other end, accepting their request."; acceptPairing(); return false; case PairStatus::NotPaired: @@ -52,9 +52,9 @@ bool LoopbackPairingHandler::requestPairing() NetworkPackage np(PACKAGE_TYPE_PAIR); createPairPackage(np); - m_pairStatus = PairStatus::Requested; + setPairStatus(PairStatus::Requested); m_pairingTimeout.start(); - bool success = m_deviceLink->sendPackage(np); + bool success = deviceLink()->sendPackage(np); return success; } @@ -62,20 +62,10 @@ bool LoopbackPairingHandler::acceptPairing() { NetworkPackage np(PACKAGE_TYPE_PAIR); createPairPackage(np); - m_pairStatus = PairStatus::Paired; - setAsPaired(); - bool success = m_deviceLink->sendPackage(np); - Q_EMIT(pairingDone()); + setPairStatus(PairStatus::Paired); + bool success = deviceLink()->sendPackage(np); + KdeConnectConfig::instance()->setDeviceProperty(m_deviceId, "publicKey", QString::fromLatin1(KdeConnectConfig::instance()->certificate().toPem())); + KdeConnectConfig::instance()->setDeviceProperty(m_deviceId, "certificate", QString::fromLatin1(KdeConnectConfig::instance()->certificate().toPem())); return success; } -void LoopbackPairingHandler::setAsPaired() -{ - KdeConnectConfig::instance()->setDeviceProperty(m_device->id(), "publicKey", m_device->publicKey().toPEM()); - KdeConnectConfig::instance()->setDeviceProperty(m_device->id(), "certificate", QString::fromLatin1(m_device->certificate().toPem())); - - m_pairStatus = PairStatus::Paired; - m_pairingTimeout.stop(); // Just in case it is started - - Q_EMIT(pairingDone()); -} diff --git a/core/backends/loopback/loopbackpairinghandler.h b/core/backends/loopback/loopbackpairinghandler.h index e283b1f19..5a28d9082 100644 --- a/core/backends/loopback/loopbackpairinghandler.h +++ b/core/backends/loopback/loopbackpairinghandler.h @@ -30,15 +30,12 @@ class LoopbackPairingHandler : public LanPairingHandler { public: - LoopbackPairingHandler(Device* device); + LoopbackPairingHandler(const QString& deviceId); virtual ~LoopbackPairingHandler() { } virtual bool requestPairing() Q_DECL_OVERRIDE; virtual bool acceptPairing() Q_DECL_OVERRIDE; -private: - virtual void setAsPaired() Q_DECL_OVERRIDE; - }; diff --git a/core/backends/pairinghandler.cpp b/core/backends/pairinghandler.cpp index 01608bd5b..0d7726306 100644 --- a/core/backends/pairinghandler.cpp +++ b/core/backends/pairinghandler.cpp @@ -20,9 +20,11 @@ #include "pairinghandler.h" -PairingHandler::PairingHandler(Device* device) +PairingHandler::PairingHandler() + : m_pairStatus(NotPaired) + , m_deviceLink(nullptr) { - m_device = device; + } void PairingHandler::setLink(DeviceLink *dl) @@ -37,4 +39,13 @@ void PairingHandler::linkDestroyed(QObject* o) m_deviceLink = Q_NULLPTR; Q_EMIT linkNull(); } -} \ No newline at end of file +} + +void PairingHandler::setPairStatus(PairingHandler::PairStatus status) +{ + if (m_pairStatus != status) { + PairStatus oldStatus = m_pairStatus; + m_pairStatus = status; + Q_EMIT pairStatusChanged(status, oldStatus); + } +} diff --git a/core/backends/pairinghandler.h b/core/backends/pairinghandler.h index 33d9224c5..4edc6c594 100644 --- a/core/backends/pairinghandler.h +++ b/core/backends/pairinghandler.h @@ -21,7 +21,6 @@ #ifndef KDECONNECT_PAIRINGHANDLER_H #define KDECONNECT_PAIRINGHANDLER_H -#include "device.h" #include "networkpackage.h" #include "devicelink.h" @@ -41,8 +40,10 @@ class PairingHandler : public QObject { Q_OBJECT -protected: +public: + + //TODO: Can we simplify this to just Paired/NotPaired, and leave the detailed status as an backend-specific thing? enum PairStatus { NotPaired, Requested, @@ -50,18 +51,13 @@ protected: Paired, }; - QTimer m_pairingTimeout; - Device* m_device; - DeviceLink* m_deviceLink; // We keep the latest link here, if this is destroyed without new link, linkDestroyed is emitted and device will destroy pairing handler - PairStatus m_pairStatus; - -public: - PairingHandler(Device* device); + PairingHandler(); virtual ~PairingHandler() { } void setLink(DeviceLink* dl); - bool isPaired() const { return m_pairStatus == PairStatus::Paired; }; - bool pairRequested() const { return m_pairStatus == PairStatus::Requested; } + bool isPaired() const { return m_pairStatus == PairStatus::Paired; } + bool isPairRequested() const { return m_pairStatus == PairStatus::Requested; } + virtual void createPairPackage(NetworkPackage& np) = 0; virtual void packageReceived(const NetworkPackage& np) = 0; @@ -70,12 +66,21 @@ public: virtual void rejectPairing() = 0; virtual void unpair() = 0; +protected: + DeviceLink* deviceLink() const; + void setPairStatus(PairStatus status); + PairStatus pairStatus() const; + public Q_SLOTS: void linkDestroyed(QObject*); virtual void pairingTimeout() = 0; +Q_SIGNALS: + void pairStatusChanged(PairStatus status, PairStatus previousStatus); + private: - virtual void setAsPaired() = 0; + DeviceLink* m_deviceLink; // We keep the latest link here, if this is destroyed without new link, linkDestroyed is emitted and device will destroy pairing handler + PairStatus m_pairStatus; Q_SIGNALS: void pairingDone(); diff --git a/core/daemon.cpp b/core/daemon.cpp index b10461356..0b97fddad 100644 --- a/core/daemon.cpp +++ b/core/daemon.cpp @@ -123,7 +123,7 @@ void Daemon::removeDevice(Device* device) void Daemon::cleanDevices() { Q_FOREACH(Device* device, d->mDevices) { - if (device->pairStatus() == Device::NotPaired && device->connectionSource() == DeviceLink::ConnectionStarted::Remotely) { + if (device->pairStatus() == PairingHandler::NotPaired && device->connectionSource() == DeviceLink::ConnectionStarted::Remotely) { removeDevice(device); } } @@ -159,16 +159,6 @@ QStringList Daemon::devices(bool onlyReachable, bool onlyPaired) const return ret; } -QByteArray Daemon::certificate(int format) const -{ - if (format == QSsl::Pem) { - return KdeConnectConfig::instance()->certificate().toPem(); - } else { - return KdeConnectConfig::instance()->certificate().toDer(); - } -} - - void Daemon::onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink* dl) { const QString& id = identityPackage.get("deviceId"); diff --git a/core/daemon.h b/core/daemon.h index f4ad571f1..66b536473 100644 --- a/core/daemon.h +++ b/core/daemon.h @@ -70,9 +70,6 @@ public Q_SLOTS: //Returns a list of ids. The respective devices can be manipulated using the dbus path: "/modules/kdeconnect/Devices/"+id Q_SCRIPTABLE QStringList devices(bool onlyReachable = false, bool onlyPaired = false) const; - //Exposing kdeconnectconfig through daemon, needed to show certificate hash in cli, but this can be extended to name, id, public key etc. if needed - Q_SCRIPTABLE QByteArray certificate(int format) const; - Q_SIGNALS: Q_SCRIPTABLE void deviceAdded(const QString& id); Q_SCRIPTABLE void deviceRemoved(const QString& id); //Note that paired devices will never be removed diff --git a/core/device.cpp b/core/device.cpp index 6648185f4..bf42d4a26 100644 --- a/core/device.cpp +++ b/core/device.cpp @@ -49,14 +49,12 @@ Q_LOGGING_CATEGORY(KDECONNECT_CORE, "kdeconnect.core") Device::Device(QObject* parent, const QString& id) : QObject(parent) , m_deviceId(id) - , m_pairStatus(Device::Paired) , m_protocolVersion(NetworkPackage::ProtocolVersion) //We don't know it yet { KdeConnectConfig::DeviceInfo info = KdeConnectConfig::instance()->getTrustedDevice(id); m_deviceName = info.deviceName; m_deviceType = str2type(info.deviceType); - m_publicKey = QCA::RSAPublicKey::fromPEM(info.publicKey); //Register in bus QDBusConnection::sessionBus().registerObject(dbusPath(), this, QDBusConnection::ExportScriptableContents | QDBusConnection::ExportAdaptors); @@ -67,21 +65,12 @@ Device::Device(QObject* parent, const NetworkPackage& identityPackage, DeviceLin , m_deviceId(identityPackage.get("deviceId")) , m_deviceName(identityPackage.get("deviceName")) , m_deviceType(str2type(identityPackage.get("deviceType"))) - , m_pairStatus(Device::NotPaired) , m_protocolVersion(identityPackage.get("protocolVersion", -1)) { addLink(identityPackage, dl); //Register in bus QDBusConnection::sessionBus().registerObject(dbusPath(), this, QDBusConnection::ExportScriptableContents | QDBusConnection::ExportAdaptors); - - //Implement deprecated signals - connect(this, &Device::pairingChanged, this, [this](bool newPairing) { - if (newPairing) - Q_EMIT pairingSuccesful(); - else - Q_EMIT unpaired(); - }); } Device::~Device() @@ -193,23 +182,20 @@ QString Device::pluginsConfigFile() const return KdeConnectConfig::instance()->deviceConfigDir(id()).absoluteFilePath("config"); } -bool Device::pairRequested() const +bool Device::isPairRequested() const { bool isPairRequested = false; Q_FOREACH(PairingHandler* ph, m_pairingHandlers) { - isPairRequested = isPairRequested || ph->pairRequested(); + isPairRequested = isPairRequested || ph->isPairRequested(); } return isPairRequested; } void Device::requestPair() { - switch(m_pairStatus) { - case Device::Paired: - Q_EMIT pairingFailed(i18n("Already paired")); - return; - case Device::NotPaired: - ; + if (isPaired()) { + Q_EMIT pairingFailed(i18n("Already paired")); + return; } if (!isReachable()) { @@ -217,20 +203,14 @@ void Device::requestPair() return; } - //Send our own public key bool success = false; Q_FOREACH(PairingHandler* ph, m_pairingHandlers.values()) { success = success || ph->requestPairing(); // If one of many pairing handlers can successfully request pairing, consider it success } if (!success) { - m_pairStatus = Device::NotPaired; Q_EMIT pairingFailed(i18n("Error contacting device")); return; } - - if (m_pairStatus == Device::Paired) { - return; - } } void Device::unpair() @@ -238,23 +218,23 @@ void Device::unpair() Q_FOREACH(PairingHandler* ph, m_pairingHandlers.values()) { ph->unpair(); } - unpairInternal(); // We do not depend on pairing handlers for unpairing, this method is likely to be called due to user events } -void Device::unpairInternal() +void Device::pairStatusChanged(PairingHandler::PairStatus status, PairingHandler::PairStatus oldStatus) { - bool alreadyUnpaired = (m_pairStatus != Device::Paired); - m_pairStatus = Device::NotPaired; - KdeConnectConfig::instance()->removeTrustedDevice(id()); - reloadPlugins(); //Will unload the plugins - if (!alreadyUnpaired) { - Q_EMIT pairingChanged(false); + if (oldStatus == PairingHandler::Paired && status == PairingHandler::NotPaired) { + KdeConnectConfig::instance()->removeTrustedDevice(m_deviceId); + Q_FOREACH(PairingHandler* ph, m_pairingHandlers.values()) { + ph->unpair(); + } } -} -void Device::pairingTimeout() -{ - Q_EMIT pairingFailed(i18n("Timed out")); + if (oldStatus == PairingHandler::NotPaired && status == PairingHandler::Paired) { + reloadPlugins(); //Will unload the plugins + } + + Q_EMIT pairingChanged(status == PairingHandler::Paired); + } static bool lessThan(DeviceLink* p1, DeviceLink* p2) @@ -280,12 +260,6 @@ void Device::addLink(const NetworkPackage& identityPackage, DeviceLink* link) setName(identityPackage.get("deviceName")); m_deviceType = str2type(identityPackage.get("deviceType")); - // Set certificate if the link is on ssl, and it is added to identity package - // This is always sets certificate when link is added to device - if (identityPackage.has("certificate")) { - m_certificate = QSslCertificate(identityPackage.get("certificate")); - } - //Theoretically we will never add two links from the same provider (the provider should destroy //the old one before this is called), so we do not have to worry about destroying old links. //-- Actually, we should not destroy them or the provider will store an invalid ref! @@ -311,8 +285,7 @@ void Device::addLink(const NetworkPackage& identityPackage, DeviceLink* link) PairingHandler* pairingHandler = link->createPairingHandler(this); m_pairingHandlers.insert(link->name(), pairingHandler); connect(m_pairingHandlers[link->name()], SIGNAL(linkNull()), this, SLOT(destroyPairingHandler())); - connect(m_pairingHandlers[link->name()], SIGNAL(pairingDone()), this, SLOT(setAsPaired())); - connect(m_pairingHandlers[link->name()], SIGNAL(unpairingDone()), this, SLOT(unpairInternal())); + connect(m_pairingHandlers[link->name()], SIGNAL(pairStatusChanged(PairStatus, PairStatus)), this, SLOT(pairStatusChanged(PairStatus, PairStatus))); connect(m_pairingHandlers[link->name()], SIGNAL(pairingFailed(const QString&)), this, SIGNAL(pairingFailed(const QString&))); } m_pairingHandlers[link->name()]->setLink(link); @@ -393,7 +366,7 @@ void Device::rejectPairing() { qCDebug(KDECONNECT_CORE) << "Rejected pairing"; - m_pairStatus = Device::NotPaired; + m_pairStatus = PairingHandler::NotPaired; Q_FOREACH(PairingHandler* ph, m_pairingHandlers.values()) { ph->rejectPairing(); @@ -408,35 +381,20 @@ void Device::acceptPairing() qCDebug(KDECONNECT_CORE) << "Accepted pairing"; bool success = false; - Q_FOREACH(PairingHandler* ph, m_pairingHandlers.values()) { - success = success || ph->acceptPairing(); - } - - if (!success) { - m_pairStatus = Device::NotPaired; - return; + Q_FOREACH(PairingHandler* ph, m_pairingHandlers) { + success = success || ph->acceptPairing(); } } -void Device::setAsPaired() -{ - - bool alreadyPaired = (m_pairStatus == Device::Paired); - - m_pairStatus = Device::Paired; - - //Save device info in the config - KdeConnectConfig::instance()->addTrustedDevice(id(), name(), type2str(m_deviceType)); - - reloadPlugins(); //Will actually load the plugins - - if (!alreadyPaired) { - Q_EMIT pairingChanged(true); +void Device::isPaired() { + Q_FOREACH(PairingHandler* ph, m_pairingHandlers) { + if (ph->isPaired()) return true; } - + return false; } + DeviceLink::ConnectionStarted Device::connectionSource() const { DeviceLink::ConnectionStarted ret = DeviceLink::Remotely; @@ -535,3 +493,24 @@ bool Device::isPluginEnabled(const QString& pluginName) const return (pluginStates.hasKey(enabledKey) ? pluginStates.readEntry(enabledKey, false) : PluginLoader::instance()->getPluginInfo(pluginName).isEnabledByDefault()); } + +//HACK +QString Device::encryptionInfo() const +{ + QString result; + + QByteArray myCertificate = KdeConnectConfig::instance()->certificate().toDer(); + for (int i=2 ; igetDeviceProperty(id(), "certificate"); + for (int i=2 ; i #include +#include "backends/pairinghandler.h" #include "networkpackage.h" #include "backends/devicelink.h" class DeviceLink; class KdeConnectPlugin; -class PairingHandler; class KDECONNECTCORE_EXPORT Device : public QObject @@ -51,10 +51,6 @@ class KDECONNECTCORE_EXPORT Device Q_PROPERTY(QStringList unsupportedPlugins READ unsupportedPlugins NOTIFY pluginsChanged) public: - enum PairStatus { - NotPaired, - Paired, - }; enum DeviceType { Unknown, @@ -84,22 +80,17 @@ public: QString name() const { return m_deviceName; } QString dbusPath() const { return "/modules/kdeconnect/devices/"+id(); } QString type() const { return type2str(m_deviceType); } - QCA::PublicKey publicKey() const { return m_publicKey; } - QSslCertificate certificate() const { return m_certificate; } - Q_SCRIPTABLE QByteArray certificate(int format) const { return (format == QSsl::Pem) ? m_certificate.toPem() : m_certificate.toDer() ;} // To expose certificate through dbus for cli QString iconName() const; QString statusIconName() const; QStringList unsupportedPlugins() const { return m_unsupportedPlugins; } + QString encryptionInfo() const; //Add and remove links void addLink(const NetworkPackage& identityPackage, DeviceLink*); void removeLink(DeviceLink*); - // Setter for public key after pairing, since it is handled by pairinghandler now - void setPublicKey(QCA::PublicKey publicKey) { m_publicKey = publicKey; } - - Q_SCRIPTABLE bool isPaired() const { return m_pairStatus==Device::Paired; } - Q_SCRIPTABLE bool pairRequested() const; + Q_SCRIPTABLE bool isPaired() const; + Q_SCRIPTABLE bool isPairRequested() const; Q_SCRIPTABLE QStringList availableLinks() const; bool isReachable() const { return !m_deviceLinks.isEmpty(); } @@ -109,13 +100,11 @@ public: Q_SCRIPTABLE QString pluginsConfigFile() const; - void pairingTimeout(); - KdeConnectPlugin* plugin(const QString& pluginName) const; void setPluginEnabled(const QString& pluginName, bool enabled); bool isPluginEnabled(const QString& pluginName) const; - PairStatus pairStatus() const; + PairingHandler::PairStatus pairStatus() const; DeviceLink::ConnectionStarted connectionSource() const; @@ -136,8 +125,8 @@ private Q_SLOTS: void linkDestroyed(QObject* o); void destroyPairingHandler(); - void setAsPaired(); - void unpairInternal(); + void pairStatusChanged(PairingHandler::PairStatus current, PairingHandler::PairStatus old); + Q_SIGNALS: Q_SCRIPTABLE void pluginsChanged(); @@ -146,9 +135,6 @@ Q_SIGNALS: Q_SCRIPTABLE void pairingFailed(const QString& error); Q_SCRIPTABLE void nameChanged(const QString& name); - QT_DEPRECATED Q_SCRIPTABLE void pairingSuccesful(); - QT_DEPRECATED Q_SCRIPTABLE void unpaired(); - private: //Methods static DeviceType str2type(const QString &deviceType); static QString type2str(DeviceType deviceType); @@ -160,9 +146,6 @@ private: //Fields (TODO: dPointer!) const QString m_deviceId; QString m_deviceName; DeviceType m_deviceType; - QCA::PublicKey m_publicKey; - QSslCertificate m_certificate; - PairStatus m_pairStatus; int m_protocolVersion; QVector m_deviceLinks; @@ -171,7 +154,6 @@ private: //Fields (TODO: dPointer!) QMultiMap m_pluginsByIncomingInterface; QMultiMap m_pluginsByOutgoingInterface; - QTimer m_pairingTimeut; QSet m_incomingCapabilities; QSet m_outgoingCapabilities; QStringList m_supportedIncomingInterfaces; diff --git a/core/kdeconnectconfig.cpp b/core/kdeconnectconfig.cpp index ce62d5f57..85d20b6e9 100644 --- a/core/kdeconnectconfig.cpp +++ b/core/kdeconnectconfig.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include "core_debug.h" #include "dbushelper.h" @@ -217,13 +219,12 @@ QStringList KdeConnectConfig::trustedDevices() } -void KdeConnectConfig::addTrustedDevice(const QString &id, const QString &name, const QString &type, const QString &publicKey) +void KdeConnectConfig::addTrustedDevice(const QString &id, const QString &name, const QString &type) { d->config->beginGroup("trustedDevices"); d->config->beginGroup(id); d->config->setValue("name", name); d->config->setValue("type", type); - d->config->setValue("publicKey", publicKey); d->config->endGroup(); d->config->endGroup(); d->config->sync(); @@ -239,8 +240,6 @@ KdeConnectConfig::DeviceInfo KdeConnectConfig::getTrustedDevice(const QString &i KdeConnectConfig::DeviceInfo info; info.deviceName = d->config->value("name", QLatin1String("unnamed")).toString(); info.deviceType = d->config->value("type", QLatin1String("unknown")).toString(); - info.publicKey = d->config->value("publicKey", QString()).toString(); - info.certificate = d->config->value("certificate", QString()).toString(); d->config->endGroup(); d->config->endGroup(); diff --git a/core/kdeconnectconfig.h b/core/kdeconnectconfig.h index 8666eb22a..e714dd20b 100644 --- a/core/kdeconnectconfig.h +++ b/core/kdeconnectconfig.h @@ -21,20 +21,22 @@ #ifndef KDECONNECTCONFIG_H #define KDECONNECTCONFIG_H -#include #include -#include #include "kdeconnectcore_export.h" +class QSslCertificate; +namespace QCA { + class PrivateKey; + class PublicKey; +} + class KDECONNECTCORE_EXPORT KdeConnectConfig { public: struct DeviceInfo { QString deviceName; QString deviceType; - QString publicKey; - QString certificate; }; static KdeConnectConfig* instance(); @@ -62,12 +64,12 @@ public: QStringList trustedDevices(); //list of ids void removeTrustedDevice(const QString &id); - void addTrustedDevice(const QString &id, const QString &name, const QString &type, const QString &publicKey); + void addTrustedDevice(const QString &id, const QString &name, const QString &type); KdeConnectConfig::DeviceInfo getTrustedDevice(const QString &id); + void setDeviceProperty(QString deviceId, QString name, QString value); QString getDeviceProperty(QString deviceId, QString name, QString defaultValue = QString()); - /* * Paths for config files, there is no guarantee the directories already exist */ diff --git a/kcm/kcm.cpp b/kcm/kcm.cpp index 329b16830..444477c05 100644 --- a/kcm/kcm.cpp +++ b/kcm/kcm.cpp @@ -180,7 +180,7 @@ void KdeConnectKcm::deviceSelected(const QModelIndex& current) } kcmUi->messages->setVisible(false); - if (currentDevice->pairRequested()) { + if (currentDevice->isPairRequested()) { kcmUi->progressBar->setVisible(true); kcmUi->unpair_button->setVisible(false); kcmUi->pair_button->setVisible(false);