Added the SignSisParser for Symbian OS

Added support for passphrases for keys for Symbian OS

Reviewed-by: Tobias Hunger
This commit is contained in:
Pawel Polanski
2010-07-27 10:46:25 +02:00
parent 2c15b30a20
commit f4b1c441aa
8 changed files with 463 additions and 11 deletions

View File

@@ -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;