2015-08-12 19:12:27 +01:00
/**
* Copyright 2015 Vineet Garg < grgvineet @ gmail . com >
*
* 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 of
* the License or ( at your option ) version 3 or any later version
* accepted by the membership of KDE e . V . ( or its successor approved
* by the membership of KDE e . V . ) , which shall act as a proxy
* defined in Section 14 of 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/>.
*/
// This class tests the behaviour of the class LanLinkProvider, be sure to kill process kdeconnectd to avoid any port binding issues
# include "../core/backends/lan/lanlinkprovider.h"
# include "../core/backends/lan/server.h"
# include "../core/backends/lan/socketlinereader.h"
# include "../core/kdeconnectconfig.h"
# include <QAbstractSocket>
# include <QSslSocket>
# include <QtTest>
2015-12-01 15:25:34 +00:00
# include <QSslKey>
2015-08-12 19:12:27 +01:00
# include <QUdpSocket>
2019-02-12 21:49:00 +00:00
# include <QtCrypto>
2015-08-12 19:12:27 +01:00
/*
2018-03-04 19:48:51 +00:00
* This class tests the working of LanLinkProvider under different conditions that when identity packet is received over TCP , over UDP and same when the device is paired .
2015-08-12 19:12:27 +01:00
* It depends on KdeConnectConfig since LanLinkProvider internally uses it .
*/
class LanLinkProviderTest : public QObject
{
Q_OBJECT
2015-12-02 17:49:00 +00:00
public :
explicit LanLinkProviderTest ( )
2017-09-03 20:39:44 +01:00
: m_lanLinkProvider ( true ) {
2015-12-02 17:49:00 +00:00
QStandardPaths : : setTestModeEnabled ( true ) ;
}
2015-08-12 19:12:27 +01:00
public Q_SLOTS :
void initTestCase ( ) ;
private Q_SLOTS :
2018-03-04 19:48:51 +00:00
void pairedDeviceTcpPacketReceived ( ) ;
void pairedDeviceUdpPacketReceived ( ) ;
2015-08-12 19:12:27 +01:00
2018-03-04 19:48:51 +00:00
void unpairedDeviceTcpPacketReceived ( ) ;
void unpairedDeviceUdpPacketReceived ( ) ;
2015-08-12 19:12:27 +01:00
private :
2017-02-14 22:03:59 +00:00
const int TEST_PORT = 8520 ;
2015-08-12 19:12:27 +01:00
// Add some private fields here
2017-09-03 20:39:44 +01:00
LanLinkProvider m_lanLinkProvider ;
Server * m_server ;
SocketLineReader * m_reader ;
QUdpSocket * m_udpSocket ;
2018-03-04 19:48:51 +00:00
QString m_identityPacket ;
2015-08-12 19:12:27 +01:00
// Attributes for test device
2017-09-03 20:39:44 +01:00
QString m_deviceId ;
QString m_name ;
QCA : : PrivateKey m_privateKey ;
QSslCertificate m_certificate ;
2015-08-12 19:12:27 +01:00
QSslCertificate generateCertificate ( QString & , QCA : : PrivateKey & ) ;
void addTrustedDevice ( ) ;
void removeTrustedDevice ( ) ;
2017-09-03 20:39:44 +01:00
void setSocketAttributes ( QSslSocket * socket ) ;
2018-03-04 19:48:51 +00:00
void testIdentityPacket ( QByteArray & identityPacket ) ;
2015-08-12 19:19:15 +01:00
2015-08-12 19:12:27 +01:00
} ;
void LanLinkProviderTest : : initTestCase ( )
{
removeTrustedDevice ( ) ; // Remove trusted device if left by chance by any test
2017-09-03 20:39:44 +01:00
m_deviceId = QStringLiteral ( " testdevice " ) ;
m_name = QStringLiteral ( " Test Device " ) ;
m_privateKey = QCA : : KeyGenerator ( ) . createRSA ( 2048 ) ;
m_certificate = generateCertificate ( m_deviceId , m_privateKey ) ;
2015-08-12 19:12:27 +01:00
2017-09-03 20:39:44 +01:00
m_lanLinkProvider . onStart ( ) ;
2015-08-12 19:12:27 +01:00
2018-03-04 19:48:51 +00:00
m_identityPacket = QStringLiteral ( " { \" id \" :1439365924847, \" type \" : \" kdeconnect.identity \" , \" body \" :{ \" deviceId \" : \" testdevice \" , \" deviceName \" : \" Test Device \" , \" protocolVersion \" :6, \" deviceType \" : \" phone \" , \" tcpPort \" : " ) + QString : : number ( TEST_PORT ) + QStringLiteral ( " }} " ) ;
2015-08-12 19:12:27 +01:00
}
2018-03-04 19:48:51 +00:00
void LanLinkProviderTest : : pairedDeviceTcpPacketReceived ( )
2015-08-12 19:12:27 +01:00
{
KdeConnectConfig * kcc = KdeConnectConfig : : instance ( ) ;
addTrustedDevice ( ) ;
QUdpSocket * mUdpServer = new QUdpSocket ;
2017-02-14 22:03:59 +00:00
bool b = mUdpServer - > bind ( QHostAddress : : LocalHost , LanLinkProvider : : UDP_PORT , QUdpSocket : : ShareAddress ) ;
2015-12-02 17:49:00 +00:00
QVERIFY ( b ) ;
2015-08-12 19:12:27 +01:00
2015-09-11 17:21:18 +01:00
QSignalSpy spy ( mUdpServer , SIGNAL ( readyRead ( ) ) ) ;
2017-09-03 20:39:44 +01:00
m_lanLinkProvider . onNetworkChange ( ) ;
2015-12-02 17:49:00 +00:00
QVERIFY ( ! spy . isEmpty ( ) | | spy . wait ( ) ) ;
2015-08-12 19:12:27 +01:00
QByteArray datagram ;
datagram . resize ( mUdpServer - > pendingDatagramSize ( ) ) ;
QHostAddress sender ;
mUdpServer - > readDatagram ( datagram . data ( ) , datagram . size ( ) , & sender ) ;
2018-03-04 19:48:51 +00:00
testIdentityPacket ( datagram ) ;
2015-08-12 19:12:27 +01:00
QJsonDocument jsonDocument = QJsonDocument : : fromJson ( datagram ) ;
2016-11-26 14:38:08 +00:00
QJsonObject body = jsonDocument . object ( ) . value ( QStringLiteral ( " body " ) ) . toObject ( ) ;
int tcpPort = body . value ( QStringLiteral ( " tcpPort " ) ) . toInt ( ) ;
2015-08-12 19:12:27 +01:00
QSslSocket socket ;
2015-09-11 17:21:18 +01:00
QSignalSpy spy2 ( & socket , SIGNAL ( connected ( ) ) ) ;
2015-08-12 19:12:27 +01:00
socket . connectToHost ( sender , tcpPort ) ;
2015-09-11 17:21:18 +01:00
QVERIFY ( spy2 . wait ( ) ) ;
2015-08-12 19:12:27 +01:00
QVERIFY2 ( socket . isOpen ( ) , " Socket disconnected immediately " ) ;
2018-03-04 19:48:51 +00:00
socket . write ( m_identityPacket . toLatin1 ( ) ) ;
2015-08-12 19:12:27 +01:00
socket . waitForBytesWritten ( 2000 ) ;
2015-09-11 17:21:18 +01:00
QSignalSpy spy3 ( & socket , SIGNAL ( encrypted ( ) ) ) ;
2015-08-12 19:12:27 +01:00
setSocketAttributes ( & socket ) ;
socket . addCaCertificate ( kcc - > certificate ( ) ) ;
socket . setPeerVerifyMode ( QSslSocket : : VerifyPeer ) ;
socket . setPeerVerifyName ( kcc - > name ( ) ) ;
socket . startServerEncryption ( ) ;
2015-09-11 17:21:18 +01:00
QVERIFY ( spy3 . wait ( ) ) ;
2015-08-12 19:12:27 +01:00
QCOMPARE ( socket . sslErrors ( ) . size ( ) , 0 ) ;
QVERIFY2 ( socket . isValid ( ) , " Server socket disconnected " ) ;
QVERIFY2 ( socket . isEncrypted ( ) , " Server socket not yet encrypted " ) ;
QVERIFY2 ( ! socket . peerCertificate ( ) . isNull ( ) , " Peer certificate is null " ) ;
removeTrustedDevice ( ) ;
delete mUdpServer ;
}
2018-03-04 19:48:51 +00:00
void LanLinkProviderTest : : pairedDeviceUdpPacketReceived ( )
2015-08-12 19:12:27 +01:00
{
KdeConnectConfig * kcc = KdeConnectConfig : : instance ( ) ;
addTrustedDevice ( ) ;
2017-09-03 20:39:44 +01:00
m_server = new Server ( this ) ;
m_udpSocket = new QUdpSocket ( this ) ;
2015-08-12 19:12:27 +01:00
2017-09-03 20:39:44 +01:00
m_server - > listen ( QHostAddress : : LocalHost , TEST_PORT ) ;
2015-08-12 19:12:27 +01:00
2017-09-03 20:39:44 +01:00
QSignalSpy spy ( m_server , SIGNAL ( newConnection ( ) ) ) ;
2015-08-12 19:12:27 +01:00
2018-03-04 19:48:51 +00:00
qint64 bytesWritten = m_udpSocket - > writeDatagram ( m_identityPacket . toLatin1 ( ) , QHostAddress : : LocalHost , LanLinkProvider : : UDP_PORT ) ; // write an identity packet to udp socket here, we do not broadcast it here
QCOMPARE ( bytesWritten , m_identityPacket . size ( ) ) ;
2015-08-12 19:12:27 +01:00
// We should have an incoming connection now, wait for incoming connection
2015-12-02 17:49:00 +00:00
QVERIFY ( ! spy . isEmpty ( ) | | spy . wait ( ) ) ;
2015-08-12 19:12:27 +01:00
2017-09-03 20:39:44 +01:00
QSslSocket * serverSocket = m_server - > nextPendingConnection ( ) ;
2015-08-12 19:12:27 +01:00
QVERIFY2 ( serverSocket ! = 0 , " Server socket is null " ) ;
QVERIFY2 ( serverSocket - > isOpen ( ) , " Server socket already closed " ) ;
2017-09-03 20:39:44 +01:00
m_reader = new SocketLineReader ( serverSocket , this ) ;
QSignalSpy spy2 ( m_reader , SIGNAL ( readyRead ( ) ) ) ;
2015-09-11 17:21:18 +01:00
QVERIFY ( spy2 . wait ( ) ) ;
2015-08-12 19:12:27 +01:00
2018-03-04 19:48:51 +00:00
QByteArray receivedPacket = m_reader - > readLine ( ) ;
testIdentityPacket ( receivedPacket ) ;
2018-10-07 19:23:20 +01:00
// Received identity packet from LanLinkProvider now start ssl
2015-08-12 19:12:27 +01:00
2015-09-11 17:21:18 +01:00
QSignalSpy spy3 ( serverSocket , SIGNAL ( encrypted ( ) ) ) ;
QVERIFY ( connect ( serverSocket , static_cast < void ( QAbstractSocket : : * ) ( QAbstractSocket : : SocketError ) > ( & QSslSocket : : error ) ,
this , [ ] ( QAbstractSocket : : SocketError error ) { qDebug ( ) < < " error: " < < error ; } ) ) ;
2015-08-12 19:12:27 +01:00
setSocketAttributes ( serverSocket ) ;
serverSocket - > addCaCertificate ( kcc - > certificate ( ) ) ;
serverSocket - > setPeerVerifyMode ( QSslSocket : : VerifyPeer ) ;
serverSocket - > setPeerVerifyName ( kcc - > deviceId ( ) ) ;
2015-09-12 21:15:19 +01:00
serverSocket - > startClientEncryption ( ) ; // Its TCP server. but SSL client
2015-09-11 17:21:18 +01:00
QVERIFY ( ! serverSocket - > isEncrypted ( ) ) ;
spy3 . wait ( 2000 ) ;
qDebug ( ) < < " xxxxxxxxx " < < serverSocket - > sslErrors ( ) ;
2015-08-12 19:12:27 +01:00
QCOMPARE ( serverSocket - > sslErrors ( ) . size ( ) , 0 ) ;
QVERIFY2 ( serverSocket - > isValid ( ) , " Server socket disconnected " ) ;
QVERIFY2 ( serverSocket - > isEncrypted ( ) , " Server socket not yet encrypted " ) ;
QVERIFY2 ( ! serverSocket - > peerCertificate ( ) . isNull ( ) , " Peer certificate is null " ) ;
removeTrustedDevice ( ) ;
2017-09-03 20:39:44 +01:00
delete m_server ;
delete m_udpSocket ;
2015-08-12 19:12:27 +01:00
}
2018-03-04 19:48:51 +00:00
void LanLinkProviderTest : : unpairedDeviceTcpPacketReceived ( )
2015-08-12 19:12:27 +01:00
{
QUdpSocket * mUdpServer = new QUdpSocket ;
2017-02-14 22:03:59 +00:00
bool b = mUdpServer - > bind ( QHostAddress : : LocalHost , LanLinkProvider : : UDP_PORT , QUdpSocket : : ShareAddress ) ;
2015-12-02 17:49:00 +00:00
QVERIFY ( b ) ;
2015-08-12 19:12:27 +01:00
2015-09-11 17:21:18 +01:00
QSignalSpy spy ( mUdpServer , SIGNAL ( readyRead ( ) ) ) ;
2017-09-03 20:39:44 +01:00
m_lanLinkProvider . onNetworkChange ( ) ;
2015-12-02 17:49:00 +00:00
QVERIFY ( ! spy . isEmpty ( ) | | spy . wait ( ) ) ;
2015-08-12 19:12:27 +01:00
QByteArray datagram ;
datagram . resize ( mUdpServer - > pendingDatagramSize ( ) ) ;
QHostAddress sender ;
mUdpServer - > readDatagram ( datagram . data ( ) , datagram . size ( ) , & sender ) ;
2018-03-04 19:48:51 +00:00
testIdentityPacket ( datagram ) ;
2015-08-12 19:12:27 +01:00
QJsonDocument jsonDocument = QJsonDocument : : fromJson ( datagram ) ;
2016-11-26 14:38:08 +00:00
QJsonObject body = jsonDocument . object ( ) . value ( QStringLiteral ( " body " ) ) . toObject ( ) ;
int tcpPort = body . value ( QStringLiteral ( " tcpPort " ) ) . toInt ( ) ;
2015-08-12 19:12:27 +01:00
QSslSocket socket ;
2015-09-11 17:21:18 +01:00
QSignalSpy spy2 ( & socket , SIGNAL ( connected ( ) ) ) ;
2015-08-12 19:12:27 +01:00
socket . connectToHost ( sender , tcpPort ) ;
2015-09-11 17:21:18 +01:00
QVERIFY ( spy2 . wait ( ) ) ;
2015-08-12 19:12:27 +01:00
QVERIFY2 ( socket . isOpen ( ) , " Socket disconnected immediately " ) ;
2018-03-04 19:48:51 +00:00
socket . write ( m_identityPacket . toLatin1 ( ) ) ;
2015-08-12 19:12:27 +01:00
socket . waitForBytesWritten ( 2000 ) ;
2015-09-11 17:21:18 +01:00
QSignalSpy spy3 ( & socket , SIGNAL ( encrypted ( ) ) ) ;
2015-08-12 19:12:27 +01:00
// We don't take care for sslErrors signal here, but signal will emit still we will get successful connection
setSocketAttributes ( & socket ) ;
socket . setPeerVerifyMode ( QSslSocket : : QueryPeer ) ;
2015-09-12 21:15:19 +01:00
socket . startServerEncryption ( ) ;
2015-08-12 19:12:27 +01:00
2015-09-11 17:21:18 +01:00
QVERIFY ( spy3 . wait ( ) ) ;
2015-08-12 19:12:27 +01:00
QVERIFY2 ( socket . isValid ( ) , " Server socket disconnected " ) ;
QVERIFY2 ( socket . isEncrypted ( ) , " Server socket not yet encrypted " ) ;
QVERIFY2 ( ! socket . peerCertificate ( ) . isNull ( ) , " Peer certificate is null " ) ;
delete mUdpServer ;
}
2018-03-04 19:48:51 +00:00
void LanLinkProviderTest : : unpairedDeviceUdpPacketReceived ( )
2015-08-12 19:12:27 +01:00
{
2017-09-03 20:39:44 +01:00
m_server = new Server ( this ) ;
m_udpSocket = new QUdpSocket ( this ) ;
2015-08-12 19:12:27 +01:00
2017-09-03 20:39:44 +01:00
m_server - > listen ( QHostAddress : : LocalHost , TEST_PORT ) ;
2015-08-12 19:12:27 +01:00
2017-09-03 20:39:44 +01:00
QSignalSpy spy ( m_server , & Server : : newConnection ) ;
2018-03-04 19:48:51 +00:00
qint64 bytesWritten = m_udpSocket - > writeDatagram ( m_identityPacket . toLatin1 ( ) , QHostAddress : : LocalHost , LanLinkProvider : : UDP_PORT ) ; // write an identity packet to udp socket here, we do not broadcast it here
QCOMPARE ( bytesWritten , m_identityPacket . size ( ) ) ;
2015-08-12 19:12:27 +01:00
2015-12-02 17:49:00 +00:00
QVERIFY ( ! spy . isEmpty ( ) | | spy . wait ( ) ) ;
2015-08-12 19:12:27 +01:00
2017-09-03 20:39:44 +01:00
QSslSocket * serverSocket = m_server - > nextPendingConnection ( ) ;
2015-08-12 19:12:27 +01:00
QVERIFY2 ( serverSocket ! = 0 , " Server socket is null " ) ;
QVERIFY2 ( serverSocket - > isOpen ( ) , " Server socket already closed " ) ;
2017-09-03 20:39:44 +01:00
m_reader = new SocketLineReader ( serverSocket , this ) ;
QSignalSpy spy2 ( m_reader , & SocketLineReader : : readyRead ) ;
2015-09-11 17:21:18 +01:00
QVERIFY ( spy2 . wait ( ) ) ;
2015-08-12 19:12:27 +01:00
2018-03-04 19:48:51 +00:00
QByteArray receivedPacket = m_reader - > readLine ( ) ;
QVERIFY2 ( ! receivedPacket . isEmpty ( ) , " Empty packet received " ) ;
2015-08-12 19:12:27 +01:00
2018-03-04 19:48:51 +00:00
testIdentityPacket ( receivedPacket ) ;
2015-08-12 19:12:27 +01:00
2018-03-04 19:48:51 +00:00
// Received identity packet from LanLinkProvider now start ssl
2015-08-12 19:12:27 +01:00
2015-09-11 17:21:18 +01:00
QSignalSpy spy3 ( serverSocket , SIGNAL ( encrypted ( ) ) ) ;
2015-08-12 19:12:27 +01:00
setSocketAttributes ( serverSocket ) ;
serverSocket - > setPeerVerifyMode ( QSslSocket : : QueryPeer ) ;
serverSocket - > startClientEncryption ( ) ; // Its TCP server. but SSL client
2015-09-11 17:21:18 +01:00
QVERIFY ( spy3 . wait ( ) ) ;
2015-08-12 19:12:27 +01:00
QVERIFY2 ( serverSocket - > isValid ( ) , " Server socket disconnected " ) ;
QVERIFY2 ( serverSocket - > isEncrypted ( ) , " Server socket not yet encrypted " ) ;
QVERIFY2 ( ! serverSocket - > peerCertificate ( ) . isNull ( ) , " Peer certificate is null " ) ;
2017-09-03 20:39:44 +01:00
delete m_server ;
delete m_udpSocket ;
2015-08-12 19:12:27 +01:00
}
2018-03-04 19:48:51 +00:00
void LanLinkProviderTest : : testIdentityPacket ( QByteArray & identityPacket )
2015-08-12 19:12:27 +01:00
{
2018-03-04 19:48:51 +00:00
QJsonDocument jsonDocument = QJsonDocument : : fromJson ( identityPacket ) ;
2015-08-12 19:12:27 +01:00
QJsonObject jsonObject = jsonDocument . object ( ) ;
2016-11-26 14:38:08 +00:00
QJsonObject body = jsonObject . value ( QStringLiteral ( " body " ) ) . toObject ( ) ;
2015-08-12 19:12:27 +01:00
QCOMPARE ( jsonObject . value ( " type " ) . toString ( ) , QString ( " kdeconnect.identity " ) ) ;
2018-03-04 19:48:51 +00:00
QVERIFY2 ( body . contains ( " deviceName " ) , " Device name not found in identity packet " ) ;
QVERIFY2 ( body . contains ( " deviceId " ) , " Device id not found in identity packet " ) ;
QVERIFY2 ( body . contains ( " protocolVersion " ) , " Protocol version not found in identity packet " ) ;
QVERIFY2 ( body . contains ( " deviceType " ) , " Device type not found in identity packet " ) ;
2015-08-12 19:12:27 +01:00
}
QSslCertificate LanLinkProviderTest : : generateCertificate ( QString & commonName , QCA : : PrivateKey & privateKey )
{
QDateTime startTime = QDateTime : : currentDateTime ( ) ;
QDateTime endTime = startTime . addYears ( 10 ) ;
QCA : : CertificateInfo certificateInfo ;
certificateInfo . insert ( QCA : : CommonName , commonName ) ;
2016-11-26 14:38:08 +00:00
certificateInfo . insert ( QCA : : Organization , QStringLiteral ( " KDE " ) ) ;
certificateInfo . insert ( QCA : : OrganizationalUnit , QStringLiteral ( " Kde connect " ) ) ;
2015-08-12 19:12:27 +01:00
QCA : : CertificateOptions certificateOptions ( QCA : : PKCS10 ) ;
certificateOptions . setSerialNumber ( 10 ) ;
certificateOptions . setInfo ( certificateInfo ) ;
certificateOptions . setValidityPeriod ( startTime , endTime ) ;
certificateOptions . setFormat ( QCA : : PKCS10 ) ;
QSslCertificate certificate = QSslCertificate ( QCA : : Certificate ( certificateOptions , privateKey ) . toPEM ( ) . toLatin1 ( ) ) ;
return certificate ;
}
2017-09-03 20:39:44 +01:00
void LanLinkProviderTest : : setSocketAttributes ( QSslSocket * socket )
2015-12-01 15:25:34 +00:00
{
2017-09-03 20:39:44 +01:00
socket - > setPrivateKey ( QSslKey ( m_privateKey . toPEM ( ) . toLatin1 ( ) , QSsl : : Rsa ) ) ;
socket - > setLocalCertificate ( m_certificate ) ;
2015-08-12 19:12:27 +01:00
}
void LanLinkProviderTest : : addTrustedDevice ( )
{
2017-09-03 20:39:44 +01:00
KdeConnectConfig * kcc = KdeConnectConfig : : instance ( ) ;
kcc - > addTrustedDevice ( m_deviceId , m_name , QStringLiteral ( " phone " ) ) ;
kcc - > setDeviceProperty ( m_deviceId , QStringLiteral ( " certificate " ) , QString : : fromLatin1 ( m_certificate . toPem ( ) ) ) ;
2015-08-12 19:12:27 +01:00
}
void LanLinkProviderTest : : removeTrustedDevice ( )
{
2017-09-03 20:39:44 +01:00
KdeConnectConfig * kcc = KdeConnectConfig : : instance ( ) ;
kcc - > removeTrustedDevice ( m_deviceId ) ;
2015-08-12 19:12:27 +01:00
}
QTEST_GUILESS_MAIN ( LanLinkProviderTest )
# include "lanlinkprovidertest.moc"