QNX: Improved generation of SSH keys for BlackBerry devices

The user is now asked where to store the generated SSH key,
before it is generated, and if that would fail, is still
enabled to select a different key.

Task-number: QTCREATORBUG-9101
Task-number: QTCREATORBUG-9102
Change-Id: I8e2f732dbcbe7bd3bd3fa9b512a7a195fa868c17
Reviewed-by: Nicolas Arnaud-Cormos <nicolas@kdab.com>
Reviewed-by: Rafael Roquetto <rafael.roquetto@kdab.com>
Reviewed-by: Mehdi Fekari <mfekari@blackberry.com>
This commit is contained in:
Tobias Nätterlund
2013-04-16 14:53:24 +02:00
committed by Tobias Nätterlund
parent 22fcb71a8e
commit 9728afadb0
6 changed files with 79 additions and 114 deletions

View File

@@ -56,6 +56,7 @@
#include <QFileInfo>
#include <QDir>
#include <QMessageBox>
#include <QDesktopServices>
namespace Qnx {
namespace Internal {
@@ -442,16 +443,14 @@ QString BlackBerryConfiguration::dataDirPath() const
if (Utils::HostOsInfo::isAnyUnixHost())
return homeDir + QLatin1String("/.rim");
#if defined(Q_OS_WIN)
if (Utils::HostOsInfo::isWindowsHost()) {
// needed because QSysInfo::windowsVersion() is not available on other
// platforms.
if (QSysInfo::windowsVersion() == QSysInfo::WV_XP)
return homeDir
+ QLatin1String("/Local Settings/Application Data/Research In Motion");
return homeDir + QLatin1String("/AppData/Local/Research in Motion");
// Get the proper storage location on Windows using QDesktopServices,
// to not hardcode "AppData/Local", as it might refer to "AppData/Roaming".
QString dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
dataDir = dataDir.left(dataDir.indexOf(QCoreApplication::organizationName()));
dataDir.append(QLatin1String("Research in Motion"));
return dataDir;
}
#endif
return QString();
}

View File

@@ -35,15 +35,6 @@
#include "blackberrydeviceconfiguration.h"
#include <ssh/sshconnection.h>
#include <ssh/sshkeygenerator.h>
#include <utils/portlist.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
#include <QDir>
#include <QFileInfo>
#include <QMessageBox>
#include <QHostInfo>
using namespace Qnx;
using namespace Qnx::Internal;
@@ -82,56 +73,3 @@ ProjectExplorer::IDevice::Ptr BlackBerryDeviceConfigurationWizard::device()
configuration->setDebugToken(m_setupPage->debugToken());
return configuration;
}
void BlackBerryDeviceConfigurationWizard::accept()
{
if (m_sshKeyPage->isGenerated()) {
if (saveKeys())
QWizard::accept();
} else {
QWizard::accept();
}
}
bool BlackBerryDeviceConfigurationWizard::saveKeys()
{
const QString privKeyPath = m_sshKeyPage->privateKey();
const QString pubKeyPath = m_sshKeyPage->publicKey();
const QString storeLocation = QFileInfo(privKeyPath).absolutePath();
if (!QDir::root().mkpath(storeLocation)) {
QMessageBox::critical(this, tr("Failure to Save Key File"),
tr("Failed to create directory: '%1'.").arg(storeLocation));
return false;
}
if (QFileInfo(privKeyPath).exists()) {
QMessageBox::critical(this, tr("Failure to Save Key File"),
tr("Private key file already exists: '%1'").arg(privKeyPath));
return false;
}
if (QFileInfo(pubKeyPath).exists()) {
QMessageBox::critical(this, tr("Failure to Save Key File"),
tr("Public key file already exists: '%1'").arg(pubKeyPath));
return false;
}
Utils::FileSaver privSaver(privKeyPath);
privSaver.write(m_sshKeyPage->keyGenerator()->privateKey());
if (!privSaver.finalize(this))
return false; // finalize shows an error message if necessary
QFile::setPermissions(privKeyPath, QFile::ReadOwner | QFile::WriteOwner);
Utils::FileSaver pubSaver(pubKeyPath);
// blackberry-connect requires an @ character to be included in the RSA comment
const QString atHost = QLatin1String("@") + QHostInfo::localHostName();
QByteArray pubKeyContent = m_sshKeyPage->keyGenerator()->publicKey();
pubKeyContent.append(atHost.toLocal8Bit());
pubSaver.write(pubKeyContent);
if (!pubSaver.finalize(this))
return false;
return true;
}

