Implemented encryption in NetworkPackage using QCA2

Fixed some bugs in the pairing process state machine
Keys are now stored in base64 in KConfig (was storing non-allowed chars)
Updated NetworkPackage tests to include encryption
Increased networkpackage version 1 -> 2
This commit is contained in:
Albert Vaca 2013-09-01 22:13:03 +02:00
parent 13589dfc0f
commit deeeb595b3
26 changed files with 240 additions and 119 deletions

View file

@ -18,4 +18,4 @@ add_subdirectory(kcm)
#add_subdirectory(kioslave) #add_subdirectory(kioslave)
add_subdirectory(plasmoid) add_subdirectory(plasmoid)
add_subdirectory(test) add_subdirectory(tests)

View file

@ -1,3 +1,8 @@
add_subdirectory(plugins)
find_package (QJSON REQUIRED)
find_package (QCA2 REQUIRED)
include_directories( include_directories(
${QJSON_INCLUDE_DIR} ${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR} ${QCA2_INCLUDE_DIR}
@ -21,13 +26,8 @@ set(kded_kdeconnect_SRCS
device.cpp device.cpp
) )
add_subdirectory(plugins)
kde4_add_plugin(kded_kdeconnect ${kded_kdeconnect_SRCS}) kde4_add_plugin(kded_kdeconnect ${kded_kdeconnect_SRCS})
find_package (QJSON REQUIRED)
find_package (QCA2 REQUIRED)
target_link_libraries(kded_kdeconnect target_link_libraries(kded_kdeconnect
${KDE4_KDECORE_LIBS} ${KDE4_KDECORE_LIBS}
${KDE4_KDEUI_LIBS} ${KDE4_KDEUI_LIBS}

View file

@ -57,10 +57,10 @@ Daemon::Daemon(QObject *parent, const QList<QVariant>&)
//http://delta.affinix.com/docs/qca/rsatest_8cpp-example.html //http://delta.affinix.com/docs/qca/rsatest_8cpp-example.html
QCA::PrivateKey privateKey = QCA::KeyGenerator().createRSA(1024); QCA::PrivateKey privateKey = QCA::KeyGenerator().createRSA(1024);
config->group("myself").writeEntry("privateKey", privateKey.toDER()); config->group("myself").writeEntry("privateKey", privateKey.toDER().toByteArray().toBase64());
QCA::PublicKey publicKey = privateKey.toPublicKey(); QCA::PublicKey publicKey = privateKey.toPublicKey();
config->group("myself").writeEntry("publicKey", publicKey.toDER()); config->group("myself").writeEntry("publicKey", publicKey.toDER().toBase64());
//TODO: Store key in a PEM file instead (KStandardDirs::locate("appdata", "private.pem")) //TODO: Store key in a PEM file instead (KStandardDirs::locate("appdata", "private.pem"))
} }

View file

@ -30,7 +30,7 @@ Device::Device(const QString& id)
m_deviceName = name; m_deviceName = name;
const QByteArray& key = data.readEntry<QByteArray>("publicKey",QByteArray()); const QByteArray& key = data.readEntry<QByteArray>("publicKey",QByteArray());
m_publicKey = QCA::RSAPublicKey::fromDER(key); m_publicKey = QCA::RSAPublicKey::fromDER(QByteArray::fromBase64(key));
m_pairStatus = Device::Paired; m_pairStatus = Device::Paired;
@ -57,12 +57,12 @@ Device::~Device()
} }
bool Device::hasPlugin(const QString& name) bool Device::hasPlugin(const QString& name) const
{ {
return m_plugins.contains(name); return m_plugins.contains(name);
} }
QStringList Device::loadedPlugins() QStringList Device::loadedPlugins() const
{ {
return m_plugins.keys(); return m_plugins.keys();
} }
@ -94,8 +94,8 @@ void Device::reloadPlugins()
} else { } else {
KdeConnectPlugin* plugin = loader->instantiatePluginForDevice(pluginName, this); KdeConnectPlugin* plugin = loader->instantiatePluginForDevice(pluginName, this);
connect(this, SIGNAL(receivedPackage(const NetworkPackage&)), connect(this, SIGNAL(receivedPackage(NetworkPackage)),
plugin, SLOT(receivePackage(const NetworkPackage&))); plugin, SLOT(receivePackage(NetworkPackage)));
newPluginMap[pluginName] = plugin; newPluginMap[pluginName] = plugin;
} }
@ -118,25 +118,16 @@ void Device::reloadPlugins()
} }
//TODO
QSslKey myPrivateKey() {
KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc");
const QString& key = config->group("myself").readEntry<QString>("privateKey",QString());
QSslKey privateKey(key.toAscii(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey);
qDebug() << "Valid public key:" << !privateKey.isNull();
return privateKey;
}
void Device::requestPair() void Device::requestPair()
{ {
if (m_pairStatus != NotPaired) { if (m_pairStatus == Paired) {
Q_EMIT pairingFailed(i18n("Already paired")); Q_EMIT pairingFailed(i18n("Already paired"));
return; return;
} }
if (m_pairStatus == Device::PairRequested) {
Q_EMIT pairingFailed(i18n("Pairing already requested for this device"));
return;
}
if (!isReachable()) { if (!isReachable()) {
Q_EMIT pairingFailed(i18n("Device not reachable")); Q_EMIT pairingFailed(i18n("Device not reachable"));
return; return;
@ -206,7 +197,8 @@ void Device::addLink(DeviceLink* link)
//the old one before this is called), so we do not have to worry about destroying old links. //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! //Actually, we should not destroy them or the provider will store an invalid ref!
connect(link, SIGNAL(receivedPackage(NetworkPackage)), this, SLOT(privateReceivedPackage(NetworkPackage))); connect(link, SIGNAL(receivedPackage(NetworkPackage)),
this, SLOT(privateReceivedPackage(NetworkPackage)));
qSort(m_deviceLinks.begin(), m_deviceLinks.end(), lessThan); qSort(m_deviceLinks.begin(), m_deviceLinks.end(), lessThan);
@ -237,12 +229,12 @@ void Device::removeLink(DeviceLink* link)
} }
} }
bool Device::sendPackage(const NetworkPackage& np) const bool Device::sendPackage(NetworkPackage& np)
{ {
//Maybe we could block here any package that is not an identity or a pairing package
if (isPaired()) { if (isPaired()) {
np.encrypt(m_publicKey);
} else {
//Maybe we could block here any package that is not an identity or a pairing package to prevent sending non encrypted data
} }
Q_FOREACH(DeviceLink* dl, m_deviceLinks) { Q_FOREACH(DeviceLink* dl, m_deviceLinks) {
@ -256,21 +248,27 @@ bool Device::sendPackage(const NetworkPackage& np) const
void Device::privateReceivedPackage(const NetworkPackage& np) void Device::privateReceivedPackage(const NetworkPackage& np)
{ {
if (np.type() == PACKAGE_TYPE_PAIR) { if (np.type() == PACKAGE_TYPE_PAIR) {
qDebug() << "Pair package"; qDebug() << "Pair package";
bool wantsPair = np.get<bool>("pair"); bool wantsPair = np.get<bool>("pair");
if (wantsPair == isPaired()) { if (wantsPair == isPaired()) {
qDebug() << "Already" << (wantsPair? "paired":"unpaired"); qDebug() << "Already" << (wantsPair? "paired":"unpaired");
if (m_pairStatus == Device::PairRequested) {
m_pairStatus = Device::NotPaired;
pairingTimer.stop();
Q_EMIT pairingFailed(i18n("Canceled by other peer"));
}
return; return;
} }
KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc");
if (wantsPair) { if (wantsPair) {
const QByteArray& key = np.get<QByteArray>("publicKey");
m_publicKey = QCA::RSAPublicKey::fromDER(QByteArray::fromBase64(key));
if (m_pairStatus == Device::PairRequested) { //We started pairing if (m_pairStatus == Device::PairRequested) { //We started pairing
qDebug() << "Pair answer"; qDebug() << "Pair answer";
@ -279,10 +277,10 @@ void Device::privateReceivedPackage(const NetworkPackage& np)
pairingTimer.stop(); pairingTimer.stop();
//Store as trusted device //Store as trusted device
const QByteArray& key = np.get<QByteArray>("publicKey"); KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc");
config->group("devices").group(id()).writeEntry("publicKey",key); config->group("devices").group(id()).writeEntry("publicKey",key);
config->group("devices").group(id()).writeEntry("name",name()); config->group("devices").group(id()).writeEntry("name",name());
m_publicKey = QCA::RSAPublicKey::fromDER(key); m_publicKey = QCA::RSAPublicKey::fromDER(QByteArray::fromBase64(key));
Q_EMIT pairingSuccesful(); Q_EMIT pairingSuccesful();
@ -290,9 +288,6 @@ void Device::privateReceivedPackage(const NetworkPackage& np)
qDebug() << "Pair request"; qDebug() << "Pair request";
const QByteArray& key = np.get<QByteArray>("publicKey");
m_publicKey = QCA::RSAPublicKey::fromDER(key);
KNotification* notification = new KNotification("pingReceived"); //KNotification::Persistent KNotification* notification = new KNotification("pingReceived"); //KNotification::Persistent
notification->setPixmap(KIcon("dialog-information").pixmap(48, 48)); notification->setPixmap(KIcon("dialog-information").pixmap(48, 48));
notification->setComponentData(KComponentData("kdeconnect", "kdeconnect")); notification->setComponentData(KComponentData("kdeconnect", "kdeconnect"));
@ -309,10 +304,12 @@ void Device::privateReceivedPackage(const NetworkPackage& np)
qDebug() << "Unpair request"; qDebug() << "Unpair request";
if (m_pairStatus == PairRequested) { if (m_pairStatus == PairRequested) {
m_pairStatus = Device::NotPaired;
pairingTimer.stop(); pairingTimer.stop();
Q_EMIT pairingFailed(i18n("Canceled by other peer")); Q_EMIT pairingFailed(i18n("Canceled by other peer"));
} } else if (m_pairStatus == Paired) {
unpair(); unpair();
}
} }
@ -323,9 +320,27 @@ void Device::privateReceivedPackage(const NetworkPackage& np)
} else { } else {
//Forward signal 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); Q_EMIT receivedPackage(np);
} else {
//TODO: Do not read the key every time
KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc");
const QByteArray& key = config->group("myself").readEntry<QByteArray>("privateKey",QByteArray());
QCA::PrivateKey privateKey = QCA::PrivateKey::fromDER(QByteArray::fromBase64(key));
//Emit decrypted package
NetworkPackage decryptedNp("");
np.decrypt(privateKey, &decryptedNp);
Q_EMIT receivedPackage(decryptedNp);
}
} }
} }
@ -348,7 +363,7 @@ void Device::acceptPairing()
} }
//Store as trusted device //Store as trusted device
config->group("devices").group(id()).writeEntry("publicKey", m_publicKey.toDER()); config->group("devices").group(id()).writeEntry("publicKey", m_publicKey.toDER().toBase64());
config->group("devices").group(id()).writeEntry("name", name()); config->group("devices").group(id()).writeEntry("name", name());
reloadPlugins(); //This will load plugins reloadPlugins(); //This will load plugins

View file

@ -71,14 +71,14 @@ public:
Q_SCRIPTABLE QStringList availableLinks() const; Q_SCRIPTABLE QStringList availableLinks() const;
Q_SCRIPTABLE bool isReachable() const { return !m_deviceLinks.empty(); } Q_SCRIPTABLE bool isReachable() const { return !m_deviceLinks.empty(); }
Q_SCRIPTABLE QStringList loadedPlugins(); Q_SCRIPTABLE QStringList loadedPlugins() const;
Q_SCRIPTABLE bool hasPlugin(const QString& name); Q_SCRIPTABLE bool hasPlugin(const QString& name) const;
//Send and receive //Send and receive
Q_SIGNALS: Q_SIGNALS:
void receivedPackage(const NetworkPackage& np); void receivedPackage(const NetworkPackage& np) const;
public Q_SLOTS: public Q_SLOTS:
virtual bool sendPackage(const NetworkPackage& np) const; virtual bool sendPackage(NetworkPackage& np);
//Dbus operations //Dbus operations
public Q_SLOTS: public Q_SLOTS:
@ -110,6 +110,7 @@ private:
QMap<QString, KdeConnectPlugin*> m_plugins; QMap<QString, KdeConnectPlugin*> m_plugins;
QTimer pairingTimer; QTimer pairingTimer;
}; };
Q_DECLARE_METATYPE(Device*) Q_DECLARE_METATYPE(Device*)

View file

@ -39,10 +39,10 @@ public:
const QString& deviceId() { return mDeviceId; } const QString& deviceId() { return mDeviceId; }
LinkProvider* provider() { return mLinkProvider; } LinkProvider* provider() { return mLinkProvider; }
virtual bool sendPackage(const NetworkPackage& np) const = 0; virtual bool sendPackage(const NetworkPackage& np) = 0;
signals: Q_SIGNALS:
void receivedPackage(const NetworkPackage& np) const; void receivedPackage(const NetworkPackage& np);
private: private:
QString mDeviceId; QString mDeviceId;

View file

@ -51,7 +51,7 @@ LanDeviceLink::LanDeviceLink(const QString& d, LinkProvider* a, QTcpSocket* sock
this, SLOT(dataReceived())); this, SLOT(dataReceived()));
} }
bool LanDeviceLink::sendPackage(const NetworkPackage& np) const bool LanDeviceLink::sendPackage(const NetworkPackage& np)
{ {
int written = mSocket->write(np.serialize()); int written = mSocket->write(np.serialize());
return written != -1; return written != -1;

View file

@ -38,7 +38,7 @@ class LanDeviceLink
public: public:
LanDeviceLink(const QString& d, LinkProvider* a, QTcpSocket* socket); LanDeviceLink(const QString& d, LinkProvider* a, QTcpSocket* socket);
bool sendPackage(const NetworkPackage& np) const; bool sendPackage(const NetworkPackage& np);
private Q_SLOTS: private Q_SLOTS:
void dataReceived(); void dataReceived();

View file

@ -28,7 +28,7 @@ LoopbackDeviceLink::LoopbackDeviceLink(const QString& deviceId, LoopbackLinkProv
} }
bool LoopbackDeviceLink::sendPackage(const NetworkPackage& toSend) const bool LoopbackDeviceLink::sendPackage(const NetworkPackage& toSend)
{ {
NetworkPackage toReceive(""); NetworkPackage toReceive("");
NetworkPackage::unserialize(toSend.serialize(), &toReceive); NetworkPackage::unserialize(toSend.serialize(), &toReceive);

View file

@ -18,8 +18,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef ECHODEVICELINK_H #ifndef LOOPBACKDEVICELINK_H
#define ECHODEVICELINK_H #define LOOPBACKDEVICELINK_H
#include "devicelink.h" #include "devicelink.h"
class LoopbackLinkProvider; class LoopbackLinkProvider;
@ -31,8 +32,8 @@ class LoopbackDeviceLink
public: public:
LoopbackDeviceLink(const QString& d, LoopbackLinkProvider* a); LoopbackDeviceLink(const QString& d, LoopbackLinkProvider* a);
bool sendPackage(const NetworkPackage& np) const; bool sendPackage(const NetworkPackage& np);
}; };
#endif // ECHODEVICELINK_H #endif

View file

@ -55,7 +55,7 @@ Q_SIGNALS:
//NOTE: The provider will to destroy the DeviceLink when it's no longer accessible, //NOTE: The provider will to destroy the DeviceLink when it's no longer accessible,
// and every user should listen to the destroyed signal to remove its references. // and every user should listen to the destroyed signal to remove its references.
// That's the reason because there is no "onConnectionLost". // That's the reason because there is no "onConnectionLost".
void onConnectionReceived(const NetworkPackage& identityPackage, DeviceLink*); void onConnectionReceived(const NetworkPackage& identityPackage, DeviceLink*) const;
}; };

