Safely store passwords #79
21 changed files with 508 additions and 195 deletions
|
|
@ -16,7 +16,7 @@ class BackupDialog : public QDialog
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit BackupDialog(QWidget *parent = 0);
|
||||
explicit BackupDialog(QWidget *parent = nullptr);
|
||||
~BackupDialog();
|
||||
|
||||
void ConnectTo(QProcess *process);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "ConnectionList.h"
|
||||
#include "ScopeGuard.h"
|
||||
#include "util.h"
|
||||
#include "PasswordManager.h"
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
#include <QSettings>
|
||||
|
|
@ -19,31 +20,38 @@ namespace {
|
|||
settings.setValue("hostaddr", stdStrToQ(cc.hostAddr()));
|
||||
settings.setValue("port", cc.port());
|
||||
settings.setValue("user", stdStrToQ(cc.user()));
|
||||
settings.setValue("password", stdStrToQ(cc.password()));
|
||||
//settings.setValue("password", stdStrToQ(cc.password()));
|
||||
settings.setValue("dbname", stdStrToQ(cc.dbname()));
|
||||
settings.setValue("sslmode", (int)cc.sslMode());
|
||||
settings.setValue("sslmode", static_cast<int>(cc.sslMode()));
|
||||
settings.setValue("sslcert", stdStrToQ(cc.sslCert()));
|
||||
settings.setValue("sslkey", stdStrToQ(cc.sslKey()));
|
||||
settings.setValue("sslrootcert", stdStrToQ(cc.sslRootCert()));
|
||||
settings.setValue("sslcrl", stdStrToQ(cc.sslCrl()));
|
||||
}
|
||||
|
||||
template <typename S, typename T>
|
||||
bool in_range(T value)
|
||||
{
|
||||
return value >= std::numeric_limits<S>::min() && value <= std::numeric_limits<S>::max();
|
||||
}
|
||||
|
||||
void LoadConnectionConfig(QSettings &settings, ConnectionConfig &cc)
|
||||
{
|
||||
cc.setName(qvarToStdStr(settings.value("name")));
|
||||
cc.setHost(qvarToStdStr(settings.value("host")));
|
||||
cc.setHostAddr(qvarToStdStr(settings.value("hostaddr")));
|
||||
cc.setPort(settings.value("port", 5432).toInt());
|
||||
int p = settings.value("port", 5432).toInt();
|
||||
if (!in_range<uint16_t>(p)) {
|
||||
p = 0; // let the user re-enter a valid value
|
||||
}
|
||||
|
||||
cc.setPort(static_cast<uint16_t>(p));
|
||||
cc.setUser(qvarToStdStr(settings.value("user")));
|
||||
// std::string encpw = qvarToStdStr(settings.value("encryptedpw"));
|
||||
// if (encpw.empty()) {
|
||||
cc.setPassword(qvarToStdStr(settings.value("password")));
|
||||
// }
|
||||
// else {
|
||||
// cc.setEncryptedPassword(encpw);
|
||||
// }
|
||||
|
||||
//cc.setPassword(qvarToStdStr(settings.value("password")));
|
||||
|
||||
cc.setDbname(qvarToStdStr(settings.value("dbname")));
|
||||
cc.setSslMode((SslMode)settings.value("sslmode").toInt());
|
||||
cc.setSslMode(static_cast<SslMode>(settings.value("sslmode").toInt()));
|
||||
cc.setSslCert(qvarToStdStr(settings.value("sslcert")));
|
||||
cc.setSslKey(qvarToStdStr(settings.value("sslkey")));
|
||||
cc.setSslRootCert(qvarToStdStr(settings.value("sslrootcert")));
|
||||
|
|
@ -69,19 +77,20 @@ QString ConnectionList::iniFileName()
|
|||
|
||||
ConnectionList::ConnectionList()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int ConnectionList::createNew()
|
||||
size_t ConnectionList::createNew()
|
||||
{
|
||||
m_connections.emplace_back(QUuid::createUuid(), ConnectionConfig());
|
||||
ConnectionConfig cc;
|
||||
cc.setUuid(QUuid::createUuid());
|
||||
m_connections.push_back(cc);
|
||||
return m_connections.size()-1;
|
||||
}
|
||||
|
||||
void ConnectionList::remove(int idx, int count)
|
||||
void ConnectionList::remove(size_t idx, size_t count)
|
||||
{
|
||||
auto f = m_connections.begin() + idx;
|
||||
auto l = f + count;
|
||||
auto f = m_connections.begin() + static_cast<int>(idx);
|
||||
auto l = f + static_cast<int>(count);
|
||||
deleteFromIni(f, l);
|
||||
m_connections.erase(f, l);
|
||||
}
|
||||
|
|
@ -91,7 +100,7 @@ void ConnectionList::deleteFromIni(t_Connections::iterator begin, t_Connections:
|
|||
QString file_name = iniFileName();
|
||||
QSettings settings(file_name, QSettings::IniFormat);
|
||||
for (auto i = begin; i != end; ++i) {
|
||||
settings.remove(i->m_uuid.toString());
|
||||
settings.remove(i->uuid().toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -111,8 +120,9 @@ void ConnectionList::load()
|
|||
SCOPE_EXIT { settings.endGroup(); };
|
||||
|
||||
ConnectionConfig cc;
|
||||
cc.setUuid(uuid);
|
||||
LoadConnectionConfig(settings, cc);
|
||||
m_connections.emplace_back(uuid, cc);
|
||||
m_connections.push_back(cc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -123,26 +133,24 @@ void ConnectionList::save()
|
|||
QString file_name = iniFileName();
|
||||
QSettings settings(file_name, QSettings::IniFormat);
|
||||
for (auto& e : m_connections) {
|
||||
settings.beginGroup(e.m_uuid.toString());
|
||||
settings.beginGroup(e.uuid().toString());
|
||||
SCOPE_EXIT { settings.endGroup(); };
|
||||
|
||||
SaveConnectionConfig(settings, e.m_config);
|
||||
e.m_config.clean();
|
||||
SaveConnectionConfig(settings, e);
|
||||
e.clean();
|
||||
}
|
||||
settings.sync();
|
||||
}
|
||||
|
||||
void ConnectionList::save(int index)
|
||||
void ConnectionList::save(size_t index)
|
||||
{
|
||||
if (index >= 0 && index < (int)m_connections.size()) {
|
||||
auto& e = m_connections[index];
|
||||
if (e.m_config.dirty()) {
|
||||
QString file_name = iniFileName();
|
||||
QSettings settings(file_name, QSettings::IniFormat);
|
||||
settings.beginGroup(e.m_uuid.toString());
|
||||
SaveConnectionConfig(settings, e.m_config);
|
||||
e.m_config.clean();
|
||||
settings.sync();
|
||||
}
|
||||
auto& e = m_connections.at(index);
|
||||
if (e.dirty()) {
|
||||
QString file_name = iniFileName();
|
||||
QSettings settings(file_name, QSettings::IniFormat);
|
||||
settings.beginGroup(e.uuid().toString());
|
||||
SaveConnectionConfig(settings, e);
|
||||
e.clean();
|
||||
settings.sync();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,47 +8,42 @@
|
|||
#include <vector>
|
||||
#include "Expected.h"
|
||||
|
||||
|
||||
class ConnectionList {
|
||||
private:
|
||||
static QString iniFileName();
|
||||
|
||||
public:
|
||||
|
||||
ConnectionList();
|
||||
int size() const { return m_connections.size(); }
|
||||
size_t size() const { return m_connections.size(); }
|
||||
|
||||
ConnectionConfig& getConfigByIdx(int idx)
|
||||
ConnectionConfig& getConfigByIdx(size_t idx)
|
||||
{
|
||||
return m_connections.at(idx).m_config;
|
||||
return m_connections.at(idx);
|
||||
}
|
||||
|
||||
int createNew();
|
||||
size_t createNew();
|
||||
|
||||
void remove(int idx, int count);
|
||||
void remove(size_t idx, size_t count);
|
||||
|
||||
void load();
|
||||
void save();
|
||||
void save(int index);
|
||||
|
||||
void save(size_t index);
|
||||
|
||||
private:
|
||||
class LijstElem {
|
||||
public:
|
||||
QUuid m_uuid;
|
||||
ConnectionConfig m_config;
|
||||
// class LijstElem {
|
||||
// public:
|
||||
// QUuid m_uuid; ///< Unique identifier, used as a key for storing password in psk db.
|
||||
// ConnectionConfig m_config;
|
||||
|
||||
LijstElem(const QUuid id, const ConnectionConfig &cfg)
|
||||
: m_uuid(id), m_config(cfg)
|
||||
{}
|
||||
};
|
||||
// LijstElem(const QUuid id, const ConnectionConfig &cfg)
|
||||
// : m_uuid(id), m_config(cfg)
|
||||
// {}
|
||||
// };
|
||||
|
||||
using t_Connections = std::vector<LijstElem>;
|
||||
using t_Connections = std::vector<ConnectionConfig>;
|
||||
t_Connections m_connections;
|
||||
|
||||
void deleteFromIni(t_Connections::iterator begin, t_Connections::iterator end);
|
||||
|
||||
|
||||
static QString iniFileName();
|
||||
};
|
||||
|
||||
#endif // CONNECTIONLIST_H
|
||||
|
|
|
|||
|
|
@ -150,6 +150,27 @@ Expected<ConnectionConfig> ConnectionListModel::get(int row)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
template <typename T>
|
||||
size_t as_size_t(T t);
|
||||
|
||||
template <>
|
||||
size_t as_size_t(int t)
|
||||
{
|
||||
BOOST_ASSERT(t >= 0);
|
||||
return static_cast<size_t>(t);
|
||||
}
|
||||
|
||||
template <>
|
||||
size_t as_size_t(long t)
|
||||
{
|
||||
BOOST_ASSERT(t >= 0);
|
||||
return static_cast<size_t>(t);
|
||||
}
|
||||
|
||||
|
||||
//void ConnectionListModel::del(const int idx)
|
||||
bool ConnectionListModel::removeRows(int row, int count, const QModelIndex &parent)
|
||||
{
|
||||
|
|
@ -159,7 +180,7 @@ bool ConnectionListModel::removeRows(int row, int count, const QModelIndex &pare
|
|||
beginRemoveRows(parent, row, row + count -1);
|
||||
SCOPE_EXIT { endRemoveRows(); };
|
||||
|
||||
m_connections->remove(row, count);
|
||||
m_connections->remove(as_size_t(row), as_size_t(count));
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
|
|
@ -176,7 +197,12 @@ void ConnectionListModel::save()
|
|||
m_connections->save();
|
||||
}
|
||||
|
||||
void ConnectionListModel::save(int index)
|
||||
void ConnectionListModel::save(size_t index)
|
||||
{
|
||||
m_connections->save(index);
|
||||
}
|
||||
|
||||
void ConnectionListModel::save(size_t index, const ConnectionConfig &cc)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,13 +34,14 @@ public:
|
|||
virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
|
||||
|
||||
void save();
|
||||
void save(int index);
|
||||
void save(size_t index);
|
||||
void save(size_t index, const ConnectionConfig &cc);
|
||||
static QString makeLongDescription(const ConnectionConfig &cfg);
|
||||
private:
|
||||
|
||||
ConnectionList *m_connections;
|
||||
|
||||
|
||||
static QString makeLongDescription(const ConnectionConfig &cfg);
|
||||
};
|
||||
|
||||
#endif // CONNECTIONLISTMODEL_H
|
||||
|
|
|
|||
|
|
@ -7,6 +7,21 @@
|
|||
#include <QStandardItemModel>
|
||||
#include "ConnectionListModel.h"
|
||||
|
||||
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
|
||||
QString pskFileName()
|
||||
{
|
||||
QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||
QDir dir(path);
|
||||
if (!dir.exists()) {
|
||||
dir.mkpath(".");
|
||||
}
|
||||
path += "/psk.ini";
|
||||
return path;
|
||||
}
|
||||
|
||||
ConnectionManagerWindow::ConnectionManagerWindow(MasterController *master, QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::ConnectionManagerWindow)
|
||||
|
|
@ -53,9 +68,13 @@ void ConnectionManagerWindow::on_currentChanged(const QModelIndex ¤t,
|
|||
{
|
||||
int currow = current.row();
|
||||
auto clm = m_masterController->getConnectionListModel();
|
||||
clm->save(prevSelection);
|
||||
if (prevSelection)
|
||||
clm->save(*prevSelection);
|
||||
m_mapper->setCurrentIndex(currow);
|
||||
prevSelection = currow;
|
||||
if (currow >= 0)
|
||||
prevSelection = static_cast<size_t>(currow);
|
||||
else
|
||||
prevSelection.reset();
|
||||
}
|
||||
|
||||
void ConnectionManagerWindow::on_actionDelete_connection_triggered()
|
||||
|
|
@ -82,7 +101,6 @@ void ConnectionManagerWindow::setupWidgetMappings()
|
|||
m_mapper->addMapping(ui->edtHost, 2);
|
||||
m_mapper->addMapping(ui->spinPort, 3);
|
||||
m_mapper->addMapping(ui->edtUser, 4);
|
||||
m_mapper->addMapping(ui->edtPassword, 5);
|
||||
m_mapper->addMapping(ui->edtDbname, 6);
|
||||
m_mapper->toFirst();
|
||||
}
|
||||
|
|
@ -90,7 +108,13 @@ void ConnectionManagerWindow::setupWidgetMappings()
|
|||
void ConnectionManagerWindow::on_actionConnect_triggered()
|
||||
{
|
||||
auto ci = ui->listView->selectionModel()->currentIndex();
|
||||
m_masterController->openSqlWindowForConnection(ci.row());
|
||||
if (ci.isValid()) {
|
||||
auto r = static_cast<size_t>(ci.row());
|
||||
m_masterController->openSqlWindowForConnection(r);
|
||||
}
|
||||
else {
|
||||
// TODO can we give unobtrusive message why it didn't work?
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionManagerWindow::on_actionQuit_application_triggered()
|
||||
|
|
@ -117,68 +141,3 @@ void ConnectionManagerWindow::on_actionManage_server_triggered()
|
|||
}
|
||||
|
||||
|
||||
|
||||
#include <botan/botan.h>
|
||||
//#include <botan/base64.h>
|
||||
//#include <botan/pbkdf.h>
|
||||
//#include <botan/block_cipher.h>
|
||||
//#include <botan/hex.h>
|
||||
#include <botan/cryptobox.h>
|
||||
|
||||
|
||||
void ConnectionManagerWindow::on_testButton_clicked()
|
||||
{
|
||||
std::string error = Botan::runtime_version_check(BOTAN_VERSION_MAJOR,
|
||||
BOTAN_VERSION_MINOR,
|
||||
BOTAN_VERSION_PATCH);
|
||||
if (error.empty()) {
|
||||
// Botan::AutoSeeded_RNG rng;
|
||||
// Botan::secure_vector<Botan::byte> salt =
|
||||
// //{ 0x3f, 0x0a, 0xb0, 0x11, 0x44, 0xfe, 0x9d, 0xf7, 0x85, 0xd3, 0x11, 0x38, 0xe2, 0xdf, 0x31, 0x42 };
|
||||
// rng.random_vec(16);
|
||||
// // salt should be random and saved with encrypted data so it can be used when we decrypt
|
||||
|
||||
// std::string password = "Hello kitty";
|
||||
// std::unique_ptr<Botan::PBKDF> pbkdf(Botan::get_pbkdf("PBKDF2(SHA-256)"));
|
||||
// Botan::OctetString aes256_key = pbkdf->derive_key(32, password, salt.data(), salt.size(), 10000);
|
||||
|
||||
// std::string plaintext("Your great-grandfather gave this watch to your granddad for good luck. Unfortunately, Dane's luck wasn't as good as his old man's.");
|
||||
// Botan::secure_vector<uint8_t> pt(plaintext.data(),plaintext.data()+plaintext.length());
|
||||
|
||||
// std::unique_ptr<Botan::Cipher_Mode> enc(Botan::get_cipher_mode("AES-256/CBC/PKCS7", Botan::ENCRYPTION));
|
||||
// enc->set_key(aes256_key);
|
||||
|
||||
// //generate fresh nonce (IV)
|
||||
// //std::unique_ptr<Botan::RandomNumberGenerator> rng(new Botan::AutoSeeded_RNG);
|
||||
// std::vector<uint8_t> iv(enc->default_nonce_length());
|
||||
// rng.randomize(iv.data(), iv.size());
|
||||
// enc->start(iv);
|
||||
// enc->finish(pt);
|
||||
// //std::cout << std::endl << enc->name() << " with iv " << Botan::hex_encode(iv) << std::endl << Botan::hex_encode(pt);
|
||||
|
||||
|
||||
//std::string s = aes256_key.as_string();// + "\n" + t.format_string();
|
||||
|
||||
std::string passphrase = "my passphrase";
|
||||
std::string plaintext("password1234");
|
||||
try {
|
||||
Botan::AutoSeeded_RNG rng;
|
||||
std::string encrypted = Botan::CryptoBox::encrypt((const uint8_t*)plaintext.data(), plaintext.length(), passphrase, rng);
|
||||
|
||||
std::string decrypted = Botan::CryptoBox::decrypt(encrypted, passphrase);
|
||||
|
||||
std::string s = encrypted + "\n" + decrypted;
|
||||
QMessageBox::information(this, "pglab",
|
||||
QString::fromUtf8(s.c_str()), QMessageBox::Yes);
|
||||
}
|
||||
catch (Botan::Decoding_Error &/*e*/) {
|
||||
QMessageBox::information(this, "pglab",
|
||||
tr("Failure to decrypt"), QMessageBox::Yes);
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
QMessageBox ::information(this, "pglab",
|
||||
QString::fromUtf8(error.c_str()), QMessageBox::Yes);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#define CONNECTIONMANAGERWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <boost/optional.hpp>
|
||||
|
||||
namespace Ui {
|
||||
class ConnectionManagerWindow;
|
||||
|
|
@ -30,14 +31,12 @@ private slots:
|
|||
void on_actionBackup_database_triggered();
|
||||
void on_actionManage_server_triggered();
|
||||
|
||||
void on_testButton_clicked();
|
||||
|
||||
private:
|
||||
Ui::ConnectionManagerWindow *ui;
|
||||
QDataWidgetMapper *m_mapper = nullptr;
|
||||
MasterController *m_masterController;
|
||||
|
||||
int prevSelection = -1;
|
||||
boost::optional<size_t> prevSelection;
|
||||
|
||||
void setupWidgetMappings();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -75,30 +75,23 @@
|
|||
<widget class="QLineEdit" name="edtUser"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Password</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="edtPassword">
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Database</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="edtDbname"/>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>SSL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QComboBox" name="cmbbxSsl">
|
||||
<property name="currentIndex">
|
||||
<number>2</number>
|
||||
|
|
@ -136,53 +129,46 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>SSL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Certificate</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<item row="6" column="1">
|
||||
<widget class="QLineEdit" name="edtCert"/>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="text">
|
||||
<string>Key</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<item row="7" column="1">
|
||||
<widget class="QLineEdit" name="edtKey"/>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Root cert.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<item row="8" column="1">
|
||||
<widget class="QLineEdit" name="edtRootCert"/>
|
||||
</item>
|
||||
<item row="10" column="0">
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Revocation list</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="10" column="1">
|
||||
<item row="9" column="1">
|
||||
<widget class="QLineEdit" name="edtCrl"/>
|
||||
</item>
|
||||
<item row="11" column="0">
|
||||
<item row="10" column="0">
|
||||
<widget class="QPushButton" name="testButton">
|
||||
<property name="text">
|
||||
<string>PushButton</string>
|
||||
|
|
@ -201,7 +187,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>25</height>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "MainWindow.h"
|
||||
#include "ServerWindow.h"
|
||||
#include "BackupDialog.h"
|
||||
#include "PasswordPromptDialog.h"
|
||||
|
||||
|
||||
MasterController::MasterController(QObject *parent) : QObject(parent)
|
||||
|
|
@ -33,39 +34,103 @@ void MasterController::showConnectionManager()
|
|||
m_connectionManagerWindow->show();
|
||||
}
|
||||
|
||||
void MasterController::openSqlWindowForConnection(int connection_index)
|
||||
void MasterController::openSqlWindowForConnection(size_t connection_index)
|
||||
{
|
||||
auto cc = m_connectionListModel->get(connection_index);
|
||||
m_connectionListModel->save(connection_index);
|
||||
if (cc.valid()) {
|
||||
auto w = new MainWindow(this, nullptr);
|
||||
w->setAttribute( Qt::WA_DeleteOnClose );
|
||||
w->setConfig(cc.get());
|
||||
w->show();
|
||||
|
||||
auto res = m_connectionListModel->get(connection_index);
|
||||
if (res.valid()) {
|
||||
auto cc = res.get();
|
||||
|
||||
m_connectionListModel->save(connection_index, cc);
|
||||
if (retrieveConnectionPassword(cc)) {
|
||||
// TODO instead of directly openening the mainwindow
|
||||
// do async connect and only open window when we have
|
||||
// working connection
|
||||
auto w = new MainWindow(this, nullptr);
|
||||
w->setAttribute( Qt::WA_DeleteOnClose );
|
||||
w->setConfig(cc);
|
||||
w->show();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MasterController::openBackupDlgForConnection(int connection_index)
|
||||
{
|
||||
auto cc = m_connectionListModel->get(connection_index);
|
||||
m_connectionListModel->save(connection_index);
|
||||
if (cc.valid()) {
|
||||
auto res = m_connectionListModel->get(connection_index);
|
||||
if (res.valid()) {
|
||||
auto cc = res.get();
|
||||
retrieveConnectionPassword(cc);
|
||||
m_connectionListModel->save(connection_index, cc);
|
||||
|
||||
auto w = new BackupDialog(nullptr); //new ServerWindow(this, nullptr);
|
||||
w->setAttribute( Qt::WA_DeleteOnClose );
|
||||
w->setConfig(cc.get());
|
||||
w->setConfig(cc);
|
||||
w->show();
|
||||
}
|
||||
}
|
||||
|
||||
void MasterController::openServerWindowForConnection(int connection_index)
|
||||
{
|
||||
auto cc = m_connectionListModel->get(connection_index);
|
||||
m_connectionListModel->save(connection_index);
|
||||
if (cc.valid()) {
|
||||
auto res = m_connectionListModel->get(connection_index);
|
||||
if (res.valid()) {
|
||||
auto cc = res.get();
|
||||
retrieveConnectionPassword(cc);
|
||||
m_connectionListModel->save(connection_index, cc);
|
||||
|
||||
auto w = new ServerWindow(this, nullptr);
|
||||
w->setAttribute( Qt::WA_DeleteOnClose );
|
||||
w->setConfig(cc.get());
|
||||
w->setConfig(cc);
|
||||
w->show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool MasterController::retrieveConnectionPassword(ConnectionConfig &cc)
|
||||
{
|
||||
// Look at config
|
||||
// - is password required, how do we know?
|
||||
// - IF is password stored in pskdb
|
||||
// - ask pskdb for password
|
||||
// - ELSE
|
||||
// - ask user for password
|
||||
QString str = ConnectionListModel::makeLongDescription(cc);
|
||||
auto dlg = std::make_unique<PasswordPromptDialog>(nullptr);
|
||||
dlg->setConnectionDescription(str);
|
||||
int exec_result = dlg->exec();
|
||||
|
||||
if (exec_result == QDialog::Accepted) {
|
||||
cc.setPassword(dlg->password().toUtf8().data());
|
||||
// - IF user checked remember password
|
||||
// - ask pskdb to store password
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool MasterController::getPasswordFromPskdb(const std::string &password_id, std::string &password)
|
||||
{
|
||||
// func: getPasswordFromPskdb
|
||||
// IF pskdb locked
|
||||
// prompt user for pskdb passphrase
|
||||
// unlock pskdb
|
||||
// get pwd
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool MasterController::storePasswordInPskdb(const std::string &password_id, const std::string password)
|
||||
{
|
||||
// func: storePasswordInPskdb
|
||||
// IF pskdb not setup
|
||||
// notify user and ask for passphrase
|
||||
// init pskdb
|
||||
// ELSE
|
||||
// IF pskdb locked
|
||||
// ask for passphrase
|
||||
// unlock
|
||||
// store pwd
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class ConnectionManagerWindow;
|
|||
class MasterController : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit MasterController(QObject *parent = 0);
|
||||
explicit MasterController(QObject *parent = nullptr);
|
||||
MasterController(const MasterController&) = delete;
|
||||
MasterController &operator=(const MasterController&) = delete;
|
||||
~MasterController();
|
||||
|
|
@ -29,7 +29,7 @@ public:
|
|||
}
|
||||
|
||||
void showConnectionManager();
|
||||
void openSqlWindowForConnection(int connection_index);
|
||||
void openSqlWindowForConnection(size_t connection_index);
|
||||
void openServerWindowForConnection(int connection_index);
|
||||
void openBackupDlgForConnection(int connection_index);
|
||||
|
||||
|
|
@ -41,7 +41,15 @@ private:
|
|||
ConnectionList *m_connectionList = nullptr;
|
||||
ConnectionListModel *m_connectionListModel = nullptr;
|
||||
ConnectionManagerWindow *m_connectionManagerWindow = nullptr;
|
||||
|
||||
|
||||
/** Retrieves the connection password from the user (directly or through the psk db)
|
||||
*
|
||||
*/
|
||||
bool retrieveConnectionPassword(ConnectionConfig &cc);
|
||||
|
||||
bool getPasswordFromPskdb(const std::string &password_id, std::string &password);
|
||||
|
||||
bool storePasswordInPskdb(const std::string &password_id, const std::string password);
|
||||
};
|
||||
|
||||
#endif // MASTERCONTROLLER_H
|
||||
|
|
|
|||
45
pglab/PassPhraseForm.cpp
Normal file
45
pglab/PassPhraseForm.cpp
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
#include "PassPhraseForm.h"
|
||||
#include "ui_PassPhraseForm.h"
|
||||
|
||||
PassPhraseForm::PassPhraseForm(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::PassPhraseForm)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
PassPhraseForm::~PassPhraseForm()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Password strength calculation:
|
||||
seperate characters in couple of groups
|
||||
|
||||
For the use of characters from each group a certain value is added to the base value
|
||||
which is meant to signify the size of the set of characters the password is based on.
|
||||
|
||||
Some analysis of relative positions might be required! Predictable placement of special charachters and uppercase/lowercase or numbers
|
||||
should be penalized.
|
||||
|
||||
These calculations should result in a search space size per character
|
||||
|
||||
the base to the power of the length of the password gives the resulting strength
|
||||
from this result we take the 10 log to get the magnitude of the value.
|
||||
|
||||
a-z 1:3 2:7 3:13 4:26
|
||||
A-Z 1:3 2:7 3:13 4:26
|
||||
0-9 1:4 2:10
|
||||
`~!@#$%^&*()_-=+[{]};:'",<.>/?\| 1:4 2:8 3:16 4:32
|
||||
space +1
|
||||
|
||||
Straf punten
|
||||
alleen speciaal karakter aan eind van string -8
|
||||
alleen hoofdletter aan begin van wachtwoord -6
|
||||
|
||||
la-~ZDv4E-O*y]C
|
||||
bYGWlDyeKKbcZBjoWX
|
||||
|
||||
*/
|
||||
22
pglab/PassPhraseForm.h
Normal file
22
pglab/PassPhraseForm.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef PASSPHRASEFORM_H
|
||||
#define PASSPHRASEFORM_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class PassPhraseForm;
|
||||
}
|
||||
|
||||
class PassPhraseForm : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PassPhraseForm(QWidget *parent = nullptr);
|
||||
~PassPhraseForm();
|
||||
|
||||
private:
|
||||
Ui::PassPhraseForm *ui;
|
||||
};
|
||||
|
||||
#endif // PASSPHRASEFORM_H
|
||||
75
pglab/PassPhraseForm.ui
Normal file
75
pglab/PassPhraseForm.ui
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PassPhraseForm</class>
|
||||
<widget class="QWidget" name="PassPhraseForm">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>397</width>
|
||||
<height>228</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout">
|
||||
<property name="horizontalSpacing">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="verticalSpacing">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Enter passphrase:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit">
|
||||
<property name="maxLength">
|
||||
<number>32767</number>
|
||||
</property>
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::NoEcho</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Repeat passphrase:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_2">
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="value">
|
||||
<number>67</number>
|
||||
</property>
|
||||
<property name="format">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
70
pglab/PasswordPromptDialog.cpp
Normal file
70
pglab/PasswordPromptDialog.cpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
#include "PasswordPromptDialog.h"
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QCheckBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QLabel>
|
||||
#include <QLayout>
|
||||
#include <QLineEdit>
|
||||
|
||||
PasswordPromptDialog::PasswordPromptDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
{
|
||||
m_connectionLabel = new QLabel(this);
|
||||
auto dialog_buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);
|
||||
|
||||
m_passwordLabel = new QLabel(this);
|
||||
m_passwordInput = new QLineEdit(this);
|
||||
m_passwordInput->setEchoMode(QLineEdit::Password);
|
||||
|
||||
m_saveCheck = new QCheckBox(this);
|
||||
|
||||
|
||||
auto mainLayout = new QGridLayout;
|
||||
int row = 0;
|
||||
mainLayout->addWidget(m_connectionLabel, row, 0, 1, 2);
|
||||
++row;
|
||||
mainLayout->addWidget(m_passwordLabel, row, 0);
|
||||
mainLayout->addWidget(m_passwordInput, row, 1);
|
||||
++row;
|
||||
mainLayout->addWidget(m_saveCheck, row, 1);
|
||||
++row;
|
||||
mainLayout->addWidget(dialog_buttons, row, 0, 1 ,2);
|
||||
setLayout(mainLayout);
|
||||
|
||||
m_passwordInput->setFocus();
|
||||
retranslateUi();
|
||||
|
||||
// QMetaObject::connectSlotsByName(BackupDialog);
|
||||
connect(dialog_buttons, &QDialogButtonBox::accepted, this, &PasswordPromptDialog::accept);
|
||||
connect(dialog_buttons, &QDialogButtonBox::rejected, this, &PasswordPromptDialog::reject);
|
||||
}
|
||||
|
||||
void PasswordPromptDialog::retranslateUi()
|
||||
{
|
||||
const char * context = "PasswordPromptDialog";
|
||||
setWindowTitle(QApplication::translate(context, "Connection password", nullptr));
|
||||
m_passwordLabel->setText(QApplication::translate(context, "Password", nullptr));
|
||||
m_passwordInput->setPlaceholderText(QApplication::translate(context, "Enter password", nullptr));
|
||||
m_saveCheck->setText(QApplication::translate(context, "Save password", nullptr));
|
||||
}
|
||||
|
||||
void PasswordPromptDialog::setConnectionDescription(const QString &description)
|
||||
{
|
||||
m_connectionLabel->setText(QString(tr("Please provide password for connection %1")).arg(description));
|
||||
|
||||
}
|
||||
|
||||
QString PasswordPromptDialog::password() const
|
||||
{
|
||||
return m_passwordInput->text();
|
||||
}
|
||||
|
||||
//void PasswordPromptDialog::accept()
|
||||
//{
|
||||
|
||||
//}
|
||||
|
||||
//void PasswordPromptDialog::reject()
|
||||
//{
|
||||
|
||||
//}
|
||||
32
pglab/PasswordPromptDialog.h
Normal file
32
pglab/PasswordPromptDialog.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef PASSWORDPROMPTDIALOG_H
|
||||
#define PASSWORDPROMPTDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class QCheckBox;
|
||||
class QLabel;
|
||||
class QLineEdit;
|
||||
|
||||
class PasswordPromptDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PasswordPromptDialog(QWidget *parent = nullptr);
|
||||
|
||||
void setConnectionDescription(const QString &description);
|
||||
|
||||
QString password() const;
|
||||
private:
|
||||
QLabel *m_connectionLabel = nullptr;
|
||||
QLabel *m_passwordLabel = nullptr;
|
||||
QLineEdit *m_passwordInput = nullptr;
|
||||
QCheckBox *m_saveCheck = nullptr;
|
||||
|
||||
void retranslateUi();
|
||||
|
||||
private slots:
|
||||
// void accept();
|
||||
// void reject();
|
||||
};
|
||||
|
||||
#endif // PASSWORDPROMPTDIALOG_H
|
||||
|
|
@ -26,14 +26,10 @@ TablesPage::TablesPage(MainWindow *parent)
|
|||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// WARNING delegates should NOT be shared!!!
|
||||
auto pglab_delegate = new PgLabItemDelegate(this);
|
||||
auto icon_delegate = new IconColumnDelegate(this);
|
||||
|
||||
SetTableViewDefault(ui->tableListTable);
|
||||
m_tablesModel = new TablesTableModel(this);
|
||||
ui->tableListTable->setModel(m_tablesModel);
|
||||
ui->tableListTable->setItemDelegate(pglab_delegate);
|
||||
ui->tableListTable->setItemDelegate(new PgLabItemDelegate(this));
|
||||
ui->tableListTable->setSortingEnabled(true);
|
||||
ui->tableListTable->sortByColumn(0, Qt::AscendingOrder);
|
||||
ui->tableListTable->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||
|
|
@ -47,14 +43,14 @@ TablesPage::TablesPage(MainWindow *parent)
|
|||
SetTableViewDefault(ui->constraintsTable);
|
||||
m_constraintModel = new ConstraintModel(this);
|
||||
ui->constraintsTable->setModel(m_constraintModel);
|
||||
ui->constraintsTable->setItemDelegateForColumn(0, icon_delegate);
|
||||
ui->constraintsTable->setItemDelegateForColumn(0, new IconColumnDelegate(this));
|
||||
|
||||
// Indexes
|
||||
SetTableViewDefault(ui->indexesTable);
|
||||
m_indexModel = new IndexModel(this);
|
||||
ui->indexesTable->setModel(m_indexModel);
|
||||
ui->indexesTable->setItemDelegate(pglab_delegate);
|
||||
ui->indexesTable->setItemDelegateForColumn(0, icon_delegate);
|
||||
ui->indexesTable->setItemDelegate(new PgLabItemDelegate(this));
|
||||
ui->indexesTable->setItemDelegateForColumn(0, new IconColumnDelegate(this));
|
||||
|
||||
// Set code editor fonts
|
||||
QFont code_font = UserConfiguration::instance()->codeFont();
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ DEFINES += _WIN32_WINNT=0x0501
|
|||
#LIBS += -LC:\VSproj\boost32\lib -LC:/PROG/LIB -lws2_32 -llibpq
|
||||
|
||||
#debug {
|
||||
LIBS += c:/prog/lib/botand_imp.lib
|
||||
LIBS += c:/prog/lib/botan_imp.lib
|
||||
#}
|
||||
|
||||
#release {
|
||||
|
|
@ -83,7 +83,9 @@ PropertyProxyModel.cpp \
|
|||
TriggerPage.cpp \
|
||||
SqlCodePreview.cpp \
|
||||
CustomFilterSortModel.cpp \
|
||||
PropertiesPage.cpp
|
||||
PropertiesPage.cpp \
|
||||
PassPhraseForm.cpp \
|
||||
PasswordPromptDialog.cpp
|
||||
|
||||
HEADERS += \
|
||||
QueryResultModel.h \
|
||||
|
|
@ -137,7 +139,9 @@ CustomDataRole.h \
|
|||
TriggerPage.h \
|
||||
SqlCodePreview.h \
|
||||
CustomFilterSortModel.h \
|
||||
PropertiesPage.h
|
||||
PropertiesPage.h \
|
||||
PassPhraseForm.h \
|
||||
PasswordPromptDialog.h
|
||||
|
||||
FORMS += mainwindow.ui \
|
||||
ConnectionManagerWindow.ui \
|
||||
|
|
@ -151,7 +155,8 @@ FORMS += mainwindow.ui \
|
|||
NamespaceFilterWidget.ui \
|
||||
ApplicationWindow.ui \
|
||||
CrudTab.ui \
|
||||
CodeGenerator.ui
|
||||
CodeGenerator.ui \
|
||||
PassPhraseForm.ui
|
||||
|
||||
RESOURCES += \
|
||||
resources.qrc
|
||||
|
|
|
|||
|
|
@ -57,6 +57,22 @@ ConnectionConfig::ConnectionConfig()
|
|||
: m_applicationName(QCoreApplication::applicationName().toUtf8().data())
|
||||
{}
|
||||
|
||||
|
||||
void ConnectionConfig::setUuid(const QUuid &uuid)
|
||||
{
|
||||
if (uuid != m_uuid) {
|
||||
m_dirty = true;
|
||||
m_uuid = uuid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const QUuid &ConnectionConfig::uuid() const
|
||||
{
|
||||
return m_uuid;
|
||||
}
|
||||
|
||||
|
||||
void ConnectionConfig::setName(std::string desc)
|
||||
{
|
||||
if (m_name != desc) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef CONNECTION_H
|
||||
#define CONNECTION_H
|
||||
|
||||
#include <QUuid>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
|
|
@ -27,6 +28,9 @@ class ConnectionConfig {
|
|||
public:
|
||||
ConnectionConfig();
|
||||
|
||||
void setUuid(const QUuid &uuid);
|
||||
const QUuid &uuid() const;
|
||||
|
||||
void setName(std::string desc);
|
||||
const std::string& name() const;
|
||||
|
||||
|
|
@ -73,6 +77,7 @@ public:
|
|||
bool dirty() const;
|
||||
void clean();
|
||||
private:
|
||||
QUuid m_uuid;
|
||||
std::string m_name;
|
||||
std::string m_host;
|
||||
std::string m_hostaddr;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += widgets
|
||||
QT += widgets core
|
||||
|
||||
TARGET = pglablib
|
||||
TEMPLATE = lib
|
||||
|
|
|
|||
0
readme.md
Normal file
0
readme.md
Normal file
Loading…
Add table
Add a link
Reference in a new issue