Passwords are now saved in a password manager.
The password manager uses strong encryption using a key derived from the passphrase using scrypt key strengthening algorithm. This ensures encryption is performed using a strong key and that brute forcing the passphrase is time consuming. If the user loses his passphrase no recovery is possible.
This commit is contained in:
parent
2230a4bd61
commit
e36924c087
27 changed files with 605 additions and 346 deletions
|
|
@ -2,11 +2,30 @@
|
|||
#include "ConnectionManagerWindow.h"
|
||||
#include "ConnectionList.h"
|
||||
#include "ConnectionListModel.h"
|
||||
#include "PasswordManager.h"
|
||||
#include "MainWindow.h"
|
||||
#include "ServerWindow.h"
|
||||
#include "BackupDialog.h"
|
||||
#include "PasswordPromptDialog.h"
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QStandardPaths>
|
||||
#include <botan/sqlite3.h>
|
||||
|
||||
namespace {
|
||||
|
||||
QString GetUserConfigDatabaseName()
|
||||
{
|
||||
QString path = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
|
||||
QDir dir(path);
|
||||
if (!dir.exists()) {
|
||||
dir.mkpath(".");
|
||||
}
|
||||
path += "/pglabuser.db";
|
||||
return path;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MasterController::MasterController(QObject *parent) : QObject(parent)
|
||||
{}
|
||||
|
|
@ -20,6 +39,21 @@ MasterController::~MasterController()
|
|||
|
||||
void MasterController::init()
|
||||
{
|
||||
//std::string dbfilename = QDir::toNativeSeparators(GetUserConfigDatabaseName()).toUtf8().data();
|
||||
//m_userConfigDatabase = std::make_shared<Botan::Sqlite3_Database>(dbfilename);
|
||||
|
||||
m_userConfigDatabase = QSqlDatabase::addDatabase("QSQLITE");
|
||||
m_userConfigDatabase.setDatabaseName(GetUserConfigDatabaseName());
|
||||
|
||||
if (!m_userConfigDatabase.open()) {
|
||||
qDebug() << "Error: connection with database fail";
|
||||
}
|
||||
else {
|
||||
qDebug() << "Database: connection ok";
|
||||
}
|
||||
|
||||
m_passwordManager = std::make_shared<PasswordManager>();
|
||||
|
||||
m_connectionList = new ConnectionList;
|
||||
m_connectionList->load();
|
||||
m_connectionListModel = new ConnectionListModel(m_connectionList, this);
|
||||
|
|
@ -41,8 +75,8 @@ void MasterController::openSqlWindowForConnection(size_t connection_index)
|
|||
if (res.valid()) {
|
||||
auto cc = res.get();
|
||||
|
||||
m_connectionListModel->save(connection_index, cc);
|
||||
if (retrieveConnectionPassword(cc)) {
|
||||
m_connectionListModel->save(connection_index, cc);
|
||||
// TODO instead of directly openening the mainwindow
|
||||
// do async connect and only open window when we have
|
||||
// working connection
|
||||
|
|
@ -55,55 +89,65 @@ void MasterController::openSqlWindowForConnection(size_t connection_index)
|
|||
|
||||
}
|
||||
|
||||
void MasterController::openBackupDlgForConnection(int connection_index)
|
||||
void MasterController::openBackupDlgForConnection(size_t connection_index)
|
||||
{
|
||||
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);
|
||||
w->show();
|
||||
if (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);
|
||||
w->show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MasterController::openServerWindowForConnection(int connection_index)
|
||||
void MasterController::openServerWindowForConnection(size_t connection_index)
|
||||
{
|
||||
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);
|
||||
w->show();
|
||||
if (retrieveConnectionPassword(cc)) {
|
||||
m_connectionListModel->save(connection_index, cc);
|
||||
auto w = new ServerWindow(this, nullptr);
|
||||
w->setAttribute( Qt::WA_DeleteOnClose );
|
||||
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
|
||||
auto pw_state = cc.passwordState();
|
||||
if (pw_state == PasswordState::NotNeeded) {
|
||||
return true;
|
||||
}
|
||||
else if (pw_state == PasswordState::SavedPasswordManager) {
|
||||
std::string pw;
|
||||
bool result = getPasswordFromPskdb(getPskId(cc), pw);
|
||||
if (result) {
|
||||
cc.setPassword(pw);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// Geen else hier want als voorgaande blok niet geretourneerd heeft moeten we wachtwoord
|
||||
// ook aan de gebruiker vragen zoals hier gebeurd.
|
||||
QString str = ConnectionListModel::makeLongDescription(cc);
|
||||
auto dlg = std::make_unique<PasswordPromptDialog>(nullptr);
|
||||
dlg->setConnectionDescription(str);
|
||||
auto dlg = std::make_unique<PasswordPromptDialog>(PasswordPromptDialog::SaveOption, nullptr);
|
||||
dlg->setDescription(QString(tr("Please provide password for connection %1")).arg(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
|
||||
|
||||
std::string password = dlg->password().toUtf8().data();
|
||||
cc.setPassword(password);
|
||||
if (dlg->saveChecked()) {
|
||||
storePasswordInPskdb(getPskId(cc), password);
|
||||
cc.setPasswordState(PasswordState::SavedPasswordManager);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
@ -112,25 +156,71 @@ bool MasterController::retrieveConnectionPassword(ConnectionConfig &cc)
|
|||
|
||||
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;
|
||||
if (!UnlockPasswordManagerIfNeeded())
|
||||
return false;
|
||||
|
||||
return m_passwordManager->get(password_id, password);
|
||||
}
|
||||
|
||||
|
||||
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
|
||||
if (!UnlockPasswordManagerIfNeeded())
|
||||
return false;
|
||||
|
||||
m_passwordManager->set(password_id, password);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MasterController::UnlockPasswordManagerIfNeeded()
|
||||
{
|
||||
if (m_passwordManager->initialized(m_userConfigDatabase)) {
|
||||
if (!m_passwordManager->locked())
|
||||
return true;
|
||||
|
||||
while (true) {
|
||||
// ask user for passphrase
|
||||
auto dlg = std::make_unique<PasswordPromptDialog>(nullptr, nullptr);
|
||||
dlg->setDescription(tr("Enter passphrase for password manager"));
|
||||
int exec_result = dlg->exec();
|
||||
bool ok = (exec_result == QDialog::Accepted);
|
||||
|
||||
// IF user gave OK
|
||||
if (ok) {
|
||||
if (m_passwordManager->openDatabase(m_userConfigDatabase, dlg->password())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Ask user for passphrase + confirmation, clearly instruct this is first setup
|
||||
// create
|
||||
auto dlg = std::make_unique<PasswordPromptDialog>(PasswordPromptDialog::ConfirmPassword, nullptr);
|
||||
dlg->setDescription(tr("Enter passphrase for password manager initialization"));
|
||||
int exec_result = dlg->exec();
|
||||
if (exec_result == QDialog::Accepted) {
|
||||
QString passphrase = dlg->password();
|
||||
if (m_passwordManager->createDatabase(m_userConfigDatabase, passphrase)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string MasterController::getPskId(const ConnectionConfig &cc)
|
||||
{
|
||||
std::string id = "dbpw/";
|
||||
id += cc.uuid().toString().toUtf8().data();
|
||||
return id;
|
||||
}
|
||||
|
||||
//std::shared_ptr<Botan::Sqlite3_Database> MasterController::getUserConfigDatabase()
|
||||
//{
|
||||
// return m_userConfigDatabase;
|
||||
//}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue