summaryrefslogtreecommitdiff
path: root/ZeroTierUI/installdialog.cpp
blob: 2f453e3d22070cbfbd9d5aa05ed13c02b3bf3645 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include "installdialog.h"
#include "mainwindow.h"
#include "ui_installdialog.h"

#include "../node/Constants.hpp"
#include "../node/Defaults.hpp"
#include "../node/SoftwareUpdater.hpp"

#ifdef __UNIX_LIKE__
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif

#include <QMainWindow>
#include <QMessageBox>
#include <QByteArray>
#include <QSslSocket>
#include <QFile>
#include <QDir>
#include <QProcess>

InstallDialog::InstallDialog(QWidget *parent) :
	QDialog(parent),
	ui(new Ui::InstallDialog),
	nam(new QNetworkAccessManager(this)),
	phase(FETCHING_NFO)
{
	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() + "\n\nAre you connected to the Internet?",QMessageBox::Ok,QMessageBox::NoButton);
		QApplication::exit(1);
	} else {
		if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute) == 200) {
			QByteArray installerData(reply->readAll());

			switch(phase) {
				case FETCHING_NFO: {
					unsigned int vMajor = 0,vMinor = 0,vRevision = 0;
					installerData.append((char)0);
					const char *err = ZeroTier::SoftwareUpdater::parseNfo(installerData.data(),vMajor,vMinor,vRevision,signedBy,signature,url);

					if (err) {
						QMessageBox::critical(this,"Download Failed","Download failed: there is a problem with the software update web site.\nTry agian later. (invalid .nfo file)",QMessageBox::Ok,QMessageBox::NoButton);
						QApplication::exit(1);
						return;
					}

					phase = FETCHING_INSTALLER;
					reply = nam->get(QNetworkRequest(QUrl(url.c_str())));
					QObject::connect(reply,SIGNAL(downloadProgress(qint64,qint64)),this,SLOT(on_downloadProgress(qint64,qint64)));
				}	break;
				case FETCHING_INSTALLER: {
					if (!ZeroTier::SoftwareUpdater::validateUpdate(installerData.data(),installerData.length(),signedBy,signature)) {
						QMessageBox::critical(this,"Download Failed","Download failed: there is a problem with the software update web site.\nTry agian later. (failed signature check)",QMessageBox::Ok,QMessageBox::NoButton);
						QApplication::exit(1);
						return;
					}

#ifdef __APPLE__
					QString zt1Caches(QDir::homePath() + "/Library/Caches/ZeroTier/One");
					QDir::root().mkpath(zt1Caches);
					QString instPath(zt1Caches+"/ZeroTierOneInstaller");

					int outfd = ::open(instPath.toStdString().c_str(),O_CREAT|O_TRUNC|O_WRONLY,0755);
					if (outfd <= 0) {
						QMessageBox::critical(this,"Download Failed",QString("Installation failed: unable to write to ")+instPath,QMessageBox::Ok,QMessageBox::NoButton);
						QApplication::exit(1);
						return;
					}
					if (::write(outfd,installerData.data(),installerData.length()) != installerData.length()) {
						QMessageBox::critical(this,"Installation Failed",QString("Installation failed: unable to write to ")+instPath,QMessageBox::Ok,QMessageBox::NoButton);
						QApplication::exit(1);
						return;
					}
					::close(outfd);
					::chmod(instPath.toStdString().c_str(),0755);

					QString installHelperPath(QCoreApplication::applicationDirPath() + "/../Resources/helpers/mac/ZeroTier One (Install).app/Contents/MacOS/applet");
					if (!QFile::exists(installHelperPath)) {
						QMessageBox::critical(this,"Unable to Locate Helper","Unable to locate install helper, cannot install service.",QMessageBox::Ok,QMessageBox::NoButton);
						QApplication::exit(1);
						return;
					}
					QProcess::execute(installHelperPath,QStringList());

					if (!QFile::exists("/Library/Application Support/ZeroTier/One/zerotier-one")) {
						QMessageBox::critical(this,"Installation Failed","Installation failed. Are you sure you entered your password correctly?",QMessageBox::Ok,QMessageBox::NoButton);
						QApplication::exit(1);
						return;
					}

					((QMainWindow *)this->parent())->setHidden(false);
					this->close();
					return;
#endif
				}	break;
			}

			ui->progressBar->setMinimum(0);
			ui->progressBar->setMaximum(100);
			ui->progressBar->setValue(0);
		} else {
			QMessageBox::critical(this,"Download Failed",QString("Download failed: HTTP status code ") + reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toString(),QMessageBox::Ok,QMessageBox::NoButton);
			QApplication::exit(1);
		}
	}
}

void InstallDialog::on_InstallDialog_rejected()
{
	QApplication::exit();
}

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);
	}
}