Skip to content
Snippets Groups Projects
Commit f4b1c441 authored by Pawel Polanski's avatar Pawel Polanski
Browse files

Added the SignSisParser for Symbian OS

Added support for passphrases for keys for Symbian OS

Reviewed-by: Tobias Hunger
parent 2c15b30a
No related branches found
No related tags found
No related merge requests found
#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
** 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 "signsisparser.h"
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/taskwindow.h>
using namespace Qt4ProjectManager;
using namespace ProjectExplorer;
using namespace ProjectExplorer::Constants;
SignsisParser::SignsisParser()
{
m_signSis.setPattern("^(error):([A-Z\\d]+):(.+)$");
m_signSis.setMinimal(true);
}
void SignsisParser::stdOutput(const QString &line)
{
QString lne = line.trimmed();
if (m_signSis.indexIn(lne) > -1) {
QString errorDescription(m_signSis.cap(3));
int index = errorDescription.indexOf(QLatin1String("error:"));
if (index >= 0) {
stdOutput(errorDescription.mid(index));
errorDescription = errorDescription.left(index);
}
Task task(Task::Error,
errorDescription /* description */,
QString(), -1,
TASK_CATEGORY_BUILDSYSTEM);
emit addTask(task);
}
IOutputParser::stdOutput(line);
}
void SignsisParser::stdError(const QString &line)
{
stdOutput(line);
IOutputParser::stdError(line);
}
#ifndef SIGNSISPARSER_H
#define SIGNSISPARSER_H
#include <projectexplorer/ioutputparser.h>
#include <QtCore/QRegExp>
namespace Qt4ProjectManager {
class SignsisParser : public ProjectExplorer::IOutputParser
{
Q_OBJECT
public:
SignsisParser();
virtual void stdOutput(const QString & line);
virtual void stdError(const QString & line);
private:
QRegExp m_signSis;
};
} // namespace Qt4ProjectExplorer
#endif // SIGNSISPARSER_H
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment