Lot of password related changes all over the place.

Password is no longer saved with the connection list.
Password is not entered along with other connection credentials.
Password is now asked for when required.
Still working on saving the password and auto retrieving it from the password manager.
This commit is contained in:
eelke 2018-11-04 11:26:20 +01:00
parent 6b9b602c64
commit 2230a4bd61
21 changed files with 508 additions and 195 deletions

View file

@ -16,7 +16,7 @@ class BackupDialog : public QDialog
Q_OBJECT Q_OBJECT
public: public:
explicit BackupDialog(QWidget *parent = 0); explicit BackupDialog(QWidget *parent = nullptr);
~BackupDialog(); ~BackupDialog();
void ConnectTo(QProcess *process); void ConnectTo(QProcess *process);

View file

@ -1,6 +1,7 @@
#include "ConnectionList.h" #include "ConnectionList.h"
#include "ScopeGuard.h" #include "ScopeGuard.h"
#include "util.h" #include "util.h"
#include "PasswordManager.h"
#include <QDir> #include <QDir>
#include <QStandardPaths> #include <QStandardPaths>
#include <QSettings> #include <QSettings>
@ -19,31 +20,38 @@ namespace {
settings.setValue("hostaddr", stdStrToQ(cc.hostAddr())); settings.setValue("hostaddr", stdStrToQ(cc.hostAddr()));
settings.setValue("port", cc.port()); settings.setValue("port", cc.port());
settings.setValue("user", stdStrToQ(cc.user())); 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("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("sslcert", stdStrToQ(cc.sslCert()));
settings.setValue("sslkey", stdStrToQ(cc.sslKey())); settings.setValue("sslkey", stdStrToQ(cc.sslKey()));
settings.setValue("sslrootcert", stdStrToQ(cc.sslRootCert())); settings.setValue("sslrootcert", stdStrToQ(cc.sslRootCert()));
settings.setValue("sslcrl", stdStrToQ(cc.sslCrl())); 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) void LoadConnectionConfig(QSettings &settings, ConnectionConfig &cc)
{ {
cc.setName(qvarToStdStr(settings.value("name"))); cc.setName(qvarToStdStr(settings.value("name")));
cc.setHost(qvarToStdStr(settings.value("host"))); cc.setHost(qvarToStdStr(settings.value("host")));
cc.setHostAddr(qvarToStdStr(settings.value("hostaddr"))); 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"))); cc.setUser(qvarToStdStr(settings.value("user")));
// std::string encpw = qvarToStdStr(settings.value("encryptedpw"));
// if (encpw.empty()) { //cc.setPassword(qvarToStdStr(settings.value("password")));
cc.setPassword(qvarToStdStr(settings.value("password")));
// }
// else {
// cc.setEncryptedPassword(encpw);
// }
cc.setDbname(qvarToStdStr(settings.value("dbname"))); 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.setSslCert(qvarToStdStr(settings.value("sslcert")));
cc.setSslKey(qvarToStdStr(settings.value("sslkey"))); cc.setSslKey(qvarToStdStr(settings.value("sslkey")));
cc.setSslRootCert(qvarToStdStr(settings.value("sslrootcert"))); cc.setSslRootCert(qvarToStdStr(settings.value("sslrootcert")));
@ -69,19 +77,20 @@ QString ConnectionList::iniFileName()
ConnectionList::ConnectionList() 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; 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 f = m_connections.begin() + static_cast<int>(idx);
auto l = f + count; auto l = f + static_cast<int>(count);
deleteFromIni(f, l); deleteFromIni(f, l);
m_connections.erase(f, l); m_connections.erase(f, l);
} }
@ -91,7 +100,7 @@ void ConnectionList::deleteFromIni(t_Connections::iterator begin, t_Connections:
QString file_name = iniFileName(); QString file_name = iniFileName();
QSettings settings(file_name, QSettings::IniFormat); QSettings settings(file_name, QSettings::IniFormat);
for (auto i = begin; i != end; ++i) { 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(); }; SCOPE_EXIT { settings.endGroup(); };
ConnectionConfig cc; ConnectionConfig cc;
cc.setUuid(uuid);
LoadConnectionConfig(settings, cc); 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(); QString file_name = iniFileName();
QSettings settings(file_name, QSettings::IniFormat); QSettings settings(file_name, QSettings::IniFormat);
for (auto& e : m_connections) { for (auto& e : m_connections) {
settings.beginGroup(e.m_uuid.toString()); settings.beginGroup(e.uuid().toString());
SCOPE_EXIT { settings.endGroup(); }; SCOPE_EXIT { settings.endGroup(); };
SaveConnectionConfig(settings, e.m_config); SaveConnectionConfig(settings, e);
e.m_config.clean(); e.clean();
} }
settings.sync(); 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.at(index);
auto& e = m_connections[index]; if (e.dirty()) {
if (e.m_config.dirty()) { QString file_name = iniFileName();
QString file_name = iniFileName(); QSettings settings(file_name, QSettings::IniFormat);
QSettings settings(file_name, QSettings::IniFormat); settings.beginGroup(e.uuid().toString());
settings.beginGroup(e.m_uuid.toString()); SaveConnectionConfig(settings, e);
SaveConnectionConfig(settings, e.m_config); e.clean();
e.m_config.clean(); settings.sync();
settings.sync();
}
} }
} }

View file

@ -8,47 +8,42 @@
#include <vector> #include <vector>
#include "Expected.h" #include "Expected.h"
class ConnectionList { class ConnectionList {
private:
static QString iniFileName();
public: public:
ConnectionList(); 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 load();
void save(); void save();
void save(int index); void save(size_t index);
private: private:
class LijstElem { // class LijstElem {
public: // public:
QUuid m_uuid; // QUuid m_uuid; ///< Unique identifier, used as a key for storing password in psk db.
ConnectionConfig m_config; // ConnectionConfig m_config;
LijstElem(const QUuid id, const ConnectionConfig &cfg) // LijstElem(const QUuid id, const ConnectionConfig &cfg)
: m_uuid(id), m_config(cfg) // : m_uuid(id), m_config(cfg)
{} // {}
}; // };
using t_Connections = std::vector<LijstElem>; using t_Connections = std::vector<ConnectionConfig>;
t_Connections m_connections; t_Connections m_connections;
void deleteFromIni(t_Connections::iterator begin, t_Connections::iterator end); void deleteFromIni(t_Connections::iterator begin, t_Connections::iterator end);
static QString iniFileName();
}; };
#endif // CONNECTIONLIST_H #endif // CONNECTIONLIST_H

View file

@ -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) //void ConnectionListModel::del(const int idx)
bool ConnectionListModel::removeRows(int row, int count, const QModelIndex &parent) 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); beginRemoveRows(parent, row, row + count -1);
SCOPE_EXIT { endRemoveRows(); }; SCOPE_EXIT { endRemoveRows(); };
m_connections->remove(row, count); m_connections->remove(as_size_t(row), as_size_t(count));
result = true; result = true;
} }
return result; return result;
@ -176,7 +197,12 @@ void ConnectionListModel::save()
m_connections->save(); m_connections->save();
} }
void ConnectionListModel::save(int index) void ConnectionListModel::save(size_t index)
{ {
m_connections->save(index); m_connections->save(index);
} }
void ConnectionListModel::save(size_t index, const ConnectionConfig &cc)
{
}

View file

@ -34,13 +34,14 @@ public:
virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override; virtual bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
void save(); 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: private:
ConnectionList *m_connections; ConnectionList *m_connections;
static QString makeLongDescription(const ConnectionConfig &cfg);
}; };
#endif // CONNECTIONLISTMODEL_H #endif // CONNECTIONLISTMODEL_H

View file

@ -7,6 +7,21 @@
#include <QStandardItemModel> #include <QStandardItemModel>
#include "ConnectionListModel.h" #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) ConnectionManagerWindow::ConnectionManagerWindow(MasterController *master, QWidget *parent)
: QMainWindow(parent) : QMainWindow(parent)
, ui(new Ui::ConnectionManagerWindow) , ui(new Ui::ConnectionManagerWindow)
@ -53,9 +68,13 @@ void ConnectionManagerWindow::on_currentChanged(const QModelIndex &current,
{ {
int currow = current.row(); int currow = current.row();
auto clm = m_masterController->getConnectionListModel(); auto clm = m_masterController->getConnectionListModel();
clm->save(prevSelection); if (prevSelection)
clm->save(*prevSelection);
m_mapper->setCurrentIndex(currow); m_mapper->setCurrentIndex(currow);
prevSelection = currow; if (currow >= 0)
prevSelection = static_cast<size_t>(currow);
else
prevSelection.reset();
} }
void ConnectionManagerWindow::on_actionDelete_connection_triggered() void ConnectionManagerWindow::on_actionDelete_connection_triggered()
@ -82,7 +101,6 @@ void ConnectionManagerWindow::setupWidgetMappings()
m_mapper->addMapping(ui->edtHost, 2); m_mapper->addMapping(ui->edtHost, 2);
m_mapper->addMapping(ui->spinPort, 3); m_mapper->addMapping(ui->spinPort, 3);
m_mapper->addMapping(ui->edtUser, 4); m_mapper->addMapping(ui->edtUser, 4);
m_mapper->addMapping(ui->edtPassword, 5);
m_mapper->addMapping(ui->edtDbname, 6); m_mapper->addMapping(ui->edtDbname, 6);
m_mapper->toFirst(); m_mapper->toFirst();
} }
@ -90,7 +108,13 @@ void ConnectionManagerWindow::setupWidgetMappings()
void ConnectionManagerWindow::on_actionConnect_triggered() void ConnectionManagerWindow::on_actionConnect_triggered()
{ {
auto ci = ui->listView->selectionModel()->currentIndex(); 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() 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);
}
}

View file

@ -2,6 +2,7 @@
#define CONNECTIONMANAGERWINDOW_H #define CONNECTIONMANAGERWINDOW_H
#include <QMainWindow> #include <QMainWindow>
#include <boost/optional.hpp>
namespace Ui { namespace Ui {
class ConnectionManagerWindow; class ConnectionManagerWindow;
@ -30,14 +31,12 @@ private slots:
void on_actionBackup_database_triggered(); void on_actionBackup_database_triggered();
void on_actionManage_server_triggered(); void on_actionManage_server_triggered();
void on_testButton_clicked();
private: private:
Ui::ConnectionManagerWindow *ui; Ui::ConnectionManagerWindow *ui;
QDataWidgetMapper *m_mapper = nullptr; QDataWidgetMapper *m_mapper = nullptr;
MasterController *m_masterController; MasterController *m_masterController;
int prevSelection = -1; boost::optional<size_t> prevSelection;
void setupWidgetMappings(); void setupWidgetMappings();
}; };

View file

@ -75,30 +75,23 @@
<widget class="QLineEdit" name="edtUser"/> <widget class="QLineEdit" name="edtUser"/>
</item> </item>
<item row="4" column="0"> <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"> <widget class="QLabel" name="label_4">
<property name="text"> <property name="text">
<string>Database</string> <string>Database</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="4" column="1">
<widget class="QLineEdit" name="edtDbname"/> <widget class="QLineEdit" name="edtDbname"/>
</item> </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"> <widget class="QComboBox" name="cmbbxSsl">
<property name="currentIndex"> <property name="currentIndex">
<number>2</number> <number>2</number>
@ -136,53 +129,46 @@
</widget> </widget>
</item> </item>
<item row="6" column="0"> <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"> <widget class="QLabel" name="label_8">
<property name="text"> <property name="text">
<string>Certificate</string> <string>Certificate</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="1"> <item row="6" column="1">
<widget class="QLineEdit" name="edtCert"/> <widget class="QLineEdit" name="edtCert"/>
</item> </item>
<item row="8" column="0"> <item row="7" column="0">
<widget class="QLabel" name="label_9"> <widget class="QLabel" name="label_9">
<property name="text"> <property name="text">
<string>Key</string> <string>Key</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="8" column="1"> <item row="7" column="1">
<widget class="QLineEdit" name="edtKey"/> <widget class="QLineEdit" name="edtKey"/>
</item> </item>
<item row="9" column="0"> <item row="8" column="0">
<widget class="QLabel" name="label_10"> <widget class="QLabel" name="label_10">
<property name="text"> <property name="text">
<string>Root cert.</string> <string>Root cert.</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="9" column="1"> <item row="8" column="1">
<widget class="QLineEdit" name="edtRootCert"/> <widget class="QLineEdit" name="edtRootCert"/>
</item> </item>
<item row="10" column="0"> <item row="9" column="0">
<widget class="QLabel" name="label_11"> <widget class="QLabel" name="label_11">
<property name="text"> <property name="text">
<string>Revocation list</string> <string>Revocation list</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="10" column="1"> <item row="9" column="1">
<widget class="QLineEdit" name="edtCrl"/> <widget class="QLineEdit" name="edtCrl"/>
</item> </item>
<item row="11" column="0"> <item row="10" column="0">
<widget class="QPushButton" name="testButton"> <widget class="QPushButton" name="testButton">
<property name="text"> <property name="text">
<string>PushButton</string> <string>PushButton</string>
@ -201,7 +187,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>800</width> <width>800</width>
<height>25</height> <height>20</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="menuFile"> <widget class="QMenu" name="menuFile">

View file