View File

@@ -51,8 +51,6 @@ public:
ProjectExplorer::IDevice::Ptr device();
void accept();
private:
enum PageId {
SetupPageId,
@@ -60,8 +58,6 @@ private:
FinalPageId
};
bool saveKeys();
BlackBerryDeviceConfigurationWizardSetupPage *m_setupPage;
BlackBerryDeviceConfigurationWizardSshKeyPage *m_sshKeyPage;
BlackBerryDeviceConfigurationWizardFinalPage *m_finalPage;

View File

@@ -30,6 +30,7 @@
****************************************************************************/
#include "blackberrydeviceconfigurationwizardpages.h"
#include "blackberryconfiguration.h"
#include "blackberrydebugtokenrequestdialog.h"
#include "blackberrysshkeysgenerator.h"
#include "ui_blackberrydeviceconfigurationwizardsetuppage.h"
@@ -40,7 +41,9 @@
#include <QFormLayout>
#include <QMessageBox>
#include <QFileDialog>
#include <QFileInfo>
#include <QHostInfo>
using namespace ProjectExplorer;
using namespace Qnx;
@@ -152,13 +155,17 @@ BlackBerryDeviceConfigurationWizardSshKeyPage::BlackBerryDeviceConfigurationWiza
: QWizardPage(parent)
, m_ui(new Ui::BlackBerryDeviceConfigurationWizardSshKeyPage)
, m_sshKeysGenerator(new BlackBerrySshKeysGenerator(this))
, m_isGenerated(false)
{
m_ui->setupUi(this);
m_ui->privateKey->setExpectedKind(Utils::PathChooser::File);
m_ui->progressBar->hide();
QString initialBrowsePath = BlackBerryConfiguration::instance().dataDirPath();
if (!QFileInfo(initialBrowsePath).exists())
initialBrowsePath = QDir::homePath();
m_ui->privateKey->setInitialBrowsePathBackup(initialBrowsePath);
setTitle(tr("SSH Key Setup"));
setSubTitle(tr("Please select an existing <b>4096</b>-bit key or click <b>Generate</b> to create a new one."));
@@ -187,7 +194,7 @@ bool BlackBerryDeviceConfigurationWizardSshKeyPage::isComplete() const
QFileInfo privateKeyFi(m_ui->privateKey->fileName().toString());
QFileInfo publicKeyFi(m_ui->publicKey->text());
return (privateKeyFi.exists() && publicKeyFi.exists()) || m_isGenerated;
return privateKeyFi.exists() && publicKeyFi.exists();
}
QString BlackBerryDeviceConfigurationWizardSshKeyPage::privateKey() const
@@ -200,46 +207,69 @@ QString BlackBerryDeviceConfigurationWizardSshKeyPage::publicKey() const
return m_ui->publicKey->text();
}
bool BlackBerryDeviceConfigurationWizardSshKeyPage::isGenerated() const
{
return m_isGenerated;
}
QSsh::SshKeyGenerator *BlackBerryDeviceConfigurationWizardSshKeyPage::keyGenerator() const
{
return m_sshKeysGenerator->keyGenerator();
}
void BlackBerryDeviceConfigurationWizardSshKeyPage::findMatchingPublicKey(const QString &privateKeyPath)
{
const QString candidate = privateKeyPath + QLatin1String(".pub");
if (QFileInfo(candidate).exists())
m_ui->publicKey->setText(candidate);
else
m_ui->publicKey->clear();
}
void BlackBerryDeviceConfigurationWizardSshKeyPage::processSshKeys(bool success)
{
m_isGenerated = success;
if (!m_isGenerated) {
setBusy(false);
if (!success) {
QMessageBox::critical(this, tr("Key Generation Failed"), m_sshKeysGenerator->error());
setBusy(false);
return;
}
const QString storeLocation = Core::ICore::userResourcePath() + QLatin1String("/qnx/")
+ field(QLatin1String(DEVICENAME_FIELD_ID)).toString();
const QString privKeyPath = storeLocation + QLatin1String("/id_rsa");
const QString pubKeyPath = storeLocation + QLatin1String("/id_rsa.pub");
const QString publicKeyPath = m_generatedPrivateKeyPath + QLatin1String(".pub");
m_ui->privateKey->setFileName(Utils::FileName::fromString(privKeyPath));
m_ui->publicKey->setText(pubKeyPath);
m_ui->privateKey->setEnabled(false);
if (!saveKeys(m_generatedPrivateKeyPath, publicKeyPath)) // saveKeys(..) will show an error message if necessary
return;
setBusy(false);
m_ui->privateKey->setFileName(Utils::FileName::fromString(m_generatedPrivateKeyPath));
m_ui->publicKey->setText(publicKeyPath);
emit completeChanged();
}
bool BlackBerryDeviceConfigurationWizardSshKeyPage::saveKeys(const QString &privateKeyFile, const QString &publicKeyFile)
{
Utils::FileSaver privSaver(privateKeyFile);
privSaver.write(m_sshKeysGenerator->keyGenerator()->privateKey());
if (!privSaver.finalize(this))
return false; // finalize shows an error message if necessary
QFile::setPermissions(privateKeyFile, QFile::ReadOwner | QFile::WriteOwner);
Utils::FileSaver pubSaver(publicKeyFile);
// blackberry-connect requires an @ character to be included in the RSA comment
const QString atHost = QLatin1String("@") + QHostInfo::localHostName();
QByteArray pubKeyContent = m_sshKeysGenerator->keyGenerator()->publicKey();
pubKeyContent.append(atHost.toLocal8Bit());
pubSaver.write(pubKeyContent);
if (!pubSaver.finalize(this))
return false;
return true;
}
void BlackBerryDeviceConfigurationWizardSshKeyPage::generateSshKeys()
{
QString lookInDir = BlackBerryConfiguration::instance().dataDirPath();
if (!QFileInfo(lookInDir).exists())
lookInDir = QDir::homePath();
QString privateKeyPath = QFileDialog::getSaveFileName(this, tr("Choose Private Key File Name"), lookInDir);
if (privateKeyPath.isEmpty())
return;
m_generatedPrivateKeyPath = privateKeyPath;
setBusy(true);
m_sshKeysGenerator->start();
}
@@ -247,6 +277,7 @@ void BlackBerryDeviceConfigurationWizardSshKeyPage::generateSshKeys()
void BlackBerryDeviceConfigurationWizardSshKeyPage::setBusy(bool busy)
{
m_ui->privateKey->setEnabled(!busy);
m_ui->publicKey->setEnabled(!busy);
m_ui->generate->setEnabled(!busy);
m_ui->progressBar->setVisible(busy);

View File

@@ -84,9 +84,6 @@ public:
QString privateKey() const;
QString publicKey() const;
bool isGenerated() const;
QSsh::SshKeyGenerator *keyGenerator() const;
private slots:
void findMatchingPublicKey(const QString &privateKeyPath);
@@ -94,13 +91,13 @@ private slots:
void generateSshKeys();
private:
void saveKeys();
bool saveKeys(const QString &privateKeyFile, const QString &publicKeyFile);
void setBusy(bool busy);
Ui::BlackBerryDeviceConfigurationWizardSshKeyPage *m_ui;
BlackBerrySshKeysGenerator *m_sshKeysGenerator;
bool m_isGenerated;
QString m_generatedPrivateKeyPath;
};
class BlackBerryDeviceConfigurationWizardFinalPage : public QWizardPage

View File

@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>413</width>
<height>139</height>
<height>92</height>
</rect>
</property>
<property name="windowTitle">
@@ -22,7 +22,18 @@
</widget>
</item>
<item row="0" column="1">
<widget class="Utils::PathChooser" name="privateKey" native="true"/>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="Utils::PathChooser" name="privateKey" native="true"/>
</item>
<item>
<widget class="QPushButton" name="generate">
<property name="text">
<string>Generate...</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
@@ -31,17 +42,10 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="generate">
<property name="text">
<string>Generate</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="publicKey">
<property name="text">
<string/>
<widget class="QLineEdit" name="publicKey">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>