Răsfoiți Sursa

Install dialog in UI.

Adam Ierymenko 11 ani în urmă
părinte
comite
67a71868cb

+ 6 - 3
ZeroTierUI/ZeroTierUI.pro

@@ -39,7 +39,8 @@ SOURCES += main.cpp\
 		../node/Utils.cpp \
 		../node/Utils.cpp \
 		../ext/lz4/lz4.c \
 		../ext/lz4/lz4.c \
 		../ext/lz4/lz4hc.c \
 		../ext/lz4/lz4hc.c \
-		networkwidget.cpp
+		networkwidget.cpp \
+    installdialog.cpp
 
 
 HEADERS  += mainwindow.h \
 HEADERS  += mainwindow.h \
 		aboutwindow.h \
 		aboutwindow.h \
@@ -88,11 +89,13 @@ HEADERS  += mainwindow.h \
 		../node/UdpSocket.hpp \
 		../node/UdpSocket.hpp \
 		../ext/lz4/lz4.h \
 		../ext/lz4/lz4.h \
 		../ext/lz4/lz4hc.h \
 		../ext/lz4/lz4hc.h \
-		networkwidget.h
+		networkwidget.h \
+    installdialog.h
 
 
 FORMS    += mainwindow.ui \
 FORMS    += mainwindow.ui \
 		aboutwindow.ui \
 		aboutwindow.ui \
-		networkwidget.ui
+		networkwidget.ui \
+    installdialog.ui
 
 
 RESOURCES += \
 RESOURCES += \
 		resources.qrc
 		resources.qrc

+ 83 - 0
ZeroTierUI/installdialog.cpp

@@ -0,0 +1,83 @@
+#include "installdialog.h"
+#include "mainwindow.h"
+#include "ui_installdialog.h"
+
+#include "../node/Defaults.hpp"
+
+#include <QMainWindow>
+#include <QMessageBox>
+#include <QByteArray>
+#include <QSslSocket>
+
+InstallDialog::InstallDialog(QWidget *parent) :
+	QDialog(parent),
+	ui(new Ui::InstallDialog),
+	nam(new QNetworkAccessManager(this))
+{
+	ui->setupUi(this);
+	QObject::connect(nam,SIGNAL(finished(QNetworkReply*)),this,SLOT(on_networkReply(QNetworkReply*)));
+
+	const char *nfoUrl = ZeroTier::ZT_DEFAULTS.updateLatestNfoURL.c_str();
+	if (!*nfoUrl) {
+		QMessageBox::critical(this,"Download Failed","Download failed: internal error: no update URL configured in build!",QMessageBox::Ok,QMessageBox::NoButton);
+		QApplication::exit(1);
+		return;
+	}
+
+	QNetworkReply *reply = nam->get(QNetworkRequest(QUrl(nfoUrl)));
+	QObject::connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(on_downloadProgress(qint64,qint64)));
+}
+
+InstallDialog::~InstallDialog()
+{
+	delete ui;
+}
+
+void InstallDialog::on_networkReply(QNetworkReply *reply)
+{
+	reply->deleteLater();
+
+	if (reply->error() != QNetworkReply::NoError) {
+		QMessageBox::critical(this,"Download Failed",QString("Download failed: ") + reply->errorString(),QMessageBox::Ok,QMessageBox::NoButton);
+		QApplication::exit(1);
+		return;
+	} else {
+		if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 200) {
+			QByteArray installerData(reply->readAll());
+			installerData.append((char)0);
+			printf("%s\n",installerData.data());
+		} else {
+			QMessageBox::critical(this,"Download Failed",QString("Download failed: HTTP status code ") + reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString(),QMessageBox::Ok,QMessageBox::NoButton);
+			QApplication::exit(1);
+			return;
+		}
+	}
+}
+
+void InstallDialog::on_InstallDialog_rejected()
+{
+	QApplication::exit();
+}
+
+//((QMainWindow *)this->parent())->setHidden(false);
+
+void InstallDialog::on_cancelButton_clicked()
+{
+	QApplication::exit();
+}
+
+void InstallDialog::on_downloadProgress(qint64 bytesReceived,qint64 bytesTotal)
+{
+	if (bytesTotal <= 0) {
+		ui->progressBar->setValue(0);
+		ui->progressBar->setMinimum(0);
+		ui->progressBar->setMaximum(0);
+	} else {
+		double pct = ((double)bytesReceived / (double)bytesTotal) * 100.0;
+		if (pct > 100.0)
+			pct = 100.0;
+		ui->progressBar->setMinimum(0);
+		ui->progressBar->setMaximum(100);
+		ui->progressBar->setValue((int)pct);
+	}
+}