View file

@ -32,15 +32,15 @@
#include <qjson/serializer.h> #include <qjson/serializer.h>
#include <qjson/qobjecthelper.h> #include <qjson/qobjecthelper.h>
#include "encryptednetworkpackage.h" const static int CURRENT_PACKAGE_VERSION = 2;
const static int CURRENT_PACKAGE_VERSION = 1;
NetworkPackage::NetworkPackage(const QString& type) NetworkPackage::NetworkPackage(const QString& type)
{ {
mId = QDateTime::currentMSecsSinceEpoch(); mId = QString::number(QDateTime::currentMSecsSinceEpoch());
mType = type; mType = type;
mBody = QVariantMap();
mVersion = CURRENT_PACKAGE_VERSION; mVersion = CURRENT_PACKAGE_VERSION;
mEncrypted = false;
} }
QByteArray NetworkPackage::serialize() const QByteArray NetworkPackage::serialize() const
@ -80,11 +80,6 @@ void NetworkPackage::unserialize(const QByteArray& a, NetworkPackage* np)
} }
//QVariant -> Object //QVariant -> Object
//NetworkPackage np;
//QJSon json(a);
//np.mId = json["id"];
//np.mType = json["type"];
//np.mBody = json["body"];
QJson::QObjectHelper::qvariant2qobject(variant,np); QJson::QObjectHelper::qvariant2qobject(variant,np);
if (np->version() > CURRENT_PACKAGE_VERSION) { if (np->version() > CURRENT_PACKAGE_VERSION) {
@ -93,6 +88,34 @@ void NetworkPackage::unserialize(const QByteArray& a, NetworkPackage* np)
} }
void NetworkPackage::encrypt (QCA::PublicKey& key)
{
qDebug() << key.toDER() << key.canEncrypt();
QByteArray serialized = serialize();
QByteArray data = key.encrypt(serialized, QCA::EME_PKCS1v15).toByteArray();
mId = QString::number(QDateTime::currentMSecsSinceEpoch());
mType = "kdeconnect.encrypted";
mBody = QVariantMap();
mBody["data"] = data.toBase64();
mVersion = CURRENT_PACKAGE_VERSION;
mEncrypted = true;
}
void NetworkPackage::decrypt (QCA::PrivateKey& key, NetworkPackage* out) const
{
QByteArray encryptedJson = QByteArray::fromBase64(get<QByteArray>("data"));
QCA::SecureArray decryptedJson;
key.decrypt(encryptedJson, &decryptedJson, QCA::EME_PKCS1v15);
unserialize(decryptedJson.toByteArray(), out);
}
void NetworkPackage::createIdentityPackage(NetworkPackage* np) void NetworkPackage::createIdentityPackage(NetworkPackage* np)
{ {
KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc"); KSharedConfigPtr config = KSharedConfig::openConfig("kdeconnectrc");
@ -106,11 +129,4 @@ void NetworkPackage::createIdentityPackage(NetworkPackage* np)
//qDebug() << "createIdentityPackage" << np->serialize(); //qDebug() << "createIdentityPackage" << np->serialize();
} }
EncryptedNetworkPackage NetworkPackage::encrypt ( const QSslKey& key ) const
{
QByteArray serialized = serialize();
return EncryptedNetworkPackage();
}