@ -5,6 +5,7 @@
#include "MainWindow.h" #include "MainWindow.h"
#include "ServerWindow.h" #include "ServerWindow.h"
#include "BackupDialog.h" #include "BackupDialog.h"
#include "PasswordPromptDialog.h"
MasterController::MasterController(QObject *parent) : QObject(parent) MasterController::MasterController(QObject *parent) : QObject(parent)
@ -33,39 +34,103 @@ void MasterController::showConnectionManager()
m_connectionManagerWindow->show(); 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); auto res = m_connectionListModel->get(connection_index);
if (cc.valid()) { if (res.valid()) {
auto w = new MainWindow(this, nullptr); auto cc = res.get();
w->setAttribute( Qt::WA_DeleteOnClose );
w->setConfig(cc.get()); m_connectionListModel->save(connection_index, cc);
w->show(); 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) void MasterController::openBackupDlgForConnection(int connection_index)
{ {
auto cc = m_connectionListModel->get(connection_index); auto res = m_connectionListModel->get(connection_index);
m_connectionListModel->save(connection_index); if (res.valid()) {
if (cc.valid()) { auto cc = res.get();
retrieveConnectionPassword(cc);
m_connectionListModel->save(connection_index, cc);
auto w = new BackupDialog(nullptr); //new ServerWindow(this, nullptr); auto w = new BackupDialog(nullptr); //new ServerWindow(this, nullptr);
w->setAttribute( Qt::WA_DeleteOnClose ); w->setAttribute( Qt::WA_DeleteOnClose );
w->setConfig(cc.get()); w->setConfig(cc);
w->show(); w->show();
} }
} }
void MasterController::openServerWindowForConnection(int connection_index) void MasterController::openServerWindowForConnection(int connection_index)
{ {
auto cc = m_connectionListModel->get(connection_index); auto res = m_connectionListModel->get(connection_index);
m_connectionListModel->save(connection_index); if (res.valid()) {
if (cc.valid()) { auto cc = res.get();
retrieveConnectionPassword(cc);
m_connectionListModel->save(connection_index, cc);
auto w = new ServerWindow(this, nullptr); auto w = new ServerWindow(this, nullptr);
w->setAttribute( Qt::WA_DeleteOnClose ); w->setAttribute( Qt::WA_DeleteOnClose );
w->setConfig(cc.get()); w->setConfig(cc);
w->show(); 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;
}

View file

@ -16,7 +16,7 @@ class ConnectionManagerWindow;
class MasterController : public QObject { class MasterController : public QObject {
Q_OBJECT Q_OBJECT
public: public:
explicit MasterController(QObject *parent = 0); explicit MasterController(QObject *parent = nullptr);
MasterController(const MasterController&) = delete; MasterController(const MasterController&) = delete;
MasterController &operator=(const MasterController&) = delete; MasterController &operator=(const MasterController&) = delete;
~MasterController(); ~MasterController();
@ -29,7 +29,7 @@ public:
} }
void showConnectionManager(); void showConnectionManager();
void openSqlWindowForConnection(int connection_index); void openSqlWindowForConnection(size_t connection_index);
void openServerWindowForConnection(int connection_index); void openServerWindowForConnection(int connection_index);
void openBackupDlgForConnection(int connection_index); void openBackupDlgForConnection(int connection_index);
@ -41,7 +41,15 @@ private:
ConnectionList *m_connectionList = nullptr; ConnectionList *m_connectionList = nullptr;
ConnectionListModel *m_connectionListModel = nullptr; ConnectionListModel *m_connectionListModel = nullptr;
ConnectionManagerWindow *m_connectionManagerWindow = 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 #endif // MASTERCONTROLLER_H

45
pglab/PassPhraseForm.cpp Normal file
View 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
View 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
View 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>

View 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()
//{
//}

View 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

View file

@ -26,14 +26,10 @@ TablesPage::TablesPage(MainWindow *parent)
{ {
ui->setupUi(this); ui->setupUi(this);
// WARNING delegates should NOT be shared!!!
auto pglab_delegate = new PgLabItemDelegate(this);
auto icon_delegate = new IconColumnDelegate(this);
SetTableViewDefault(ui->tableListTable); SetTableViewDefault(ui->tableListTable);
m_tablesModel = new TablesTableModel(this); m_tablesModel = new TablesTableModel(this);
ui->tableListTable->setModel(m_tablesModel); ui->tableListTable->setModel(m_tablesModel);
ui->tableListTable->setItemDelegate(pglab_delegate); ui->tableListTable->setItemDelegate(new PgLabItemDelegate(this));
ui->tableListTable->setSortingEnabled(true); ui->tableListTable->setSortingEnabled(true);
ui->tableListTable->sortByColumn(0, Qt::AscendingOrder); ui->tableListTable->sortByColumn(0, Qt::AscendingOrder);
ui->tableListTable->setSelectionBehavior(QAbstractItemView::SelectRows); ui->tableListTable->setSelectionBehavior(QAbstractItemView::SelectRows);
@ -47,14 +43,14 @@ TablesPage::TablesPage(MainWindow *parent)
SetTableViewDefault(ui->constraintsTable); SetTableViewDefault(ui->constraintsTable);
m_constraintModel = new ConstraintModel(this); m_constraintModel = new ConstraintModel(this);
ui->constraintsTable->setModel(m_constraintModel); ui->constraintsTable->setModel(m_constraintModel);
ui->constraintsTable->setItemDelegateForColumn(0, icon_delegate); ui->constraintsTable->setItemDelegateForColumn(0, new IconColumnDelegate(this));
// Indexes // Indexes
SetTableViewDefault(ui->indexesTable); SetTableViewDefault(ui->indexesTable);
m_indexModel = new IndexModel(this); m_indexModel = new IndexModel(this);
ui->indexesTable->setModel(m_indexModel); ui->indexesTable->setModel(m_indexModel);
ui->indexesTable->setItemDelegate(pglab_delegate); ui->indexesTable->setItemDelegate(new PgLabItemDelegate(this));
ui->indexesTable->setItemDelegateForColumn(0, icon_delegate); ui->indexesTable->setItemDelegateForColumn(0, new IconColumnDelegate(this));
// Set code editor fonts // Set code editor fonts
QFont code_font = UserConfiguration::instance()->codeFont(); QFont code_font = UserConfiguration::instance()->codeFont();

View file

@ -23,7 +23,7 @@ DEFINES += _WIN32_WINNT=0x0501
#LIBS += -LC:\VSproj\boost32\lib -LC:/PROG/LIB -lws2_32 -llibpq #LIBS += -LC:\VSproj\boost32\lib -LC:/PROG/LIB -lws2_32 -llibpq
#debug { #debug {
LIBS += c:/prog/lib/botand_imp.lib LIBS += c:/prog/lib/botan_imp.lib
#} #}
#release { #release {
@ -83,7 +83,9 @@ PropertyProxyModel.cpp \
TriggerPage.cpp \ TriggerPage.cpp \
SqlCodePreview.cpp \ SqlCodePreview.cpp \
CustomFilterSortModel.cpp \ CustomFilterSortModel.cpp \
PropertiesPage.cpp PropertiesPage.cpp \
PassPhraseForm.cpp \
PasswordPromptDialog.cpp
HEADERS += \ HEADERS += \
QueryResultModel.h \ QueryResultModel.h \
@ -137,7 +139,9 @@ CustomDataRole.h \
TriggerPage.h \ TriggerPage.h \
SqlCodePreview.h \ SqlCodePreview.h \
CustomFilterSortModel.h \ CustomFilterSortModel.h \
PropertiesPage.h PropertiesPage.h \
PassPhraseForm.h \
PasswordPromptDialog.h
FORMS += mainwindow.ui \ FORMS += mainwindow.ui \
ConnectionManagerWindow.ui \ ConnectionManagerWindow.ui \
@ -151,7 +155,8 @@ FORMS += mainwindow.ui \
NamespaceFilterWidget.ui \ NamespaceFilterWidget.ui \
ApplicationWindow.ui \ ApplicationWindow.ui \
CrudTab.ui \ CrudTab.ui \
CodeGenerator.ui CodeGenerator.ui \
PassPhraseForm.ui
RESOURCES += \ RESOURCES += \
resources.qrc resources.qrc

View file

@ -57,6 +57,22 @@ ConnectionConfig::ConnectionConfig()
: m_applicationName(QCoreApplication::applicationName().toUtf8().data()) : 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) void ConnectionConfig::setName(std::string desc)
{ {
if (m_name != desc) { if (m_name != desc) {

View file

@ -1,6 +1,7 @@
#ifndef CONNECTION_H #ifndef CONNECTION_H
#define CONNECTION_H #define CONNECTION_H
#include <QUuid>
#include <vector> #include <vector>
#include <string> #include <string>
@ -27,6 +28,9 @@ class ConnectionConfig {
public: public:
ConnectionConfig(); ConnectionConfig();
void setUuid(const QUuid &uuid);
const QUuid &uuid() const;
void setName(std::string desc); void setName(std::string desc);
const std::string& name() const; const std::string& name() const;
@ -73,6 +77,7 @@ public:
bool dirty() const; bool dirty() const;
void clean(); void clean();
private: private:
QUuid m_uuid;
std::string m_name; std::string m_name;
std::string m_host; std::string m_host;
std::string m_hostaddr; std::string m_hostaddr;

View file

@ -4,7 +4,7 @@
# #
#------------------------------------------------- #-------------------------------------------------
QT += widgets QT += widgets core
TARGET = pglablib TARGET = pglablib
TEMPLATE = lib TEMPLATE = lib

0
readme.md Normal file
View file