+ 33 - 0
ZeroTierUI/installdialog.h

@@ -0,0 +1,33 @@
+#ifndef INSTALLDIALOG_H
+#define INSTALLDIALOG_H
+
+#include <QDialog>
+#include <QNetworkAccessManager>
+#include <QUrl>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+
+namespace Ui {
+class InstallDialog;
+}
+
+class InstallDialog : public QDialog
+{
+	Q_OBJECT
+
+public:
+	explicit InstallDialog(QWidget *parent = 0);
+	~InstallDialog();
+
+private slots:
+	void on_networkReply(QNetworkReply *reply);
+	void on_InstallDialog_rejected();
+	void on_cancelButton_clicked();
+	void on_downloadProgress(qint64 bytesReceived,qint64 bytesTotal);
+
+private:
+	Ui::InstallDialog *ui;
+	QNetworkAccessManager *nam;
+};
+
+#endif // INSTALLDIALOG_H

+ 131 - 0
ZeroTierUI/installdialog.ui

@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>InstallDialog</class>
+ <widget class="QDialog" name="InstallDialog">
+  <property name="windowModality">
+   <enum>Qt::ApplicationModal</enum>
+  </property>
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>547</width>
+    <height>231</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Install ZeroTier One Service</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="resources.qrc">
+    <normaloff>:/img/zt1icon.png</normaloff>:/img/zt1icon.png</iconset>
+  </property>
+  <property name="sizeGripEnabled">
+   <bool>true</bool>
+  </property>
+  <property name="modal">
+   <bool>true</bool>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <property name="leftMargin">
+    <number>6</number>
+   </property>
+   <property name="topMargin">
+    <number>6</number>
+   </property>
+   <property name="rightMargin">
+    <number>6</number>
+   </property>
+   <property name="bottomMargin">
+    <number>6</number>
+   </property>
+   <item>
+    <widget class="QLabel" name="label">
+     <property name="sizePolicy">
+      <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="font">
+      <font>
+       <pointsize>14</pointsize>
+      </font>
+     </property>
+     <property name="text">
+      <string>Since this is your first time running ZeroTier One on this computer, the virtual Ethernet service must be downloaded and installed.
+
+Please wait while the service downloads, then you will be prompted to enter an administrator password to install it.</string>
+     </property>
+     <property name="textFormat">
+      <enum>Qt::PlainText</enum>
+     </property>
+     <property name="alignment">
+      <set>Qt::AlignCenter</set>
+     </property>
+     <property name="wordWrap">
+      <bool>true</bool>
+     </property>
+     <property name="margin">
+      <number>10</number>
+     </property>
+     <property name="textInteractionFlags">
+      <set>Qt::NoTextInteraction</set>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QProgressBar" name="progressBar">
+     <property name="maximum">
+      <number>0</number>
+     </property>
+     <property name="value">
+      <number>0</number>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QWidget" name="widget" native="true">
+     <layout class="QHBoxLayout" name="horizontalLayout">
+      <property name="leftMargin">
+       <number>0</number>
+      </property>
+      <property name="topMargin">
+       <number>0</number>
+      </property>
+      <property name="rightMargin">
+       <number>0</number>
+      </property>
+      <property name="bottomMargin">
+       <number>0</number>
+      </property>
+      <item>
+       <spacer name="horizontalSpacer">
+        <property name="orientation">
+         <enum>Qt::Horizontal</enum>
+        </property>
+        <property name="sizeHint" stdset="0">
+         <size>
+          <width>40</width>
+          <height>20</height>
+         </size>
+        </property>
+       </spacer>
+      </item>
+      <item>
+       <widget class="QPushButton" name="cancelButton">
+        <property name="text">
+         <string>Cancel and Exit</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>

