diff --git a/src/plugins/qt4projectmanager/qt-s60/certificatepathchooser.cpp b/src/plugins/qt4projectmanager/qt-s60/certificatepathchooser.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7c31c853291c326049c89433eb0a157c7178e806 --- /dev/null +++ b/src/plugins/qt4projectmanager/qt-s60/certificatepathchooser.cpp @@ -0,0 +1,46 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "certificatepathchooser.h" + +#include <QMessageBox> + +#include "s60certificateinfo.h" + +CertificatePathChooser::CertificatePathChooser(QWidget *parent) : + Utils::PathChooser(parent) +{ +} + +bool CertificatePathChooser::validatePath(const QString &path, QString *errorMessage) +{ + if (Utils::PathChooser::validatePath(path, errorMessage)) + return S60CertificateInfo::validateCertificate(path, errorMessage) == S60CertificateInfo::CertificateValid; + return false; +} diff --git a/src/plugins/qt4projectmanager/qt-s60/certificatepathchooser.h b/src/plugins/qt4projectmanager/qt-s60/certificatepathchooser.h new file mode 100644 index 0000000000000000000000000000000000000000..667611e43c92ba6e774d6e68b71f078583646e10 --- /dev/null +++ b/src/plugins/qt4projectmanager/qt-s60/certificatepathchooser.h @@ -0,0 +1,45 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef CERTIFICATEPATHCHOOSER_H +#define CERTIFICATEPATHCHOOSER_H + +#include "utils/pathchooser.h" + +class CertificatePathChooser : public Utils::PathChooser +{ + Q_DISABLE_COPY(CertificatePathChooser) + Q_OBJECT +public: + explicit CertificatePathChooser(QWidget *parent = 0); + + virtual bool validatePath(const QString &path, QString *errorMessage = 0); +}; + +#endif // CERTIFICATEPATHCHOOSER_H diff --git a/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri b/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri index 92318932b707e9d879c3569f1560aae184fabcfc..df0d186af59c1f6a789b7dfbc4bab0fcff8c38f9 100644 --- a/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri +++ b/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri @@ -21,7 +21,9 @@ SOURCES += $$PWD/s60devices.cpp \ $$PWD/s60createpackageparser.cpp \ $$PWD/passphraseforkeydialog.cpp \ $$PWD/s60deployconfiguration.cpp \ - $$PWD/s60deployconfigurationwidget.cpp + $$PWD/s60deployconfigurationwidget.cpp \ + $$PWD/s60certificateinfo.cpp \ + $$PWD/certificatepathchooser.cpp HEADERS += $$PWD/s60devices.h \ $$PWD/s60devicespreferencepane.h \ $$PWD/s60manager.h \ @@ -42,6 +44,8 @@ HEADERS += $$PWD/s60devices.h \ $$PWD/s60createpackageparser.h \ $$PWD/passphraseforkeydialog.h \ $$PWD/s60deployconfiguration.h \ - $$PWD/s60deployconfigurationwidget.h + $$PWD/s60deployconfigurationwidget.h \ + $$PWD/s60certificateinfo.h \ + $$PWD/certificatepathchooser.h FORMS += $$PWD/s60devicespreferencepane.ui \ $$PWD/s60createpackagestep.ui diff --git a/src/plugins/qt4projectmanager/qt-s60/s60certificateinfo.cpp b/src/plugins/qt4projectmanager/qt-s60/s60certificateinfo.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f44c0a047ce316bd0613982249b0159fde5c0a43 --- /dev/null +++ b/src/plugins/qt4projectmanager/qt-s60/s60certificateinfo.cpp @@ -0,0 +1,90 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "s60certificateinfo.h" + +#include <QDateTime> +#include <QFileInfo> +#include <QCoreApplication> + +#include <botan/x509cert.h> + +S60CertificateInfo::CertificateState S60CertificateInfo::validateCertificate(const QString &certFilePath, QString *errorString) +{ + bool certFileCorrupted = false; + CertificateState result = CertificateValid; + Botan::X509_Certificate *certificate = 0; + try { + certificate = new Botan::X509_Certificate(certFilePath.toStdString()); + if (certificate) { + const char * const CERTIFICATE_DATE_FORMAT = "yyyy/M/d h:mm:ss UTC"; + + QDateTime startTime = QDateTime::fromString(QString::fromStdString(certificate->start_time()), + QLatin1String(CERTIFICATE_DATE_FORMAT)); + QDateTime startTimeUTC(startTime.date(), startTime.time(), Qt::UTC); + + QDateTime endTime = QDateTime::fromString(QString::fromStdString(certificate->end_time()), + QLatin1String(CERTIFICATE_DATE_FORMAT)); + QDateTime endTimeUTC(endTime.date(), endTime.time(), Qt::UTC); + + QDateTime currentTime(QDateTime::currentDateTimeUtc()); + if (currentTime > endTimeUTC) { + if (errorString) + *errorString = QCoreApplication::translate( + "S60Utils::validateCertificate", + "The \"%1\" certificate has already expired and cannot be used.\nExpiration date: %2.") + .arg(QFileInfo(certFilePath).fileName()) + .arg(endTimeUTC.toLocalTime().toString()); + result = CertificateError; + } else if (currentTime < startTimeUTC) { + if (errorString) + *errorString = QCoreApplication::translate( + "S60Utils::validateCertificate", + "The \"%1\" certificate is not yet valid.\nValid from: %2.") + .arg(QFileInfo(certFilePath).fileName()) + .arg(startTimeUTC.toLocalTime().toString()); + result = CertificateWarning; //This certificate may be valid in the near future + } + } else + certFileCorrupted = true; + } catch (Botan::Exception &e) { + Q_UNUSED(e) + certFileCorrupted = true; + } + delete certificate; + if (certFileCorrupted) { + if (errorString) + *errorString = QCoreApplication::translate( + "S60Utils::validateCertificate", + "The \"%1\" certificate is not a valid X.509 certificate.") + .arg(QFileInfo(certFilePath).baseName()); + result = CertificateError; + } + return result; +} diff --git a/src/plugins/qt4projectmanager/qt-s60/s60certificateinfo.h b/src/plugins/qt4projectmanager/qt-s60/s60certificateinfo.h new file mode 100644 index 0000000000000000000000000000000000000000..e3c961328d51ff4c8e37a572bc87a403faa09607 --- /dev/null +++ b/src/plugins/qt4projectmanager/qt-s60/s60certificateinfo.h @@ -0,0 +1,44 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef S60CERTIFICATEINFO_H +#define S60CERTIFICATEINFO_H + +class S60CertificateInfo +{ +public: + enum CertificateState { + CertificateValid, + CertificateWarning, + CertificateError + }; + static CertificateState validateCertificate(const QString &certFilePath, QString *errorString = 0); +}; + +#endif // S60CERTIFICATEINFO_H diff --git a/src/plugins/qt4projectmanager/qt-s60/s60createpackagestep.cpp b/src/plugins/qt4projectmanager/qt-s60/s60createpackagestep.cpp index 328064508f53d1e9714985cbaac48597ea57d42a..e874371ae6ff0d9fae16b54cb13ff2a6e614dde9 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60createpackagestep.cpp +++ b/src/plugins/qt4projectmanager/qt-s60/s60createpackagestep.cpp @@ -37,6 +37,7 @@ #include "abldparser.h" #include "sbsv2parser.h" #include "passphraseforkeydialog.h" +#include "s60certificateinfo.h" #include <coreplugin/coreconstants.h> @@ -191,6 +192,9 @@ bool S60CreatePackageStep::init() m_makeCmd = tmp; } + if (signingMode() == SignCustom && !validateCustomSigningResources()) + return false; + m_environment = qt4BuildConfiguration()->environment(); m_cancel = false; @@ -352,22 +356,6 @@ void S60CreatePackageStep::run(QFutureInterface<bool> &fi) bool S60CreatePackageStep::createOnePackage() { - // Setup everything... - Q_ASSERT(!m_process); - m_process = new QProcess(); - m_process->setEnvironment(m_environment.toStringList()); - - connect(m_process, SIGNAL(readyReadStandardOutput()), - this, SLOT(processReadyReadStdOutput()), - Qt::DirectConnection); - connect(m_process, SIGNAL(readyReadStandardError()), - this, SLOT(processReadyReadStdError()), - Qt::DirectConnection); - - connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), - this, SLOT(packageDone(int, QProcess::ExitStatus)), - Qt::DirectConnection); - // Setup arguments: m_args.clear(); if (m_createSmartInstaller) { @@ -380,9 +368,7 @@ bool S60CreatePackageStep::createOnePackage() else m_args << QLatin1String("sis"); - if (signingMode() == SignCustom - && !customSignaturePath().isEmpty() && QFileInfo(customSignaturePath()).exists() - && !customKeyPath().isEmpty() && QFileInfo(customKeyPath()).exists()) { + if (signingMode() == SignCustom) { m_args << QLatin1String(MAKE_CERTIFICATE_ARGUMENT) + QDir::toNativeSeparators(customSignaturePath()) << QLatin1String(MAKE_KEY_ARGUMENT) + QDir::toNativeSeparators(customKeyPath()); @@ -398,6 +384,23 @@ bool S60CreatePackageStep::createOnePackage() if (!wd.exists()) wd.mkpath(wd.absolutePath()); + + // Setup process... + Q_ASSERT(!m_process); + m_process = new QProcess(); + m_process->setEnvironment(m_environment.toStringList()); + + connect(m_process, SIGNAL(readyReadStandardOutput()), + this, SLOT(processReadyReadStdOutput()), + Qt::DirectConnection); + connect(m_process, SIGNAL(readyReadStandardError()), + this, SLOT(processReadyReadStdError()), + Qt::DirectConnection); + + connect(m_process, SIGNAL(finished(int, QProcess::ExitStatus)), + this, SLOT(packageDone(int, QProcess::ExitStatus)), + Qt::DirectConnection); + m_process->setWorkingDirectory(wd.absolutePath()); // Setup parsers: @@ -437,6 +440,58 @@ bool S60CreatePackageStep::createOnePackage() return true; } +bool S60CreatePackageStep::validateCustomSigningResources() +{ + Q_ASSERT(signingMode() == SignCustom); + + QString errorString; + if (customSignaturePath().isEmpty()) + errorString = tr("Certificate file has not heen defined. " + "Please define certificate file in the project's options."); + else if (!QFileInfo(customSignaturePath()).exists()) + errorString = tr("Certificate file \"%1\" does not exist. " + "Please define certificate file in the project's options.").arg(customSignaturePath()); + + if (customKeyPath().isEmpty()) + errorString = tr("Key file has not heen defined. " + "Please define certificate file in the project's options."); + else if (!QFileInfo(customKeyPath()).exists()) + errorString = tr("Key file \"%1\" does not exist. " + "Please define certificate file in the project's options.").arg(customKeyPath()); + + if (!errorString.isEmpty()) { + emit addOutput(errorString, BuildStep::ErrorMessageOutput); + emit addTask(ProjectExplorer::Task(ProjectExplorer::Task::Error, + errorString, + QString(), -1, + ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)); + return false; + } + + S60CertificateInfo::CertificateState certState = S60CertificateInfo::validateCertificate(customSignaturePath(), &errorString); + switch (certState) { + case S60CertificateInfo::CertificateError: + emit addOutput(errorString, BuildStep::ErrorMessageOutput); + emit addTask(ProjectExplorer::Task(ProjectExplorer::Task::Error, + errorString, + QString(), -1, + ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)); + return false; + case S60CertificateInfo::CertificateWarning: + emit addOutput(errorString, BuildStep::MessageOutput); + emit addTask(ProjectExplorer::Task(ProjectExplorer::Task::Warning, + errorString, + QString(), -1, + ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM)); + break; + default: + break; + } + return true; +} + + + void S60CreatePackageStep::packageWarningDialogDone() { if (m_patchWarningDialog) @@ -828,8 +883,13 @@ QString S60CreatePackageStepConfigWidget::summaryText() const QString text; switch(m_signStep->signingMode()) { case S60CreatePackageStep::SignCustom: - text = tr("signed with certificate %1 and key file %2") - .arg(m_signStep->customSignaturePath(), m_signStep->customKeyPath()); + if (!m_signStep->customSignaturePath().isEmpty() + && !m_signStep->customKeyPath().isEmpty()) + text = tr("signed with \"%1\" certificate and \"%2\" key file") + .arg(QFileInfo(m_signStep->customSignaturePath()).fileName(), + QFileInfo(m_signStep->customKeyPath()).fileName()); + else + text = tr("signed with a certificate and a key that need to be defined"); break; case S60CreatePackageStep::NotSigned: text = tr("not signed"); diff --git a/src/plugins/qt4projectmanager/qt-s60/s60createpackagestep.h b/src/plugins/qt4projectmanager/qt-s60/s60createpackagestep.h index 136a9bb96eed1b04e59df98e23a7549a6f2167eb..f4c90a7bdc7f2c76903e12162f9ccdaf35e92b07 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60createpackagestep.h +++ b/src/plugins/qt4projectmanager/qt-s60/s60createpackagestep.h @@ -138,6 +138,7 @@ private: void setupProcess(); bool createOnePackage(); + bool validateCustomSigningResources(); QString generateKeyId(const QString &keyPath) const; QString loadPassphraseForKey(const QString &keyId); diff --git a/src/plugins/qt4projectmanager/qt-s60/s60createpackagestep.ui b/src/plugins/qt4projectmanager/qt-s60/s60createpackagestep.ui index b9eccf5ad1a12f332d5eea3c9be279cc98f4f009..5539f614a26618d66ec66cd3db9eba3b878c49c5 100644 --- a/src/plugins/qt4projectmanager/qt-s60/s60createpackagestep.ui +++ b/src/plugins/qt4projectmanager/qt-s60/s60createpackagestep.ui @@ -7,7 +7,7 @@ <x>0</x> <y>0</y> <width>517</width> - <height>135</height> + <height>156</height> </rect> </property> <property name="windowTitle"> @@ -87,9 +87,9 @@ </widget> </item> <item row="0" column="1"> - <widget class="Utils::PathChooser" name="signaturePath" native="true"> + <widget class="CertificatePathChooser" name="signaturePath" native="true"> <property name="promptDialogTitle" stdset="0"> - <string>Choose certificate file (.cer)</string> + <string>Choose certificate file</string> </property> </widget> </item> @@ -167,6 +167,12 @@ <signal>browsingFinished()</signal> </slots> </customwidget> + <customwidget> + <class>CertificatePathChooser</class> + <extends>QWidget</extends> + <header location="global">qt4projectmanager/qt-s60/certificatepathchooser.h</header> + <container>1</container> + </customwidget> </customwidgets> <resources/> <connections/>