UI: ConfManager: Save/load config.

This commit is contained in:
Nodir Temirkhodjaev 2019-10-26 09:55:03 +05:00
parent 74025ea602
commit 8a38887679
16 changed files with 349 additions and 76 deletions

View File

@ -1,5 +1,5 @@
<RCC>
<qresource prefix="/stat">
<qresource prefix="/conf">
<file>migrations/1.sql</file>
</qresource>
</RCC>

View File

@ -6,9 +6,13 @@
#include <sqlite/sqlitestmt.h>
#include "../fortcommon.h"
#include "../fortsettings.h"
#include "../util/dateutil.h"
#include "../util/fileutil.h"
#include "../util/net/netutil.h"
#include "../util/osutil.h"
#include "addressgroup.h"
#include "appgroup.h"
#include "firewallconf.h"
Q_DECLARE_LOGGING_CATEGORY(CLOG_CONF_MANAGER)
@ -22,19 +26,87 @@ Q_LOGGING_CATEGORY(CLOG_CONF_MANAGER, "fort.confManager")
namespace {
const char * const sqlPragmas =
"PRAGMA journal_mode = WAL;"
"PRAGMA locking_mode = EXCLUSIVE;"
"PRAGMA synchronous = NORMAL;"
;
const char * const sqlSelectAddressGroups =
"SELECT addr_group_id, include_all, exclude_all,"
" include_text, exclude_text"
" FROM address_group"
" ORDER BY order_index;"
;
const char * const sqlSelectAppGroups =
"SELECT app_group_id, enabled,"
" fragment_packet, period_enabled,"
" limit_in_enabled, limit_out_enabled,"
" speed_limit_in, speed_limit_out,"
" name, block_text, allow_text,"
" period_from, period_to"
" FROM app_group"
" ORDER BY order_index;"
;
const char * const sqlInsertAddressGroup =
"INSERT INTO address_group(addr_group_id, order_index,"
" include_all, exclude_all, include_text, exclude_text)"
" VALUES(?1, ?2, ?3, ?4, ?5, ?6);"
;
const char * const sqlUpdateAddressGroup =
"UPDATE address_group"
" SET order_index = ?2,"
" include_all = ?3, exclude_all = ?4,"
" include_text = ?5, exclude_text = ?6"
" WHERE addr_group_id = ?1;"
;
const char * const sqlInsertAppGroup =
"INSERT INTO app_group(app_group_id, order_index, enabled,"
" fragment_packet, period_enabled,"
" limit_in_enabled, limit_out_enabled,"
" speed_limit_in, speed_limit_out,"
" name, block_text, allow_text,"
" period_from, period_to)"
" VALUES(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14);"
;
const char * const sqlUpdateAppGroup =
"UPDATE app_group"
" SET order_index = ?2, enabled = ?3,"
" fragment_packet = ?4, period_enabled = ?5,"
" limit_in_enabled = ?6, limit_out_enabled = ?7,"
" speed_limit_in = ?8, speed_limit_out = ?9,"
" name = ?10, block_text = ?11, allow_text = ?12,"
" period_from = ?13, period_to = ?14"
" WHERE app_group_id = ?1;"
;
}
ConfManager::ConfManager(const QString &filePath,
ConfManager::ConfManager(FortSettings *fortSettings,
QObject *parent) :
QObject(parent),
m_sqliteDb(new SqliteDb(filePath))
m_fortSettings(fortSettings),
m_sqliteDb(new SqliteDb(fortSettings->confFilePath()))
{
}
ConfManager::~ConfManager()
{
delete m_sqliteDb;
}
void ConfManager::setErrorMessage(const QString &errorMessage)
{
if (m_errorMessage != errorMessage) {
m_errorMessage = errorMessage;
emit errorMessageChanged();
}
}
bool ConfManager::initialize()
{
if (!m_sqliteDb->open()) {
@ -54,3 +126,200 @@ bool ConfManager::initialize()
return true;
}
FirewallConf *ConfManager::cloneConf(const FirewallConf &conf,
QObject *parent)
{
auto newConf = new FirewallConf(parent);
newConf->copy(conf);
return newConf;
}
void ConfManager::setupDefault(FirewallConf &conf) const
{
AddressGroup *inetGroup = conf.inetAddressGroup();
inetGroup->setExcludeText(NetUtil::localIpv4Networks().join('\n'));
auto appGroup = new AppGroup();
appGroup->setName("Main");
appGroup->setAllowText(FileUtil::appBinLocation() + '/');
conf.addAppGroup(appGroup);
}
bool ConfManager::load(FirewallConf &conf)
{
bool isNewConf = true;
if (!loadFromDb(conf, isNewConf)) {
setErrorMessage(m_sqliteDb->errorMessage());
return false;
}
if (isNewConf && !m_fortSettings->readConf(conf, isNewConf)) {
setErrorMessage(m_fortSettings->errorMessage());
return false;
}
if (isNewConf) {
setupDefault(conf);
}
return true;
}
bool ConfManager::save(const FirewallConf &conf, bool onlyFlags)
{
if (!onlyFlags && !saveToDb(conf))
return false;
if (!m_fortSettings->writeConfIni(conf)) {
setErrorMessage(m_fortSettings->errorMessage());
return false;
}
// Remove old JSON config.
FileUtil::removeFile(m_fortSettings->confOldFilePath());
FileUtil::removeFile(m_fortSettings->confBackupFilePath());
return true;
}
bool ConfManager::loadFromDb(FirewallConf &conf, bool &isNew)
{
// Load Address Groups
{
SqliteStmt stmt;
if (!stmt.prepare(m_sqliteDb->db(), sqlSelectAddressGroups))
return false;
int index = 0;
while (stmt.step() == SqliteStmt::StepRow) {
auto addrGroup = conf.addressGroupsList().at(index);
Q_ASSERT(addrGroup != nullptr);
addrGroup->setId(stmt.columnInt64(0));
addrGroup->setIncludeAll(stmt.columnInt(1));
addrGroup->setExcludeAll(stmt.columnInt(2));
addrGroup->setIncludeText(stmt.columnText(3));
addrGroup->setExcludeText(stmt.columnText(4));
if (++index > 1)
break;
}
if (index == 0) {
isNew = true;
return true;
}
isNew = false;
}
// Load App Groups
{
SqliteStmt stmt;
if (!stmt.prepare(m_sqliteDb->db(), sqlSelectAppGroups))
return false;
while (stmt.step() == SqliteStmt::StepRow) {
auto appGroup = new AppGroup();
appGroup->setId(stmt.columnInt64(0));
appGroup->setEnabled(stmt.columnInt(1));
appGroup->setFragmentPacket(stmt.columnInt(2));
appGroup->setPeriodEnabled(stmt.columnInt(3));
appGroup->setLimitInEnabled(stmt.columnInt(4));
appGroup->setLimitOutEnabled(stmt.columnInt(5));
appGroup->setSpeedLimitIn(quint32(stmt.columnInt(6)));
appGroup->setSpeedLimitOut(quint32(stmt.columnInt(7)));
appGroup->setName(stmt.columnText(8));
appGroup->setBlockText(stmt.columnText(9));
appGroup->setAllowText(stmt.columnText(10));
appGroup->setPeriodFrom(stmt.columnText(11));
appGroup->setPeriodTo(stmt.columnText(12));
conf.addAppGroup(appGroup);
}
}
return true;
}
bool ConfManager::saveToDb(const FirewallConf &conf)
{
bool ok = true;
m_sqliteDb->beginTransaction();
// Save Address Groups
int orderIndex = 0;
for (AddressGroup *addrGroup : conf.addressGroupsList()) {
const bool rowExists = (addrGroup->id() != 0);
if (!addrGroup->edited() && rowExists)
continue;
const QVariantList vars = QVariantList()
<< (rowExists ? addrGroup->id() : QVariant())
<< orderIndex++
<< addrGroup->includeAll()
<< addrGroup->excludeAll()
<< addrGroup->includeText()
<< addrGroup->excludeText()
;
const char *sql = rowExists ? sqlUpdateAddressGroup : sqlInsertAddressGroup;
m_sqliteDb->executeEx(sql, vars, 0, &ok);
if (!ok) goto end;
if (!rowExists) {
addrGroup->setId(m_sqliteDb->lastInsertRowid());
}
addrGroup->setEdited(false);
}
// Save App Groups
orderIndex = 0;
for (AppGroup *appGroup : conf.appGroupsList()) {
const bool rowExists = (appGroup->id() != 0);
if (!appGroup->edited() && rowExists)
continue;
const QVariantList vars = QVariantList()
<< (rowExists ? appGroup->id() : QVariant())
<< orderIndex++
<< appGroup->enabled()
<< appGroup->fragmentPacket()
<< appGroup->periodEnabled()
<< appGroup->limitInEnabled()
<< appGroup->limitOutEnabled()
<< appGroup->speedLimitIn()
<< appGroup->speedLimitOut()
<< appGroup->name()
<< appGroup->blockText()
<< appGroup->allowText()
<< appGroup->periodFrom()
<< appGroup->periodTo()
;
const char *sql = rowExists ? sqlUpdateAppGroup : sqlInsertAppGroup;
m_sqliteDb->executeEx(sql, vars, 0, &ok);
if (!ok) goto end;
if (!rowExists) {
appGroup->setId(m_sqliteDb->lastInsertRowid());
}
appGroup->setEdited(false);
}
end:
if (!ok) {
setErrorMessage(m_sqliteDb->errorMessage());
}
m_sqliteDb->endTransaction(ok);
return ok;
}

View File

@ -6,23 +6,46 @@
#include "../util/classhelpers.h"
QT_FORWARD_DECLARE_CLASS(FirewallConf)
QT_FORWARD_DECLARE_CLASS(FortSettings)
QT_FORWARD_DECLARE_CLASS(SqliteDb)
QT_FORWARD_DECLARE_CLASS(SqliteStmt)
class ConfManager : public QObject
{
Q_OBJECT
Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged)
public:
explicit ConfManager(const QString &filePath,
explicit ConfManager(FortSettings *fortSettings,
QObject *parent = nullptr);
~ConfManager() override;
CLASS_DELETE_COPY_MOVE(ConfManager)
bool initialize();
FirewallConf *cloneConf(const FirewallConf &conf,
QObject *parent = nullptr);
bool load(FirewallConf &conf);
bool save(const FirewallConf &conf, bool onlyFlags = false);
QString errorMessage() const { return m_errorMessage; }
signals:
void errorMessageChanged();
private:
void setErrorMessage(const QString &errorMessage);
void setupDefault(FirewallConf &conf) const;
bool loadFromDb(FirewallConf &conf, bool &isNew);
bool saveToDb(const FirewallConf &conf);
private:
QString m_errorMessage;
FortSettings *m_fortSettings;
SqliteDb *m_sqliteDb;
};

View File

@ -1,7 +1,5 @@
#include "firewallconf.h"
#include "../util/fileutil.h"
#include "../util/net/netutil.h"
#include "addressgroup.h"
#include "appgroup.h"
@ -26,8 +24,7 @@ FirewallConf::FirewallConf(QObject *parent) :
m_quotaDayMb(0),
m_quotaMonthMb(0)
{
m_addressGroups.append(new AddressGroup(this));
m_addressGroups.append(new AddressGroup(this));
setupAddressGroups();
}
void FirewallConf::setProvBoot(bool provBoot)
@ -252,6 +249,9 @@ void FirewallConf::addAppGroupByName(const QString &name)
void FirewallConf::moveAppGroup(int from, int to)
{
m_appGroups.at(from)->setEdited(true);
m_appGroups.at(to)->setEdited(true);
m_appGroups.move(from, to);
emit appGroupsChanged();
}
@ -267,6 +267,12 @@ void FirewallConf::removeAppGroup(int from, int to)
emit appGroupsChanged();
}
void FirewallConf::setupAddressGroups()
{
m_addressGroups.append(new AddressGroup(this));
m_addressGroups.append(new AddressGroup(this));
}
void FirewallConf::copyFlags(const FirewallConf &o)
{
setProvBoot(o.provBoot());
@ -355,14 +361,3 @@ void FirewallConf::fromVariant(const QVariant &v)
addAppGroup(appGroup);
}
}
void FirewallConf::setupDefault()
{
AddressGroup *inetGroup = inetAddressGroup();
inetGroup->setExcludeText(NetUtil::localIpv4Networks().join('\n'));
auto appGroup = new AppGroup();
appGroup->setName("Main");
appGroup->setAllowText(FileUtil::appBinLocation() + '/');
addAppGroup(appGroup);
}