+ 17 - 10
ZeroTierUI/mainwindow.cpp

@@ -2,6 +2,7 @@
 #include "aboutwindow.h"
 #include "aboutwindow.h"
 #include "networkwidget.h"
 #include "networkwidget.h"
 #include "ui_mainwindow.h"
 #include "ui_mainwindow.h"
+#include "installdialog.h"
 
 
 #include <string>
 #include <string>
 #include <map>
 #include <map>
@@ -54,16 +55,14 @@ static void handleZTMessage(void *arg,unsigned long id,const char *line)
 MainWindow::MainWindow(QWidget *parent) :
 MainWindow::MainWindow(QWidget *parent) :
 	QMainWindow(parent),
 	QMainWindow(parent),
 	ui(new Ui::MainWindow),
 	ui(new Ui::MainWindow),
-	nam(new QNetworkAccessManager(this))
+	pollServiceTimerId(0)
 {
 {
 	ui->setupUi(this);
 	ui->setupUi(this);
-	this->startTimer(1000); // poll service every second
+	this->pollServiceTimerId = this->startTimer(1000);
 	this->setEnabled(false); // gets enabled when updates are received
 	this->setEnabled(false); // gets enabled when updates are received
 	mainWindow = this;
 	mainWindow = this;
 	this->cyclesSinceResponseFromService = 0;
 	this->cyclesSinceResponseFromService = 0;
 
 
-	QObject::connect(nam,SIGNAL(finished(QNetworkReply*)),this,SLOT(on_networkReply(QNetworkReply*)));
-
 	if (ui->networkListWidget->verticalScrollBar())
 	if (ui->networkListWidget->verticalScrollBar())
 		ui->networkListWidget->verticalScrollBar()->setSingleStep(8);
 		ui->networkListWidget->verticalScrollBar()->setSingleStep(8);
 
 
@@ -84,11 +83,15 @@ void MainWindow::timerEvent(QTimerEvent *event)
 {
 {
 	event->accept();
 	event->accept();
 
 
+	if (this->isHidden())
+		return;
+
 	if (!zeroTierClient) {
 	if (!zeroTierClient) {
 		std::string authToken;
 		std::string authToken;
 		if (!ZeroTier::Utils::readFile(ZeroTier::Node::LocalClient::authTokenDefaultUserPath().c_str(),authToken)) {
 		if (!ZeroTier::Utils::readFile(ZeroTier::Node::LocalClient::authTokenDefaultUserPath().c_str(),authToken)) {
 #ifdef __APPLE__
 #ifdef __APPLE__
-			if (QFile::exists("/Library/Application Support/ZeroTier/One/zerotier-one")) {
+			//if (QFile::exists("/Library/Application Support/ZeroTier/One/zerotier-one")) {
+			if (false) {
 				// Run the little AppleScript hack that asks for admin credentials and
 				// Run the little AppleScript hack that asks for admin credentials and
 				// then installs the auth token file in the current user's home.
 				// then installs the auth token file in the current user's home.
 				QString authHelperPath(QCoreApplication::applicationDirPath() + "/../Resources/helpers/mac/ZeroTier One (Authenticate).app/Contents/MacOS/applet");
 				QString authHelperPath(QCoreApplication::applicationDirPath() + "/../Resources/helpers/mac/ZeroTier One (Authenticate).app/Contents/MacOS/applet");
@@ -105,11 +108,18 @@ void MainWindow::timerEvent(QTimerEvent *event)
 				}
 				}
 				QProcess::execute(authHelperPath,QStringList());
 				QProcess::execute(authHelperPath,QStringList());
 			} else {
 			} else {
-				// Download the latest version and install it
+				// If the service is not installed, download the installer and run it
+				// for the first time.
 				this->setEnabled(false);
 				this->setEnabled(false);
+				InstallDialog *id = new InstallDialog(this);
+				id->setModal(true);
+				id->show();
+				this->setHidden(true);
+				return;
 
 
 				// Run the little AppleScript hack that asks for admin credentials and
 				// Run the little AppleScript hack that asks for admin credentials and
 				// then installs the auth token file in the current user's home.
 				// then installs the auth token file in the current user's home.
+				/*
 				QString installHelperPath(QCoreApplication::applicationDirPath() + "/../Resources/helpers/mac/ZeroTier One (Install).app/Contents/MacOS/applet");
 				QString installHelperPath(QCoreApplication::applicationDirPath() + "/../Resources/helpers/mac/ZeroTier One (Install).app/Contents/MacOS/applet");
 				if (!QFile::exists(installHelperPath)) {
 				if (!QFile::exists(installHelperPath)) {
 					QMessageBox::critical(this,"Unable to Locate Helper","Unable to locate install helper, cannot install service.",QMessageBox::Ok,QMessageBox::NoButton);
 					QMessageBox::critical(this,"Unable to Locate Helper","Unable to locate install helper, cannot install service.",QMessageBox::Ok,QMessageBox::NoButton);
@@ -117,6 +127,7 @@ void MainWindow::timerEvent(QTimerEvent *event)
 					return;
 					return;
 				}
 				}
 				QProcess::execute(installHelperPath,QStringList());
 				QProcess::execute(installHelperPath,QStringList());
+				*/
 			}
 			}
 #endif
 #endif
 
 
@@ -306,7 +317,3 @@ void MainWindow::on_addressButton_clicked()
 {
 {
 	QApplication::clipboard()->setText(this->myAddress);
 	QApplication::clipboard()->setText(this->myAddress);
 }
 }
-
-void MainWindow::on_networkReply(QNetworkReply *reply)
-{
-}

+ 1 - 6
ZeroTierUI/mainwindow.h

@@ -4,10 +4,6 @@
 #include <QMainWindow>
 #include <QMainWindow>
 #include <QEvent>
 #include <QEvent>
 #include <QString>
 #include <QString>
-#include <QNetworkAccessManager>
-#include <QUrl>
-#include <QNetworkRequest>
-#include <QNetworkReply>
 
 
 #include <map>
 #include <map>
 #include <vector>
 #include <vector>
@@ -55,15 +51,14 @@ private slots:
 	void on_actionAbout_triggered();
 	void on_actionAbout_triggered();
 	void on_networkIdLineEdit_textChanged(const QString &text);
 	void on_networkIdLineEdit_textChanged(const QString &text);
 	void on_addressButton_clicked();
 	void on_addressButton_clicked();
-	void on_networkReply(QNetworkReply *reply);
 
 
 private:
 private:
 	Ui::MainWindow *ui;
 	Ui::MainWindow *ui;
 
 
-	QNetworkAccessManager *nam;
 	QString myAddress;
 	QString myAddress;
 	QString myStatus;
 	QString myStatus;
 	QString myVersion;
 	QString myVersion;
+	int pollServiceTimerId;
 	unsigned int numPeers;
 	unsigned int numPeers;
 	unsigned int cyclesSinceResponseFromService;
 	unsigned int cyclesSinceResponseFromService;
 	std::map< std::string,std::vector<std::string> > networks;
 	std::map< std::string,std::vector<std::string> > networks;

+ 113 - 0
ext/installfiles/linux/install.tmpl.sh

@@ -0,0 +1,113 @@
+#!/bin/bash
+
+export PATH=/bin:/usr/bin:/sbin:/usr/sbin
+shopt -s expand_aliases
+
+dryRun=0
+
+echo "*** ZeroTier One install/update ***"
+
+if [ "$UID" -ne 0 ]; then
+	echo "Not running as root so doing dry run (no modifications to system)..."
+	dryRun=1
+fi
+
+if [ $dryRun -gt 0 ]; then
+	alias ln="echo '>> dry run: ln'"
+	alias rm="echo '>> dry run: rm'"
+	alias mv="echo '>> dry run: mv'"
+	alias chown="echo '>> dry run: chown'"
+	alias chgrp="echo '>> dry run: chgrp'"
+	alias launchctl="echo '>> dry run: launchctl'"
+	alias zerotier-cli="echo '>> dry run: zerotier-cli'"
+fi
+
+zthome="/Library/Application Support/ZeroTier/One"
+ztapp=`mdfind kMDItemCFBundleIdentifier == 'com.zerotier.ZeroTierOne'`
+if [ ! -d "$ztapp" ]; then
+	ztapp="/Applications/ZeroTier One.app"
+fi
+
+scriptPath="`dirname "$0"`/`basename "$0"`"
+if [ ! -r "$scriptPath" ]; then
+	scriptPath="$0"
+	if [ ! -r "$scriptPath" ]; then
+		echo "Installer cannot determine its own path; $scriptPath is not readable."
+		exit 2
+	fi
+fi
+
+endMarkerIndex=`grep -a -b -E '^################' "$scriptPath" | head -c 16 | cut -d : -f 1`
+if [ "$endMarkerIndex" -le 100 ]; then
+	echo 'Internal error: unable to find end of script / start of binary data marker.'
+	exit 2
+fi
+blobStart=`expr $endMarkerIndex + 17`
+if [ "$blobStart" -le "$endMarkerIndex" ]; then
+	echo 'Internal error: unable to find end of script / start of binary data marker.'
+	exit 2
+fi
+
+echo 'Extracting files...'
+if [ $dryRun -gt 0 ]; then
+	echo ">> dry run: tail -c +$blobStart \"$scriptPath\" | bunzip2 -c | tar -xvop -C / -f -"
+else
+	tail -c +$blobStart "$scriptPath" | bunzip2 -c | tar -xvop -C / -f -
+fi
+
+if [ $dryRun -eq 0 -a ! -d "/Applications/ZeroTier One_app.LATEST" ]; then
+	echo 'Archive extraction failed, cannot find zerotier-one binary.'
+	exit 2
+fi
+
+echo 'Installing/updating ZeroTier One.app...'
+
+if [ -d "$ztapp" ]; then
+	# Preserve ownership of existing .app and install new version in the
+	# same location.
+	currentAppOwner=`stat -f '%u' "$ztapp"`
+	currentAppGroup=`stat -f '%g' "$ztapp"`
+	if [ ! -z "$currentAppOwner" -a ! -z "$currentAppGroup" ]; then
+		rm -rf "$ztapp"
+		mv -f "/Application/ZeroTier One_app.LATEST" "$ztapp"
+		chown -R $currentAppOwner "$ztapp"
+		chgrp -R $currentAppGroup "$ztapp"
+	else
+		rm -rf "$ztapp"
+		mv -f "/Application/ZeroTier One_app.LATEST" "$ztapp"
+	fi
+else
+	# If there is no existing app, just drop the shipped one into place
+	mv -f "/Applications/ZeroTier One_app.LATEST" "/Applications/ZeroTier One.app"
+fi
+
+echo 'Installing zerotier-cli command line utility...'
+
+ln -sf "/Library/Application Support/ZeroTier/One/zerotier-one" /usr/bin/zerotier-cli
+
+if [ ! -f '/Library/Application Support/ZeroTier/One/authtoken.secret' ]; then
+	echo 'Pre-creating authtoken.secret for ZeroTier service...'
+	if [ $dryRun -eq 0 ]; then
+		rm -f '/Library/Application Support/ZeroTier/One/authtoken.secret'
+		head -c 1024 /dev/urandom | md5 | head -c 24 >'/Library/Application Support/ZeroTier/One/authtoken.secret'
+		chmod 0600 '/Library/Application Support/ZeroTier/One/authtoken.secret'
+	fi
+fi
+
+echo 'Installing and (re-)starting zerotier-one service via launchctl...'
+
+if [ ! -z "`launchctl list | grep -F com.zerotier.one`" ]; then
+	launchctl unload /Library/LaunchDaemons/com.zerotier.one.plist
+fi
+launchctl load /Library/LaunchDaemons/com.zerotier.one.plist
+
+sleep 1
+zerotier-cli info
+
+exit 0
+
+# Do not remove the last line or add a carriage return to it! The installer
+# looks for an unterminated line beginning with 16 #'s in itself to find
+# the binary blob data, which is appended after it.
+
+################