258 lines
7.8 KiB
C++
258 lines
7.8 KiB
C++
#include "ConnectionController.h"
|
|
#include "MasterController.h"
|
|
#include "ConnectionManagerWindow.h"
|
|
#include "ConnectionListModel.h"
|
|
#include "PasswordManager.h"
|
|
#include "DatabaseWindow.h"
|
|
#include "ServerWindow.h"
|
|
#include "BackupDialog.h"
|
|
#include "PasswordPromptDialog.h"
|
|
#include "ConnectionConfigurationWidget.h"
|
|
#include <QInputDialog>
|
|
#include <QMessageBox>
|
|
#include <QTimer>
|
|
|
|
|
|
ConnectionController::ConnectionController(MasterController *parent)
|
|
: QObject(parent)
|
|
, m_masterController(parent)
|
|
, m_relockTimer(new QTimer(this))
|
|
{
|
|
m_relockTimer->setSingleShot(true);
|
|
m_relockTimer->setTimerType(Qt::VeryCoarseTimer);
|
|
// Force signal to go through queue so when the password manager is relocked after 0msec
|
|
// the code that retrieves the password is garanteed to run before the signal is handled
|
|
// because only after the password is retrieved the loop has a chance to run.
|
|
m_relockTimer->callOnTimeout(this, &ConnectionController::relock, Qt::QueuedConnection);
|
|
}
|
|
|
|
ConnectionController::~ConnectionController()
|
|
{
|
|
delete m_connectionManagerWindow;
|
|
delete m_connectionTreeModel;
|
|
}
|
|
|
|
void ConnectionController::init()
|
|
{
|
|
m_passwordManager = std::make_shared<PasswordManager>();
|
|
|
|
m_connectionTreeModel = new ConnectionTreeModel(this, m_masterController->userConfigDatabase());
|
|
m_connectionTreeModel->load();
|
|
|
|
m_connectionManagerWindow = new ConnectionManagerWindow(m_masterController, nullptr);
|
|
m_connectionManagerWindow->show();
|
|
}
|
|
|
|
void ConnectionController::showConnectionManager()
|
|
{
|
|
m_connectionManagerWindow->show();
|
|
}
|
|
|
|
void ConnectionController::openSqlWindowForConnection(QModelIndex index)
|
|
{
|
|
auto config = ConnectionTreeModel::getConfigFromModelIndex(index);
|
|
if (config) {
|
|
|
|
if (retrieveConnectionPassword(*config)) {
|
|
m_connectionTreeModel->save(*config);
|
|
// TODO instead of directly openening the mainwindow
|
|
// do async connect and only open window when we have
|
|
// working connection
|
|
auto w = new DatabaseWindow(m_masterController, nullptr);
|
|
w->setAttribute( Qt::WA_DeleteOnClose );
|
|
w->setConfig(*config);
|
|
w->showMaximized();
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void ConnectionController::openBackupDlgForConnection(QModelIndex index)
|
|
{
|
|
auto config = ConnectionTreeModel::getConfigFromModelIndex(index);
|
|
if (config) {
|
|
if (retrieveConnectionPassword(*config)) {
|
|
m_connectionTreeModel->save(*config);
|
|
auto w = new BackupDialog(nullptr); //new ServerWindow(this, nullptr);
|
|
w->setAttribute( Qt::WA_DeleteOnClose );
|
|
w->setConfig(*config);
|
|
w->show();
|
|
}
|
|
}
|
|
}
|
|
|
|
void ConnectionController::createConnection()
|
|
{
|
|
ConnectionConfig cc;
|
|
cc.setUuid(QUuid::createUuid());
|
|
ConnectionConfigurationWidget::editExistingInWindow(this, cc);
|
|
}
|
|
|
|
void ConnectionController::editConnection(QModelIndex index)
|
|
{
|
|
auto config = ConnectionTreeModel::getConfigFromModelIndex(index);
|
|
if (config) {
|
|
ConnectionConfigurationWidget::editExistingInWindow(this, *config);
|
|
}
|
|
}
|
|
|
|
void ConnectionController::addGroup()
|
|
{
|
|
auto result = QInputDialog::getText(nullptr, tr("Add new connection group"),
|
|
tr("Group name"));
|
|
if (!result.isEmpty()) {
|
|
auto res = m_connectionTreeModel->addGroup(result);
|
|
if (std::holds_alternative<QSqlError>(res)) {
|
|
QMessageBox::critical(nullptr, tr("Add group failed"),
|
|
tr("Failed to add group.\n") +
|
|
std::get<QSqlError>(res).text());
|
|
}
|
|
}
|
|
}
|
|
|
|
void ConnectionController::removeGroup(QModelIndex index)
|
|
{
|
|
auto group = ConnectionTreeModel::getGroupFromModelIndex(index);
|
|
if (group) {
|
|
auto btn = QMessageBox::question(nullptr, tr("Connection group"),
|
|
tr("Remove the selected group and all connections contained in the group?"),
|
|
QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
|
|
QMessageBox::NoButton);
|
|
if (btn == QMessageBox::Yes) {
|
|
m_connectionTreeModel->removeGroup(index.row());
|
|
}
|
|
}
|
|
}
|
|
|
|
std::shared_ptr<PasswordManager> ConnectionController::passwordManager()
|
|
{
|
|
return m_passwordManager;
|
|
}
|
|
|
|
void ConnectionController::openServerWindowForConnection(QModelIndex index)
|
|
{
|
|
auto config = ConnectionTreeModel::getConfigFromModelIndex(index);
|
|
if (config) {
|
|
if (retrieveConnectionPassword(*config)) {
|
|
m_connectionTreeModel->save(*config);
|
|
auto w = new ServerWindow(m_masterController, nullptr);
|
|
w->setAttribute( Qt::WA_DeleteOnClose );
|
|
w->setConfig(*config);
|
|
w->show();
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ConnectionController::retrieveConnectionPassword(ConnectionConfig &cc)
|
|
{
|
|
auto enc_pwd = cc.encodedPassword();
|
|
if (!enc_pwd.empty()) {
|
|
std::string pw;
|
|
bool result = decodePassword(getPskId(cc), cc.encodedPassword(), pw);// 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 = cc.makeLongDescription();
|
|
auto dlg = std::make_unique<PasswordPromptDialog>(PasswordPromptDialog::SaveOption, nullptr);
|
|
dlg->setCaption(tr("Connection password prompt"));
|
|
dlg->setDescription(QString(tr("Please provide password for connection %1")).arg(str));
|
|
int exec_result = dlg->exec();
|
|
|
|
if (exec_result == QDialog::Accepted) {
|
|
std::string password = dlg->password().toUtf8().data();
|
|
cc.setPassword(password);
|
|
if (dlg->saveChecked()) {
|
|
std::string encoded_pw;
|
|
if (encodePassword(getPskId(cc), password, encoded_pw)) {
|
|
cc.setEncodedPassword(encoded_pw);
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool ConnectionController::decodePassword(const std::string &password_id, const std::string &enc_password, std::string &password)
|
|
{
|
|
if (!UnlockPasswordManagerIfNeeded())
|
|
return false;
|
|
|
|
password = m_passwordManager->decrypt(password_id, enc_password);
|
|
return true;
|
|
}
|
|
|
|
bool ConnectionController::encodePassword(const std::string &password_id, const std::string &password, std::string &enc_password)
|
|
{
|
|
if (!UnlockPasswordManagerIfNeeded())
|
|
return false;
|
|
|
|
enc_password = m_passwordManager->encrypt(password_id, password);
|
|
return true;
|
|
}
|
|
|
|
bool ConnectionController::UnlockPasswordManagerIfNeeded()
|
|
{
|
|
auto&& user_cfg_db = m_masterController->userConfigDatabase();
|
|
if (m_passwordManager->initialized(user_cfg_db)) {
|
|
if (!m_passwordManager->locked())
|
|
return true;
|
|
|
|
while (true) {
|
|
// ask user for passphrase
|
|
auto dlg = std::make_unique<PasswordPromptDialog>(PasswordPromptDialog::RememberPassword, nullptr);
|
|
dlg->setCaption(tr("Unlock password manager"));
|
|
dlg->setDescription(tr("Enter password for password manager"));
|
|
int exec_result = dlg->exec();
|
|
bool ok = (exec_result == QDialog::Accepted);
|
|
|
|
if (!ok) {
|
|
// leave this retry loop
|
|
break;
|
|
}
|
|
// user gave OK, if succeeds return true otherwise loop a prompt for password again.
|
|
if (m_passwordManager->openDatabase(user_cfg_db, dlg->password())) {
|
|
int rem = dlg->remember();
|
|
if (rem >= 0) {
|
|
int timeout = rem * 60 * 1000; /// rem is in minutes, timeout in millisec
|
|
m_relockTimer->start(timeout);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
// Ask user for passphrase + confirmation, clearly instruct this is first setup
|
|
// create
|
|
auto dlg = std::make_unique<PasswordPromptDialog>(PasswordPromptDialog::ConfirmPassword, nullptr);
|
|
dlg->setCaption(tr("Password manager setup"));
|
|
dlg->setDescription(tr("Enter a strong password for password manager initialization. A strong key will be "
|
|
"derived from your password and it will be impossible to recover anything from the "
|
|
"password manager without the password you enter here."));
|
|
int exec_result = dlg->exec();
|
|
if (exec_result == QDialog::Accepted) {
|
|
QString passphrase = dlg->password();
|
|
if (m_passwordManager->createDatabase(user_cfg_db, passphrase))
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
std::string ConnectionController::getPskId(const ConnectionConfig &cc)
|
|
{
|
|
std::string id = "dbpw/";
|
|
id += cc.uuid().toString().toUtf8().data();
|
|
return id;
|
|
}
|
|
|
|
void ConnectionController::relock()
|
|
{
|
|
m_passwordManager->closeDatabase();
|
|
}
|
|
|
|
|
|
|