View File

@ -136,8 +136,6 @@ public:
QVariant toVariant() const;
void fromVariant(const QVariant &v);
void setupDefault();
signals:
void provBootChanged();
void filterEnabledChanged();
@ -168,6 +166,9 @@ public slots:
void moveAppGroup(int from, int to);
void removeAppGroup(int from, int to);
private:
void setupAddressGroups();
private:
uint m_provBoot : 1;
uint m_filterEnabled : 1;

View File

@ -1,10 +1,8 @@
PRAGMA user_version = 1;
PRAGMA journal_mode = WAL;
CREATE TABLE IF NOT EXISTS address_group(
addr_group_id INTEGER PRIMARY KEY,
order INTEGER NOT NULL,
order_index INTEGER NOT NULL,
include_all BOOLEAN NOT NULL,
exclude_all BOOLEAN NOT NULL,
include_text TEXT NOT NULL,
@ -13,7 +11,7 @@ CREATE TABLE IF NOT EXISTS address_group(
CREATE TABLE IF NOT EXISTS app_group(
app_group_id INTEGER PRIMARY KEY,
order INTEGER NOT NULL,
order_index INTEGER NOT NULL,
enabled BOOLEAN NOT NULL,
fragment_packet BOOLEAN NOT NULL,
period_enabled BOOLEAN NOT NULL,

View File

@ -57,15 +57,14 @@ FortManager::FortManager(FortSettings *fortSettings,
m_graphWindowState(new WidgetWindowStateWatcher(this)),
m_fortSettings(fortSettings),
m_firewallConf(new FirewallConf(this)),
m_firewallConfToEdit(nullConf()),
m_firewallConfToEdit(nullptr),
m_graphWindowAction(nullptr),
m_filterEnabledAction(nullptr),
m_stopTrafficAction(nullptr),
m_stopInetTrafficAction(nullptr),
m_quotaManager(new QuotaManager(fortSettings, this)),
m_statManager(new StatManager(fortSettings->statFilePath(),
m_quotaManager, this)),
m_confManager(new ConfManager(fortSettings->confDbFilePath(), this)),
m_statManager(new StatManager(fortSettings, m_quotaManager, this)),
m_confManager(new ConfManager(fortSettings, this)),
m_driverManager(new DriverManager(this)),
m_logManager(new LogManager(m_statManager,
m_driverManager->driverWorker(), this)),
@ -353,8 +352,9 @@ void FortManager::showWindow()
|| checkPassword()))
return;
if (m_firewallConfToEdit == nullConf()) {
setFirewallConfToEdit(cloneConf(*m_firewallConf));
if (m_firewallConfToEdit == nullptr) {
auto newConf = m_confManager->cloneConf(*m_firewallConf, this);
setFirewallConfToEdit(newConf);
}
m_appWindow->show();
@ -373,7 +373,7 @@ void FortManager::closeWindow()
m_appWindow->hide();
setFirewallConfToEdit(nullConf());
setFirewallConfToEdit(nullptr);
}
void FortManager::showGraphWindow()
@ -493,16 +493,16 @@ bool FortManager::saveConf(bool onlyFlags)
bool FortManager::applyConf(bool onlyFlags)
{
Q_ASSERT(m_firewallConfToEdit != nullConf());
Q_ASSERT(m_firewallConfToEdit != nullptr);
FirewallConf *newConf = cloneConf(*m_firewallConfToEdit);
auto newConf = m_confManager->cloneConf(*m_firewallConfToEdit, this);
return saveSettings(newConf, onlyFlags);
}
bool FortManager::applyConfImmediateFlags()
{
Q_ASSERT(m_firewallConfToEdit != nullConf());
Q_ASSERT(m_firewallConfToEdit != nullptr);
m_firewallConf->copyImmediateFlags(*m_firewallConfToEdit);
@ -514,7 +514,7 @@ void FortManager::setFirewallConfToEdit(FirewallConf *conf)
if (m_firewallConfToEdit == conf)
return;
if (m_firewallConfToEdit != nullConf()
if (m_firewallConfToEdit != nullptr
&& m_firewallConfToEdit != m_firewallConf) {
m_firewallConfToEdit->deleteLater();
}
@ -527,26 +527,19 @@ void FortManager::setFirewallConfToEdit(FirewallConf *conf)
bool FortManager::loadSettings(FirewallConf *conf)
{
bool isNewConf;
if (!m_fortSettings->readConf(*conf, isNewConf)) {
showErrorBox("Load Settings: " + m_fortSettings->errorMessage());
if (!m_confManager->load(*conf)) {
showErrorBox("Load Settings: " + m_confManager->errorMessage());
return false;
}
if (isNewConf) {
conf->setupDefault();
}
return updateDriverConf(conf);
}
bool FortManager::saveSettings(FirewallConf *newConf, bool onlyFlags,
bool immediateFlags)
{
if (!(onlyFlags ? m_fortSettings->writeConfIni(*newConf)
: m_fortSettings->writeConf(*newConf))) {
showErrorBox("Save Settings: " + m_fortSettings->errorMessage());
if (!m_confManager->save(*newConf, onlyFlags)) {
showErrorBox("Save Settings: " + m_confManager->errorMessage());
return false;
}
@ -623,15 +616,6 @@ void FortManager::saveTrayFlags()
updateDriverConf(m_firewallConf, true);
}
FirewallConf *FortManager::cloneConf(const FirewallConf &conf)
{
auto newConf = new FirewallConf(this);
newConf->copy(conf);
return newConf;
}
void FortManager::saveWindowState()
{
m_fortSettings->setWindowGeometry(m_appWindowState->geometry());

View File

@ -94,8 +94,6 @@ private slots:
void saveTrayFlags();
private:
FirewallConf *nullConf() const { return nullptr; }
void setFirewallConfToEdit(FirewallConf *conf);
static void registerQmlTypes();
@ -133,8 +131,6 @@ private:
void updateLogManager(bool active);
void updateStatManager(FirewallConf *conf);
FirewallConf *cloneConf(const FirewallConf &conf);
void saveWindowState();
void restoreWindowState();

View File

@ -160,24 +160,24 @@ QString FortSettings::statFilePath() const
return statPath() + QLatin1String("FortFirewall.stat");
}
QString FortSettings::confDbFilePath() const
QString FortSettings::confFilePath() const
{
return profilePath() + QLatin1String("FortFirewall.config");
}
QString FortSettings::confFilePath() const
QString FortSettings::confOldFilePath() const
{
return profilePath() + QLatin1String("FortFirewall.conf");
}
QString FortSettings::confBackupFilePath() const
{
return confFilePath() + QLatin1String(".backup");
return confOldFilePath() + QLatin1String(".backup");
}
bool FortSettings::readConf(FirewallConf &conf, bool &isNew)
{
const QString filePath = confFilePath();
const QString filePath = confOldFilePath();
const QString backupFilePath = confBackupFilePath();
const bool fileExists = FileUtil::fileExists(filePath);
@ -213,7 +213,7 @@ bool FortSettings::tryToReadConf(FirewallConf &conf, const QString &filePath)
bool FortSettings::writeConf(const FirewallConf &conf)
{
const QString filePath = confFilePath();
const QString filePath = confOldFilePath();
const QString backupFilePath = confBackupFilePath();
if (!writeConfIni(conf)) {

View File

@ -162,7 +162,10 @@ public:
QString statPath() const { return m_statPath; }
QString statFilePath() const;
QString confDbFilePath() const;
QString confFilePath() const;
QString confOldFilePath() const;
QString confBackupFilePath() const;
QString controlPath() const { return m_controlPath; }
@ -193,9 +196,6 @@ private:
void setErrorMessage(const QString &errorMessage);
QString confFilePath() const;
QString confBackupFilePath() const;
bool tryToReadConf(FirewallConf &conf, const QString &filePath);
QVariant migrateConf(const QVariant &confVar);

View File

@ -1,7 +1,5 @@
PRAGMA user_version = 1;
PRAGMA journal_mode = WAL;
CREATE TABLE IF NOT EXISTS app(
app_id INTEGER PRIMARY KEY,
path TEXT UNIQUE NOT NULL,

View File

@ -7,6 +7,7 @@
#include "../conf/firewallconf.h"
#include "../fortcommon.h"
#include "../fortsettings.h"
#include "../util/dateutil.h"
#include "../util/fileutil.h"
#include "../util/osutil.h"
@ -55,7 +56,7 @@ bool migrateFunc(SqliteDb *db, int version, void *ctx)
}
StatManager::StatManager(const QString &filePath,
StatManager::StatManager(FortSettings *fortSettings,
QuotaManager *quotaManager,
QObject *parent) :
QObject(parent),
@ -72,7 +73,7 @@ StatManager::StatManager(const QString &filePath,
m_lastTick(0),
m_quotaManager(quotaManager),
m_conf(nullptr),
m_sqliteDb(new SqliteDb(filePath))
m_sqliteDb(new SqliteDb(fortSettings->statFilePath()))
{
}

View File

@ -9,6 +9,7 @@
#include "../util/classhelpers.h"
QT_FORWARD_DECLARE_CLASS(FirewallConf)
QT_FORWARD_DECLARE_CLASS(FortSettings)
QT_FORWARD_DECLARE_CLASS(QuotaManager)
QT_FORWARD_DECLARE_CLASS(SqliteDb)
QT_FORWARD_DECLARE_CLASS(SqliteStmt)
@ -18,7 +19,7 @@ class StatManager : public QObject
Q_OBJECT
public:
explicit StatManager(const QString &filePath,
explicit StatManager(FortSettings *fortSettings,
QuotaManager *quotaManager,
QObject *parent = nullptr);
~StatManager() override;

View File

@ -1,6 +1,7 @@
#include "statsql.h"
const char * const StatSql::sqlPragmas =
"PRAGMA journal_mode = WAL;"
"PRAGMA locking_mode = EXCLUSIVE;"
"PRAGMA synchronous = NORMAL;"
;

View File

@ -22,6 +22,12 @@ Q_LOGGING_CATEGORY(CLOG_APPINFOCACHE, "fort.appInfoWorker")
namespace {
const char * const sqlPragmas =
"PRAGMA journal_mode = WAL;"
"PRAGMA locking_mode = EXCLUSIVE;"
"PRAGMA synchronous = NORMAL;"
;
const char * const sqlSelectAppInfo =
"SELECT file_descr, company_name,"
" product_name, product_ver, file_mod_time, icon_id"
@ -103,6 +109,8 @@ void AppInfoManager::setupDb(const QString &filePath)
return;
}
m_sqliteDb->execute(sqlPragmas);
if (!m_sqliteDb->migrate(":/appinfocache/migrations",
DATABASE_USER_VERSION, true)) {
logCritical() << "Migration error" << filePath;

View File

@ -1,7 +1,5 @@
PRAGMA user_version = 3;
PRAGMA journal_mode = WAL;
CREATE TABLE app(
path TEXT PRIMARY KEY,
file_descr TEXT,