Mercurial > trustbridge
diff ui/createinstallerdialog.cpp @ 571:6c4fff146999
Implement codesigning in the administrator tool
author | Andre Heinecke <aheinecke@intevation.de> |
---|---|
date | Fri, 23 May 2014 16:17:18 +0000 |
parents | 421b69eeffe3 |
children | 49168bcb02e2 |
line wrap: on
line diff
--- a/ui/createinstallerdialog.cpp Fri May 23 16:16:33 2014 +0000 +++ b/ui/createinstallerdialog.cpp Fri May 23 16:17:18 2014 +0000 @@ -19,10 +19,25 @@ #include <QStyle> #include <QApplication> #include <QMessageBox> +#include <QTemporaryDir> + +/* Static information used in codesigning */ +#ifndef SIGN_HASH +#define SIGN_HASH "sha256" +#endif +#ifndef SIGN_URL +#define SIGN_URL "https://wald.intevation.org/projects/trustbridge/" +#endif +#ifndef SIGN_PUBLISHER +#define SIGN_PUBLISHER "TrustBridge Test with ümlaut" +#endif + CreateInstallerDialog::CreateInstallerDialog(QMainWindow *parent) : QDialog(parent), - mProgress(this) + mProgress(this), + mInstallerPath(), + mCurrentWorkingDir(NULL) { QSettings settings; setWindowTitle(tr("Create binary installer")); @@ -116,7 +131,6 @@ setLayout(topLayout); mProgress.setWindowModality(Qt::WindowModal); - mProgress.setLabelText(tr("Creating installer package...")); mProgress.setCancelButton(0); mProgress.setRange(0,0); mProgress.setMinimumDuration(0); @@ -162,9 +176,18 @@ void CreateInstallerDialog::processFinished(int exitCode, QProcess::ExitStatus exitStatus) { + if (mCurrentWorkingDir) { + delete mCurrentWorkingDir; + mCurrentWorkingDir = NULL; + } FinishedDialog *fin = new FinishedDialog(0, tr("Created installer in %1.") .arg(mSaveFile->text()), mNSISProc.readAll(), false); qDebug() << "Finished: " << mNSISProc.readAll(); + mProgress.setLabelText(tr("Signing installer package...")); + if (!signFile(mInstallerPath)) { + showErrorMessage(tr("Failed to sign installer package.")); + QFile::remove(mInstallerPath); + } mProgress.cancel(); fin->show(); close(); @@ -172,12 +195,17 @@ void CreateInstallerDialog::processError(QProcess::ProcessError error) { + if (mCurrentWorkingDir) { + delete mCurrentWorkingDir; + mCurrentWorkingDir = NULL; + } qDebug() << "Error: " << mNSISProc.readAll(); mProgress.cancel(); } void CreateInstallerDialog::createInstaller() { + mProgress.setLabelText(tr("Creating installer package...")); QDir binDir(mBinaryFolder->text()); QDir outDir(mSaveFile->text()); if (mBinaryFolder->text().isEmpty() || !binDir.exists()) { @@ -201,28 +229,39 @@ return; } + QTemporaryDir *signedFilesDir = codesignBinaries(binDir.path() + "/windows"); + + if (!signedFilesDir) { + /* Error messages should have been shown by the codesign function */ + return; + } + + mProgress.setLabelText(tr("Creating NSIS package...")); + /* Copy windows directory contents to tmpdir */ QStringList arguments; mNSISProc.setProgram("makensis"); mNSISProc.setProcessChannelMode(QProcess::MergedChannels); mNSISProc.setWorkingDirectory(outDir.path()); #ifdef Q_OS_WIN - arguments << QString::fromLatin1("/Dfiles_dir=") + binDir.path().replace("/", "\\") + "\\windows"; + arguments << QString::fromLatin1("/Dfiles_dir=") + signedFilesDir->path().replace("/", "\\"); arguments << "/Dpath_sep=\\"; foreach (const QString &key, keys) { QString value = options.value(key, QString()).toString(); if (key == "setupname") { value = value.arg(outDir.path().replace("/", "\\") + "\\"); + mInstallerPath = value; } arguments << QString::fromLatin1("/D%1=%2").arg(key, value); } #else - arguments << QString::fromLatin1("-Dfiles_dir=") + binDir.path() + "/windows"; + arguments << QString::fromLatin1("-Dfiles_dir=") + signedFilesDir->path(); arguments << "-Dpath_sep=/"; foreach (const QString &key, keys) { QString value = options.value(key, QString()).toString(); if (key == "setupname") { value = value.arg(outDir.path() + "/"); + mInstallerPath = value; } arguments << QString::fromLatin1("-D%1=%2").arg(key, value); } @@ -242,6 +281,85 @@ } } +bool CreateInstallerDialog::signFile(QString filePath) { + QProcess signProc; + signProc.setProcessChannelMode(QProcess::MergedChannels); + signProc.setProgram("osslsigncode"); + QStringList arguments; + + QSettings mySettings; + + QString publisher = mySettings.value("sign_publisher", SIGN_PUBLISHER).toString(); + QString url = mySettings.value("sign_url", SIGN_URL).toString(); + QString hash = mySettings.value("sign_hash", SIGN_HASH).toString(); + + arguments << "sign" << "-certs" << mCertFile->text() << "-key" + << mCertFile->text() << "-n" << publisher << "-i" << + url << "-h" << hash << "-in" << filePath << "-out" << filePath + ".signed"; + + qDebug() << "Starting osslsigncode with arguments: " << arguments; + signProc.setArguments(arguments); + signProc.start(); + + if (!signProc.waitForFinished(30000)) { + qDebug() << "Signing takes longer then 30 seconds. Aborting."; + return false; + } + + if (signProc.exitStatus() != QProcess::NormalExit || + signProc.exitCode() != 0) { + qDebug() << "Error process returned: " << signProc.exitCode(); + qDebug() << "Output: " << signProc.readAllStandardOutput(); + return false; + } + + if (!QFile::remove(filePath)) { + qDebug() << "Failed to remove file."; + return false; + } + if (!QFile::copy(filePath + ".signed", filePath)) { + qDebug() << "Failed to copy signed file in place."; + return false; + } + if (!QFile::remove(filePath + ".signed")) { + qDebug() << "Failed to remove signed."; + return false; + } + return true; +} + + +QTemporaryDir *CreateInstallerDialog::codesignBinaries(const QDir& sourceDir) { + QTemporaryDir* target = new QTemporaryDir(); + /* Copy all files from the source dir to a temporary location */ + mProgress.setLabelText(tr("Signing binaries...")); + + mProgress.show(); + foreach (const QFileInfo& entry, sourceDir.entryInfoList()) { + QString targetPath = target->path() + QString::fromLatin1("/") + entry.fileName(); + if (entry.fileName() == "." || entry.fileName() == "..") { + continue; + } + if (!QFile::copy(entry.absoluteFilePath(), targetPath)) { + qDebug() << "Failed to copy: " << entry.absoluteFilePath() << " to: " << targetPath; + showErrorMessage(tr("Failed to copy binaries to temporary location.")); + mProgress.cancel(); + return NULL; + } + if (entry.suffix() == "exe") { + if (!signFile(targetPath)) { + showErrorMessage(tr("Failed to sign binaries with osslsigncode.\n" + "Please check that %1 is a valid code signing certificate and that" + "osslsigncode can be found in the PATH.").arg(mCertFile->text())); + mProgress.cancel(); + return NULL; + } + } + } + mProgress.cancel(); + return target; +} + FinishedDialog::FinishedDialog(QDialog *parent, QString msg, QString details, bool isErr): QDialog(parent)