mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-10 20:13:24 -08:00
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Desktop / Configure (push) Waiting to run
Build Desktop / vcpkg baseline (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Fedora 45 release (push) Blocked by required conditions
Build Desktop / Fedora 45 debug (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 sanitize (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 cover (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 27 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / Prune caches (push) Waiting to run
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
Add --set key=value to override a section-qualified scalar configuration key for a single run and --print-config to print the effective configuration, with secrets redacted. SettingsCache owns the override map, so reads see the override without rewriting the ini file, and rebuilds the disallowed-name regexps when users/disallowedregexp is overridden. Bare keys and array-scoped keys are rejected because array loops read them relative to the active group, where a full-key override would either be ignored or rewrite every entry. Cover the ini, default, override, override-only-key, regexp-rebuild, secret-redaction, and parse paths with a server-labelled gtest.
126 lines
3.6 KiB
C++
126 lines
3.6 KiB
C++
#include "settingscache.h"
|
|
|
|
#include <QCoreApplication>
|
|
#include <QDebug>
|
|
#include <QFile>
|
|
#include <QStandardPaths>
|
|
#include <QStringList>
|
|
#include <QVariant>
|
|
#include <qlogging.h>
|
|
#include <qnamespace.h>
|
|
#include <qsystemdetection.h>
|
|
|
|
class QObject;
|
|
|
|
SettingsCache::SettingsCache(const QString &fileName, QSettings::Format format, QObject *parent)
|
|
: QSettings(fileName, format, parent)
|
|
{
|
|
// first, figure out if we are running in portable mode
|
|
isPortableBuild = QFile::exists(qApp->applicationDirPath() + "/portable.dat");
|
|
|
|
rebuildDisallowedRegExps();
|
|
}
|
|
|
|
QVariant SettingsCache::value(const QString &key, const QVariant &defaultValue) const
|
|
{
|
|
const auto it = overrides.constFind(key);
|
|
if (it != overrides.constEnd()) {
|
|
return it.value();
|
|
}
|
|
return QSettings::value(key, defaultValue);
|
|
}
|
|
|
|
void SettingsCache::setOverride(const QString &key, const QVariant &value)
|
|
{
|
|
overrides.insert(key, value);
|
|
}
|
|
|
|
bool SettingsCache::parseOverride(const QString &entry, QString &key, QVariant &value)
|
|
{
|
|
const int separator = entry.indexOf('=');
|
|
if (separator <= 0) {
|
|
return false;
|
|
}
|
|
|
|
const QString parsedKey = entry.left(separator).trimmed();
|
|
if (parsedKey.isEmpty() || !parsedKey.contains('/')) {
|
|
// A bare key is read relative to the active QSettings group by array
|
|
// loops, so one override could rewrite every room, channel, or game type.
|
|
return false;
|
|
}
|
|
|
|
const QStringList segments = parsedKey.split('/');
|
|
if (segments.last() == "size") {
|
|
return false;
|
|
}
|
|
for (const QString &segment : segments) {
|
|
bool isNumber = false;
|
|
segment.toInt(&isNumber);
|
|
if (isNumber) {
|
|
// Numeric segments identify array entries, which are read relative
|
|
// to the active array group and never match a full-key override.
|
|
return false;
|
|
}
|
|
}
|
|
|
|
key = parsedKey;
|
|
value = entry.mid(separator + 1);
|
|
return true;
|
|
}
|
|
|
|
bool SettingsCache::isSecretKey(const QString &key)
|
|
{
|
|
const QString lower = key.toLower();
|
|
return lower.contains("password") || lower.contains("secret") || lower.contains("legacy_backup_key");
|
|
}
|
|
|
|
QStringList SettingsCache::effectiveKeys() const
|
|
{
|
|
QStringList keys = allKeys();
|
|
for (auto it = overrides.constBegin(); it != overrides.constEnd(); ++it) {
|
|
if (!keys.contains(it.key())) {
|
|
keys.append(it.key());
|
|
}
|
|
}
|
|
keys.sort();
|
|
return keys;
|
|
}
|
|
|
|
void SettingsCache::rebuildDisallowedRegExps()
|
|
{
|
|
disallowedRegExp.clear();
|
|
|
|
QStringList disallowedRegExpStr = value("users/disallowedregexp", "").toString().split(",", Qt::SkipEmptyParts);
|
|
disallowedRegExpStr.removeDuplicates();
|
|
for (const QString ®ExpStr : disallowedRegExpStr) {
|
|
disallowedRegExp.append(QRegularExpression(QString("\\A%1\\z").arg(regExpStr)));
|
|
}
|
|
}
|
|
|
|
QString SettingsCache::guessConfigurationPath()
|
|
{
|
|
const QString fileName = "servatrice.ini";
|
|
if (QFile::exists(qApp->applicationDirPath() + "/portable.dat")) {
|
|
qDebug() << "Portable mode enabled";
|
|
return fileName;
|
|
}
|
|
|
|
QString guessFileName;
|
|
|
|
// application directory path
|
|
guessFileName = QCoreApplication::applicationDirPath() + "/" + fileName;
|
|
if (QFile::exists(guessFileName)) {
|
|
return guessFileName;
|
|
}
|
|
|
|
#ifdef Q_OS_UNIX
|
|
// /etc
|
|
guessFileName = "/etc/servatrice/" + fileName;
|
|
if (QFile::exists(guessFileName)) {
|
|
return guessFileName;
|
|
}
|
|
#endif
|
|
|
|
guessFileName = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + "/" + fileName;
|
|
return guessFileName;
|
|
}
|