diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fab7372 --- /dev/null +++ b/.gitignore @@ -0,0 +1,73 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + diff --git a/colnod-connector.pro b/colnod-connector.pro new file mode 100644 index 0000000..41bdb50 --- /dev/null +++ b/colnod-connector.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + src/app \ + test diff --git a/src/app/app.pro b/src/app/app.pro new file mode 100644 index 0000000..619e67b --- /dev/null +++ b/src/app/app.pro @@ -0,0 +1,8 @@ +TEMPLATE = app + +QT += core sql network +CONFIG += debug console + +SOURCES += main.cpp + +include(../colnod/colnod.pri) diff --git a/src/app/main.cpp b/src/app/main.cpp new file mode 100644 index 0000000..5088a36 --- /dev/null +++ b/src/app/main.cpp @@ -0,0 +1,10 @@ +#include +#include "requestmanager.h" + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + //RequestManager *reqman = new RequestManager(); + + return a.exec(); +} diff --git a/src/colnod/colnod.pri b/src/colnod/colnod.pri new file mode 100644 index 0000000..0e9925b --- /dev/null +++ b/src/colnod/colnod.pri @@ -0,0 +1,9 @@ +INCLUDEPATH += $$PWD +#SRC_DIR = $$PWD +message($$PWD) +SOURCES += \ + $$PWD/requestmanager.cpp + +HEADERS += \ + $$PWD/requestmanager.h +message($$SOURCES) diff --git a/src/colnod/requestmanager.cpp b/src/colnod/requestmanager.cpp new file mode 100644 index 0000000..959d78a --- /dev/null +++ b/src/colnod/requestmanager.cpp @@ -0,0 +1,124 @@ +#include "requestmanager.h" + +RequestManager::RequestManager() +{ + manager = new QNetworkAccessManager(); + token = ""; + loginStatus = false; + + QFile configFile(QDir::current().filePath("config.json")); + + if (!configFile.open(QIODevice::ReadOnly)) { + qCritical() << "Couldn't open config file config.json" << QDir::current().filePath("config.json"); + QCoreApplication::exit(-1); + return; + } + + this->config = QJsonDocument::fromJson(configFile.readAll()); + QObject::connect(manager, &QNetworkAccessManager::sslErrors, this, &RequestManager::onSSLError); +} + +void RequestManager::login(QString host, QString username, QString password) +{ + QNetworkRequest request; + QString hash = encryptedPassword(password); + authHeader = getLoginHeader(username, hash); + QJsonObject reqBody = { + {"password", hash}, + {"username", username} + }; + this->host = host; + + request.setUrl(host + "/AaaManager/authSession"); + request.setRawHeader("Authorization", authHeader.toLocal8Bit()); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json; charset=UTF-8"); + QJsonDocument jsonDocument; + jsonDocument.setObject(reqBody); + QNetworkReply* reply = manager->post(request, jsonDocument.toJson()); + QObject::connect(reply, &QNetworkReply::finished, [=]() { + if (reply->error()) + { + qDebug() << reply->errorString(); + loginStatus = false; + qDebug() << reply->readAll(); + return; + } + jsonResponse = reply->readAll(); + prepareAuthHeader(); + emit successLogin(); + reply->deleteLater(); + }); +} + +void RequestManager::getRequest(QString endpoint) +{ + QNetworkRequest request; + request.setUrl(host + endpoint); + request.setRawHeader("Authorization", authHeader.toLocal8Bit()); + QNetworkReply* reply = manager->post(request, QByteArray()); + QObject::connect(reply, &QNetworkReply::finished, [=]() { + if (reply->error()) + { + qDebug() << reply->errorString(); + qDebug() << reply->readAll(); + return; + } + + //print reply info + auto items = reply->rawHeaderPairs(); + for (auto item : items) + { + qDebug() << item; + } + auto reqHeaderName = reply->request().rawHeaderList(); + for (QString header : reqHeaderName) + { + qDebug() << reply->request().rawHeader(header.toUtf8()); + } + qDebug() << reply->attribute(QNetworkRequest::HttpStatusCodeAttribute); + + jsonResponse = reply->readAll(); + emit responseReady(); + }); +} + +QString RequestManager::getFromJson(QString json, QString member) +{ + QJsonParseError err; + QJsonDocument document = QJsonDocument::fromJson(json.toUtf8(),&err); + if (err.error != 0) + { + qDebug() << err.errorString(); + } + return document[member].toString(); +} + +QString RequestManager::encryptedPassword(QString password) +{ + return QCryptographicHash::hash(password.toLocal8Bit(), QCryptographicHash::Sha512).toHex().toUpper(); +} + +QString RequestManager::getLoginHeader(QString username, QString hash) +{ + QString authValue = username + ":" + hash; + return "Basic " + authValue.toLocal8Bit().toBase64(); +} + +void RequestManager::prepareAuthHeader() +{ + token = getFromJson(jsonResponse, "id"); + QString authValue = token + ":"; + authHeader = "Basic" + authValue.toLocal8Bit().toBase64(); +} + +void RequestManager::onSSLError(QNetworkReply *reply, const QList &errors) +{ + qDebug() << "Network SSL errors"; + for (const auto &error : errors) + { + if (error.error() == QSslError::SelfSignedCertificate) + reply->ignoreSslErrors(errors); + qDebug() << error.errorString(); + } + +} diff --git a/src/colnod/requestmanager.h b/src/colnod/requestmanager.h new file mode 100644 index 0000000..e2b1923 --- /dev/null +++ b/src/colnod/requestmanager.h @@ -0,0 +1,62 @@ +#ifndef REQUESTMANAGER_H +#define REQUESTMANAGER_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class RequestManager : public QObject +{ + Q_OBJECT + +public: + RequestManager(); + void login(QString endpoint, QString username, QString password); + void getRequest(QString endpoint); + void fetchSubjects(QString endpoint); + const QJsonDocument &getConfig() const {return config;} + const QString &getResponse() const {return jsonResponse;} + QString getToken(){return token;} +private: + + QString getFromJson(QString json, QString member); + QString encryptedPassword(QString password); + QString getLoginHeader(QString username, QString hash); + void prepareAuthHeader(); +private slots: + void onSSLError(QNetworkReply *reply, const QList &errors); + +signals: + void successLogin(); + void responseReady(); + + +private: + QNetworkAccessManager* manager; + + QJsonDocument config; + QString authHeader; + QString host; + QString token; + QString jsonResponse; + bool loginStatus; + QString tenant; + +}; + +#endif // REQUESTMANAGER_H diff --git a/src/config.json b/src/config.json new file mode 100644 index 0000000..7ac48e0 --- /dev/null +++ b/src/config.json @@ -0,0 +1,5 @@ +{ + "host": "https://localhost:8080", + "username": "spaceti", + "password": "SuperSecretPassword" +} \ No newline at end of file diff --git a/test/test.pro b/test/test.pro new file mode 100644 index 0000000..13debd0 --- /dev/null +++ b/test/test.pro @@ -0,0 +1,5 @@ +TEMPLATE = subdirs + +SUBDIRS += \ + unitTests + diff --git a/test/unitTests/UnitTest.cpp b/test/unitTests/UnitTest.cpp new file mode 100644 index 0000000..abf55aa --- /dev/null +++ b/test/unitTests/UnitTest.cpp @@ -0,0 +1,66 @@ +#include "unittest.h" + +void UnitTest::loginSuccessfully() +{ + RequestManager* testAccess = new RequestManager(); + QJsonDocument config = testAccess->getConfig(); + QSignalSpy spy(testAccess, SIGNAL(successLogin())); + testAccess->login(host, email, password); + spy.wait(); + QVERIFY(spy.isValid()); + QCOMPARE(spy.count(), 1); + QString json = testAccess->getResponse(); + qDebug() << json; + QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8()); + QVERIFY2(doc["id"].isString(), "No parameter 'id' in response"); +} + +//POST request w/o datas +void UnitTest::getSubjects() +{ + RequestManager* testAccess = new RequestManager(); + testAccess->login(host, email, password); + QSignalSpy spy(testAccess, SIGNAL(responseReady())); + testAccess->getRequest("/SubjectManager/getSubjects"); + spy.wait(); + QVERIFY(spy.isValid()); + QCOMPARE(spy.count(), 1); + QString json = testAccess->getResponse(); + QJsonDocument doc = QJsonDocument::fromJson(json.toUtf8()); + QVERIFY(doc.isObject()); + QVERIFY2(doc["items"].isArray(), "No parameter 'id' in response"); + qDebug() << doc["items"].toArray()[0].toObject()["id"].toString(); + QVERIFY2(doc["items"].toArray()[0].toObject()["id"].isString(), "ada"); + +} + +void UnitTest::getTokens() +{ + RequestManager* testAccess = new RequestManager(); + testAccess->login(host, email, password); + QSignalSpy spy(testAccess, SIGNAL(responseReady())); + testAccess->getRequest("/TokenManager/getTokens"); + QCOMPARE(spy.count(), 0); + spy.wait(); + QVERIFY(spy.isValid()); + QCOMPARE(spy.count(), 1); + qDebug() << testAccess->getResponse(); +} + +void UnitTest::getTokensOpenManager() +{ + RequestManager* testAccess = new RequestManager(); + testAccess->login(host, email, password); + QSignalSpy spy(testAccess, SIGNAL(responseReady())); + testAccess->getRequest("/OpenManager/getTokenSubject"); + QCOMPARE(spy.count(), 0); + spy.wait(); + QVERIFY(spy.isValid()); + QCOMPARE(spy.count(), 1); + QString response = testAccess->getResponse(); + QVERIFY(!response.isEmpty()); + qDebug() << response; +} + + +QTEST_MAIN(UnitTest) diff --git a/test/unitTests/config.json b/test/unitTests/config.json new file mode 100644 index 0000000..7ac48e0 --- /dev/null +++ b/test/unitTests/config.json @@ -0,0 +1,5 @@ +{ + "host": "https://localhost:8080", + "username": "spaceti", + "password": "SuperSecretPassword" +} \ No newline at end of file diff --git a/test/unitTests/unitTests.pro b/test/unitTests/unitTests.pro new file mode 100644 index 0000000..b8f8c78 --- /dev/null +++ b/test/unitTests/unitTests.pro @@ -0,0 +1,14 @@ +QT -= gui +QT += core sql network testlib + +HEADERS += \ + unittest.h +SOURCES += \ + unittest.cpp + +include(../../src/colnod/colnod.pri) + +# Default rules for deployment. +qnx: target.path = /tmp/$${TARGET}/bin +else: unix:!android: target.path = /opt/$${TARGET}/bin +!isEmpty(target.path): INSTALLS += target diff --git a/test/unitTests/unittest.h b/test/unitTests/unittest.h new file mode 100644 index 0000000..ae27657 --- /dev/null +++ b/test/unitTests/unittest.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include + + +class UnitTest : public QObject +{ + Q_OBJECT + +private slots: + + void loginSuccessfully(); + + + void getTokens(); + void getTokensOpenManager(); + void getSubjects(); + +private: + // QString host = "https://localhost:8080"; //colnod server (ssh -L 8080:192.168.254.11:8443 penta-master) + QString host = "https://192.168.1.3:8443"; //local testing server + QString password = "spaceti1"; + QString email = "spaceti"; +};