Commit 41bdf342 authored by Rafael Roquetto's avatar Rafael Roquetto Committed by Tobias Hunger

Initial implementation of BB key management

Change-Id: Iba9c264b6c5809a0714da69591248fc2962c6526
Reviewed-by: Nicolas Arnaud-Cormos's avatarNicolas Arnaud-Cormos <nicolas@kdab.com>
Reviewed-by: default avatarTobias Hunger <tobias.hunger@digia.com>
parent 5686983e
/**************************************************************************
**
** Copyright (C) 2011 - 2013 Research In Motion
**
** Contact: Research In Motion (blackberry-qt@qnx.com)
** Contact: KDAB (info@kdab.com)
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "blackberrycertificate.h"
#include "blackberryconfiguration.h"
#include <utils/hostosinfo.h>
#include <QProcess>
#include <QFile>
#include <QTextStream>
namespace Qnx {
namespace Internal {
BlackBerryCertificate::BlackBerryCertificate(const QString &fileName,
const QString &author, const QString &storePass, QObject *parent) :
QObject(parent),
m_fileName(fileName),
m_author(author),
m_storePass(storePass),
m_process(new QProcess(this))
{
}
void BlackBerryCertificate::load()
{
if (m_process->state() != QProcess::NotRunning) {
emit finished(BlackBerryCertificate::Busy);
return;
}
QStringList arguments;
arguments << QLatin1String("-keystore")
<< m_fileName
<< QLatin1String("-list")
<< QLatin1String("-verbose")
<< QLatin1String("-storepass")
<< m_storePass;
connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)),
this, SLOT(loadFinished()));
connect(m_process, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(processError()));
m_process->start(command(), arguments);
}
void BlackBerryCertificate::store()
{
if (m_process->state() != QProcess::NotRunning) {
emit finished(BlackBerryCertificate::Busy);
return;
}
QFile file(m_fileName);
if (file.exists())
file.remove();
QStringList arguments;
arguments << QLatin1String("-genkeypair")
<< QLatin1String("-storepass")
<< m_storePass
<< QLatin1String("-author")
<< m_author
<< QLatin1String("-keystore")
<< m_fileName;
connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)),
this, SLOT(storeFinished(int)));
connect(m_process, SIGNAL(error(QProcess::ProcessError)),
this, SLOT(processError()));
m_process->start(command(), arguments);
}
QString BlackBerryCertificate::fileName() const
{
return m_fileName;
}
QString BlackBerryCertificate::author() const
{
return m_author;
}
QString BlackBerryCertificate::id() const
{
QString tmpId = fileName();
return tmpId.replace(QLatin1String("/"), QLatin1String("-"));
}
void BlackBerryCertificate::storeFinished(int status)
{
m_process->disconnect();
if (status == 0)
emit finished(BlackBerryCertificate::Success);
else
emit finished(BlackBerryCertificate::Error);
}
void BlackBerryCertificate::loadFinished()
{
m_process->disconnect();
ResultCode status = Error;
QTextStream processOutput(m_process);
while (!processOutput.atEnd()) {
QString chunk = processOutput.readLine();
if (chunk.contains(
QLatin1String("Error: Failed to decrypt keystore, invalid password"))) {
status = WrongPassword;
break;
} else if (chunk.startsWith(QLatin1String("Owner:"))) {
chunk.remove(QLatin1String("Owner:"));
m_author = chunk.remove(QLatin1String("CN=")).trimmed();
status = Success;
break;
}
}
emit finished(status);
}
void BlackBerryCertificate::processError()
{
m_process->disconnect();
emit finished(Error);
}
QString BlackBerryCertificate::command() const
{
QString command = BlackBerryConfiguration::instance()
.qnxEnv().value(QLatin1String("QNX_HOST"))
+ QLatin1String("/usr/bin/blackberry-keytool");
if (Utils::HostOsInfo::isWindowsHost())
command += QLatin1String(".bat");
return command;
}
} // namespace Internal
} // namespace Qnx
/**************************************************************************
**
** Copyright (C) 2011 - 2013 Research In Motion
**
** Contact: Research In Motion (blackberry-qt@qnx.com)
** Contact: KDAB (info@kdab.com)
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef QNX_INTERNAL_BLACKBERRYCERTIFICATE_H
#define QNX_INTERNAL_BLACKBERRYCERTIFICATE_H
#include <QObject>
#include <QString>
QT_BEGIN_NAMESPACE
class QProcess;
QT_END_NAMESPACE
namespace Qnx {
namespace Internal {
class BlackBerryCertificate : public QObject
{
Q_OBJECT
public:
enum ResultCode {
Success,
Busy,
WrongPassword,
Error
};
BlackBerryCertificate(const QString &fileName,
const QString &author = QString(),
const QString &storePass = QString(),
QObject *parent = 0);
void load();
void store();
QString fileName() const;
QString author() const;
QString id() const;
signals:
void loaded();
void stored();
void finished(int status);
private slots:
void storeFinished(int status);
void loadFinished();
void processError();
private:
QString command() const;
QString m_fileName;
QString m_author;
QString m_storePass;
QProcess *m_process;
};
} // namespace Internal
} // namespace Qnx
#endif // QNX_INTERNAL_BLACKBERRYCERTIFICATE_H
/**************************************************************************
**
** Copyright (C) 2011 - 2013 Research In Motion
**
** Contact: Research In Motion (blackberry-qt@qnx.com)
** Contact: KDAB (info@kdab.com)
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#include "blackberrycertificatemodel.h"
#include "blackberrycertificate.h"
#include "blackberryconfiguration.h"
#include <coreplugin/icore.h>
#include <QSettings>
#include <QStringList>
namespace Qnx {
namespace Internal {
const QLatin1String SettingsGroup("BlackBerryConfiguration");
const QLatin1String CertificateGroup("Certificates");
BlackBerryCertificateModel::BlackBerryCertificateModel(QObject *parent) :
QAbstractTableModel(parent),
m_activeCertificate(0)
{
load();
}
BlackBerryCertificateModel::~BlackBerryCertificateModel()
{
}
int BlackBerryCertificateModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return m_certificates.count();
}
int BlackBerryCertificateModel::columnCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return ColumnCount;
}
QVariant BlackBerryCertificateModel::data(const QModelIndex &index, int role) const
{
if (index.row() >= rowCount() || index.column() >= columnCount())
return QVariant();
const BlackBerryCertificate *cert = m_certificates.at(index.row());
if (role == Qt::CheckStateRole) {
if (index.column() == CertActive)
return (m_activeCertificate == cert) ? Qt::Checked : Qt::Unchecked;
} else if (role == Qt::DisplayRole) {
if (index.column() == CertPath)
return cert->fileName();
else if (index.column() == CertAuthor)
return cert->author();
}
return QVariant();
}
QVariant BlackBerryCertificateModel::headerData(int section,
Qt::Orientation orientation, int role) const
{
if (role != Qt::DisplayRole)
return QVariant();
if (orientation == Qt::Vertical)
return section;
switch (section) {
case CertPath:
return tr("Path");
case CertAuthor:
return tr("Author");
case CertActive:
return tr("Active");
default:
break;
}
return section;
}
bool BlackBerryCertificateModel::setData(const QModelIndex &ind,
const QVariant &value, int role)
{
Q_UNUSED(value);
if (role == Qt::CheckStateRole && ind.column() == CertActive) {
const int oldIndex = m_certificates.indexOf(m_activeCertificate);
m_activeCertificate = m_certificates.at(ind.row());
if (oldIndex >= 0)
emit dataChanged(index(oldIndex, CertActive), index(oldIndex, CertActive));
emit dataChanged(ind, ind);
return true;
}
return false;
}
bool BlackBerryCertificateModel::removeRows(int row, int count,
const QModelIndex &parent)
{
beginRemoveRows(parent, row, row + count - 1);
for (int i = 0; i < count; i++) {
BlackBerryCertificate *cert = m_certificates.takeAt(row);
//XXX shall we also delete from disk?
delete cert;
}
endRemoveRows();
return true;
}
Qt::ItemFlags BlackBerryCertificateModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable;
switch (index.column()) {
case CertActive:
flags |= Qt::ItemIsUserCheckable;
break;
default:
break;
}
return flags;
}
BlackBerryCertificate * BlackBerryCertificateModel::activeCertificate() const
{
return m_activeCertificate;
}
QList<BlackBerryCertificate*> BlackBerryCertificateModel::certificates() const
{
return m_certificates;
}
bool BlackBerryCertificateModel::insertCertificate(BlackBerryCertificate *certificate)
{
if (m_certificates.contains(certificate))
return false;
beginInsertRows(QModelIndex(), m_certificates.count(), m_certificates.count());
if (m_certificates.isEmpty())
m_activeCertificate = certificate;
certificate->setParent(this);
m_certificates << certificate;
endInsertRows();
return true;
}
void BlackBerryCertificateModel::load()
{
BlackBerryConfiguration &configuration = BlackBerryConfiguration::instance();
m_certificates = configuration.certificates();
m_activeCertificate = configuration.activeCertificate();
}
} // namespace Internal
} // namespace Qnx
/**************************************************************************
**
** Copyright (C) 2011 - 2013 Research In Motion
**
** Contact: Research In Motion (blackberry-qt@qnx.com)
** Contact: KDAB (info@kdab.com)
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef QNX_INTERNAL_BLACKBERRYCERTIFICATESTOREMODEL_H
#define QNX_INTERNAL_BLACKBERRYCERTIFICATESTOREMODEL_H
#include <QAbstractTableModel>
#include <QList>
namespace Qnx {
namespace Internal {
class BlackBerryCertificate;
class BlackBerryCertificateModel : public QAbstractTableModel
{
Q_OBJECT
public:
explicit BlackBerryCertificateModel(QObject *parent = 0);
~BlackBerryCertificateModel();
int rowCount(const QModelIndex &parent = QModelIndex()) const;
int columnCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index,
int role = Qt::DisplayRole) const;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const;
bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole);
bool removeRows(int row, int count,
const QModelIndex &parent = QModelIndex());
bool insertCertificate(BlackBerryCertificate *certificate);
Qt::ItemFlags flags(const QModelIndex &index) const;
BlackBerryCertificate *activeCertificate() const;
QList<BlackBerryCertificate*> certificates() const;
private slots:
void load();
private:
enum Columns {
CertPath,
CertAuthor,
CertActive,
ColumnCount
};
QList<BlackBerryCertificate*> m_certificates;
BlackBerryCertificate *m_activeCertificate;
};
} // namespace Internal
} // namespace Qnx
#endif // QNX_INTERNAL_BLACKBERRYCERTIFICATESTOREMODEL_H
......@@ -31,6 +31,7 @@
#include "blackberryconfiguration.h"
#include "blackberryqtversion.h"
#include "blackberrycertificate.h"
#include "qnxutils.h"
#include <coreplugin/icore.h>
......@@ -62,22 +63,29 @@ namespace Internal {
namespace {
const QLatin1String SettingsGroup("BlackBerryConfiguration");
const QLatin1String NDKLocationKey("NDKLocation");
const QLatin1String CertificateGroup("Certificates");
}
BlackBerryConfiguration::BlackBerryConfiguration(QObject *parent)
:QObject(parent)
{
loadSetting();
connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()), this, SLOT(saveSetting()));
loadSettings();
connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()), this, SLOT(saveSettings()));
}
bool BlackBerryConfiguration::setConfig(const QString &ndkPath)
bool BlackBerryConfiguration::setNdkPath(const QString &ndkPath)
{
if (ndkPath.isEmpty())
return false;
m_config.ndkPath = ndkPath;
m_config.qnxEnv = QnxUtils::parseEnvironmentFile(QnxUtils::envFilePath(ndkPath));
return refresh();
}
bool BlackBerryConfiguration::refresh()
{
m_config.qnxEnv = QnxUtils::parseEnvironmentFile(QnxUtils::envFilePath(m_config.ndkPath));
QString ndkTarget = m_config.qnxEnv.value(QLatin1String("QNX_TARGET"));
QString sep = QString::fromLatin1("%1qnx6").arg(QDir::separator());
......@@ -120,12 +128,83 @@ bool BlackBerryConfiguration::setConfig(const QString &ndkPath)
return true;
}
void BlackBerryConfiguration::setupConfiguration(const QString &ndkPath)
void BlackBerryConfiguration::loadCertificates()
{
QSettings *settings = Core::ICore::instance()->settings();
settings->beginGroup(SettingsGroup);
settings->beginGroup(CertificateGroup);
foreach (QString certificateId, settings->childGroups()) {
settings->beginGroup(certificateId);
BlackBerryCertificate *cert =
new BlackBerryCertificate(settings->value(QLatin1String(Qnx::Constants::QNX_KEY_PATH)).toString(),
settings->value(QLatin1String(Qnx::Constants::QNX_KEY_AUTHOR)).toString());