From d2170f1adb12e335dea153749d043be07ff9a0fa Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Wed, 8 Aug 2018 23:05:34 +0200 Subject: [PATCH] some more work, still not connected to mqtt tho --- libnymea-app-core/connection/awsclient.cpp | 255 ++++++++++++++++---- libnymea-app-core/connection/awsclient.h | 17 +- libnymea-app-core/connection/sigv4utils.cpp | 122 ++++++++++ libnymea-app-core/connection/sigv4utils.h | 27 +++ libnymea-app-core/jsonrpc/jsonrpcclient.cpp | 2 +- libnymea-app-core/libnymea-app-core.pro | 6 +- nymea-app/ui/connection/CloudLoginPage.qml | 11 + nymea-app/ui/connection/ConnectPage.qml | 2 +- tests/testrunner/testrunner.cpp | 2 +- tests/testrunner/testrunner.pro | 5 +- tests/tests.pro | 2 +- 11 files changed, 397 insertions(+), 54 deletions(-) create mode 100644 libnymea-app-core/connection/sigv4utils.cpp create mode 100644 libnymea-app-core/connection/sigv4utils.h diff --git a/libnymea-app-core/connection/awsclient.cpp b/libnymea-app-core/connection/awsclient.cpp index 84f81a1f..da38eaa3 100644 --- a/libnymea-app-core/connection/awsclient.cpp +++ b/libnymea-app-core/connection/awsclient.cpp @@ -7,7 +7,13 @@ #include #include +#include "qmqtt.h" +#include "sigv4utils.h" + static QByteArray clientId = "8rjhfdlf9jf1suok2jcrltd6v"; +static QByteArray region = "eu-west-1"; +//static QByteArray service = "iotdevicegateway"; +static QByteArray service = "iotdata"; AWSClient::AWSClient(QObject *parent) : QObject(parent) { @@ -18,6 +24,12 @@ AWSClient::AWSClient(QObject *parent) : QObject(parent) m_username = settings.value("username").toString(); m_accessToken = settings.value("accessToken").toByteArray(); m_idToken = settings.value("idToken").toByteArray(); + m_refreshToken = settings.value("refreshToken").toByteArray(); + + m_accessKeyId = settings.value("accessKeyId").toByteArray(); + m_secretKey = settings.value("secretKey").toByteArray(); + m_sessionToken = settings.value("sessionToken").toByteArray(); + } bool AWSClient::isLoggedIn() const @@ -55,46 +67,46 @@ void AWSClient::login(const QString &username, const QString &password) authParams.insert("PASSWORD", password); params.insert("AuthParameters", authParams); - QJsonDocument jsonDoc = QJsonDocument::fromVariant(params); + QJsonDocument jsonDoc = QJsonDocument::fromVariant(params); QByteArray payload = jsonDoc.toJson(QJsonDocument::Compact); - QNetworkReply *reply = m_nam->post(request, payload); - connect(reply, &QNetworkReply::finished, this, &AWSClient::initiateAuthReply); + qDebug() << "Logging in to AWS as user:" << username; + + QNetworkReply *reply = m_nam->post(request, payload); + connect(reply, &QNetworkReply::finished, this, [this, reply]() { + reply->deleteLater(); + if (reply->error() != QNetworkReply::NoError) { + qWarning() << "Error logging in to aws:" << reply->error() << reply->errorString(); + return; + } + QByteArray data = reply->readAll(); + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + qWarning() << "Failed to parse AWS login response" << error.errorString(); + return; + } + + QVariantMap authenticationResult = jsonDoc.toVariant().toMap().value("AuthenticationResult").toMap(); + m_accessToken = authenticationResult.value("AccessToken").toByteArray(); + m_idToken = authenticationResult.value("IdToken").toByteArray(); + m_refreshToken = authenticationResult.value("RefreshToken").toByteArray(); + + QSettings settings; + settings.beginGroup("cloud"); + settings.setValue("accessToken", m_accessToken); + settings.setValue("idToken", m_idToken); + settings.setValue("refreshToken", m_refreshToken); + + qDebug() << "AWS login successful" << qUtf8Printable(jsonDoc.toJson(QJsonDocument::Indented)); + emit isLoggedInChanged(); + + }); } -void AWSClient::initiateAuthReply() +void AWSClient::getId() { - QNetworkReply* reply = static_cast(sender()); - reply->deleteLater(); - QByteArray data = reply->readAll(); - - if (reply->error() != QNetworkReply::NoError) { - qWarning() << "Error logging in to aws:" << reply->error() << reply->errorString() << qUtf8Printable(data); - return; - } - - QJsonParseError error; - QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); - if (error.error != QJsonParseError::NoError) { - qWarning() << "Failed to parse AWS login response" << error.errorString(); - return; - } - - QVariantMap authenticationResult = jsonDoc.toVariant().toMap().value("AuthenticationResult").toMap(); - - m_accessToken = authenticationResult.value("AccessToken").toByteArray(); - m_idToken = authenticationResult.value("IdToken").toByteArray(); - QSettings settings; - settings.beginGroup("cloud"); - settings.setValue("accessToken", m_accessToken); - settings.setValue("idToken", m_idToken); - - qDebug() << "AWS login successful"; - emit isLoggedInChanged(); - -// return; // Why should we call GetId? Ask Luca - QUrl url("https://cognito-identity.eu-west-1.amazonaws.com/"); QUrlQuery query; @@ -114,19 +126,174 @@ void AWSClient::initiateAuthReply() params.insert("IdentityPoolId", "eu-west-1:108a174c-5786-40f9-966a-1a0cd33d6801"); params.insert("Logins", logins); - jsonDoc = QJsonDocument::fromVariant(params); + QJsonDocument jsonDoc = QJsonDocument::fromVariant(params); QByteArray payload = jsonDoc.toJson(QJsonDocument::Compact); - reply = m_nam->post(request, payload); - connect(reply, &QNetworkReply::finished, this, &AWSClient::getIdReply); + QNetworkReply *reply = m_nam->post(request, payload); + connect(reply, &QNetworkReply::finished, this, [this, reply]() { + reply->deleteLater(); + if (reply->error() != QNetworkReply::NoError) { + qWarning() << "Error calling GetId" << reply->error() << reply->errorString(); + return; + } + QByteArray data = reply->readAll(); + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + qWarning() << "Error parsing json reply for GetId" << error.errorString(); + return; + } + QByteArray identityId = jsonDoc.toVariant().toMap().value("IdentityId").toByteArray(); + + qDebug() << "Received cognito identity id" << identityId; + getCredentialsForIdentity(identityId); + + }); } -void AWSClient::getIdReply() +void AWSClient::getCredentialsForIdentity(const QString &identityId) { - QNetworkReply* reply = static_cast(sender()); - reply->deleteLater(); - QByteArray data = reply->readAll(); - qDebug() << "GetID reply" << reply->error() << reply->errorString() << qUtf8Printable(data); + QUrl url("https://cognito-identity.eu-west-1.amazonaws.com/"); + + QUrlQuery query; + query.addQueryItem("Action", "GetCredentialsForIdentity"); + query.addQueryItem("Version", "2016-06-30"); + url.setQuery(query); + + QNetworkRequest request(url); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-amz-json-1.0"); + request.setRawHeader("Host", "cognito-identity.eu-west-1.amazonaws.com"); + request.setRawHeader("X-Amz-Target", "AWSCognitoIdentityService.GetCredentialsForIdentity"); + + QVariantMap logins; + logins.insert("cognito-idp.eu-west-1.amazonaws.com/eu-west-1_6eX6YjmXr", m_idToken); + + QVariantMap params; + params.insert("IdentityId", identityId); + params.insert("Logins", logins); + + QJsonDocument jsonDoc = QJsonDocument::fromVariant(params); + QByteArray payload = jsonDoc.toJson(QJsonDocument::Compact); + + qDebug() << "Calling GetCredentialsForIdentity:" << request.url(); + qDebug() << "Headers:"; + foreach (const QByteArray &headerName, request.rawHeaderList()) { + qDebug() << headerName << ":" << request.rawHeader(headerName); + } + qDebug() << "Payload:" << qUtf8Printable(payload); + + QNetworkReply *reply = m_nam->post(request, payload); + connect(reply, &QNetworkReply::finished, this, [this, reply]() { + reply->deleteLater(); + if (reply->error() != QNetworkReply::NoError) { + qWarning() << "Error calling GetCredentialsForIdentity" << reply->errorString(); + return; + } + QByteArray data = reply->readAll(); + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); + if (error.error != QJsonParseError::NoError) { + qWarning() << "Error parsing JSON reply from GetCredentialsForIdentity" << error.errorString(); + return; + } + QVariantMap credentialsMap = jsonDoc.toVariant().toMap().value("Credentials").toMap(); + + m_accessKeyId = credentialsMap.value("AccessKeyId").toByteArray(); + m_secretKey = credentialsMap.value("SecretKey").toByteArray(); + m_sessionToken = credentialsMap.value("SessionToken").toByteArray(); + m_expirationDate = QDateTime::fromSecsSinceEpoch(credentialsMap.value("Expiration").toLongLong()); + + QSettings settings; + settings.beginGroup("cloud"); + settings.setValue("accessKeyId", m_accessKeyId); + settings.setValue("secretKey", m_secretKey); + settings.setValue("sessionToken", m_sessionToken); + + qDebug() << "Raw GetCredentialsForIdentity reply:" << qUtf8Printable(data); + qDebug() << "GetCredentialsForIdentity reply: \nAccess Key ID:" << m_accessKeyId << "\nSecret Key:" << m_secretKey << "\nsessionkey:" << m_sessionToken << "\nExpiration:" << m_expirationDate; + + postToMQTT(); + }); +} + +void AWSClient::connectMQTT() +{ + + QString host = "a2addxakg5juii.iot.eu-west-1.amazonaws.com"; + QString uri = "/mqtt"; + + QNetworkRequest request(QUrl("wss://" + host + uri)); + request.setRawHeader("Host", host.toUtf8()); + + QByteArray dateTime = SigV4Utils::getCurrentDateTime(); +// QByteArray canonicalQueryString = SigV4Utils::getCanonicalQueryString(request, m_accessKeyId, m_secretKey, m_sessionToken, region, service, QByteArray()); + QByteArray canonicalQueryString = SigV4Utils::getCanonicalQueryString(request, m_accessKeyId, m_secretKey, QByteArray(), region, service, QByteArray()); + + QString signedRequestUrl = "wss://" + host + uri + '?' + canonicalQueryString; + + qDebug() << "Connecting MQTT to" << signedRequestUrl; + + QMQTT::Client *mqttClient = new QMQTT::Client(signedRequestUrl, QString(clientId), QWebSocketProtocol::VersionLatest, false); + mqttClient->setClientId(QString(clientId)); + mqttClient->setPort(443); + mqttClient->setVersion(QMQTT::V3_1_1); + + connect(mqttClient, &QMQTT::Client::connected, this, []{ + qDebug() << "MQTT connected"; + }); + connect(mqttClient, &QMQTT::Client::disconnected, this, []{ + qDebug() << "MQTT disconnected"; + }); + connect(mqttClient, &QMQTT::Client::error, this, [](const QMQTT::ClientError error){ + qDebug() << "MQTT error" << error; + }); + mqttClient->connectToHost(); +} + +void AWSClient::postToMQTT() +{ + QString host = "a2addxakg5juii.iot.eu-west-1.amazonaws.com"; + QString topic = "850593e9-f2ab-4e89-913a-16f848d48867/eu-west-1:88c8b0f1-3f26-46cb-81f3-ccc37dcb543a/"; + QString path = "/topics/" + topic.toUtf8().toPercentEncoding().toPercentEncoding().toPercentEncoding() + "?qos=0"; +// QString path1 = "/topics/" + topic.toUtf8().toPercentEncoding().toPercentEncoding() + "?qos=0"; + + QVariantMap params; + params.insert("message", "Hello box"); + QByteArray payload = QJsonDocument::fromVariant(params).toJson(QJsonDocument::Compact); + + QByteArray dateTime = SigV4Utils::getCurrentDateTime(); +// dateTime = "20180808T134011Z"; + + + QNetworkRequest request("https://" + host + path); + request.setRawHeader("content-type", "application/json"); + request.setRawHeader("host", host.toUtf8()); + request.setRawHeader("x-amz-date", dateTime); + request.setRawHeader("x-amz-security-token", m_sessionToken); +// request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-amz-json-1.0"); + + + QByteArray canonicalRequest = SigV4Utils::getCanonicalRequest(QNetworkAccessManager::PostOperation, request, payload); + qDebug() << "canonical request:" << qUtf8Printable(canonicalRequest); + QByteArray stringToSign = SigV4Utils::getStringToSign(canonicalRequest, dateTime, region, service); + qDebug() << "string to sign:" << stringToSign; + QByteArray signature = SigV4Utils::getSignature(stringToSign, m_secretKey, dateTime, region, service); + qDebug() << "signature:" << signature; + QByteArray authorizeHeader = SigV4Utils::getAuthorizationHeader(m_accessKeyId, dateTime, region, service, request, signature); + + request.setRawHeader("Authorization", authorizeHeader); + + qDebug() << "Posting to MQTT:" << request.url().toString(); + qDebug() << "HEADERS:"; + foreach (const QByteArray &headerName, request.rawHeaderList()) { + qDebug() << headerName << ":" << request.rawHeader(headerName); + } + qDebug() << "Payload:" << payload; + QNetworkReply *reply = m_nam->post(request, payload); + connect(reply, &QNetworkReply::finished, this, [reply]() { + reply->deleteLater(); + qDebug() << "post reply" << reply->readAll(); + }); } void AWSClient::fetchDevices() @@ -160,6 +327,9 @@ void AWSClient::fetchDevices() ret.append(d); } emit devicesFetched(ret); + + + }); } @@ -168,3 +338,4 @@ QByteArray AWSClient::accessToken() const { return m_accessToken; } + diff --git a/libnymea-app-core/connection/awsclient.h b/libnymea-app-core/connection/awsclient.h index eb98194c..372430bd 100644 --- a/libnymea-app-core/connection/awsclient.h +++ b/libnymea-app-core/connection/awsclient.h @@ -3,9 +3,9 @@ #include #include +#include class QNetworkAccessManager; -struct SRPUser; class AWSDevice { public: @@ -28,6 +28,9 @@ public: Q_INVOKABLE void fetchDevices(); + Q_INVOKABLE void postToMQTT(); + Q_INVOKABLE void getId(); + QByteArray accessToken() const; signals: @@ -35,9 +38,9 @@ signals: void devicesFetched(QList devices); -private slots: - void initiateAuthReply(); - void getIdReply(); +private: + void getCredentialsForIdentity(const QString &identityId); + void connectMQTT(); private: QNetworkAccessManager *m_nam = nullptr; @@ -45,6 +48,12 @@ private: QString m_username; QByteArray m_accessToken; QByteArray m_idToken; + QByteArray m_refreshToken; + + QByteArray m_accessKeyId; + QByteArray m_secretKey; + QByteArray m_sessionToken; + QDateTime m_expirationDate; }; #endif // AWSCLIENT_H diff --git a/libnymea-app-core/connection/sigv4utils.cpp b/libnymea-app-core/connection/sigv4utils.cpp new file mode 100644 index 00000000..865aa23d --- /dev/null +++ b/libnymea-app-core/connection/sigv4utils.cpp @@ -0,0 +1,122 @@ +#include "sigv4utils.h" + +#include +#include +#include +#include +#include +#include + +SigV4Utils::SigV4Utils() +{ + +} + +QByteArray SigV4Utils::getCurrentDateTime() +{ + return QDateTime::currentDateTime().toUTC().toString("yyyyMMddThhmmssZ").toUtf8(); +} + +QByteArray SigV4Utils::getCanonicalQueryString(const QNetworkRequest &request, const QByteArray &accessKeyId, const QByteArray &secretAccessKey, const QByteArray &sessionToken, const QByteArray ®ion, const QByteArray &service, const QByteArray &payload) +{ + QByteArray algorithm = "AWS4-HMAC-SHA256"; + QByteArray dateTime = getCurrentDateTime(); + QByteArray credentialScope = getCredentialScope(algorithm, dateTime, region, service); + + QByteArray canonicalQueryString; + canonicalQueryString += "X-Amz-Algorithm=AWS4-HMAC-SHA256"; + canonicalQueryString += "&X-Amz-Credential=" + QByteArray(accessKeyId + '/' + credentialScope).toPercentEncoding(); + canonicalQueryString += "&X-Amz-Date=" + dateTime; + if (request.rawHeaderList().count() > 0){ + canonicalQueryString += "&X-Amz-SignedHeaders=" + request.rawHeaderList().join(';').toLower(); + } + + QByteArray canonicalRequest = getCanonicalRequest(QNetworkAccessManager::GetOperation, request, payload); + + QByteArray stringToSign = getStringToSign(canonicalRequest, dateTime, region, service); + QByteArray signature = getSignature(stringToSign, secretAccessKey, dateTime, region, service); + + canonicalQueryString += "&X-Amz-Signature=" + signature; + + if (!sessionToken.isEmpty()) { + canonicalQueryString += "&X-Amz-Security-Token=" + sessionToken.toPercentEncoding(); + } + + return canonicalQueryString; +} + +QByteArray SigV4Utils::getSignatureKey(const QByteArray &key, const QByteArray &date, const QByteArray ®ion, const QByteArray &service) +{ + QCryptographicHash::Algorithm hashAlgorithm = QCryptographicHash::Sha256; + return QMessageAuthenticationCode::hash("aws4_request", + QMessageAuthenticationCode::hash(service, + QMessageAuthenticationCode::hash(region, + QMessageAuthenticationCode::hash(date, "AWS4"+key, + hashAlgorithm), hashAlgorithm), hashAlgorithm), hashAlgorithm); +} + +QByteArray SigV4Utils::getCanonicalRequest(QNetworkAccessManager::Operation operation, const QNetworkRequest &request, const QByteArray &payload) +{ + QByteArray canonicalRequest; + + QByteArray method; + switch (operation) { + case QNetworkAccessManager::GetOperation: + method = "GET"; + break; + case QNetworkAccessManager::PostOperation: + method = "POST"; + break; + default: + Q_ASSERT_X(false, "Network operation not implemented", "SigV4Utils"); + } + QByteArray uri = request.url().path().toUtf8(); + QUrlQuery query(request.url()); + QList > queryItems = query.queryItems(); + QStringList queryItemStrings; + for (int i = 0; i < queryItems.count(); i++) { + QPair queryItem = queryItems.at(i); + queryItemStrings.append(queryItem.first + '=' + queryItem.second); + } + queryItemStrings.sort(Qt::CaseInsensitive); + + QByteArray canonicalQueryString = queryItemStrings.join('&').toUtf8(); + + QByteArray canonicalHeaders; + foreach(const QByteArray &headerName, request.rawHeaderList()) { + canonicalHeaders += headerName.toLower() + ':' + request.rawHeader(headerName) + '\n'; + } + + QByteArray payloadHash = QCryptographicHash::hash(payload, QCryptographicHash::Sha256).toHex(); + + canonicalRequest = method + '\n' + uri + '\n' + canonicalQueryString + '\n' + canonicalHeaders + '\n' + request.rawHeaderList().join(';').toLower() + '\n' + payloadHash; + return canonicalRequest; +} + +QByteArray SigV4Utils::getCredentialScope(const QByteArray &algorithm, const QByteArray &dateTime, const QByteArray ®ion, const QByteArray &service) +{ + QByteArray credentialScope = dateTime.left(8) + '/' + region + '/' + service + "/aws4_request"; + return credentialScope; +} + +QByteArray SigV4Utils::getStringToSign(const QByteArray &canonicalRequest, const QByteArray &dateTime, const QByteArray ®ion, const QByteArray &service) +{ + QByteArray algorithm = "AWS4-HMAC-SHA256"; + QByteArray credentialScope = getCredentialScope(algorithm, dateTime, region, service); + + QByteArray stringToSign = algorithm + '\n' + dateTime + '\n' + credentialScope + '\n' + QCryptographicHash::hash(canonicalRequest, QCryptographicHash::Sha256).toHex(); + return stringToSign; +} + +QByteArray SigV4Utils::getSignature(const QByteArray &stringToSign, const QByteArray &secretAccessKey, const QByteArray &dateTime, const QString ®ion, const QString &service) +{ + QByteArray signingKey = getSignatureKey(secretAccessKey, dateTime.left(8), region.toUtf8(), service.toUtf8()); + QByteArray signature = QMessageAuthenticationCode::hash(stringToSign, signingKey, QCryptographicHash::Sha256).toHex(); + return signature; +} + +QByteArray SigV4Utils::getAuthorizationHeader(const QByteArray &accessKeyId, const QByteArray &dateTime, const QString ®ion, const QString &service, const QNetworkRequest &request, const QByteArray &signature) +{ + QByteArray authHeader = "AWS4-HMAC-SHA256 Credential=" + accessKeyId + '/' + dateTime.left(8) + '/' + region.toUtf8() + '/' + service.toUtf8() + '/' + "aws4_request, SignedHeaders=" + request.rawHeaderList().join(';').toLower() + ", Signature=" + signature; + return authHeader; +} diff --git a/libnymea-app-core/connection/sigv4utils.h b/libnymea-app-core/connection/sigv4utils.h new file mode 100644 index 00000000..4861869e --- /dev/null +++ b/libnymea-app-core/connection/sigv4utils.h @@ -0,0 +1,27 @@ +#ifndef SIGV4UTILS_H +#define SIGV4UTILS_H + +#include +#include +#include + +class SigV4Utils +{ +public: + SigV4Utils(); + + static QByteArray getCurrentDateTime(); + + + static QByteArray getCanonicalQueryString(const QNetworkRequest &request, const QByteArray &accessKeyId, const QByteArray &secretAccessKey, const QByteArray &sessionToken, const QByteArray ®ion, const QByteArray &service, const QByteArray &payload); + static QByteArray getCanonicalRequest(QNetworkAccessManager::Operation operation, const QNetworkRequest &request, const QByteArray &payload); + static QByteArray getCanonicalHeaders(const QNetworkRequest &request); + static QByteArray getCredentialScope(const QByteArray &algorithm, const QByteArray &dateTime, const QByteArray ®ion, const QByteArray &service); + static QByteArray getStringToSign(const QByteArray &canonicalRequest, const QByteArray &dateTime, const QByteArray ®ion, const QByteArray &service); + static QByteArray getSignatureKey(const QByteArray &key, const QByteArray &date, const QByteArray ®ion, const QByteArray &service); + static QByteArray getSignature(const QByteArray &stringToSign, const QByteArray &secretAccessKey, const QByteArray &dateTime, const QString ®ion, const QString &service); + static QByteArray getAuthorizationHeader(const QByteArray &accessKeyId, const QByteArray &dateTime, const QString ®ion, const QString &service, const QNetworkRequest &request, const QByteArray &signature); + +}; + +#endif // SIGV4UTILS_H diff --git a/libnymea-app-core/jsonrpc/jsonrpcclient.cpp b/libnymea-app-core/jsonrpc/jsonrpcclient.cpp index e903ac32..a4c9d0b4 100644 --- a/libnymea-app-core/jsonrpc/jsonrpcclient.cpp +++ b/libnymea-app-core/jsonrpc/jsonrpcclient.cpp @@ -269,7 +269,7 @@ void JsonRpcClient::sendRequest(const QVariantMap &request) { QVariantMap newRequest = request; newRequest.insert("token", m_token); - qDebug() << "Sending request" << qUtf8Printable(QJsonDocument::fromVariant(newRequest).toJson()); +// qDebug() << "Sending request" << qUtf8Printable(QJsonDocument::fromVariant(newRequest).toJson()); m_connection->sendData(QJsonDocument::fromVariant(newRequest).toJson(QJsonDocument::Compact) + "\n"); } diff --git a/libnymea-app-core/libnymea-app-core.pro b/libnymea-app-core/libnymea-app-core.pro index 55c1cddb..8c1a1df1 100644 --- a/libnymea-app-core/libnymea-app-core.pro +++ b/libnymea-app-core/libnymea-app-core.pro @@ -12,7 +12,8 @@ include(../config.pri) } DEFINES += QT_STATIC include(../qmqtt/src/mqtt/mqtt.pri) -HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS +HEADERS += $$PUBLIC_HEADERS $$PRIVATE_HEADERS \ + connection/sigv4utils.h QT -= gui QT += network websockets bluetooth @@ -77,7 +78,8 @@ SOURCES += \ ruletemplates/stateevaluatortemplate.cpp \ ruletemplates/statedescriptortemplate.cpp \ discovery/bluetoothservicediscovery.cpp \ - connection/cloudtransport.cpp + connection/cloudtransport.cpp \ + connection/sigv4utils.cpp HEADERS += \ engine.h \ diff --git a/nymea-app/ui/connection/CloudLoginPage.qml b/nymea-app/ui/connection/CloudLoginPage.qml index 50a9f718..4c1d4718 100644 --- a/nymea-app/ui/connection/CloudLoginPage.qml +++ b/nymea-app/ui/connection/CloudLoginPage.qml @@ -39,5 +39,16 @@ Page { Engine.awsClient.login(usernameTextField.text, passwordTextField.text); } } + + Button { + Layout.fillWidth: true + text: "GetId" + onClicked: Engine.awsClient.getId(); + } + Button { + Layout.fillWidth: true + text: "Post to MQTT" + onClicked: Engine.awsClient.postToMQTT(); + } } } diff --git a/nymea-app/ui/connection/ConnectPage.qml b/nymea-app/ui/connection/ConnectPage.qml index 2e116be5..9bbcffbf 100644 --- a/nymea-app/ui/connection/ConnectPage.qml +++ b/nymea-app/ui/connection/ConnectPage.qml @@ -88,7 +88,7 @@ Page { ListElement { iconSource: "../images/network-vpn.svg"; text: qsTr("Manual connection"); page: "ManualConnectPage.qml" } ListElement { iconSource: "../images/bluetooth.svg"; text: qsTr("Wireless setup"); page: "BluetoothDiscoveryPage.qml"; } ListElement { iconSource: "../images/cloud.svg"; text: qsTr("Cloud login"); page: "CloudLoginPage.qml" } - ListElement { iconSource: "../images/stock_application.svg"; text: qsTr("App settings"); page: "AppSettingsPage.qml" } + ListElement { iconSource: "../images/stock_application.svg"; text: qsTr("App settings"); page: "../AppSettingsPage.qml" } } onClicked: { pageStack.push(model.get(index).page); diff --git a/tests/testrunner/testrunner.cpp b/tests/testrunner/testrunner.cpp index 2fb19810..09683aaf 100644 --- a/tests/testrunner/testrunner.cpp +++ b/tests/testrunner/testrunner.cpp @@ -6,7 +6,7 @@ #include #endif -#include "libmea-core.h" +#include "libnymea-app-core.h" int main(int argc, char **argv) { diff --git a/tests/testrunner/testrunner.pro b/tests/testrunner/testrunner.pro index 3bbfb163..7004fa5f 100644 --- a/tests/testrunner/testrunner.pro +++ b/tests/testrunner/testrunner.pro @@ -10,8 +10,9 @@ INCLUDEPATH += ../../nymea-app/ \ ../../libnymea-common/ \ ../../libnymea-app-core/ -LIBS += -L$$top_builddir/libmea-core/ -lmea-core \ - -L$$top_builddir/libnymea-common/ -lnymea-common +LIBS += -L$$top_builddir/libnymea-app-core/ -lnymea-app-core \ + -L$$top_builddir/libnymea-common/ -lnymea-common \ + -lavahi-common -lavahi-client win32:Debug:LIBS += -L$$top_builddir/libmea-core/debug \ -L$$top_builddir/libnymea-common/debug win32:Release:LIBS += -L$$top_builddir/libmea-core/release \ diff --git a/tests/tests.pro b/tests/tests.pro index d5430750..7029fcc9 100644 --- a/tests/tests.pro +++ b/tests/tests.pro @@ -1,3 +1,3 @@ TEMPLATE = subdirs -SUBDIRS = testrunner +SUBDIRS = testrunner unit