Commit f4b1c441 authored by Pawel Polanski's avatar Pawel Polanski

Added the SignSisParser for Symbian OS

Added support for passphrases for keys for Symbian OS

Reviewed-by: Tobias Hunger
parent 2c15b30a
#include "passphraseforkeydialog.h"
#include <QtGui/QDialogButtonBox>
#include <QtGui/QLabel>
#include <QtGui/QFormLayout>
#include <QtGui/QLineEdit>
#include <QtGui/QCheckBox>
using namespace Qt4ProjectManager;
PassphraseForKeyDialog::PassphraseForKeyDialog(const QString &keyName, QWidget *parent)
: QDialog(parent)
{
QFormLayout *formLayout = new QFormLayout(this);
setLayout(formLayout);
QLabel *passphraseLabel = new QLabel(this);
passphraseLabel->setText(tr("Passphrase:"));
passphraseLabel->setObjectName(QString::fromUtf8("passphraseLabel"));
formLayout->setWidget(0, QFormLayout::LabelRole, passphraseLabel);
QLineEdit *passphraseLineEdit = new QLineEdit(this);
passphraseLineEdit->setObjectName(QString::fromUtf8("passphraseLineEdit"));
passphraseLineEdit->setEchoMode(QLineEdit::Password);
connect(passphraseLineEdit, SIGNAL(textChanged(QString)), this, SLOT(setPassphrase(QString)));
formLayout->setWidget(0, QFormLayout::FieldRole, passphraseLineEdit);
m_checkBox = new QCheckBox(this);
m_checkBox->setText(tr("Save passphrase"));
m_checkBox->setObjectName(QString::fromUtf8("checkBox"));
m_checkBox->setToolTip(tr("This is an insecure option. Password will be saved as a plain text!"));
formLayout->setWidget(1, QFormLayout::LabelRole, m_checkBox);
QDialogButtonBox *buttonBox = new QDialogButtonBox(this);
buttonBox->setObjectName(QString::fromUtf8("buttonBox"));
buttonBox->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
formLayout->setWidget(2, QFormLayout::FieldRole, buttonBox);
setWindowTitle(tr("Passphrase for %1").arg(keyName));
setFixedSize( sizeHint() );
}
void PassphraseForKeyDialog::accept()
{
done(1);
}
void PassphraseForKeyDialog::reject()
{
done(0);
}
void PassphraseForKeyDialog::setPassphrase(const QString &passphrase)
{
m_passphrase = passphrase;
}
QString PassphraseForKeyDialog::passphrase() const
{
return m_passphrase;
}
bool PassphraseForKeyDialog::savePassphrase() const
{
return m_checkBox->isChecked();
}
#ifndef PASSPHRASEFORKEYDIALOG_H
#define PASSPHRASEFORKEYDIALOG_H
#include <QtGui/QDialog>
class QCheckBox;
namespace Qt4ProjectManager {
class PassphraseForKeyDialog : public QDialog
{
Q_OBJECT
public:
explicit PassphraseForKeyDialog(const QString &keyName, QWidget *parent = 0);
QString passphrase() const;
bool savePassphrase() const;
protected slots:
void accept();
void reject();
void setPassphrase(const QString &passphrase);
private:
QCheckBox *m_checkBox;
QString m_passphrase;
};
} // namespace Qt4ProjectManager
#endif // PASSPHRASEFORKEYDIALOG_H
......@@ -16,7 +16,9 @@ SOURCES += $$PWD/s60devices.cpp \
$$PWD/rvctparser.cpp \
$$PWD/winscwparser.cpp \
qt-s60/s60createpackagestep.cpp \
qt-s60/s60deploystep.cpp
qt-s60/s60deploystep.cpp \
qt-s60/signsisparser.cpp \
qt-s60/passphraseforkeydialog.cpp
HEADERS += $$PWD/s60devices.h \
$$PWD/s60devicespreferencepane.h \
$$PWD/s60manager.h \
......@@ -32,6 +34,8 @@ HEADERS += $$PWD/s60devices.h \
$$PWD/rvctparser.h \
$$PWD/winscwparser.h \
qt-s60/s60createpackagestep.h \
qt-s60/s60deploystep.h
qt-s60/s60deploystep.h \
qt-s60/signsisparser.h \
qt-s60/passphraseforkeydialog.h
FORMS += $$PWD/s60devicespreferencepane.ui \
qt-s60/s60createpackagestep.ui
......@@ -34,6 +34,8 @@
#include "qt4nodes.h"
#include "qt4project.h"
#include "abldparser.h"
#include "signsisparser.h"
#include "passphraseforkeydialog.h"
#include <projectexplorer/buildconfiguration.h>
#include <projectexplorer/target.h>
......@@ -43,6 +45,10 @@
#include <QtCore/QDir>
#include <QtCore/QTimer>
#include <QtCore/QCryptographicHash>
#include <QSettings>
#include <QMessageBox>
using namespace Qt4ProjectManager::Internal;
......@@ -52,6 +58,10 @@ namespace {
const char * const CERTIFICATE_KEY("Qt4ProjectManager.S60CreatePackageStep.Certificate");
const char * const KEYFILE_KEY("Qt4ProjectManager.S60CreatePackageStep.Keyfile");
const char * const SMART_INSTALLER_KEY("Qt4ProjectManager.S60CreatorPackageStep.SmartInstaller");
const char * const MAKE_PASSPHRASE_ARGUMENT("QT_SIS_PASSPHRASE=");
const char * const MAKE_KEY_ARGUMENT("QT_SIS_KEY=");
const char * const MAKE_CERTIFICATE_ARGUMENT("QT_SIS_CERTIFICATE=");
}
S60CreatePackageStep::S60CreatePackageStep(ProjectExplorer::BuildConfiguration *bc) :
......@@ -62,7 +72,9 @@ S60CreatePackageStep::S60CreatePackageStep(ProjectExplorer::BuildConfiguration *
m_process(0),
m_timer(0),
m_eventLoop(0),
m_futureInterface(0)
m_futureInterface(0),
m_errorType(ErrorNone),
m_settings(0)
{
ctor_package();
}
......@@ -72,11 +84,14 @@ S60CreatePackageStep::S60CreatePackageStep(ProjectExplorer::BuildConfiguration *
m_signingMode(bs->m_signingMode),
m_customSignaturePath(bs->m_customSignaturePath),
m_customKeyPath(bs->m_customKeyPath),
m_passphrase(bs->m_passphrase),
m_createSmartInstaller(bs->m_createSmartInstaller),
m_outputParserChain(0),
m_timer(0),
m_eventLoop(0),
m_futureInterface(0)
m_futureInterface(0),
m_errorType(ErrorNone),
m_settings(0)
{
ctor_package();
}
......@@ -88,7 +103,9 @@ S60CreatePackageStep::S60CreatePackageStep(ProjectExplorer::BuildConfiguration *
m_outputParserChain(0),
m_timer(0),
m_eventLoop(0),
m_futureInterface(0)
m_futureInterface(0),
m_errorType(ErrorNone),
m_settings(0)
{
ctor_package();
}
......@@ -96,6 +113,11 @@ S60CreatePackageStep::S60CreatePackageStep(ProjectExplorer::BuildConfiguration *
void S60CreatePackageStep::ctor_package()
{
setDisplayName(tr("Create SIS Package", "Create SIS package build step name"));
connect(this, SIGNAL(badPassphrase()),
this, SLOT(definePassphrase()), Qt::QueuedConnection);
m_settings = new QSettings(QSettings::IniFormat, QSettings::UserScope,
QLatin1String("Nokia"), QLatin1String("QtCreatorKeys"), this);
}
S60CreatePackageStep::~S60CreatePackageStep()
......@@ -116,7 +138,7 @@ bool S60CreatePackageStep::fromMap(const QVariantMap &map)
{
m_signingMode = (SigningMode)map.value(QLatin1String(SIGNMODE_KEY)).toInt();
m_customSignaturePath = map.value(QLatin1String(CERTIFICATE_KEY)).toString();
m_customKeyPath = map.value(QLatin1String(KEYFILE_KEY)).toString();
setCustomKeyPath(map.value(QLatin1String(KEYFILE_KEY)).toString());
m_createSmartInstaller = map.value(QLatin1String(SMART_INSTALLER_KEY), false).toBool();
return BuildStep::fromMap(map);
}
......@@ -155,21 +177,85 @@ bool S60CreatePackageStep::init()
else
m_args << QLatin1String("sis");
if (signingMode() == SignCustom) {
m_args << QLatin1String("QT_SIS_CERTIFICATE=") + QDir::toNativeSeparators(customSignaturePath())
<< QLatin1String("QT_SIS_KEY=") + QDir::toNativeSeparators(customKeyPath());
m_args << QLatin1String(MAKE_CERTIFICATE_ARGUMENT) + QDir::toNativeSeparators(customSignaturePath())
<< QLatin1String(MAKE_KEY_ARGUMENT) + QDir::toNativeSeparators(customKeyPath());
setPassphrase(loadPassphraseForKey(m_keyId));
if (!passphrase().isEmpty()) {
m_args << QLatin1String(MAKE_PASSPHRASE_ARGUMENT) + passphrase();
}
}
delete m_outputParserChain;
m_outputParserChain = new ProjectExplorer::GnuMakeParser;
m_outputParserChain->appendOutputParser(new Qt4ProjectManager::AbldParser);
m_outputParserChain->appendOutputParser(new Qt4ProjectManager::SignsisParser);
connect(m_outputParserChain, SIGNAL(addOutput(QString, ProjectExplorer::BuildStep::OutputFormat)),
this, SLOT(outputAdded(QString, ProjectExplorer::BuildStep::OutputFormat)));
connect(m_outputParserChain, SIGNAL(addTask(ProjectExplorer::Task)),
this, SLOT(taskAdded(ProjectExplorer::Task)));
this, SLOT(taskAdded(ProjectExplorer::Task)), Qt::DirectConnection);
return true;
}
void S60CreatePackageStep::definePassphrase()
{
PassphraseForKeyDialog *passwordDialog
= new PassphraseForKeyDialog(QFileInfo(customKeyPath()).fileName());
if (passwordDialog->exec()) {
setPassphrase(passwordDialog->passphrase());
if (passwordDialog->savePassphrase())
savePassphraseForKey(m_keyId, passphrase());
} else
m_errorType = ErrorUndefined;
delete passwordDialog;
passwordDialog = 0;
m_waitCondition.wakeAll();
}
void S60CreatePackageStep::savePassphraseForKey(const QString &keyId, const QString &passphrase)
{
m_settings->beginGroup("keys");
if (passphrase.isEmpty())
m_settings->remove(keyId);
else
m_settings->setValue(keyId, obfuscatePassphrase(passphrase, keyId));
m_settings->endGroup();
}
QString S60CreatePackageStep::loadPassphraseForKey(const QString &keyId)
{
m_settings->beginGroup("keys");
QString passphrase = elucidatePassphrase(m_settings->value(keyId, QByteArray()).toByteArray(), keyId);
m_settings->endGroup();
return passphrase;
}
QByteArray S60CreatePackageStep::obfuscatePassphrase(const QString &passphrase, const QString &key) const
{
QByteArray byteArray = passphrase.toUtf8();
char *data = byteArray.data();
const QChar *keyData = key.data();
int keyDataSize = key.size();
for (int i = 0; i <byteArray.size(); ++i)
data[i] = data[i]^keyData[i%keyDataSize].toAscii();
return byteArray.toBase64();
}
QString S60CreatePackageStep::elucidatePassphrase(QByteArray obfuscatedPassphrase, const QString &key) const
{
QByteArray byteArray = QByteArray::fromBase64(obfuscatedPassphrase);
char *data = byteArray.data();
const QChar *keyData = key.data();
int keyDataSize = key.size();
for (int i = 0; i < byteArray.size(); ++i)
data[i] = data[i]^keyData[i%keyDataSize].toAscii();
return byteArray.data();
}
void S60CreatePackageStep::run(QFutureInterface<bool> &fi)
{
m_futureInterface = &fi;
......@@ -242,6 +328,33 @@ void S60CreatePackageStep::slotProcessFinished(int, QProcess::ExitStatus)
emit addOutput(tr("The process \"%1\" crashed.").arg(QDir::toNativeSeparators(m_makeCmd)), BuildStep::ErrorMessageOutput);
}
switch (m_errorType) {
case ErrorUndefined:
m_eventLoop->exit(false);
return;
case ErrorBadPassphrase: {
emit badPassphrase();
QMutexLocker locker(&m_mutex);
//waiting for the user to input new passphrase or to abort
m_waitCondition.wait(&m_mutex);
if( m_errorType == ErrorUndefined ) {
m_eventLoop->exit(true);
return;
} else {
QRegExp passphraseRegExp("^"+QLatin1String(MAKE_PASSPHRASE_ARGUMENT)+"(.+)$");
int index = m_args.indexOf(passphraseRegExp);
if (index>=0)
m_args.removeAt(index);
if (!passphrase().isEmpty())
m_args << QLatin1String(MAKE_PASSPHRASE_ARGUMENT) + passphrase();
}
break;
}
default:
m_workingDirectories.removeFirst();
break;
}
if (m_workingDirectories.isEmpty() || !returnValue) {
m_eventLoop->exit(returnValue);
} else {
......@@ -253,7 +366,8 @@ void S60CreatePackageStep::slotProcessFinished(int, QProcess::ExitStatus)
bool S60CreatePackageStep::startProcess()
{
QString workingDirectory = m_workingDirectories.takeFirst();
m_errorType = ErrorNone;
QString workingDirectory = m_workingDirectories.first();
QDir wd(workingDirectory);
if (!wd.exists())
wd.mkpath(wd.absolutePath());
......@@ -327,15 +441,35 @@ void S60CreatePackageStep::taskAdded(const ProjectExplorer::Task &task)
// TODO which kind of tasks do we get from package building?
// No absoulte path
}
if (task.type == ProjectExplorer::Task::Error) {
if (task.description.contains(QLatin1String("bad password"))
|| task.description.contains(QLatin1String("bad decrypt")))
m_errorType = ErrorBadPassphrase;
else if (m_errorType == ErrorNone)
m_errorType = ErrorUndefined;
}
emit addTask(editable);
}
QString S60CreatePackageStep::generateKeyId(const QString &keyPath) const
{
if (keyPath.isEmpty())
return QString();
QFile file(keyPath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return QString();
//key file is quite small in size
return QCryptographicHash::hash(file.readAll(),
QCryptographicHash::Md5).toHex();
}
void S60CreatePackageStep::outputAdded(const QString &string, ProjectExplorer::BuildStep::OutputFormat format)
{
emit addOutput(string, format);
}
bool S60CreatePackageStep::immutable() const
{
return false;
......@@ -374,6 +508,27 @@ QString S60CreatePackageStep::customKeyPath() const
void S60CreatePackageStep::setCustomKeyPath(const QString &path)
{
m_customKeyPath = path;
m_keyId = generateKeyId(m_customKeyPath);
}
QString S60CreatePackageStep::passphrase() const
{
return m_passphrase;
}
void S60CreatePackageStep::setPassphrase(const QString &passphrase)
{
m_passphrase = passphrase;
}
QString S60CreatePackageStep::keyId() const
{
return m_keyId;
}
void S60CreatePackageStep::setKeyId(const QString &keyId)
{
m_keyId = keyId;
}
bool S60CreatePackageStep::createsSmartInstaller() const
......@@ -387,6 +542,17 @@ void S60CreatePackageStep::setCreatesSmartInstaller(bool value)
static_cast<Qt4BuildConfiguration *>(buildConfiguration())->emitS60CreatesSmartInstallerChanged();
}
void S60CreatePackageStep::resetPassphrases()
{
m_settings->beginGroup("keys");
QStringList keys = m_settings->allKeys();
foreach (QString key, keys) {
m_settings->setValue(key, "");
}
m_settings->remove("");
m_settings->endGroup();
}
// #pragma mark -- S60SignBuildStepFactory
S60CreatePackageStepFactory::S60CreatePackageStepFactory(QObject *parent) :
......@@ -478,6 +644,8 @@ S60CreatePackageStepConfigWidget::S60CreatePackageStepConfigWidget(S60CreatePack
this, SLOT(updateFromUi()));
connect(m_ui.smartInstaller, SIGNAL(clicked()),
this, SLOT(updateFromUi()));
connect(m_ui.resetPassphrasesButton, SIGNAL(clicked()),
this, SLOT(resetPassphrases()));
}
void S60CreatePackageStepConfigWidget::updateUi()
......@@ -504,6 +672,19 @@ void S60CreatePackageStepConfigWidget::updateFromUi()
updateUi();
}
void S60CreatePackageStepConfigWidget::resetPassphrases()
{
QMessageBox msgBox(QMessageBox::Question, tr("Reset passwords"),
tr("Do you want to reset all saved passwords for used keys?"),
QMessageBox::Yes|QMessageBox::No, this);
msgBox.button(QMessageBox::Yes)->setText(tr("Reset"));
msgBox.button(QMessageBox::No)->setText(tr("Cancel"));
msgBox.setDefaultButton(QMessageBox::No);
msgBox.setEscapeButton(QMessageBox::No);
if (msgBox.exec() == QMessageBox::Yes)
m_signStep->resetPassphrases();
}
QString S60CreatePackageStepConfigWidget::summaryText() const
{
QString text;
......
......@@ -35,6 +35,11 @@
#include <projectexplorer/buildstep.h>
#include <qt4projectmanager/makestep.h>
#include <QMutex>
#include <QWaitCondition>
class QSettings;
namespace Qt4ProjectManager {
namespace Internal {
......@@ -59,6 +64,7 @@ public:
ProjectExplorer::BuildStep *clone(ProjectExplorer::BuildConfiguration *parent, ProjectExplorer::BuildStep::Type type, ProjectExplorer::BuildStep *product);
};
class S60CreatePackageStep : public ProjectExplorer::BuildStep
{
Q_OBJECT
......@@ -85,9 +91,18 @@ public:
void setCustomSignaturePath(const QString &path);
QString customKeyPath() const;
void setCustomKeyPath(const QString &path);
QString passphrase() const ;
void setPassphrase(const QString &passphrase);
QString keyId() const;
void setKeyId(const QString &keyId);
bool createsSmartInstaller() const;
void setCreatesSmartInstaller(bool value);
void resetPassphrases();
signals:
void badPassphrase();
protected:
S60CreatePackageStep(ProjectExplorer::BuildConfiguration *bc, S60CreatePackageStep *bs);
S60CreatePackageStep(ProjectExplorer::BuildConfiguration *bc, const QString &id);
......@@ -102,11 +117,25 @@ private slots:
void taskAdded(const ProjectExplorer::Task &task);
void outputAdded(const QString &string, ProjectExplorer::BuildStep::OutputFormat format);
void checkForCancel();
void definePassphrase();
private:
enum ErrorType {
ErrorNone = 0,
ErrorUndefined,
ErrorBadPassphrase
};
void stdOutput(const QString &line);
void stdError(const QString &line);
bool startProcess();
QString generateKeyId(const QString &keyPath) const;
QString loadPassphraseForKey(const QString &keyId);
void savePassphraseForKey(const QString &keyId, const QString &passphrase);
QString elucidatePassphrase(QByteArray obfuscatedPassphrase, const QString &key) const;
QByteArray obfuscatePassphrase(const QString &passphrase, const QString &key) const;
QStringList m_workingDirectories;
QString m_makeCmd;
......@@ -118,6 +147,8 @@ private:
SigningMode m_signingMode;
QString m_customSignaturePath;
QString m_customKeyPath;
QString m_passphrase;
QString m_keyId;
bool m_createSmartInstaller;
ProjectExplorer::IOutputParser *m_outputParserChain;
......@@ -125,6 +156,12 @@ private:
QTimer *m_timer;
QEventLoop *m_eventLoop;
QFutureInterface<bool> *m_futureInterface;
ErrorType m_errorType;
QWaitCondition m_waitCondition;
QMutex m_mutex;
QSettings *m_settings;
};
class S60CreatePackageStepConfigWidget : public ProjectExplorer::BuildStepConfigWidget
......@@ -139,6 +176,7 @@ public:
private slots:
void updateUi();
void updateFromUi();
void resetPassphrases();
private:
S60CreatePackageStep *m_signStep;
......
......@@ -90,6 +90,33 @@
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="resetPassphrasesButton">
<property name="toolTip">
<string>Resets saved passphrases for all used keys</string>
</property>
<property name="text">
<string>Reset passphrases</string>
</property>
</widget>
</item>
<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>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
......
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 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