Merge pull request #324 from AdenKoperczak/high_privilege_warning

High privilege warning
This commit is contained in:
Dan Paulat 2025-01-12 23:02:31 -06:00 committed by GitHub
commit 6ef24bf4ed
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 210 additions and 14 deletions

View file

@ -51,9 +51,11 @@ find_package(Qt${QT_VERSION_MAJOR}
set(SRC_EXE_MAIN source/scwx/qt/main/main.cpp)
set(HDR_MAIN source/scwx/qt/main/application.hpp
source/scwx/qt/main/check_privilege.hpp
source/scwx/qt/main/main_window.hpp
source/scwx/qt/main/process_validation.hpp)
set(SRC_MAIN source/scwx/qt/main/application.cpp
source/scwx/qt/main/check_privilege.cpp
source/scwx/qt/main/main_window.cpp
source/scwx/qt/main/process_validation.cpp)
set(UI_MAIN source/scwx/qt/main/main_window.ui)

View file

@ -0,0 +1,136 @@
#include <scwx/qt/settings/general_settings.hpp>
#include <scwx/qt/main/check_privilege.hpp>
#include <QtGlobal>
#include <QStandardPaths>
#include <filesystem>
#include <QObject>
#include <QMessageBox>
#include <QCheckBox>
#ifdef _WIN32
# include <windows.h>
#else
# include <unistd.h>
#endif
namespace scwx::qt::main
{
bool is_high_privilege()
{
#if defined(_WIN32)
bool isAdmin = false;
HANDLE token = NULL;
TOKEN_ELEVATION elevation;
DWORD elevationSize = sizeof(TOKEN_ELEVATION);
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
{
return false;
}
if (!GetTokenInformation(
token, TokenElevation, &elevation, elevationSize, &elevationSize))
{
CloseHandle(token);
return false;
}
isAdmin = elevation.TokenIsElevated;
CloseHandle(token);
return isAdmin;
#elif defined(Q_OS_UNIX)
// On UNIX root is always uid 0. On Linux this is enforced by the kernel.
return geteuid() == 0;
#else
return false;
#endif
}
#if defined(_WIN32)
static const QString message = QObject::tr(
"Supercell Wx has been run with administrator permissions. It is "
"recommended to run it without administrator permissions Do you wish to "
"continue?");
#elif defined(Q_OS_UNIX)
static const QString message = QObject::tr(
"Supercell Wx has been run as root. It is recommended to run it as a normal "
"user. Do you wish to continue?");
#else
static const QString message = QObject::tr("");
#endif
static const QString title = QObject::tr("Supercell Wx");
static const QString checkBoxText =
QObject::tr("Do not show this warning again.");
class PrivilegeChecker::Impl
{
public:
explicit Impl() :
highPrivilege_ {is_high_privilege()},
dialog_ {QMessageBox::Icon::Warning, title, message},
checkBox_(new QCheckBox(checkBoxText, &dialog_))
{
const std::string appDataPath {
QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)
.toStdString()};
hasAppData_ = std::filesystem::exists(appDataPath);
dialog_.setStandardButtons(QMessageBox::Yes | QMessageBox::No);
dialog_.setDefaultButton(QMessageBox::No);
dialog_.setCheckBox(checkBox_);
};
bool hasAppData_;
bool firstCheckCheckBoxState_ {true};
bool highPrivilege_;
QMessageBox dialog_;
QCheckBox* checkBox_;
};
PrivilegeChecker::PrivilegeChecker() :
p(std::make_unique<PrivilegeChecker::Impl>())
{
}
PrivilegeChecker::~PrivilegeChecker() = default;
bool PrivilegeChecker::pre_settings_check()
{
if (p->hasAppData_ || !p->highPrivilege_)
{
return false;
}
const int result = p->dialog_.exec();
p->firstCheckCheckBoxState_ = p->checkBox_->isChecked();
return result != QMessageBox::Yes;
}
bool PrivilegeChecker::post_settings_check()
{
auto& highPrivilegeWarningEnabled =
settings::GeneralSettings::Instance().high_privilege_warning_enabled();
if (!highPrivilegeWarningEnabled.GetValue() || !p->highPrivilege_)
{
return false;
}
else if (!p->hasAppData_)
{
highPrivilegeWarningEnabled.StageValue(!p->firstCheckCheckBoxState_);
return false;
}
switch (p->dialog_.exec())
{
case QMessageBox::Yes:
highPrivilegeWarningEnabled.StageValue(!p->checkBox_->isChecked());
return false;
case QMessageBox::No:
default:
return true;
}
}
} // namespace scwx::qt::main

View file

@ -0,0 +1,30 @@
#pragma once
#include <memory>
namespace scwx::qt::main
{
bool is_high_privilege();
class PrivilegeChecker
{
public:
explicit PrivilegeChecker();
~PrivilegeChecker();
PrivilegeChecker(const PrivilegeChecker&) = delete;
PrivilegeChecker& operator=(const PrivilegeChecker&) = delete;
PrivilegeChecker(const PrivilegeChecker&&) = delete;
PrivilegeChecker& operator=(const PrivilegeChecker&&) = delete;
// returning true means check failed.
bool pre_settings_check();
bool post_settings_check();
private:
class Impl;
std::unique_ptr<Impl> p;
};
} // namespace scwx::qt::main

View file

@ -13,6 +13,7 @@
#include <scwx/qt/settings/general_settings.hpp>
#include <scwx/qt/types/qt_types.hpp>
#include <scwx/qt/ui/setup/setup_wizard.hpp>
#include <scwx/qt/main/check_privilege.hpp>
#include <scwx/network/cpr.hpp>
#include <scwx/util/environment.hpp>
#include <scwx/util/logger.hpp>
@ -78,6 +79,13 @@ int main(int argc, char* argv[])
QStandardPaths::setTestModeEnabled(true);
}
// Test to see if scwx was run with high privilege
scwx::qt::main::PrivilegeChecker privilegeChecker;
if (privilegeChecker.pre_settings_check())
{
return 0;
}
// Start the io_context main loop
boost::asio::io_context& ioContext = scwx::util::io_context();
auto work = boost::asio::make_work_guard(ioContext);
@ -117,20 +125,27 @@ int main(int argc, char* argv[])
// Check process modules for compatibility
scwx::qt::main::CheckProcessModules();
// Run initial setup if required
if (scwx::qt::ui::setup::SetupWizard::IsSetupRequired())
int result = 0;
if (privilegeChecker.post_settings_check())
{
scwx::qt::ui::setup::SetupWizard w;
w.show();
a.exec();
result = 1;
}
// Run Qt main loop
int result;
else
{
scwx::qt::main::MainWindow w;
w.show();
result = a.exec();
// Run initial setup if required
if (scwx::qt::ui::setup::SetupWizard::IsSetupRequired())
{
scwx::qt::ui::setup::SetupWizard w;
w.show();
a.exec();
}
// Run Qt main loop
{
scwx::qt::main::MainWindow w;
w.show();
result = a.exec();
}
}
// Deinitialize application

View file

@ -80,6 +80,7 @@ public:
warningsProvider_.SetDefault(defaultWarningsProviderValue);
cursorIconAlwaysOn_.SetDefault(false);
radarSiteThreshold_.SetDefault(0.0);
highPrivilegeWarningEnabled_.SetDefault(true);
fontSizes_.SetElementMinimum(1);
fontSizes_.SetElementMaximum(72);
@ -175,6 +176,8 @@ public:
SettingsVariable<std::string> warningsProvider_ {"warnings_provider"};
SettingsVariable<bool> cursorIconAlwaysOn_ {"cursor_icon_always_on"};
SettingsVariable<double> radarSiteThreshold_ {"radar_site_threshold"};
SettingsVariable<bool> highPrivilegeWarningEnabled_ {
"high_privilege_warning_enabled"};
};
GeneralSettings::GeneralSettings() :
@ -210,7 +213,8 @@ GeneralSettings::GeneralSettings() :
&p->updateNotificationsEnabled_,
&p->warningsProvider_,
&p->cursorIconAlwaysOn_,
&p->radarSiteThreshold_});
&p->radarSiteThreshold_,
&p->highPrivilegeWarningEnabled_});
SetDefaults();
}
GeneralSettings::~GeneralSettings() = default;
@ -375,6 +379,11 @@ SettingsVariable<double>& GeneralSettings::radar_site_threshold() const
return p->radarSiteThreshold_;
}
SettingsVariable<bool>& GeneralSettings::high_privilege_warning_enabled() const
{
return p->highPrivilegeWarningEnabled_;
}
bool GeneralSettings::Shutdown()
{
bool dataChanged = false;
@ -385,6 +394,7 @@ bool GeneralSettings::Shutdown()
dataChanged |= p->loopTime_.Commit();
dataChanged |= p->processModuleWarningsEnabled_.Commit();
dataChanged |= p->trackLocation_.Commit();
dataChanged |= p->highPrivilegeWarningEnabled_.Commit();
return dataChanged;
}
@ -429,7 +439,9 @@ bool operator==(const GeneralSettings& lhs, const GeneralSettings& rhs)
rhs.p->updateNotificationsEnabled_ &&
lhs.p->warningsProvider_ == rhs.p->warningsProvider_ &&
lhs.p->cursorIconAlwaysOn_ == rhs.p->cursorIconAlwaysOn_ &&
lhs.p->radarSiteThreshold_ == rhs.p->radarSiteThreshold_);
lhs.p->radarSiteThreshold_ == rhs.p->radarSiteThreshold_ &&
lhs.p->highPrivilegeWarningEnabled_ ==
rhs.p->highPrivilegeWarningEnabled_);
}
} // namespace settings

View file

@ -56,6 +56,7 @@ public:
SettingsVariable<std::string>& warnings_provider() const;
SettingsVariable<bool>& cursor_icon_always_on() const;
SettingsVariable<double>& radar_site_threshold() const;
SettingsVariable<bool>& high_privilege_warning_enabled() const;
static GeneralSettings& Instance();

@ -1 +1 @@
Subproject commit 24ececcd183d3b8961e5638da89f0eb36309cd6b
Subproject commit 1f3e1259130a5eb4a6df37d721fe6c8301213e7e