mirror of
https://github.com/tnodir/fort
synced 2024-11-16 02:25:21 +00:00
519 lines
15 KiB
C++
519 lines
15 KiB
C++
#include "fortsettings.h"
|
|
|
|
#include <QCommandLineParser>
|
|
#include <QCoreApplication>
|
|
#include <QFileInfo>
|
|
|
|
#include <fort_version.h>
|
|
|
|
#include <conf/firewallconf.h>
|
|
#include <manager/envmanager.h>
|
|
#include <util/dateutil.h>
|
|
#include <util/fileutil.h>
|
|
#include <util/osutil.h>
|
|
#include <util/startuputil.h>
|
|
#include <util/stringutil.h>
|
|
|
|
namespace {
|
|
|
|
bool g_isPortable = false;
|
|
|
|
QString pathSlash(const QString &path)
|
|
{
|
|
return FileUtil::pathSlash(FileUtil::absolutePath(path));
|
|
}
|
|
|
|
QString expandPath(const QString &path, EnvManager *envManager = nullptr)
|
|
{
|
|
const auto expPath = envManager ? envManager->expandString(path) : path;
|
|
return pathSlash(expPath);
|
|
}
|
|
|
|
}
|
|
|
|
FortSettings::FortSettings(QObject *parent) : Settings(parent) { }
|
|
|
|
QString FortSettings::confFilePath() const
|
|
{
|
|
return profilePath() + APP_BASE + ".config";
|
|
}
|
|
|
|
QString FortSettings::statFilePath() const
|
|
{
|
|
return statPath() + APP_BASE + ".stat";
|
|
}
|
|
|
|
QString FortSettings::statBlockFilePath() const
|
|
{
|
|
return statFilePath() + "-block";
|
|
}
|
|
|
|
QString FortSettings::cacheFilePath() const
|
|
{
|
|
return noCache() && !hasService() ? ":memory:" : cachePath() + "appinfo.db";
|
|
}
|
|
|
|
QString FortSettings::passwordUnlockedTillText() const
|
|
{
|
|
if (passwordUnlockType() == UnlockDisabled)
|
|
return QString();
|
|
|
|
return unlockTypeStrings().at(passwordUnlockType());
|
|
}
|
|
|
|
void FortSettings::setPassword(const QString &password)
|
|
{
|
|
setPasswordHash(StringUtil::cryptoHash(password));
|
|
}
|
|
|
|
bool FortSettings::checkPassword(const QString &password) const
|
|
{
|
|
return StringUtil::cryptoHash(password) == passwordHash();
|
|
}
|
|
|
|
bool FortSettings::isPasswordRequired() const
|
|
{
|
|
return hasPassword() && !passwordChecked();
|
|
}
|
|
|
|
void FortSettings::setPasswordChecked(bool checked, UnlockType unlockType)
|
|
{
|
|
if (m_passwordChecked == checked && m_passwordUnlockType == unlockType)
|
|
return;
|
|
|
|
m_passwordChecked = checked;
|
|
m_passwordUnlockType = checked ? unlockType : UnlockDisabled;
|
|
|
|
emit passwordCheckedChanged();
|
|
}
|
|
|
|
void FortSettings::resetCheckedPassword(UnlockType unlockType)
|
|
{
|
|
if (unlockType != UnlockDisabled && unlockType != m_passwordUnlockType)
|
|
return;
|
|
|
|
setPasswordChecked(false);
|
|
}
|
|
|
|
void FortSettings::setupGlobal()
|
|
{
|
|
const QFileInfo appFileInfo(FileUtil::nativeAppFilePath());
|
|
|
|
// Set working directory
|
|
FileUtil::setCurrentDirectory(appFileInfo.path());
|
|
|
|
// Is portable?
|
|
g_isPortable = FileUtil::fileExists(appFileInfo.path() + "/README.portable");
|
|
|
|
// Global settings from program's binary directory
|
|
const QSettings settings(appFileInfo.filePath() + ".ini", QSettings::IniFormat);
|
|
|
|
// High-DPI scale factor rounding policy
|
|
const auto dpiPolicy = settings.value("global/dpiPolicy").toString();
|
|
if (!dpiPolicy.isEmpty()) {
|
|
qputenv("QT_SCALE_FACTOR_ROUNDING_POLICY", dpiPolicy.toLatin1());
|
|
}
|
|
|
|
m_hasService = StartupUtil::isServiceInstalled();
|
|
m_isUserAdmin = OsUtil::isUserAdmin();
|
|
|
|
m_noCache = settings.value("global/noCache").toBool();
|
|
m_canInstallDriver = settings.value("global/canInstallDriver").toBool();
|
|
m_defaultLanguage = settings.value("global/defaultLanguage").toString();
|
|
|
|
m_profilePath = settings.value("global/profileDir").toString();
|
|
m_statPath = settings.value("global/statDir").toString();
|
|
m_cachePath = settings.value("global/cacheDir").toString();
|
|
m_userPath = settings.value("global/userDir").toString();
|
|
m_logsPath = settings.value("global/logsDir").toString();
|
|
}
|
|
|
|
void FortSettings::initialize(const QStringList &args, EnvManager *envManager)
|
|
{
|
|
processArguments(args);
|
|
|
|
setupPaths(envManager);
|
|
createPaths();
|
|
|
|
setupIni(profilePath() + APP_BASE + ".ini");
|
|
}
|
|
|
|
void FortSettings::processArguments(const QStringList &args)
|
|
{
|
|
QCommandLineParser parser;
|
|
|
|
const QCommandLineOption profileOption(QStringList() << "p"
|
|
<< "profile",
|
|
"Directory to store settings.", "profile");
|
|
parser.addOption(profileOption);
|
|
|
|
const QCommandLineOption statOption("stat", "Directory to store statistics.", "stat");
|
|
parser.addOption(statOption);
|
|
|
|
const QCommandLineOption cacheOption("cache", "Directory to store cache.", "cache");
|
|
parser.addOption(cacheOption);
|
|
|
|
const QCommandLineOption logsOption("logs", "Directory to store logs.", "logs");
|
|
parser.addOption(logsOption);
|
|
|
|
const QCommandLineOption uninstallOption("u", "Uninstall booted provider and startup entries.");
|
|
parser.addOption(uninstallOption);
|
|
|
|
const QCommandLineOption installOption("i", "Install startup entries.");
|
|
parser.addOption(installOption);
|
|
|
|
const QCommandLineOption noCacheOption("no-cache", "Don't use cache on disk.");
|
|
parser.addOption(noCacheOption);
|
|
|
|
const QCommandLineOption langOption("lang", "Default language.", "lang", "en");
|
|
parser.addOption(langOption);
|
|
|
|
const QCommandLineOption serviceOption("service", "Is running as a service?");
|
|
parser.addOption(serviceOption);
|
|
|
|
const QCommandLineOption controlOption(QStringList() << "c"
|
|
<< "control",
|
|
"Control running instance by executing the command.", "control");
|
|
parser.addOption(controlOption);
|
|
|
|
parser.addVersionOption();
|
|
parser.addHelpOption();
|
|
|
|
parser.process(args);
|
|
|
|
// No Cache
|
|
if (parser.isSet(noCacheOption)) {
|
|
m_noCache = true;
|
|
}
|
|
|
|
// Default Language
|
|
if (parser.isSet(langOption)) {
|
|
m_defaultLanguage = parser.value(langOption);
|
|
}
|
|
|
|
// Is service
|
|
if (parser.isSet(serviceOption)) {
|
|
m_isService = m_hasService = true;
|
|
}
|
|
|
|
// Profile Path
|
|
if (parser.isSet(profileOption)) {
|
|
m_profilePath = parser.value(profileOption);
|
|
}
|
|
|
|
// Statistics Path
|
|
if (parser.isSet(statOption)) {
|
|
m_statPath = parser.value(statOption);
|
|
}
|
|
|
|
// Cache Path
|
|
if (parser.isSet(cacheOption)) {
|
|
m_cachePath = parser.value(cacheOption);
|
|
}
|
|
|
|
// Logs Path
|
|
if (parser.isSet(logsOption)) {
|
|
m_logsPath = parser.value(logsOption);
|
|
}
|
|
|
|
// Control command
|
|
m_controlCommand = parser.value(controlOption);
|
|
|
|
// Other Arguments
|
|
m_args = parser.positionalArguments();
|
|
}
|
|
|
|
void FortSettings::setupPaths(EnvManager *envManager)
|
|
{
|
|
// Profile Path
|
|
if (m_profilePath.isEmpty()) {
|
|
m_isDefaultProfilePath = true;
|
|
m_profilePath = defaultProfilePath(hasService());
|
|
} else {
|
|
m_profilePath = expandPath(m_profilePath, envManager);
|
|
}
|
|
|
|
// Statistics Path
|
|
if (m_statPath.isEmpty()) {
|
|
m_statPath = m_profilePath;
|
|
} else {
|
|
m_statPath = expandPath(m_statPath, envManager);
|
|
}
|
|
|
|
// Cache Path
|
|
if (m_cachePath.isEmpty()) {
|
|
m_cachePath = m_profilePath + "cache/";
|
|
} else {
|
|
m_cachePath = expandPath(m_cachePath, envManager);
|
|
}
|
|
|
|
// User Settings Path
|
|
if (m_userPath.isEmpty()) {
|
|
m_userPath = defaultProfilePath(isService());
|
|
} else {
|
|
m_userPath = expandPath(m_userPath, envManager);
|
|
}
|
|
|
|
// Logs Path
|
|
if (m_logsPath.isEmpty()) {
|
|
m_logsPath = m_userPath + "logs/";
|
|
} else {
|
|
m_logsPath = expandPath(m_logsPath, envManager);
|
|
}
|
|
}
|
|
|
|
void FortSettings::createPaths()
|
|
{
|
|
FileUtil::makePath(profilePath());
|
|
FileUtil::makePath(statPath());
|
|
FileUtil::makePath(logsPath());
|
|
if (!noCache()) {
|
|
FileUtil::makePath(cachePath());
|
|
}
|
|
FileUtil::makePath(userPath());
|
|
|
|
// Remove old cache file
|
|
// TODO: COMPAT: Remove after v4.1.0 (via v4.0.0)
|
|
FileUtil::removeFile(cachePath() + "appinfocache.db");
|
|
|
|
// Copy .ini to .user.ini
|
|
// TODO: COMPAT: Remove after v4.1.0 (via v4.0.0)
|
|
const QString iniUserPath = userPath() + APP_BASE + ".user.ini";
|
|
if (!isService() && !FileUtil::fileExists(iniUserPath)) {
|
|
FileUtil::copyFile(profilePath() + APP_BASE + ".ini", iniUserPath);
|
|
}
|
|
}
|
|
|
|
bool FortSettings::isPortable()
|
|
{
|
|
return g_isPortable;
|
|
}
|
|
|
|
QString FortSettings::defaultProfilePath(bool isService)
|
|
{
|
|
// Is portable?
|
|
if (isPortable()) {
|
|
return FileUtil::appBinLocation() + "/Data/";
|
|
}
|
|
|
|
// Is service?
|
|
if (isService) {
|
|
const QString servicePath =
|
|
FileUtil::expandPath(QLatin1String("%ProgramData%\\") + APP_NAME);
|
|
return pathSlash(servicePath);
|
|
}
|
|
|
|
return pathSlash(FileUtil::appConfigLocation());
|
|
}
|
|
|
|
void FortSettings::readConfIni(FirewallConf &conf) const
|
|
{
|
|
ini()->beginGroup("confFlags");
|
|
conf.setBootFilter(iniBool("bootFilter"));
|
|
conf.setFilterEnabled(iniBool("filterEnabled", true));
|
|
conf.setFilterLocals(iniBool("filterLocals"));
|
|
conf.setBlockTraffic(iniBool("blockTraffic"));
|
|
conf.setBlockInetTraffic(iniBool("blockInetTraffic"));
|
|
conf.setAllowAllNew(iniBool("allowAllNew", true));
|
|
conf.setAskToConnect(iniBool("askToConnect"));
|
|
conf.setLogStat(iniBool("logStat", true));
|
|
conf.setLogStatNoFilter(iniBool("logStatNoFilter", true));
|
|
conf.setLogBlocked(iniBool("logBlocked", true));
|
|
conf.setLogAllowedIp(iniBool("logAllowedIp", true));
|
|
conf.setLogBlockedIp(iniBool("logBlockedIp", true));
|
|
conf.setLogAlertedBlockedIp(iniBool("logAlertedBlockedIp"));
|
|
conf.setAppBlockAll(iniBool("appBlockAll", true));
|
|
conf.setAppAllowAll(iniBool("appAllowAll"));
|
|
conf.setupAppGroupBits(iniUInt("appGroupBits", DEFAULT_APP_GROUP_BITS));
|
|
ini()->endGroup();
|
|
|
|
ini()->beginGroup("stat");
|
|
conf.setActivePeriodEnabled(iniBool("activePeriodEnabled"));
|
|
conf.setActivePeriodFrom(DateUtil::reformatTime(iniText("activePeriodFrom")));
|
|
conf.setActivePeriodTo(DateUtil::reformatTime(iniText("activePeriodTo")));
|
|
ini()->endGroup();
|
|
|
|
// Ini Options
|
|
readConfIniOptions(conf.ini());
|
|
}
|
|
|
|
void FortSettings::readConfIniOptions(const IniOptions &ini) const
|
|
{
|
|
// Check Password on Uninstall
|
|
if (ini.checkPasswordOnUninstall()) {
|
|
setCacheValue(passwordHashKey(), StartupUtil::registryPasswordHash());
|
|
}
|
|
}
|
|
|
|
void FortSettings::writeConfIni(const FirewallConf &conf)
|
|
{
|
|
bool changed = false;
|
|
|
|
if (conf.flagsEdited()) {
|
|
ini()->beginGroup("confFlags");
|
|
setIniValue("bootFilter", conf.bootFilter());
|
|
setIniValue("filterEnabled", conf.filterEnabled());
|
|
setIniValue("filterLocals", conf.filterLocals());
|
|
setIniValue("blockTraffic", conf.blockTraffic());
|
|
setIniValue("blockInetTraffic", conf.blockInetTraffic());
|
|
setIniValue("allowAllNew", conf.allowAllNew());
|
|
setIniValue("askToConnect", conf.askToConnect());
|
|
setIniValue("logStat", conf.logStat());
|
|
setIniValue("logStatNoFilter", conf.logStatNoFilter());
|
|
setIniValue("logBlocked", conf.logBlocked());
|
|
setIniValue("logAllowedIp", conf.logAllowedIp());
|
|
setIniValue("logBlockedIp", conf.logBlockedIp());
|
|
setIniValue("logAlertedBlockedIp", conf.logAlertedBlockedIp());
|
|
setIniValue("appBlockAll", conf.appBlockAll());
|
|
setIniValue("appAllowAll", conf.appAllowAll());
|
|
setIniValue("appGroupBits", conf.appGroupBits(), DEFAULT_APP_GROUP_BITS);
|
|
ini()->endGroup();
|
|
|
|
ini()->beginGroup("stat");
|
|
setIniValue("activePeriodEnabled", conf.activePeriodEnabled());
|
|
setIniValue("activePeriodFrom", conf.activePeriodFrom());
|
|
setIniValue("activePeriodTo", conf.activePeriodTo());
|
|
ini()->endGroup();
|
|
|
|
changed = true;
|
|
}
|
|
|
|
// Ini Options
|
|
if (conf.iniEdited()) {
|
|
writeConfIniOptions(conf.ini());
|
|
|
|
changed = true;
|
|
}
|
|
|
|
if (changed) {
|
|
iniFlush();
|
|
}
|
|
}
|
|
|
|
void FortSettings::writeConfIniOptions(const IniOptions &ini)
|
|
{
|
|
// Save changed keys
|
|
ini.save();
|
|
|
|
// Password
|
|
const bool isPasswordSet = (ini.hasPasswordSet() && ini.hasPassword() != hasPassword());
|
|
if (isPasswordSet || !ini.password().isEmpty()) {
|
|
setPassword(ini.password());
|
|
}
|
|
|
|
// Check Password on Uninstall
|
|
if (ini.checkPasswordOnUninstallSet() || ini.hasPasswordSet()) {
|
|
StartupUtil::setRegistryPasswordHash(
|
|
ini.checkPasswordOnUninstall() ? passwordHash() : QString());
|
|
|
|
saveIniValue(passwordHashKey(), passwordHash());
|
|
}
|
|
}
|
|
|
|
void FortSettings::migrateIniOnStartup()
|
|
{
|
|
int version;
|
|
if (checkIniVersion(version))
|
|
return;
|
|
|
|
// COMPAT: v3.4.0
|
|
if (version < 0x030400) {
|
|
// Windows Explorer integration: Args changed
|
|
if (StartupUtil::isExplorerIntegrated()) {
|
|
StartupUtil::setExplorerIntegrated(false);
|
|
StartupUtil::setExplorerIntegrated(true);
|
|
}
|
|
}
|
|
|
|
// COMPAT: v3.8.1
|
|
if (version < 0x030801) {
|
|
setCacheValue("confFlags/bootFilter", ini()->value("confFlags/provBoot"));
|
|
}
|
|
|
|
// COMPAT: v3.8.4
|
|
if (version < 0x030804) {
|
|
setCacheValue("confFlags/askToConnect", false);
|
|
}
|
|
|
|
// COMPAT: v3.9.10
|
|
if (version < 0x030910) {
|
|
setCacheValue("confFlags/blockTraffic", ini()->value("confFlags/stopTraffic"));
|
|
setCacheValue("confFlags/blockInetTraffic", ini()->value("confFlags/stopInetTraffic"));
|
|
setCacheValue("quota/blockInetTraffic", ini()->value("quota/stopInetTraffic"));
|
|
}
|
|
}
|
|
|
|
void FortSettings::migrateIniOnWrite()
|
|
{
|
|
int version;
|
|
if (checkIniVersionOnWrite(version))
|
|
return;
|
|
|
|
Settings::migrateIniOnWrite();
|
|
|
|
// COMPAT: v3.4.0: .ini ~> .user.ini
|
|
if (version < 0x030400) {
|
|
removeIniKey("base/language");
|
|
removeIniKey("hotKey");
|
|
removeIniKey("stat/trafUnit");
|
|
removeIniKey("graphWindow/visible");
|
|
removeIniKey("graphWindow/geometry");
|
|
removeIniKey("graphWindow/maximized");
|
|
removeIniKey("optWindow");
|
|
removeIniKey("progWindow");
|
|
removeIniKey("zoneWindow");
|
|
removeIniKey("connWindow");
|
|
}
|
|
|
|
// COMPAT: v3.8.1
|
|
if (version < 0x030801) {
|
|
removeIniKey("confFlags/provBoot");
|
|
ini()->setValue("confFlags/bootFilter", cacheValue("confFlags/bootFilter"));
|
|
}
|
|
|
|
// COMPAT: v3.9.10
|
|
if (version < 0x030910) {
|
|
removeIniKey("confFlags/stopTraffic");
|
|
removeIniKey("confFlags/stopInetTraffic");
|
|
removeIniKey("quota/stopInetTraffic");
|
|
ini()->setValue("confFlags/blockTraffic", cacheValue("confFlags/blockTraffic"));
|
|
ini()->setValue("confFlags/blockInetTraffic", cacheValue("confFlags/blockInetTraffic"));
|
|
ini()->setValue("quota/blockInetTraffic", cacheValue("quota/blockInetTraffic"));
|
|
}
|
|
}
|
|
|
|
bool FortSettings::wasMigrated() const
|
|
{
|
|
int version;
|
|
if (checkIniVersion(version))
|
|
return false;
|
|
|
|
#if 0
|
|
// COMPAT: v3.0.0
|
|
if (version < 0x030000 && appVersion() >= 0x030000)
|
|
return true;
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
|
|
bool FortSettings::canMigrate(QString &viaVersion) const
|
|
{
|
|
int version;
|
|
if (checkIniVersion(version))
|
|
return true;
|
|
|
|
// COMPAT: v3.0.0
|
|
if (version < 0x030000 && appVersion() > 0x030000) {
|
|
viaVersion = "3.0.0";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
QStringList FortSettings::unlockTypeStrings()
|
|
{
|
|
return { tr("Window closed"), tr("Session lockout"), tr("Program exit") };
|
|
}
|