View file

@ -27,7 +27,7 @@
#include <QString> #include <QString>
#include <QVariant> #include <QVariant>
#include <QStringList> #include <QStringList>
#include <QSslKey> #include <QtCrypto>
#include <qjson/parser.h> #include <qjson/parser.h>
@ -38,24 +38,29 @@ class EncryptedNetworkPackage;
class NetworkPackage : public QObject class NetworkPackage : public QObject
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY( long id READ id WRITE setId ) Q_PROPERTY( QString id READ id WRITE setId )
Q_PROPERTY( QString type READ type WRITE setType ) Q_PROPERTY( QString type READ type WRITE setType )
Q_PROPERTY( QVariantMap body READ body WRITE setBody ) Q_PROPERTY( QVariantMap body READ body WRITE setBody )
Q_PROPERTY( int version READ version WRITE setVersion ) Q_PROPERTY( int version READ version WRITE setVersion )
Q_PROPERTY( bool isEncrypted READ isEncrypted WRITE setEncrypted )
public: public:
NetworkPackage(const QString& type); NetworkPackage(const QString& type);
static void unserialize(const QByteArray&, NetworkPackage*); static void unserialize(const QByteArray& json, NetworkPackage* out);
QByteArray serialize() const; QByteArray serialize() const;
void encrypt(QCA::PublicKey& key);
void decrypt(QCA::PrivateKey& key, NetworkPackage* out) const;
static void createIdentityPackage(NetworkPackage*); static void createIdentityPackage(NetworkPackage*);
long id() const { return mId; } QString id() const { return mId; }
const QString& type() const { return mType; } const QString& type() const { return mType; }
QVariantMap& body() { return mBody; } QVariantMap& body() { return mBody; }
int version() const { return mVersion; } 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, type and version can not be accessed through these.
template<typename T> T get(const QString& key, const T& defaultValue = default_arg<T>::get()) const { template<typename T> T get(const QString& key, const T& defaultValue = default_arg<T>::get()) const {
@ -65,16 +70,16 @@ public:
bool has(const QString& key) const { return mBody.contains(key); } bool has(const QString& key) const { return mBody.contains(key); }
EncryptedNetworkPackage encrypt(const QSslKey& key) const;
private: private:
void setId(long id) { mId = id; } void setId(QString id) { mId = id; }
void setType(const QString& t) { mType = t; } void setType(const QString& t) { mType = t; }
void setBody(const QVariantMap& b) { mBody = b; } void setBody(const QVariantMap& b) { mBody = b; }
void setVersion(int v) { mVersion = v; } void setVersion(int v) { mVersion = v; }
void setEncrypted(bool b) { mEncrypted = b; }
long mId; QString mId;
QString mType; QString mType;
bool mEncrypted;
QVariantMap mBody; //json in the Android side QVariantMap mBody; //json in the Android side
int mVersion; int mVersion;

View file

@ -2,6 +2,11 @@ find_package(KDE4 REQUIRED)
find_package(QJSON REQUIRED) find_package(QJSON REQUIRED)
find_package(QCA2 REQUIRED) find_package(QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
)
include(KDE4Defaults) include(KDE4Defaults)
include_directories(${KDE4_INCLUDES}) include_directories(${KDE4_INCLUDES})

View file

@ -2,6 +2,11 @@ find_package(KDE4 REQUIRED)
find_package(QJSON REQUIRED) find_package(QJSON REQUIRED)
find_package(QCA2 REQUIRED) find_package(QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
)
include(KDE4Defaults) include(KDE4Defaults)
include_directories(${KDE4_INCLUDES}) include_directories(${KDE4_INCLUDES})

View file

@ -2,6 +2,11 @@ find_package(KDE4 REQUIRED)
find_package(QJSON REQUIRED) find_package(QJSON REQUIRED)
find_package(QCA2 REQUIRED) find_package(QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
)
include(KDE4Defaults) include(KDE4Defaults)
include_directories(${KDE4_INCLUDES}) include_directories(${KDE4_INCLUDES})

View file

@ -49,6 +49,10 @@ public Q_SLOTS:
private: private:
Device* mDevice; Device* mDevice;
// The Initializer object sets things up, and also does cleanup when it goes out of scope
// Since the plugins use their own memory, they need their own initializer in order to send encrypted packages
QCA::Initializer init;
}; };
#endif #endif

