add pushbuttin auth support

pull/1/head
Michael Zanetti 2018-04-11 02:31:33 +02:00
parent f070e67bfc
commit f89b68973e
12 changed files with 592 additions and 52 deletions

View File

@ -92,6 +92,7 @@ void Engine::onConnectedChanged()
m_deviceManager->clear();
m_ruleManager->clear();
if (m_jsonRpcClient->connected()) {
qDebug() << "Engine: inital setup required:" << m_jsonRpcClient->initialSetupRequired() << "auth required:" << m_jsonRpcClient->authenticationRequired();
if (!m_jsonRpcClient->initialSetupRequired() && !m_jsonRpcClient->authenticationRequired()) {
m_deviceManager->init();
m_ruleManager->init();

View File

@ -37,6 +37,8 @@ JsonRpcClient::JsonRpcClient(NymeaConnection *connection, QObject *parent) :
{
connect(m_connection, &NymeaConnection::connectedChanged, this, &JsonRpcClient::onInterfaceConnectedChanged);
connect(m_connection, &NymeaConnection::dataAvailable, this, &JsonRpcClient::dataReceived);
registerNotificationHandler(this, "notificationReceived");
}
QString JsonRpcClient::nameSpace() const
@ -78,6 +80,38 @@ void JsonRpcClient::setNotificationsEnabled(bool enabled)
void JsonRpcClient::setNotificationsEnabledResponse(const QVariantMap &params)
{
qDebug() << "Notifications enabled:" << params;
m_connected = true;
emit connectedChanged(true);
}
void JsonRpcClient::notificationReceived(const QVariantMap &data)
{
qDebug() << "JsonRpcClient: Notification received" << data;
//JsonRpcClient: Notification received QMap(("id", QVariant(double, 2))("notification", QVariant(QString, "JSONRPC.PushButtonAuthFinished"))("params", QVariant(QVariantMap, QMap(("success", QVariant(bool, true))("token", QVariant(QString, "FJPaAJ8FEtrqcC+/s0s/lAcDubz0OyEtwbRsyFIWM9c="))("transactionId", QVariant(double, 2))))))
if (data.value("notification").toString() == "JSONRPC.PushButtonAuthFinished") {
qDebug() << "Push button auth finished.";
if (data.value("params").toMap().value("transactionId").toInt() != m_pendingPushButtonTransaction) {
qDebug() << "This push button transaction is not what we're waiting for...";
return;
}
m_pendingPushButtonTransaction = -1;
if (data.value("params").toMap().value("success").toBool()) {
qDebug() << "Push button auth succeeded";
m_token = data.value("params").toMap().value("token").toByteArray();
QSettings settings;
settings.beginGroup("jsonTokens");
settings.setValue(m_serverUuid, m_token);
settings.endGroup();
emit authenticationRequiredChanged();
setNotificationsEnabled(true);
} else {
emit pushButtonAuthFailed();
}
}
}
bool JsonRpcClient::connected() const
@ -95,6 +129,11 @@ bool JsonRpcClient::authenticationRequired() const
return m_authenticationRequired && m_token.isEmpty();
}
bool JsonRpcClient::pushButtonAuthAvailable() const
{
return m_pushButtonAuthAvailable;
}
int JsonRpcClient::createUser(const QString &username, const QString &password)
{
QVariantMap params;
@ -118,11 +157,22 @@ int JsonRpcClient::authenticate(const QString &username, const QString &password
return reply->commandId();
}
int JsonRpcClient::requestPushButtonAuth(const QString &deviceName)
{
qDebug() << "Requesting push button auth for device:" << deviceName;
QVariantMap params;
params.insert("deviceName", deviceName);
JsonRpcReply *reply = createReply("JSONRPC.RequestPushButtonAuth", params, this, "processRequestPushButtonAuth");
m_replies.insert(reply->commandId(), reply);
m_connection->sendData(QJsonDocument::fromVariant(reply->requestMap()).toJson());
return reply->commandId();
}
void JsonRpcClient::processAuthenticate(const QVariantMap &data)
{
qDebug() << "authenticate response" << data;
if (data.value("status").toString() == "success" && data.value("params").toMap().value("success").toBool()) {
qDebug() << "authentication successful";
m_token = data.value("params").toMap().value("token").toByteArray();
QSettings settings;
settings.beginGroup("jsonTokens");
@ -131,6 +181,9 @@ void JsonRpcClient::processAuthenticate(const QVariantMap &data)
emit authenticationRequiredChanged();
setNotificationsEnabled(true);
} else {
qWarning() << "Authentication failed";
emit authenticationFailed();
}
}
@ -140,6 +193,19 @@ void JsonRpcClient::processCreateUser(const QVariantMap &data)
if (data.value("status").toString() == "success" && data.value("params").toMap().value("error").toString() == "UserErrorNoError") {
m_initialSetupRequired = false;
emit initialSetupRequiredChanged();
} else {
qDebug() << "Emitting create user failed";
emit createUserFailed(data.value("params").toMap().value("error").toString());
}
}
void JsonRpcClient::processRequestPushButtonAuth(const QVariantMap &data)
{
qDebug() << "requestPushButtonAuth response" << data;
if (data.value("status").toString() == "success" && data.value("params").toMap().value("success").toBool()) {
m_pendingPushButtonTransaction = data.value("params").toMap().value("transactionId").toInt();
} else {
emit pushButtonAuthFailed();
}
}
@ -201,48 +267,58 @@ void JsonRpcClient::dataReceived(const QByteArray &data)
if (dataMap.value("id").toInt() == 0) {
m_initialSetupRequired = dataMap.value("initialSetupRequired").toBool();
m_authenticationRequired = dataMap.value("authenticationRequired").toBool();
m_pushButtonAuthAvailable = dataMap.value("pushButtonAuthAvailable").toBool();
qDebug() << "Handshake received" << "initRequired:" << m_initialSetupRequired << "authRequired:" << m_authenticationRequired << "pushButtonAvailable:" << m_pushButtonAuthAvailable;;
m_serverUuid = dataMap.value("uuid").toString();
emit pushButtonAuthAvailableChanged();
QString protoVersionString = dataMap.value("protocol version").toString();
if (!protoVersionString.contains('.')) {
protoVersionString.prepend("0.");
}
QVersionNumber minimumRequiredVersion = QVersionNumber(1, 0);
QVersionNumber protocolVersion = QVersionNumber::fromString(protoVersionString);
if (protocolVersion < minimumRequiredVersion) {
m_connection->disconnect();
emit invalidProtocolVersion(protocolVersion.toString(), minimumRequiredVersion.toString());
return;
}
if (m_initialSetupRequired) {
emit initialSetupRequiredChanged();
} else if (m_authenticationRequired) {
return;
}
if (m_authenticationRequired) {
QSettings settings;
settings.beginGroup("jsonTokens");
m_token = settings.value(m_serverUuid).toByteArray();
settings.endGroup();
emit authenticationRequiredChanged();
if (!m_token.isEmpty()) {
setNotificationsEnabled(true);
if (m_token.isEmpty()) {
return;
}
}
m_connected = true;
emit connectedChanged(true);
QVersionNumber minimumRequiredVersion = QVersionNumber(1, 0);
QVersionNumber protocolVersion = QVersionNumber::fromString(protoVersionString);
if (protocolVersion < minimumRequiredVersion) {
m_connection->disconnect();
emit invalidProtocolVersion(protocolVersion.toString(), minimumRequiredVersion.toString());
}
setNotificationsEnabled(true);
}
// check if this is a reply to a request
int commandId = dataMap.value("id").toInt();
JsonRpcReply *reply = m_replies.take(commandId);
if (reply) {
// qDebug() << QString("JsonRpc: got response for %1.%2: %3").arg(reply->nameSpace(), reply->method(), QString::fromUtf8(jsonDoc.toJson(QJsonDocument::Indented))) << reply->callback() << reply->callback();
qDebug() << QString("JsonRpc: got response for %1.%2: %3").arg(reply->nameSpace(), reply->method(), QString::fromUtf8(jsonDoc.toJson(QJsonDocument::Indented))) << reply->callback() << reply->callback();
if (dataMap.value("status").toString() == "unauthorized") {
qWarning() << "Something's off with the token";
m_authenticationRequired = true;
m_token.clear();
QSettings settings;
settings.beginGroup("jsonTokens");
settings.setValue(m_serverUuid, m_token);
settings.endGroup();
emit authenticationRequiredChanged();
}

View File

@ -37,6 +37,7 @@ class JsonRpcClient : public JsonHandler
Q_PROPERTY(bool connected READ connected NOTIFY connectedChanged)
Q_PROPERTY(bool initialSetupRequired READ initialSetupRequired NOTIFY initialSetupRequiredChanged)
Q_PROPERTY(bool authenticationRequired READ authenticationRequired NOTIFY authenticationRequiredChanged)
Q_PROPERTY(bool pushButtonAuthAvailable READ pushButtonAuthAvailable NOTIFY pushButtonAuthAvailableChanged)
public:
explicit JsonRpcClient(NymeaConnection *connection, QObject *parent = 0);
@ -52,21 +53,24 @@ public:
bool connected() const;
bool initialSetupRequired() const;
bool authenticationRequired() const;
bool pushButtonAuthAvailable() const;
// ui methods
Q_INVOKABLE int createUser(const QString &username, const QString &password);
Q_INVOKABLE int authenticate(const QString &username, const QString &password, const QString &deviceName);
Q_INVOKABLE int requestPushButtonAuth(const QString &deviceName);
// json handler
Q_INVOKABLE void processAuthenticate(const QVariantMap &data);
Q_INVOKABLE void processCreateUser(const QVariantMap &data);
signals:
void initialSetupRequiredChanged();
void authenticationRequiredChanged();
void pushButtonAuthAvailableChanged();
void connectedChanged(bool connected);
void tokenChanged();
void invalidProtocolVersion(const QString &actualVersion, const QString &minimumVersion);
void authenticationFailed();
void pushButtonAuthFailed();
void createUserFailed(const QString &error);
void responseReceived(const int &commandId, const QVariantMap &response);
@ -86,12 +90,22 @@ private:
bool m_connected = false;
bool m_initialSetupRequired = false;
bool m_authenticationRequired = false;
bool m_pushButtonAuthAvailable = false;
int m_pendingPushButtonTransaction = -1;
QString m_serverUuid;
QByteArray m_token;
QByteArray m_receiveBuffer;
void setNotificationsEnabled(bool enabled);
// json handler
Q_INVOKABLE void processAuthenticate(const QVariantMap &data);
Q_INVOKABLE void processCreateUser(const QVariantMap &data);
Q_INVOKABLE void processRequestPushButtonAuth(const QVariantMap &data);
Q_INVOKABLE void setNotificationsEnabledResponse(const QVariantMap &params);
Q_INVOKABLE void notificationReceived(const QVariantMap &data);
void sendRequest(const QVariantMap &request);
};

View File

@ -88,11 +88,29 @@ void NymeaConnection::onSslErrors(const QList<QSslError> &errors)
QByteArray storedFingerPrint = settings.value(m_currentUrl.toString()).toByteArray();
settings.endGroup();
if (storedFingerPrint == error.certificate().digest(QCryptographicHash::Sha256).toBase64()) {
QByteArray certificateFingerprint;
QByteArray digest = error.certificate().digest(QCryptographicHash::Sha256);
for (int i = 0; i < digest.length(); i++) {
if (certificateFingerprint.length() > 0) {
certificateFingerprint.append(":");
}
certificateFingerprint.append(digest.mid(i,1).toHex().toUpper());
}
if (storedFingerPrint == certificateFingerprint) {
ignoredErrors.append(error);
} else {
// QString cn = error.certificate().issuerInfo(QSslCertificate::CommonName);
emit verifyConnectionCertificate(error.certificate().issuerInfo(QSslCertificate::CommonName).first(), error.certificate().digest(QCryptographicHash::Sha256).toBase64());
QStringList info;
info << tr("Common Name:") << error.certificate().issuerInfo(QSslCertificate::CommonName);
info << tr("Oragnisation:") <<error.certificate().issuerInfo(QSslCertificate::Organization);
info << tr("Locality:") << error.certificate().issuerInfo(QSslCertificate::LocalityName);
info << tr("Oragnisational Unit:")<< error.certificate().issuerInfo(QSslCertificate::OrganizationalUnitName);
info << tr("Country:")<< error.certificate().issuerInfo(QSslCertificate::CountryName);
// info << tr("State:")<< error.certificate().issuerInfo(QSslCertificate::StateOrProvinceName);
// info << tr("Name Qualifier:")<< error.certificate().issuerInfo(QSslCertificate::DistinguishedNameQualifier);
// info << tr("Email:")<< error.certificate().issuerInfo(QSslCertificate::EmailAddress);
emit verifyConnectionCertificate(info, certificateFingerprint);
}
} else {
// Reject the connection on all other errors...

View File

@ -28,7 +28,7 @@ public:
void sendData(const QByteArray &data);
signals:
void verifyConnectionCertificate(const QString &commonName, const QByteArray &fingerprint);
void verifyConnectionCertificate(const QStringList &issuerInfo, const QByteArray &fingerprint);
void connectedChanged(bool connected);
void connectionError();
void dataAvailable(const QByteArray &data);

View File

@ -142,5 +142,7 @@
<file>ui/magic/SelectStateDescriptorPage.qml</file>
<file>ui/images/select-none.svg</file>
<file>ui/images/edit.svg</file>
<file>ui/PushButtonAuthPage.qml</file>
<file>ui/images/dialog-error-symbolic.svg</file>
</qresource>
</RCC>

View File

@ -22,7 +22,7 @@ Page {
target: Engine.connection
onVerifyConnectionCertificate: {
print("verify cert!")
certDialog.commonName = commonName
certDialog.issuerInfo = issuerInfo
certDialog.fingerprint = fingerprint
certDialog.open();
}
@ -156,32 +156,78 @@ Page {
Dialog {
id: certDialog
width: parent.width * .8
height: parent.height * .8
width: Math.min(parent.width * .9, 400)
height: content.height
x: (parent.width - width) / 2
y: (parent.height - height) / 2
standardButtons: Dialog.Yes | Dialog.No
property var fingerprint
property string commonName
property var issuerInfo
ColumnLayout {
anchors.fill: parent
anchors { left: parent.left; right: parent.right; top: parent.top }
height: childrenRect.height
spacing: app.margins
RowLayout {
Layout.fillWidth: true
spacing: app.margins
ColorIcon {
Layout.preferredHeight: app.iconSize * 2
Layout.preferredWidth: height
name: "../images/dialog-warning-symbolic.svg"
color: app.guhAccent
}
Label {
id: titleLabel
Layout.fillWidth: true
wrapMode: Text.WordWrap
text: qsTr("Warning")
color: app.guhAccent
font.pixelSize: app.largeFont
}
}
Label {
Layout.fillWidth: true
wrapMode: Text.WordWrap
text: "The authenticity of this nymea box cannot be verified. Do you want to trust this device?"
text: "The authenticity of this nymea box cannot be verified."
}
Label {
Layout.fillWidth: true
wrapMode: Text.WordWrap
text: "Device name: " + certDialog.commonName
text: "If this is the first time you connect to this box, this is expected. Once you trust a box, you should never see this message again for that one. If you see this message multiple times for the same box, something suspicious is going on!"
}
GridLayout {
columns: 2
Repeater {
model: certDialog.issuerInfo
Label {
Layout.fillWidth: true
wrapMode: Text.WordWrap
text: modelData
}
}
}
Label {
Layout.fillWidth: true
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
text: "Fingerprint: " + certDialog.fingerprint
}
Label {
Layout.fillWidth: true
wrapMode: Text.WordWrap
text: "Do you want to trust this device?"
font.bold: true
}
}
onAccepted: {

View File

@ -14,9 +14,37 @@ Page {
onBackPressed: root.backPressed()
}
Connections {
target: Engine.jsonRpcClient
onAuthenticationFailed: {
var popup = errorDialog.createObject(root)
popup.text = qsTr("Sorry, that wasn't right. Try again please.")
popup.open();
}
onCreateUserFailed: {
print("create user failed")
var text
switch (error) {
case "UserErrorInvalidUserId":
text = qsTr("The email you've entered isn't valid.");
break;
case "UserErrorBadPassword":
text = qsTr("The password you've chose is too weak.");
break;
default:
text = qsTr("An error happened creating the user.");
}
// var popup = errorDialog.createObject(root, {title: qsTr("Error creating user"), text: text})
var popup = errorDialog.createObject(root, {title: "Error creating user", text: text})
popup.open();
}
}
ColumnLayout {
anchors.fill: parent
anchors.margins: app.margins
spacing: app.margins
Label {
Layout.fillWidth: true
@ -26,29 +54,66 @@ Page {
wrapMode: Text.WordWrap
}
Label {
text: "Username:"
ColumnLayout {
Layout.fillWidth: true
Label {
text: "Your e-mail address:"
Layout.fillWidth: true
}
TextField {
id: usernameTextField
Layout.fillWidth: true
inputMethodHints: Qt.ImhEmailCharactersOnly
placeholderText: "john.smith@cooldomain.com"
}
}
TextField {
id: usernameTextField
ColumnLayout {
Layout.fillWidth: true
inputMethodHints: Qt.ImhEmailCharactersOnly
Label {
Layout.fillWidth: true
text: "Password:"
}
TextField {
id: passwordTextField
Layout.fillWidth: true
echoMode: TextInput.Password
}
}
ColumnLayout {
Layout.fillWidth: true
visible: Engine.jsonRpcClient.initialSetupRequired
Label {
Layout.fillWidth: true
text: "Confirm password:"
}
TextField {
id: confirmPasswordTextField
Layout.fillWidth: true
echoMode: TextInput.Password
}
}
Label {
Layout.fillWidth: true
text: "Password:"
}
TextField {
id: passwordTextField
Layout.fillWidth: true
echoMode: TextInput.Password
visible: Engine.jsonRpcClient.initialSetupRequired
opacity: (passwordTextField.text.length > 0 && passwordTextField.text.length < 8) || passwordTextField.text != confirmPasswordTextField.text ? 1 : 0
text: passwordTextField.text.length < 8 ? qsTr("This password isn't long enought to be secure, add some more characters please.")
: qsTr("The passwords don't match.")
wrapMode: Text.WordWrap
Layout.preferredHeight: confirmPasswordTextField.height * 2
color: app.guhAccent
}
Button {
Layout.fillWidth: true
text: "OK"
enabled: usernameTextField.text.length >= 5 && passwordTextField.text.length >= 8
&& (!Engine.jsonRpcClient.initialSetupRequired || confirmPasswordTextField.text == passwordTextField.text)
onClicked: {
console.log("foooo")
if (Engine.jsonRpcClient.initialSetupRequired) {
print("create user")
Engine.jsonRpcClient.createUser(usernameTextField.text, passwordTextField.text);
@ -63,4 +128,11 @@ Page {
Layout.fillWidth: true
}
}
Component {
id: errorDialog
ErrorDialog {
}
}
}

View File

@ -0,0 +1,77 @@
import QtQuick 2.5
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.1
import Mea 1.0
import "components"
Page {
id: root
signal backPressed();
header: GuhHeader {
text: "Welcome to nymea!"
backButtonVisible: true
onBackPressed: {
root.backPressed();
}
}
Component.objectName: {
Engine.jsonRpcClient.requestPushButtonAuth("");
}
Connections {
target: Engine.jsonRpcClient
onPushButtonAuthFailed: {
var popup = errorDialog.createObject(root)
popup.text = qsTr("Sorry, something went wrong during the setup. Try again please.")
popup.open();
popup.accepted.connect(function() {root.backPressed()})
}
}
ColumnLayout {
anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter }
anchors.margins: app.margins
spacing: app.margins
RowLayout {
Layout.fillWidth: true
spacing: app.margins
ColorIcon {
height: app.iconSize * 2
width: height
color: app.guhAccent
name: "../images/info.svg"
}
Label {
color: app.guhAccent
text: qsTr("Authentication required")
wrapMode: Text.WordWrap
Layout.fillWidth: true
font.pixelSize: app.largeFont
}
}
Label {
Layout.fillWidth: true
text: "Please press the button on your nymea box to authenticate this device."
wrapMode: Text.WordWrap
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
}
}
Component {
id: errorDialog
ErrorDialog {
}
}
}

View File

@ -1,9 +1,11 @@
import QtQuick 2.8
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.2
Dialog {
width: parent.width * .6
height: parent.height * .6
id: root
width: Math.min(parent.width * .6, 400)
// height: content.height
x: (parent.width - width) / 2
y: (parent.height - height) / 2
@ -12,9 +14,40 @@ Dialog {
standardButtons: Dialog.Ok
Label {
id: contentLabel
width: parent.width
wrapMode: Text.WordWrap
header: Item {
implicitHeight: headerRow.height + app.margins * 2
implicitWidth: parent.width
RowLayout {
id: headerRow
anchors { left: parent.left; right: parent.right; top: parent.top; margins: app.margins }
spacing: app.margins
ColorIcon {
Layout.preferredHeight: app.iconSize * 2
Layout.preferredWidth: height
name: "../images/dialog-error-symbolic.svg"
color: app.guhAccent
}
Label {
id: titleLabel
Layout.fillWidth: true
wrapMode: Text.WordWrap
text: root.title
color: app.guhAccent
font.pixelSize: app.largeFont
}
}
}
ColumnLayout {
id: content
anchors { left: parent.left; top: parent.top; right: parent.right }
height: childrenRect.height
Label {
id: contentLabel
Layout.fillWidth: true
wrapMode: Text.WordWrap
}
}
}

View File

@ -0,0 +1,182 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="96"
height="96"
id="svg4874"
version="1.1"
inkscape:version="0.91+devel r"
viewBox="0 0 96 96.000001"
sodipodi:docname="dialog-error-symbolic.svg">
<defs
id="defs4876" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="7.024999"
inkscape:cx="-10.960861"
inkscape:cy="37.302478"
inkscape:document-units="px"
inkscape:current-layer="g4780"
showgrid="true"
showborder="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="true"
inkscape:object-nodes="true"
inkscape:snap-smooth-nodes="true"
inkscape:snap-midpoints="true"
inkscape:snap-object-midpoints="true"
inkscape:snap-center="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:snap-global="true">
<inkscape:grid
type="xygrid"
id="grid5451"
empspacing="8" />
<sodipodi:guide
orientation="1,0"
position="8,-8.0000001"
id="guide4063" />
<sodipodi:guide
orientation="1,0"
position="4,-8.0000001"
id="guide4065" />
<sodipodi:guide
orientation="0,1"
position="-8,88.000001"
id="guide4067" />
<sodipodi:guide
orientation="0,1"
position="-8,92.000001"
id="guide4069" />
<sodipodi:guide
orientation="0,1"
position="104,4"
id="guide4071" />
<sodipodi:guide
orientation="0,1"
position="-5,8.0000001"
id="guide4073" />
<sodipodi:guide
orientation="1,0"
position="92,-8.0000001"
id="guide4075" />
<sodipodi:guide
orientation="1,0"
position="88,-8.0000001"
id="guide4077" />
<sodipodi:guide
orientation="0,1"
position="-8,84.000001"
id="guide4074" />
<sodipodi:guide
orientation="1,0"
position="12,-8.0000001"
id="guide4076" />
<sodipodi:guide
orientation="0,1"
position="-5,12"
id="guide4078" />
<sodipodi:guide
orientation="1,0"
position="84,-9.0000001"
id="guide4080" />
<sodipodi:guide
position="48,-8.0000001"
orientation="1,0"
id="guide4170" />
<sodipodi:guide
position="-8,48"
orientation="0,1"
id="guide4172" />
</sodipodi:namedview>
<metadata
id="metadata4879">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(67.857146,-78.50504)">
<g
transform="matrix(0,-1,-1,0,373.50506,516.50504)"
id="g4845"
style="display:inline">
<g
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="next01.png"
transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)"
id="g4778"
inkscape:label="Layer 1">
<g
transform="matrix(-1,0,0,1,575.99999,611)"
id="g4780"
style="display:inline">
<rect
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
id="rect4782"
width="96.037987"
height="96"
x="-438.00244"
y="345.36221"
transform="scale(-1,1)" />
<path
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#808080;fill-opacity:1;stroke:none"
d="m 364.0904,368.96573 c -0.0215,-0.0161 -0.0354,-0.0404 -0.0567,-0.0566 -0.0253,-0.0201 -0.057,-0.0305 -0.0821,-0.0508 z"
id="path4157" />
<path
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#808080;fill-opacity:1;stroke:none"
d="m 364.07673,417.80167 -0.13873,0.10742 c 0.0251,-0.0203 0.0569,-0.0307 0.0821,-0.0508 0.0214,-0.0162 0.0353,-0.0405 0.0567,-0.0566 z"
id="path4344" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:none;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.00079107;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 432,393.36133 c 0,23.17236 -18.83538,42 -42.01562,42 -23.18025,0 -42.01563,-18.82764 -42.01563,-42 0,-23.17236 18.83538,-42 42.01563,-42 23.18024,0 42.01562,18.82764 42.01562,42 z m -4.00195,0 c 0,-21.00932 -16.99476,-37.99805 -38.01367,-37.99805 -21.01892,0 -38.01563,16.98873 -38.01563,37.99805 0,21.00931 16.99671,37.99804 38.01563,37.99805 21.01891,0 38.01367,-16.98874 38.01367,-37.99805 z"
id="path4116"
inkscape:connector-curvature="0" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:none;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.00079155;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 406.57617,373.94727 -36.01367,36 2.82812,2.83007 36.01368,-36 -2.82813,-2.83007 z"
id="path4305"
inkscape:connector-curvature="0" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:none;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.00079155;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 373.39062,373.94727 -2.82812,2.83007 36.01367,36 2.82813,-2.83007 -36.01368,-36 z"
id="path4307"
inkscape:connector-curvature="0" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

@ -42,7 +42,7 @@ ApplicationWindow {
Connections {
target: Engine.jsonRpcClient
onConnectedChanged: {
print("json client connected changed")
print("json client connected changed", Engine.jsonRpcClient.connected)
if (Engine.jsonRpcClient.connected) {
settings.lastConnectedHost = Engine.connection.url
}
@ -68,14 +68,33 @@ ApplicationWindow {
}
function init() {
print("calling init. Auth required:", Engine.jsonRpcClient.authenticationRequired, "initial setup required:", Engine.jsonRpcClient.initialSetupRequired, "jsonrpc connected:", Engine.jsonRpcClient.connected)
pageStack.clear()
discovery.discovering = false;
if (!Engine.connection.connected) {
pageStack.push(Qt.resolvedUrl("ConnectPage.qml"))
print("starting discovery")
discovery.discovering = true;
return;
}
if (Engine.jsonRpcClient.authenticationRequired || Engine.jsonRpcClient.initialSetupRequired) {
var page = pageStack.push(Qt.resolvedUrl("LoginPage.qml"));
page.backPressed.connect(function() {
settings.lastConnectedHost = "";
Engine.connection.disconnect()
})
if (Engine.jsonRpcClient.pushButtonAuthAvailable) {
print("opening push button auth")
var page = pageStack.push(Qt.resolvedUrl("PushButtonAuthPage.qml"))
page.backPressed.connect(function() {
settings.lastConnectedHost = "";
Engine.connection.disconnect();
init();
})
} else {
var page = pageStack.push(Qt.resolvedUrl("LoginPage.qml"));
page.backPressed.connect(function() {
settings.lastConnectedHost = "";
Engine.connection.disconnect()
init();
})
}
} else if (Engine.jsonRpcClient.connected) {
pageStack.push(Qt.resolvedUrl("MainPage.qml"))
} else {