diff --git a/kded/daemon.cpp b/kded/daemon.cpp index b7f6cb443..873d1018c 100644 --- a/kded/daemon.cpp +++ b/kded/daemon.cpp @@ -152,7 +152,7 @@ void Daemon::onNewDeviceLink(const NetworkPackage& identityPackage, DeviceLink* } Q_EMIT deviceVisibilityChanged(id, true); - + } void Daemon::onDeviceReachableStatusChanged() diff --git a/kded/device.cpp b/kded/device.cpp index 7979ea647..4d2cf804e 100644 --- a/kded/device.cpp +++ b/kded/device.cpp @@ -44,6 +44,12 @@ Device::Device(const NetworkPackage& identityPackage, DeviceLink* dl) m_deviceId = identityPackage.get("deviceId"); m_deviceName = identityPackage.get("deviceName"); + int protocolVersion = identityPackage.get("protocolVersion"); + if (protocolVersion != NetworkPackage::ProtocolVersion) { + qDebug() << "WARNING: Device uses a different protocol version" << protocolVersion << "expected" << NetworkPackage::ProtocolVersion; + //TODO: Do something + } + addLink(dl); m_pairStatus = Device::Device::NotPaired; @@ -320,14 +326,7 @@ void Device::privateReceivedPackage(const NetworkPackage& np) } else { - if (!np.isEncrypted()) { - //TODO: The other side doesn't know that we are already paired - qDebug() << "Warning: A paired device is sending an unencrypted package"; - - //Forward package - Q_EMIT receivedPackage(np); - - } else { + if (np.type() == PACKAGE_TYPE_ENCRYPTED) { //TODO: Do not read the key every time KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc"); @@ -338,6 +337,15 @@ void Device::privateReceivedPackage(const NetworkPackage& np) NetworkPackage decryptedNp(""); np.decrypt(privateKey, &decryptedNp); Q_EMIT receivedPackage(decryptedNp); + + } else { + + //TODO: The other side doesn't know that we are already paired + qDebug() << "Warning: A paired device is sending an unencrypted package"; + + //Forward package + Q_EMIT receivedPackage(np); + } diff --git a/kded/linkproviders/lanlinkprovider.cpp b/kded/linkproviders/lanlinkprovider.cpp index 862c72f2b..885605e01 100644 --- a/kded/linkproviders/lanlinkprovider.cpp +++ b/kded/linkproviders/lanlinkprovider.cpp @@ -76,9 +76,9 @@ void LanLinkProvider::newUdpConnection() mUdpServer->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort); NetworkPackage* np = new NetworkPackage(""); - NetworkPackage::unserialize(datagram,np); + bool success = NetworkPackage::unserialize(datagram,np); - if (np->version() > 0 && np->type() == PACKAGE_TYPE_IDENTITY) { + if (success && np->type() == PACKAGE_TYPE_IDENTITY) { NetworkPackage np2(""); NetworkPackage::createIdentityPackage(&np2); @@ -206,9 +206,9 @@ void LanLinkProvider::dataReceived() qDebug() << "LanLinkProvider received reply:" << data; NetworkPackage np(""); - NetworkPackage::unserialize(data,&np); + bool success = NetworkPackage::unserialize(data,&np); - if (np.version() > 0 && np.type() == PACKAGE_TYPE_IDENTITY) { + if (success && np.type() == PACKAGE_TYPE_IDENTITY) { const QString& id = np.get("deviceId"); LanDeviceLink* dl = new LanDeviceLink(id, this, socket); diff --git a/kded/networkpackage.cpp b/kded/networkpackage.cpp index 9277ff88c..fec98dfbb 100644 --- a/kded/networkpackage.cpp +++ b/kded/networkpackage.cpp @@ -32,15 +32,11 @@ #include #include -const static int CURRENT_PACKAGE_VERSION = 2; - NetworkPackage::NetworkPackage(const QString& type) { mId = QString::number(QDateTime::currentMSecsSinceEpoch()); mType = type; mBody = QVariantMap(); - mVersion = CURRENT_PACKAGE_VERSION; - mEncrypted = false; } QByteArray NetworkPackage::serialize() const @@ -66,7 +62,7 @@ QByteArray NetworkPackage::serialize() const return json; } -void NetworkPackage::unserialize(const QByteArray& a, NetworkPackage* np) +bool NetworkPackage::unserialize(const QByteArray& a, NetworkPackage* np) { qDebug() << "Unserialize: " << a; @@ -76,15 +72,13 @@ void NetworkPackage::unserialize(const QByteArray& a, NetworkPackage* np) QVariantMap variant = parser.parse(a, &ok).toMap(); if (!ok) { qDebug() << "Unserialization error:" << parser.errorLine() << parser.errorString(); - np->setVersion(-1); + return false; } //QVariant -> Object QJson::QObjectHelper::qvariant2qobject(variant,np); - if (np->version() > CURRENT_PACKAGE_VERSION) { - qDebug() << "Warning: package version" << np->version() << "is greater than supported version" << CURRENT_PACKAGE_VERSION; - } + return true; } @@ -93,28 +87,26 @@ void NetworkPackage::encrypt (QCA::PublicKey& key) QByteArray serialized = serialize(); - int chunkSize = key.maximumEncryptSize(QCA::EME_PKCS1v15); + int chunkSize = key.maximumEncryptSize(NetworkPackage::EncryptionAlgorithm); QStringList chunks; while (!serialized.isEmpty()) { QByteArray chunk = serialized.left(chunkSize); serialized = serialized.mid(chunkSize); - QByteArray encryptedChunk = key.encrypt(chunk, QCA::EME_PKCS1v15).toByteArray(); + QByteArray encryptedChunk = key.encrypt(chunk, NetworkPackage::EncryptionAlgorithm).toByteArray(); chunks.append( encryptedChunk.toBase64() ); } qDebug() << chunks.size() << "chunks"; mId = QString::number(QDateTime::currentMSecsSinceEpoch()); - mType = "kdeconnect.encrypted"; + mType = PACKAGE_TYPE_ENCRYPTED; mBody = QVariantMap(); mBody["data"] = chunks; - mVersion = CURRENT_PACKAGE_VERSION; - mEncrypted = true; } -void NetworkPackage::decrypt (QCA::PrivateKey& key, NetworkPackage* out) const +bool NetworkPackage::decrypt (QCA::PrivateKey& key, NetworkPackage* out) const { const QStringList& chunks = mBody["data"].toStringList(); @@ -122,12 +114,16 @@ void NetworkPackage::decrypt (QCA::PrivateKey& key, NetworkPackage* out) const Q_FOREACH(const QString& chunk, chunks) { QByteArray encryptedChunk = QByteArray::fromBase64(chunk.toAscii()); QCA::SecureArray decryptedChunk; - key.decrypt(encryptedChunk, &decryptedChunk, QCA::EME_PKCS1v15); + bool success = key.decrypt(encryptedChunk, &decryptedChunk, NetworkPackage::EncryptionAlgorithm); + if (!success) { + return false; + } decryptedJson.append(decryptedChunk.toByteArray()); } - unserialize(decryptedJson, out); + return unserialize(decryptedJson, out); + } @@ -136,11 +132,10 @@ void NetworkPackage::createIdentityPackage(NetworkPackage* np) { KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc"); QString id = config->group("myself").readEntry("id",""); - np->mId = time(NULL); - np->mType = PACKAGE_TYPE_IDENTITY; - np->mVersion = CURRENT_PACKAGE_VERSION; + np->mId = QString::number(QDateTime::currentMSecsSinceEpoch()); np->set("deviceId", id); np->set("deviceName", QHostInfo::localHostName()); + np->set("protocolVersion", NetworkPackage::ProtocolVersion); //qDebug() << "createIdentityPackage" << np->serialize(); } diff --git a/kded/networkpackage.h b/kded/networkpackage.h index 6e5798b84..df297d8b8 100644 --- a/kded/networkpackage.h +++ b/kded/networkpackage.h @@ -41,47 +41,41 @@ class NetworkPackage : public QObject Q_PROPERTY( QString id READ id WRITE setId ) Q_PROPERTY( QString type READ type WRITE setType ) Q_PROPERTY( QVariantMap body READ body WRITE setBody ) - Q_PROPERTY( int version READ version WRITE setVersion ) - Q_PROPERTY( bool isEncrypted READ isEncrypted WRITE setEncrypted ) public: + const static QCA::EncryptionAlgorithm EncryptionAlgorithm = QCA::EME_PKCS1v15; + const static int ProtocolVersion = 3; + NetworkPackage(const QString& type); - static void unserialize(const QByteArray& json, NetworkPackage* out); - QByteArray serialize() const; - - void encrypt(QCA::PublicKey& key); - void decrypt(QCA::PrivateKey& key, NetworkPackage* out) const; - static void createIdentityPackage(NetworkPackage*); - QString id() const { return mId; } + QByteArray serialize() const; + static bool unserialize(const QByteArray& json, NetworkPackage* out); + + void encrypt(QCA::PublicKey& key); + bool decrypt(QCA::PrivateKey& key, NetworkPackage* out) const; + + const QString& id() const { return mId; } const QString& type() const { return mType; } QVariantMap& body() { return mBody; } - int version() const { return mVersion; } - bool isEncrypted() const { return mEncrypted; } - //Get and set info from body. Note that id, type and version can not be accessed through these. + //Get and set info from body. Note that id and type can not be accessed through these. template T get(const QString& key, const T& defaultValue = default_arg::get()) const { return mBody.value(key,defaultValue).template value(); //Important note: Awesome template syntax is awesome } template void set(const QString& key, const T& value) { mBody[key] = QVariant(value); } - bool has(const QString& key) const { return mBody.contains(key); } private: - void setId(QString id) { mId = id; } + void setId(const QString& id) { mId = id; } void setType(const QString& t) { mType = t; } void setBody(const QVariantMap& b) { mBody = b; } - void setVersion(int v) { mVersion = v; } - void setEncrypted(bool b) { mEncrypted = b; } QString mId; QString mType; - bool mEncrypted; - QVariantMap mBody; //json in the Android side - int mVersion; + QVariantMap mBody; }; diff --git a/kded/networkpackagetypes.h b/kded/networkpackagetypes.h index 618a9bf76..915f6c103 100644 --- a/kded/networkpackagetypes.h +++ b/kded/networkpackagetypes.h @@ -24,6 +24,7 @@ #define PACKAGE_TYPE_IDENTITY QString("kdeconnect.identity") #define PACKAGE_TYPE_PAIR QString("kdeconnect.pair") #define PACKAGE_TYPE_PING QString("kdeconnect.ping") +#define PACKAGE_TYPE_ENCRYPTED QString("kdeconnect.encrypted") #define PACKAGE_TYPE_NOTIFICATION QString("kdeconnect.notification") #define PACKAGE_TYPE_BATTERY QString("kdeconnect.battery") #define PACKAGE_TYPE_TELEPHONY QString("kdeconnect.telephony") diff --git a/tests/networkpackagetests.cpp b/tests/networkpackagetests.cpp index 4090f7d56..b2f3096f8 100644 --- a/tests/networkpackagetests.cpp +++ b/tests/networkpackagetests.cpp @@ -63,14 +63,12 @@ void NetworkPackageTests::networkPackageTest() QCOMPARE( np.id(), np2.id() ); QCOMPARE( np.type(), np2.type() ); - QCOMPARE( np.version(), np2.version() ); QCOMPARE( np.body(), np2.body() ); - QByteArray json("{ \"id\": \"123\", \"type\": \"test\", \"body\": { \"testing\": true }, \"version\": 3 }"); + QByteArray json("{ \"id\": \"123\", \"type\": \"test\", \"body\": { \"testing\": true } }"); //qDebug() << json; NetworkPackage::unserialize(json,&np2); QCOMPARE( np2.id(), QString("123") ); - QCOMPARE( np2.version(), 3 ); QCOMPARE( (np2.get("testing")), true ); QCOMPARE( (np2.get("not_testing")), false ); QCOMPARE( (np2.get("not_testing",true)), true ); @@ -78,8 +76,6 @@ void NetworkPackageTests::networkPackageTest() //NetworkPackage::unserialize("this is not json",&np2); //QtTest::ignoreMessage(QtSystemMsg, "json_parser - syntax error found, forcing abort, Line 1 Column 0"); //QtTest::ignoreMessage(QtDebugMsg, "Unserialization error: 1 \"syntax error, unexpected string\""); - //QCOMPARE( np2.version(), -1 ); - } @@ -100,27 +96,26 @@ void NetworkPackageTests::networkPackageEncryptionTest() //Encrypt and decrypt np - QCOMPARE( original.isEncrypted(), false ); + QCOMPARE( original.type(), QString("com.test") ); original.encrypt(publicKey); - QCOMPARE( original.isEncrypted(), true ); + QCOMPARE( original.type(), PACKAGE_TYPE_ENCRYPTED ); original.decrypt(privateKey, &decrypted); - QCOMPARE( original.isEncrypted(), true ); - QCOMPARE( decrypted.isEncrypted(), false ); + QCOMPARE( original.type(), PACKAGE_TYPE_ENCRYPTED ); + QCOMPARE( decrypted.type(), QString("com.test") ); //np should be equal top np2 QCOMPARE( decrypted.id(), copy.id() ); QCOMPARE( decrypted.type(), copy.type() ); - QCOMPARE( decrypted.version(), copy.version() ); QCOMPARE( decrypted.body(), copy.body() ); //Test for long package encryption that need multi-chunk encryption - QByteArray json = "{ \"body\" : { \"nowPlaying\" : \"A really long song name - A really long artist name\", \"player\" : \"A really long player name\" }, \"id\" : \"A really long package id\", \"isEncrypted\" : false, \"type\" : \"kdeconnect.a_really_long_package_type\", \"version\" : 2 }\n"; + QByteArray json = "{ \"body\" : { \"nowPlaying\" : \"A really long song name - A really long artist name\", \"player\" : \"A really long player name\", \"the_meaning_of_life_the_universe_and_everything\" : \"42\" }, \"id\" : \"A really long package id\", \"type\" : \"kdeconnect.a_really_really_long_package_type\" }\n"; qDebug() << "EME_PKCS1_OAEP maximumEncryptSize" << publicKey.maximumEncryptSize(QCA::EME_PKCS1_OAEP); qDebug() << "EME_PKCS1v15 maximumEncryptSize" << publicKey.maximumEncryptSize(QCA::EME_PKCS1v15); - QCOMPARE( json.size() > publicKey.maximumEncryptSize(QCA::EME_PKCS1v15), true ); + QCOMPARE( json.size() > publicKey.maximumEncryptSize(NetworkPackage::EncryptionAlgorithm), true ); NetworkPackage::unserialize(json, &original); original.encrypt(publicKey);