View file

@ -2,6 +2,11 @@ find_package(KDE4 REQUIRED)
find_package(QJSON REQUIRED) find_package(QJSON REQUIRED)
find_package(QCA2 REQUIRED) find_package(QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
)
include(KDE4Defaults) include(KDE4Defaults)
include_directories(${KDE4_INCLUDES}) include_directories(${KDE4_INCLUDES})

View file

@ -2,6 +2,11 @@ find_package(KDE4 REQUIRED)
find_package(QJSON REQUIRED) find_package(QJSON REQUIRED)
find_package(QCA2 REQUIRED) find_package(QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
)
include(KDE4Defaults) include(KDE4Defaults)
include_directories(${KDE4_INCLUDES}) include_directories(${KDE4_INCLUDES})

View file

@ -2,6 +2,11 @@ find_package(KDE4 REQUIRED)
find_package(QJSON REQUIRED) find_package(QJSON REQUIRED)
find_package(QCA2 REQUIRED) find_package(QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
)
include(KDE4Defaults) include(KDE4Defaults)
include_directories(${KDE4_INCLUDES}) include_directories(${KDE4_INCLUDES})

View file

@ -2,6 +2,11 @@ find_package(KDE4 REQUIRED)
find_package(QJSON REQUIRED) find_package(QJSON REQUIRED)
find_package(QCA2 REQUIRED) find_package(QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
)
include(KDE4Defaults) include(KDE4Defaults)
include_directories(${KDE4_INCLUDES}) include_directories(${KDE4_INCLUDES})

View file

@ -2,6 +2,11 @@ find_package(KDE4 REQUIRED)
find_package(QJSON REQUIRED) find_package(QJSON REQUIRED)
find_package(QCA2 REQUIRED) find_package(QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
)
include(KDE4Defaults) include(KDE4Defaults)
include_directories(${KDE4_INCLUDES}) include_directories(${KDE4_INCLUDES})

View file

@ -1,18 +0,0 @@
set(kded_kdeconnect_tests_SRCS
../daemon/networkpackage.cpp
backendtests.cpp
)
kde4_add_unit_test(kded_kdeconnect_tests ${kded_kdeconnect_tests_SRCS})
target_link_libraries(kded_kdeconnect_tests
${KDE4_KDECORE_LIBS}
${KDE4_KDEUI_LIBS}
kdnssd
qjson
${QT_QTTEST_LIBRARY}
${QT_QTNETWORK_LIBRARY}
)
add_test(kded_kdeconnect_tests ${CMAKE_CURRENT_BINARY_DIR}/kded_kdeconnect_tests)

25
tests/CMakeLists.txt Normal file
View file

@ -0,0 +1,25 @@
set( EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR} )
find_package(QJSON REQUIRED)
find_package(QCA2 REQUIRED)
include_directories(
${QJSON_INCLUDE_DIR}
${QCA2_INCLUDE_DIR}
)
set(kdeconnect_tests_SRCS
../daemon/networkpackage.cpp
networkpackagetests.cpp
)
kde4_add_unit_test(kdeconnect_tests ${kdeconnect_tests_SRCS})
target_link_libraries(kdeconnect_tests
${KDE4_KDECORE_LIBS}
${KDE4_KDEUI_LIBS}
${QJSON_LIBRARIES}
${QCA2_LIBRARIES}
${QT_QTTEST_LIBRARY}
${QT_QTNETWORK_LIBRARY}
)

View file

@ -18,21 +18,21 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#include "backendtests.h" #include "networkpackagetests.h"
#include "../daemon/networkpackage.h" #include "../daemon/networkpackage.h"
#include <qtest_kde.h> #include <qtest_kde.h>
#include <QtTest> #include <QtTest>
QTEST_KDEMAIN(BackendTests, NoGUI); QTEST_KDEMAIN(NetworkPackageTests, NoGUI);
void BackendTests::initTestCase() void NetworkPackageTests::initTestCase()
{ {
// Called before the first testfunction is executed // Called before the first testfunction is executed
} }
void BackendTests::dummyTest() void NetworkPackageTests::dummyTest()
{ {
QDate date; QDate date;
date.setYMD( 1967, 3, 11 ); date.setYMD( 1967, 3, 11 );
@ -41,7 +41,7 @@ void BackendTests::dummyTest()
QCOMPARE( QDate::longMonthName(date.month()), QString("March") ); QCOMPARE( QDate::longMonthName(date.month()), QString("March") );
} }
void BackendTests::networkPackageTest() void NetworkPackageTests::networkPackageTest()
{ {
NetworkPackage np("com.test"); NetworkPackage np("com.test");
@ -64,10 +64,10 @@ void BackendTests::networkPackageTest()
QCOMPARE( np.version(), np2.version() ); QCOMPARE( np.version(), np2.version() );
QCOMPARE( np.body(), np2.body() ); 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 }, \"version\": 3 }");
//qDebug() << json; //qDebug() << json;
NetworkPackage::unserialize(json,&np2); NetworkPackage::unserialize(json,&np2);
QCOMPARE( np2.id(), long(123) ); QCOMPARE( np2.id(), QString("123") );
QCOMPARE( np2.version(), 3 ); QCOMPARE( np2.version(), 3 );
QCOMPARE( (np2.get<bool>("testing")), true ); QCOMPARE( (np2.get<bool>("testing")), true );
QCOMPARE( (np2.get<bool>("not_testing")), false ); QCOMPARE( (np2.get<bool>("not_testing")), false );
@ -78,22 +78,53 @@ void BackendTests::networkPackageTest()
//QtTest::ignoreMessage(QtDebugMsg, "Unserialization error: 1 \"syntax error, unexpected string\""); //QtTest::ignoreMessage(QtDebugMsg, "Unserialization error: 1 \"syntax error, unexpected string\"");
//QCOMPARE( np2.version(), -1 ); //QCOMPARE( np2.version(), -1 );
}
void NetworkPackageTests::networkPackageEncryptionTest()
{
NetworkPackage original("com.test");
original.set("hello","hola");
NetworkPackage copy("");
NetworkPackage::unserialize(original.serialize(), &copy);
NetworkPackage decrypted("");
QCA::Initializer init;
QCA::PrivateKey privateKey = QCA::KeyGenerator().createRSA(1024);
QCA::PublicKey publicKey = privateKey.toPublicKey();
//Encrypt and decrypt np
QCOMPARE( original.isEncrypted(), false );
original.encrypt(publicKey);
QCOMPARE( original.isEncrypted(), true );
original.decrypt(privateKey, &decrypted);
QCOMPARE( original.isEncrypted(), true );
QCOMPARE( decrypted.isEncrypted(), false );
//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() );
} }
void BackendTests::cleanupTestCase() void NetworkPackageTests::cleanupTestCase()
{ {
// Called after the last testfunction was executed // Called after the last testfunction was executed
} }
void BackendTests::init() void NetworkPackageTests::init()
{ {
// Called before each testfunction is executed // Called before each testfunction is executed
} }
void BackendTests::cleanup() void NetworkPackageTests::cleanup()
{ {
// Called after every testfunction // Called after every testfunction
} }
#include "backendtests.moc"

View file

@ -18,12 +18,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
#ifndef BACKENDTESTS_H #ifndef NETWORKPACKAGETESTS_H
#define BACKENDTESTS_H #define NETWORKPACKAGETESTS_H
#include <QObject> #include <QObject>
class BackendTests : public QObject class NetworkPackageTests : public QObject
{ {
Q_OBJECT Q_OBJECT
@ -32,6 +32,7 @@ private Q_SLOTS:
void dummyTest(); void dummyTest();
void networkPackageTest(); void networkPackageTest();
void networkPackageEncryptionTest();
void cleanupTestCase(); void cleanupTestCase();
@ -40,4 +41,4 @@ private Q_SLOTS:
}; };
#endif // BACKENDTESTS_H #endif