mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
make DomainServerSettingsManager thread-safe for use in content backup
This commit is contained in:
parent
d9f2e1986f
commit
1c053730eb
6 changed files with 153 additions and 152 deletions
|
@ -58,7 +58,7 @@ DomainContentBackupManager::DomainContentBackupManager(const QString& backupDire
|
|||
_lastCheck(usecTimestampNow())
|
||||
{
|
||||
setObjectName("DomainContentBackupManager");
|
||||
|
||||
|
||||
// Make sure the backup directory exists.
|
||||
QDir(_backupDirectory).mkpath(".");
|
||||
|
||||
|
|
|
@ -435,10 +435,11 @@ SharedNodePointer DomainGatekeeper::processAgentConnectRequest(const NodeConnect
|
|||
if (!userPerms.can(NodePermissions::Permission::canConnectPastMaxCapacity) && !isWithinMaxCapacity()) {
|
||||
// we can't allow this user to connect because we are at max capacity
|
||||
QString redirectOnMaxCapacity;
|
||||
const QVariant* redirectOnMaxCapacityVariant =
|
||||
valueForKeyPath(_server->_settingsManager.getSettingsMap(), MAXIMUM_USER_CAPACITY_REDIRECT_LOCATION);
|
||||
if (redirectOnMaxCapacityVariant && redirectOnMaxCapacityVariant->canConvert<QString>()) {
|
||||
redirectOnMaxCapacity = redirectOnMaxCapacityVariant->toString();
|
||||
|
||||
QVariant redirectOnMaxCapacityVariant =
|
||||
_server->_settingsManager.valueOrDefaultValueForKeyPath(MAXIMUM_USER_CAPACITY_REDIRECT_LOCATION);
|
||||
if (redirectOnMaxCapacityVariant.canConvert<QString>()) {
|
||||
redirectOnMaxCapacity = redirectOnMaxCapacityVariant.toString();
|
||||
qDebug() << "Redirection domain:" << redirectOnMaxCapacity;
|
||||
}
|
||||
|
||||
|
@ -610,9 +611,9 @@ bool DomainGatekeeper::verifyUserSignature(const QString& username,
|
|||
|
||||
bool DomainGatekeeper::isWithinMaxCapacity() {
|
||||
// find out what our maximum capacity is
|
||||
const QVariant* maximumUserCapacityVariant =
|
||||
valueForKeyPath(_server->_settingsManager.getSettingsMap(), MAXIMUM_USER_CAPACITY);
|
||||
unsigned int maximumUserCapacity = maximumUserCapacityVariant ? maximumUserCapacityVariant->toUInt() : 0;
|
||||
QVariant maximumUserCapacityVariant =
|
||||
_server->_settingsManager.valueOrDefaultValueForKeyPath(MAXIMUM_USER_CAPACITY);
|
||||
unsigned int maximumUserCapacity = !maximumUserCapacityVariant.isValid() ? maximumUserCapacityVariant.toUInt() : 0;
|
||||
|
||||
if (maximumUserCapacity > 0) {
|
||||
unsigned int connectedUsers = _server->countConnectedUsers();
|
||||
|
|
|
@ -84,21 +84,22 @@ void DomainMetadata::descriptorsChanged() {
|
|||
// get descriptors
|
||||
assert(_metadata[DESCRIPTORS].canConvert<QVariantMap>());
|
||||
auto& state = *static_cast<QVariantMap*>(_metadata[DESCRIPTORS].data());
|
||||
auto& settings = static_cast<DomainServer*>(parent())->_settingsManager.getSettingsMap();
|
||||
auto& descriptors = static_cast<DomainServer*>(parent())->_settingsManager.getDescriptorsMap();
|
||||
|
||||
static const QString DESCRIPTORS_GROUP_KEYPATH = "descriptors";
|
||||
auto descriptorsMap = static_cast<DomainServer*>(parent())->_settingsManager.valueForKeyPath(DESCRIPTORS).toMap();
|
||||
|
||||
// copy simple descriptors (description/maturity)
|
||||
state[Descriptors::DESCRIPTION] = descriptors[Descriptors::DESCRIPTION];
|
||||
state[Descriptors::MATURITY] = descriptors[Descriptors::MATURITY];
|
||||
state[Descriptors::DESCRIPTION] = descriptorsMap[Descriptors::DESCRIPTION];
|
||||
state[Descriptors::MATURITY] = descriptorsMap[Descriptors::MATURITY];
|
||||
|
||||
// copy array descriptors (hosts/tags)
|
||||
state[Descriptors::HOSTS] = descriptors[Descriptors::HOSTS].toList();
|
||||
state[Descriptors::TAGS] = descriptors[Descriptors::TAGS].toList();
|
||||
state[Descriptors::HOSTS] = descriptorsMap[Descriptors::HOSTS].toList();
|
||||
state[Descriptors::TAGS] = descriptorsMap[Descriptors::TAGS].toList();
|
||||
|
||||
// parse capacity
|
||||
static const QString CAPACITY = "security.maximum_user_capacity";
|
||||
const QVariant* capacityVariant = valueForKeyPath(settings, CAPACITY);
|
||||
unsigned int capacity = capacityVariant ? capacityVariant->toUInt() : 0;
|
||||
QVariant capacityVariant = static_cast<DomainServer*>(parent())->_settingsManager.valueForKeyPath(CAPACITY);
|
||||
unsigned int capacity = capacityVariant.isValid() ? capacityVariant.toUInt() : 0;
|
||||
state[Descriptors::CAPACITY] = capacity;
|
||||
|
||||
#if DEV_BUILD || PR_BUILD
|
||||
|
|
|
@ -75,8 +75,8 @@ bool DomainServer::forwardMetaverseAPIRequest(HTTPConnection* connection,
|
|||
std::initializer_list<QString> optionalData,
|
||||
bool requireAccessToken) {
|
||||
|
||||
auto accessTokenVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ACCESS_TOKEN_KEY_PATH);
|
||||
if (accessTokenVariant == nullptr && requireAccessToken) {
|
||||
auto accessTokenVariant = _settingsManager.valueForKeyPath(ACCESS_TOKEN_KEY_PATH);
|
||||
if (!accessTokenVariant.isValid() && requireAccessToken) {
|
||||
connection->respond(HTTPConnection::StatusCode400, "User access token has not been set");
|
||||
return true;
|
||||
}
|
||||
|
@ -112,8 +112,8 @@ bool DomainServer::forwardMetaverseAPIRequest(HTTPConnection* connection,
|
|||
req.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
req.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
|
||||
|
||||
if (accessTokenVariant != nullptr) {
|
||||
auto accessTokenHeader = QString("Bearer ") + accessTokenVariant->toString();
|
||||
if (accessTokenVariant.isValid()) {
|
||||
auto accessTokenHeader = QString("Bearer ") + accessTokenVariant.toString();
|
||||
req.setRawHeader("Authorization", accessTokenHeader.toLatin1());
|
||||
}
|
||||
|
||||
|
@ -417,8 +417,8 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() {
|
|||
const QString X509_PRIVATE_KEY_OPTION = "key";
|
||||
const QString X509_KEY_PASSPHRASE_ENV = "DOMAIN_SERVER_KEY_PASSPHRASE";
|
||||
|
||||
QString certPath = _settingsManager.getSettingsMap().value(X509_CERTIFICATE_OPTION).toString();
|
||||
QString keyPath = _settingsManager.getSettingsMap().value(X509_PRIVATE_KEY_OPTION).toString();
|
||||
QString certPath = _settingsManager.valueForKeyPath(X509_CERTIFICATE_OPTION).toString();
|
||||
QString keyPath = _settingsManager.valueForKeyPath(X509_PRIVATE_KEY_OPTION).toString();
|
||||
|
||||
if (!certPath.isEmpty() && !keyPath.isEmpty()) {
|
||||
// the user wants to use the following cert and key for HTTPS
|
||||
|
@ -461,8 +461,7 @@ bool DomainServer::optionallySetupOAuth() {
|
|||
const QString OAUTH_CLIENT_SECRET_ENV = "DOMAIN_SERVER_CLIENT_SECRET";
|
||||
const QString REDIRECT_HOSTNAME_OPTION = "hostname";
|
||||
|
||||
const QVariantMap& settingsMap = _settingsManager.getSettingsMap();
|
||||
_oauthProviderURL = QUrl(settingsMap.value(OAUTH_PROVIDER_URL_OPTION).toString());
|
||||
_oauthProviderURL = QUrl(_settingsManager.valueForKeyPath(OAUTH_PROVIDER_URL_OPTION).toString());
|
||||
|
||||
// if we don't have an oauth provider URL then we default to the default node auth url
|
||||
if (_oauthProviderURL.isEmpty()) {
|
||||
|
@ -472,9 +471,9 @@ bool DomainServer::optionallySetupOAuth() {
|
|||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
accountManager->setAuthURL(_oauthProviderURL);
|
||||
|
||||
_oauthClientID = settingsMap.value(OAUTH_CLIENT_ID_OPTION).toString();
|
||||
_oauthClientID = _settingsManager.valueForKeyPath(OAUTH_CLIENT_ID_OPTION).toString();
|
||||
_oauthClientSecret = QProcessEnvironment::systemEnvironment().value(OAUTH_CLIENT_SECRET_ENV);
|
||||
_hostname = settingsMap.value(REDIRECT_HOSTNAME_OPTION).toString();
|
||||
_hostname = _settingsManager.valueForKeyPath(REDIRECT_HOSTNAME_OPTION).toString();
|
||||
|
||||
if (!_oauthClientID.isEmpty()) {
|
||||
if (_oauthProviderURL.isEmpty()
|
||||
|
@ -499,11 +498,11 @@ static const QString METAVERSE_DOMAIN_ID_KEY_PATH = "metaverse.id";
|
|||
|
||||
void DomainServer::getTemporaryName(bool force) {
|
||||
// check if we already have a domain ID
|
||||
const QVariant* idValueVariant = valueForKeyPath(_settingsManager.getSettingsMap(), METAVERSE_DOMAIN_ID_KEY_PATH);
|
||||
QVariant idValueVariant = _settingsManager.valueForKeyPath(METAVERSE_DOMAIN_ID_KEY_PATH);
|
||||
|
||||
qInfo() << "Requesting temporary domain name";
|
||||
if (idValueVariant) {
|
||||
qDebug() << "A domain ID is already present in domain-server settings:" << idValueVariant->toString();
|
||||
if (idValueVariant.isValid()) {
|
||||
qDebug() << "A domain ID is already present in domain-server settings:" << idValueVariant.toString();
|
||||
if (force) {
|
||||
qDebug() << "Requesting temporary domain name to replace current ID:" << getID();
|
||||
} else {
|
||||
|
@ -543,9 +542,6 @@ void DomainServer::handleTempDomainSuccess(QNetworkReply& requestReply) {
|
|||
auto settingsDocument = QJsonDocument::fromJson(newSettingsJSON.toUtf8());
|
||||
_settingsManager.recurseJSONObjectAndOverwriteSettings(settingsDocument.object(), DomainSettings);
|
||||
|
||||
// store the new ID and auto networking setting on disk
|
||||
_settingsManager.persistToFile();
|
||||
|
||||
// store the new token to the account info
|
||||
auto accountManager = DependencyManager::get<AccountManager>();
|
||||
accountManager->setTemporaryDomain(id, key);
|
||||
|
@ -647,8 +643,6 @@ void DomainServer::setupNodeListAndAssignments() {
|
|||
QVariant localPortValue = _settingsManager.valueOrDefaultValueForKeyPath(CUSTOM_LOCAL_PORT_OPTION);
|
||||
int domainServerPort = localPortValue.toInt();
|
||||
|
||||
QVariantMap& settingsMap = _settingsManager.getSettingsMap();
|
||||
|
||||
int domainServerDTLSPort = INVALID_PORT;
|
||||
|
||||
if (_isUsingDTLS) {
|
||||
|
@ -656,8 +650,9 @@ void DomainServer::setupNodeListAndAssignments() {
|
|||
|
||||
const QString CUSTOM_DTLS_PORT_OPTION = "dtls-port";
|
||||
|
||||
if (settingsMap.contains(CUSTOM_DTLS_PORT_OPTION)) {
|
||||
domainServerDTLSPort = (unsigned short) settingsMap.value(CUSTOM_DTLS_PORT_OPTION).toUInt();
|
||||
auto dtlsPortVariant = _settingsManager.valueForKeyPath(CUSTOM_DTLS_PORT_OPTION);
|
||||
if (dtlsPortVariant.isValid()) {
|
||||
domainServerDTLSPort = (unsigned short) dtlsPortVariant.toUInt();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -687,9 +682,9 @@ void DomainServer::setupNodeListAndAssignments() {
|
|||
nodeList->setSessionUUID(_overridingDomainID);
|
||||
isMetaverseDomain = true; // assume metaverse domain
|
||||
} else {
|
||||
const QVariant* idValueVariant = valueForKeyPath(settingsMap, METAVERSE_DOMAIN_ID_KEY_PATH);
|
||||
if (idValueVariant) {
|
||||
nodeList->setSessionUUID(idValueVariant->toString());
|
||||
QVariant idValueVariant = _settingsManager.valueForKeyPath(METAVERSE_DOMAIN_ID_KEY_PATH);
|
||||
if (idValueVariant.isValid()) {
|
||||
nodeList->setSessionUUID(idValueVariant.toString());
|
||||
isMetaverseDomain = true; // if we have an ID, we'll assume we're a metaverse domain
|
||||
} else {
|
||||
nodeList->setSessionUUID(QUuid::createUuid()); // Use random UUID
|
||||
|
@ -758,10 +753,10 @@ bool DomainServer::resetAccountManagerAccessToken() {
|
|||
QString accessToken = QProcessEnvironment::systemEnvironment().value(ENV_ACCESS_TOKEN_KEY);
|
||||
|
||||
if (accessToken.isEmpty()) {
|
||||
const QVariant* accessTokenVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ACCESS_TOKEN_KEY_PATH);
|
||||
QVariant accessTokenVariant = _settingsManager.valueForKeyPath(ACCESS_TOKEN_KEY_PATH);
|
||||
|
||||
if (accessTokenVariant && accessTokenVariant->canConvert(QMetaType::QString)) {
|
||||
accessToken = accessTokenVariant->toString();
|
||||
if (accessTokenVariant.isValid() && accessTokenVariant.canConvert(QMetaType::QString)) {
|
||||
accessToken = accessTokenVariant.toString();
|
||||
} else {
|
||||
qWarning() << "No access token is present. Some operations that use the metaverse API will fail.";
|
||||
qDebug() << "Set an access token via the web interface, in your user config"
|
||||
|
@ -892,31 +887,26 @@ void DomainServer::updateICEServerAddresses() {
|
|||
}
|
||||
|
||||
void DomainServer::parseAssignmentConfigs(QSet<Assignment::Type>& excludedTypes) {
|
||||
const QString ASSIGNMENT_CONFIG_REGEX_STRING = "config-([\\d]+)";
|
||||
QRegExp assignmentConfigRegex(ASSIGNMENT_CONFIG_REGEX_STRING);
|
||||
|
||||
const QVariantMap& settingsMap = _settingsManager.getSettingsMap();
|
||||
const QString ASSIGNMENT_CONFIG_PREFIX = "config-";
|
||||
|
||||
// scan for assignment config keys
|
||||
QStringList variantMapKeys = settingsMap.keys();
|
||||
int configIndex = variantMapKeys.indexOf(assignmentConfigRegex);
|
||||
for (int i = 0; i < Assignment::AllTypes; ++i) {
|
||||
QVariant assignmentConfigVariant = _settingsManager.valueOrDefaultValueForKeyPath(ASSIGNMENT_CONFIG_PREFIX + QString::number(i));
|
||||
|
||||
while (configIndex != -1) {
|
||||
// figure out which assignment type this matches
|
||||
Assignment::Type assignmentType = (Assignment::Type) assignmentConfigRegex.cap(1).toInt();
|
||||
if (assignmentConfigVariant.isValid()) {
|
||||
// figure out which assignment type this matches
|
||||
Assignment::Type assignmentType = static_cast<Assignment::Type>(i);
|
||||
|
||||
if (assignmentType < Assignment::AllTypes && !excludedTypes.contains(assignmentType)) {
|
||||
QVariant mapValue = settingsMap[variantMapKeys[configIndex]];
|
||||
QVariantList assignmentList = mapValue.toList();
|
||||
if (!excludedTypes.contains(assignmentType)) {
|
||||
QVariantList assignmentList = assignmentConfigVariant.toList();
|
||||
|
||||
if (assignmentType != Assignment::AgentType) {
|
||||
createStaticAssignmentsForType(assignmentType, assignmentList);
|
||||
if (assignmentType != Assignment::AgentType) {
|
||||
createStaticAssignmentsForType(assignmentType, assignmentList);
|
||||
}
|
||||
|
||||
excludedTypes.insert(assignmentType);
|
||||
}
|
||||
|
||||
excludedTypes.insert(assignmentType);
|
||||
}
|
||||
|
||||
configIndex = variantMapKeys.indexOf(assignmentConfigRegex, configIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -928,10 +918,10 @@ void DomainServer::addStaticAssignmentToAssignmentHash(Assignment* newAssignment
|
|||
|
||||
void DomainServer::populateStaticScriptedAssignmentsFromSettings() {
|
||||
const QString PERSISTENT_SCRIPTS_KEY_PATH = "scripts.persistent_scripts";
|
||||
const QVariant* persistentScriptsVariant = valueForKeyPath(_settingsManager.getSettingsMap(), PERSISTENT_SCRIPTS_KEY_PATH);
|
||||
QVariant persistentScriptsVariant = _settingsManager.valueOrDefaultValueForKeyPath(PERSISTENT_SCRIPTS_KEY_PATH);
|
||||
|
||||
if (persistentScriptsVariant) {
|
||||
QVariantList persistentScriptsList = persistentScriptsVariant->toList();
|
||||
if (persistentScriptsVariant.isValid()) {
|
||||
QVariantList persistentScriptsList = persistentScriptsVariant.toList();
|
||||
foreach(const QVariant& persistentScriptVariant, persistentScriptsList) {
|
||||
QVariantMap persistentScript = persistentScriptVariant.toMap();
|
||||
|
||||
|
@ -1954,13 +1944,12 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
|
||||
auto getSetting = [this](QString keyPath, QVariant& value) -> bool {
|
||||
QVariantMap& settingsMap = _settingsManager.getSettingsMap();
|
||||
QVariant* var = valueForKeyPath(settingsMap, keyPath);
|
||||
if (var == nullptr) {
|
||||
auto getSetting = [this](QString keyPath, QVariant value) -> bool {
|
||||
|
||||
value = _settingsManager.valueForKeyPath(keyPath);
|
||||
if (!value.isValid()) {
|
||||
return false;
|
||||
}
|
||||
value = *var;
|
||||
return true;
|
||||
};
|
||||
|
||||
|
@ -2028,8 +2017,8 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
if (connection->requestOperation() == QNetworkAccessManager::GetOperation) {
|
||||
const QString URI_WIZARD = "/wizard/";
|
||||
const QString WIZARD_COMPLETED_ONCE_KEY_PATH = "wizard.completed_once";
|
||||
const QVariant* wizardCompletedOnce = valueForKeyPath(_settingsManager.getSettingsMap(), WIZARD_COMPLETED_ONCE_KEY_PATH);
|
||||
const bool completedOnce = wizardCompletedOnce && wizardCompletedOnce->toBool();
|
||||
QVariant wizardCompletedOnce = _settingsManager.valueForKeyPath(WIZARD_COMPLETED_ONCE_KEY_PATH);
|
||||
const bool completedOnce = wizardCompletedOnce.isValid() && wizardCompletedOnce.toBool();
|
||||
|
||||
if (url.path() != URI_WIZARD && url.path().endsWith('/') && !completedOnce) {
|
||||
// First visit, redirect to the wizard
|
||||
|
@ -2326,8 +2315,8 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
return true;
|
||||
|
||||
} else if (url.path() == "/domain_settings") {
|
||||
auto accessTokenVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ACCESS_TOKEN_KEY_PATH);
|
||||
if (!accessTokenVariant) {
|
||||
auto accessTokenVariant = _settingsManager.valueForKeyPath(ACCESS_TOKEN_KEY_PATH);
|
||||
if (!accessTokenVariant.isValid()) {
|
||||
connection->respond(HTTPConnection::StatusCode400);
|
||||
return true;
|
||||
}
|
||||
|
@ -2360,8 +2349,8 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
return forwardMetaverseAPIRequest(connection, "/api/v1/domains/" + domainID, "domain",
|
||||
{ }, { "network_address", "network_port", "label" });
|
||||
} else if (url.path() == URI_API_PLACES) {
|
||||
auto accessTokenVariant = valueForKeyPath(_settingsManager.getSettingsMap(), ACCESS_TOKEN_KEY_PATH);
|
||||
if (!accessTokenVariant->isValid()) {
|
||||
auto accessTokenVariant = _settingsManager.valueForKeyPath(ACCESS_TOKEN_KEY_PATH);
|
||||
if (!accessTokenVariant.isValid()) {
|
||||
connection->respond(HTTPConnection::StatusCode400, "User access token has not been set");
|
||||
return true;
|
||||
}
|
||||
|
@ -2409,7 +2398,7 @@ bool DomainServer::handleHTTPRequest(HTTPConnection* connection, const QUrl& url
|
|||
|
||||
QUrl url { NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/api/v1/places/" + place_id };
|
||||
|
||||
url.setQuery("access_token=" + accessTokenVariant->toString());
|
||||
url.setQuery("access_token=" + accessTokenVariant.toString());
|
||||
|
||||
QNetworkRequest req(url);
|
||||
req.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
|
@ -2604,10 +2593,11 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
|
|||
|
||||
const QByteArray UNAUTHENTICATED_BODY = "You do not have permission to access this domain-server.";
|
||||
|
||||
QVariantMap& settingsMap = _settingsManager.getSettingsMap();
|
||||
QVariant adminUsersVariant = _settingsManager.valueForKeyPath(ADMIN_USERS_CONFIG_KEY);
|
||||
QVariant adminRolesVariant = _settingsManager.valueForKeyPath(ADMIN_ROLES_CONFIG_KEY);
|
||||
|
||||
if (!_oauthProviderURL.isEmpty()
|
||||
&& (settingsMap.contains(ADMIN_USERS_CONFIG_KEY) || settingsMap.contains(ADMIN_ROLES_CONFIG_KEY))) {
|
||||
&& (adminUsersVariant.isValid() || adminRolesVariant.isValid())) {
|
||||
QString cookieString = connection->requestHeaders().value(HTTP_COOKIE_HEADER_KEY);
|
||||
|
||||
const QString COOKIE_UUID_REGEX_STRING = HIFI_SESSION_COOKIE_KEY + "=([\\d\\w-]+)($|;)";
|
||||
|
@ -2618,7 +2608,7 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
|
|||
cookieUUID = cookieUUIDRegex.cap(1);
|
||||
}
|
||||
|
||||
if (valueForKeyPath(settingsMap, BASIC_AUTH_USERNAME_KEY_PATH)) {
|
||||
if (_settingsManager.valueForKeyPath(BASIC_AUTH_USERNAME_KEY_PATH).isValid()) {
|
||||
qDebug() << "Config file contains web admin settings for OAuth and basic HTTP authentication."
|
||||
<< "These cannot be combined - using OAuth for authentication.";
|
||||
}
|
||||
|
@ -2628,13 +2618,13 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
|
|||
DomainServerWebSessionData sessionData = _cookieSessionHash.value(cookieUUID);
|
||||
QString profileUsername = sessionData.getUsername();
|
||||
|
||||
if (settingsMap.value(ADMIN_USERS_CONFIG_KEY).toStringList().contains(profileUsername)) {
|
||||
if (_settingsManager.valueForKeyPath(ADMIN_USERS_CONFIG_KEY).toStringList().contains(profileUsername)) {
|
||||
// this is an authenticated user
|
||||
return true;
|
||||
}
|
||||
|
||||
// loop the roles of this user and see if they are in the admin-roles array
|
||||
QStringList adminRolesArray = settingsMap.value(ADMIN_ROLES_CONFIG_KEY).toStringList();
|
||||
QStringList adminRolesArray = _settingsManager.valueForKeyPath(ADMIN_ROLES_CONFIG_KEY).toStringList();
|
||||
|
||||
if (!adminRolesArray.isEmpty()) {
|
||||
foreach(const QString& userRole, sessionData.getRoles()) {
|
||||
|
@ -2679,7 +2669,7 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
|
|||
// we don't know about this user yet, so they are not yet authenticated
|
||||
return false;
|
||||
}
|
||||
} else if (valueForKeyPath(settingsMap, BASIC_AUTH_USERNAME_KEY_PATH)) {
|
||||
} else if (_settingsManager.valueForKeyPath(BASIC_AUTH_USERNAME_KEY_PATH).isValid()) {
|
||||
// config file contains username and password combinations for basic auth
|
||||
const QByteArray BASIC_AUTH_HEADER_KEY = "Authorization";
|
||||
|
||||
|
@ -2698,10 +2688,10 @@ bool DomainServer::isAuthenticatedRequest(HTTPConnection* connection, const QUrl
|
|||
QString headerPassword = credentialList[1];
|
||||
|
||||
// we've pulled a username and password - now check if there is a match in our basic auth hash
|
||||
QString settingsUsername = valueForKeyPath(settingsMap, BASIC_AUTH_USERNAME_KEY_PATH)->toString();
|
||||
const QVariant* settingsPasswordVariant = valueForKeyPath(settingsMap, BASIC_AUTH_PASSWORD_KEY_PATH);
|
||||
QString settingsUsername = _settingsManager.valueForKeyPath(BASIC_AUTH_USERNAME_KEY_PATH).toString();
|
||||
QVariant settingsPasswordVariant = _settingsManager.valueForKeyPath(BASIC_AUTH_PASSWORD_KEY_PATH);
|
||||
|
||||
QString settingsPassword = settingsPasswordVariant ? settingsPasswordVariant->toString() : "";
|
||||
QString settingsPassword = settingsPasswordVariant.isValid() ? settingsPasswordVariant.toString() : "";
|
||||
QString hexHeaderPassword = headerPassword.isEmpty() ?
|
||||
"" : QCryptographicHash::hash(headerPassword.toUtf8(), QCryptographicHash::Sha256).toHex();
|
||||
|
||||
|
@ -2838,13 +2828,14 @@ ReplicationServerInfo serverInformationFromSettings(QVariantMap serverMap, Repli
|
|||
}
|
||||
|
||||
void DomainServer::updateReplicationNodes(ReplicationServerDirection direction) {
|
||||
auto settings = _settingsManager.getSettingsMap();
|
||||
|
||||
if (settings.contains(BROADCASTING_SETTINGS_KEY)) {
|
||||
auto broadcastSettingsVariant = _settingsManager.valueForKeyPath(BROADCASTING_SETTINGS_KEY);
|
||||
|
||||
if (broadcastSettingsVariant.isValid()) {
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
std::vector<HifiSockAddr> replicationNodesInSettings;
|
||||
|
||||
auto replicationSettings = settings.value(BROADCASTING_SETTINGS_KEY).toMap();
|
||||
auto replicationSettings = broadcastSettingsVariant.toMap();
|
||||
|
||||
QString serversKey = direction == Upstream ? "upstream_servers" : "downstream_servers";
|
||||
QString replicationDirection = direction == Upstream ? "upstream" : "downstream";
|
||||
|
@ -2920,13 +2911,12 @@ void DomainServer::updateUpstreamNodes() {
|
|||
|
||||
void DomainServer::updateReplicatedNodes() {
|
||||
// Make sure we have downstream nodes in our list
|
||||
auto settings = _settingsManager.getSettingsMap();
|
||||
|
||||
static const QString REPLICATED_USERS_KEY = "users";
|
||||
_replicatedUsernames.clear();
|
||||
|
||||
if (settings.contains(BROADCASTING_SETTINGS_KEY)) {
|
||||
auto replicationSettings = settings.value(BROADCASTING_SETTINGS_KEY).toMap();
|
||||
|
||||
auto replicationVariant = _settingsManager.valueForKeyPath(BROADCASTING_SETTINGS_KEY);
|
||||
if (replicationVariant.isValid()) {
|
||||
auto replicationSettings = replicationVariant.toMap();
|
||||
if (replicationSettings.contains(REPLICATED_USERS_KEY)) {
|
||||
auto usersSettings = replicationSettings.value(REPLICATED_USERS_KEY).toList();
|
||||
for (auto& username : usersSettings) {
|
||||
|
@ -3114,17 +3104,17 @@ void DomainServer::processPathQueryPacket(QSharedPointer<ReceivedMessage> messag
|
|||
|
||||
// check out paths in the _configMap to see if we have a match
|
||||
auto keypath = QString(PATHS_SETTINGS_KEYPATH_FORMAT).arg(SETTINGS_PATHS_KEY).arg(pathQuery);
|
||||
const QVariant* pathMatch = valueForKeyPath(_settingsManager.getSettingsMap(), keypath);
|
||||
QVariant pathMatch = _settingsManager.valueForKeyPath(keypath);
|
||||
|
||||
if (pathMatch || pathQuery == INDEX_PATH) {
|
||||
if (pathMatch.isValid() || pathQuery == INDEX_PATH) {
|
||||
// we got a match, respond with the resulting viewpoint
|
||||
auto nodeList = DependencyManager::get<LimitedNodeList>();
|
||||
|
||||
QString responseViewpoint;
|
||||
|
||||
// if we didn't match the path BUT this is for the index path then send back our default
|
||||
if (pathMatch) {
|
||||
responseViewpoint = pathMatch->toMap()[PATH_VIEWPOINT_KEY].toString();
|
||||
if (pathMatch.isValid()) {
|
||||
responseViewpoint = pathMatch.toMap()[PATH_VIEWPOINT_KEY].toString();
|
||||
} else {
|
||||
const QString DEFAULT_INDEX_PATH = "/0,0,0/0,0,0,1";
|
||||
responseViewpoint = DEFAULT_INDEX_PATH;
|
||||
|
|
|
@ -38,6 +38,9 @@
|
|||
#include "DomainServerNodeData.h"
|
||||
|
||||
const QString SETTINGS_DESCRIPTION_RELATIVE_PATH = "/resources/describe-settings.json";
|
||||
const QString SETTINGS_PATH = "/settings";
|
||||
const QString SETTINGS_PATH_JSON = SETTINGS_PATH + ".json";
|
||||
const QString CONTENT_SETTINGS_PATH_JSON = "/content-settings.json";
|
||||
|
||||
const QString DESCRIPTION_SETTINGS_KEY = "settings";
|
||||
const QString SETTING_DEFAULT_KEY = "default";
|
||||
|
@ -190,6 +193,9 @@ void DomainServerSettingsManager::processSettingsRequestPacket(QSharedPointer<Re
|
|||
}
|
||||
|
||||
void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList) {
|
||||
// since we're called from the DomainServerSettingsManager constructor, we don't take a write lock here
|
||||
// even though we change the underlying config map
|
||||
|
||||
_argumentList = argumentList;
|
||||
|
||||
_configMap.loadConfig(_argumentList);
|
||||
|
@ -448,17 +454,6 @@ void DomainServerSettingsManager::setupConfigMap(const QStringList& argumentList
|
|||
unpackPermissions();
|
||||
}
|
||||
|
||||
QVariantMap& DomainServerSettingsManager::getDescriptorsMap() {
|
||||
static const QString DESCRIPTORS{ "descriptors" };
|
||||
|
||||
auto& settingsMap = getSettingsMap();
|
||||
if (!getSettingsMap().contains(DESCRIPTORS)) {
|
||||
settingsMap.insert(DESCRIPTORS, QVariantMap());
|
||||
}
|
||||
|
||||
return *static_cast<QVariantMap*>(getSettingsMap()[DESCRIPTORS].data());
|
||||
}
|
||||
|
||||
void DomainServerSettingsManager::initializeGroupPermissions(NodePermissionsMap& permissionsRows,
|
||||
QString groupName, NodePermissionsPointer perms) {
|
||||
// this is called when someone has used the domain-settings webpage to add a group. They type the group's name
|
||||
|
@ -487,6 +482,9 @@ void DomainServerSettingsManager::initializeGroupPermissions(NodePermissionsMap&
|
|||
void DomainServerSettingsManager::packPermissionsForMap(QString mapName,
|
||||
NodePermissionsMap& permissionsRows,
|
||||
QString keyPath) {
|
||||
// grab a write lock on the settings mutex since we're about to change the config map
|
||||
QWriteLocker locker(&_settingsLock);
|
||||
|
||||
// find (or create) the "security" section of the settings map
|
||||
QVariant* security = _configMap.valueForKeyPath("security", true);
|
||||
if (!security->canConvert(QMetaType::QVariantMap)) {
|
||||
|
@ -576,15 +574,15 @@ bool DomainServerSettingsManager::unpackPermissionsForKeypath(const QString& key
|
|||
|
||||
mapPointer->clear();
|
||||
|
||||
QVariant* permissions = _configMap.valueForKeyPath(keyPath, true);
|
||||
if (!permissions->canConvert(QMetaType::QVariantList)) {
|
||||
QVariant permissions = valueForKeyPath(keyPath);
|
||||
|
||||
if (!permissions.canConvert(QMetaType::QVariantList)) {
|
||||
qDebug() << "Failed to extract permissions for key path" << keyPath << "from settings.";
|
||||
(*permissions) = QVariantList();
|
||||
}
|
||||
|
||||
bool needPack = false;
|
||||
|
||||
QList<QVariant> permissionsList = permissions->toList();
|
||||
QList<QVariant> permissionsList = permissions.toList();
|
||||
foreach (QVariant permsHash, permissionsList) {
|
||||
NodePermissionsPointer perms { new NodePermissions(permsHash.toMap()) };
|
||||
QString id = perms->getID();
|
||||
|
@ -1068,12 +1066,22 @@ NodePermissions DomainServerSettingsManager::getForbiddensForGroup(const QUuid&
|
|||
return getForbiddensForGroup(groupKey.first, groupKey.second);
|
||||
}
|
||||
|
||||
QVariant DomainServerSettingsManager::valueForKeyPath(const QString& keyPath) {
|
||||
QReadLocker locker(&_settingsLock);
|
||||
auto foundValue = _configMap.valueForKeyPath(keyPath);
|
||||
return foundValue ? *foundValue : QVariant();
|
||||
}
|
||||
|
||||
QVariant DomainServerSettingsManager::valueOrDefaultValueForKeyPath(const QString& keyPath) {
|
||||
QReadLocker locker(&_settingsLock);
|
||||
const QVariant* foundValue = _configMap.valueForKeyPath(keyPath);
|
||||
|
||||
if (foundValue) {
|
||||
return *foundValue;
|
||||
} else {
|
||||
// we don't need the settings lock anymore since we're done reading from the config map
|
||||
_settingsLock.unlock();
|
||||
|
||||
int dotIndex = keyPath.indexOf('.');
|
||||
|
||||
QString groupKey = keyPath.mid(0, dotIndex);
|
||||
|
@ -1112,9 +1120,6 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection
|
|||
// we recurse one level deep below each group for the appropriate setting
|
||||
bool restartRequired = recurseJSONObjectAndOverwriteSettings(postedObject, endpointType);
|
||||
|
||||
// store whatever the current _settingsMap is to file
|
||||
persistToFile();
|
||||
|
||||
// return success to the caller
|
||||
QString jsonSuccess = "{\"status\": \"success\"}";
|
||||
connection->respond(HTTPConnection::StatusCode200, jsonSuccess.toUtf8(), "application/json");
|
||||
|
@ -1216,16 +1221,9 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection
|
|||
}
|
||||
|
||||
bool DomainServerSettingsManager::restoreSettingsFromObject(QJsonObject settingsToRestore, SettingsType settingsType) {
|
||||
|
||||
if (thread() != QThread::currentThread()) {
|
||||
bool success;
|
||||
|
||||
BLOCKING_INVOKE_METHOD(this, "restoreSettingsFromObject",
|
||||
Q_RETURN_ARG(bool, success),
|
||||
Q_ARG(QJsonObject, settingsToRestore),
|
||||
Q_ARG(SettingsType, settingsType));
|
||||
return success;
|
||||
}
|
||||
// grab a write lock since we're about to change the settings map
|
||||
QWriteLocker locker(&_settingsLock);
|
||||
|
||||
QJsonArray* filteredDescriptionArray = settingsType == DomainSettings
|
||||
? &_domainSettingsDescription : &_contentSettingsDescription;
|
||||
|
@ -1341,6 +1339,10 @@ bool DomainServerSettingsManager::restoreSettingsFromObject(QJsonObject settings
|
|||
} else {
|
||||
// restore completed, persist the new settings
|
||||
qDebug() << "Restore completed, persisting restored settings to file";
|
||||
|
||||
// let go of the write lock since we're done making changes to the config map
|
||||
locker.unlock();
|
||||
|
||||
persistToFile();
|
||||
return true;
|
||||
}
|
||||
|
@ -1352,20 +1354,6 @@ QJsonObject DomainServerSettingsManager::settingsResponseObjectForType(const QSt
|
|||
bool includeDefaults, bool isForBackup) {
|
||||
QJsonObject responseObject;
|
||||
|
||||
if (thread() != QThread::currentThread()) {
|
||||
|
||||
BLOCKING_INVOKE_METHOD(this, "settingsResponseObjectForType",
|
||||
Q_RETURN_ARG(QJsonObject, responseObject),
|
||||
Q_ARG(QString, typeValue),
|
||||
Q_ARG(bool, isAuthenticated),
|
||||
Q_ARG(bool, includeDomainSettings),
|
||||
Q_ARG(bool, includeContentSettings),
|
||||
Q_ARG(bool, includeDefaults),
|
||||
Q_ARG(bool, isForBackup));
|
||||
|
||||
return responseObject;
|
||||
}
|
||||
|
||||
if (!typeValue.isEmpty() || isAuthenticated) {
|
||||
// convert the string type value to a QJsonValue
|
||||
QJsonValue queryType = typeValue.isEmpty() ? QJsonValue() : QJsonValue(typeValue.toInt());
|
||||
|
@ -1414,21 +1402,21 @@ QJsonObject DomainServerSettingsManager::settingsResponseObjectForType(const QSt
|
|||
QVariant variantValue;
|
||||
|
||||
if (!groupKey.isEmpty()) {
|
||||
QVariant settingsMapGroupValue = _configMap.value(groupKey);
|
||||
QVariant settingsMapGroupValue = valueForKeyPath(groupKey);
|
||||
|
||||
if (!settingsMapGroupValue.isNull()) {
|
||||
variantValue = settingsMapGroupValue.toMap().value(settingName);
|
||||
}
|
||||
} else {
|
||||
variantValue = _configMap.value(settingName);
|
||||
variantValue = valueForKeyPath(settingName);
|
||||
}
|
||||
|
||||
// final check for inclusion
|
||||
// either we include default values or we don't but this isn't a default value
|
||||
if (includeDefaults || !variantValue.isNull()) {
|
||||
if (includeDefaults || variantValue.isValid()) {
|
||||
QJsonValue result;
|
||||
|
||||
if (variantValue.isNull()) {
|
||||
if (!variantValue.isValid()) {
|
||||
// no value for this setting, pass the default
|
||||
if (settingObject.contains(SETTING_DEFAULT_KEY)) {
|
||||
result = settingObject[SETTING_DEFAULT_KEY];
|
||||
|
@ -1567,6 +1555,10 @@ QJsonObject DomainServerSettingsManager::settingDescriptionFromGroup(const QJson
|
|||
|
||||
bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject,
|
||||
SettingsType settingsType) {
|
||||
|
||||
// take a write lock since we're about to overwrite settings in the config map
|
||||
QWriteLocker locker(&_settingsLock);
|
||||
|
||||
static const QString SECURITY_ROOT_KEY = "security";
|
||||
static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist";
|
||||
static const QString BROADCASTING_KEY = "broadcasting";
|
||||
|
@ -1664,6 +1656,12 @@ bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJ
|
|||
}
|
||||
}
|
||||
|
||||
// we're done making changes to the config map, let go of our read lock
|
||||
locker.unlock();
|
||||
|
||||
// store whatever the current config map is to file
|
||||
persistToFile();
|
||||
|
||||
return needRestart;
|
||||
}
|
||||
|
||||
|
@ -1690,6 +1688,9 @@ bool permissionVariantLessThan(const QVariant &v1, const QVariant &v2) {
|
|||
}
|
||||
|
||||
void DomainServerSettingsManager::sortPermissions() {
|
||||
// take a write lock since we're about to change the config map data
|
||||
QWriteLocker locker(&_settingsLock);
|
||||
|
||||
// sort the permission-names
|
||||
QVariant* standardPermissions = _configMap.valueForKeyPath(AGENT_STANDARD_PERMISSIONS_KEYPATH);
|
||||
if (standardPermissions && standardPermissions->canConvert(QMetaType::QVariantList)) {
|
||||
|
@ -1726,11 +1727,15 @@ void DomainServerSettingsManager::persistToFile() {
|
|||
QFile settingsFile(_configMap.getUserConfigFilename());
|
||||
|
||||
if (settingsFile.open(QIODevice::WriteOnly)) {
|
||||
// take a read lock so we can grab the config and write it to file
|
||||
QReadLocker locker(&_settingsLock);
|
||||
settingsFile.write(QJsonDocument::fromVariant(_configMap.getConfig()).toJson());
|
||||
} else {
|
||||
qCritical("Could not write to JSON settings file. Unable to persist settings.");
|
||||
|
||||
// failed to write, reload whatever the current config state is
|
||||
// with a write lock since we're about to overwrite the config map
|
||||
QWriteLocker locker(&_settingsLock);
|
||||
_configMap.loadConfig(_argumentList);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,6 @@
|
|||
|
||||
const QString SETTINGS_PATHS_KEY = "paths";
|
||||
|
||||
const QString SETTINGS_PATH = "/settings";
|
||||
const QString SETTINGS_PATH_JSON = SETTINGS_PATH + ".json";
|
||||
const QString CONTENT_SETTINGS_PATH_JSON = "/content-settings.json";
|
||||
const QString AGENT_STANDARD_PERMISSIONS_KEYPATH = "security.standard_permissions";
|
||||
const QString AGENT_PERMISSIONS_KEYPATH = "security.permissions";
|
||||
const QString IP_PERMISSIONS_KEYPATH = "security.ip_permissions";
|
||||
|
@ -53,11 +50,12 @@ public:
|
|||
bool handleAuthenticatedHTTPRequest(HTTPConnection* connection, const QUrl& url);
|
||||
|
||||
void setupConfigMap(const QStringList& argumentList);
|
||||
|
||||
// each of the three methods in this group takes a read lock of _settingsLock
|
||||
// and cannot be called when the a write lock is held by the same thread
|
||||
QVariant valueOrDefaultValueForKeyPath(const QString& keyPath);
|
||||
|
||||
QVariantMap& getSettingsMap() { return _configMap.getConfig(); }
|
||||
|
||||
QVariantMap& getDescriptorsMap();
|
||||
QVariant valueForKeyPath(const QString& keyPath);
|
||||
bool containsKeyPath(const QString& keyPath) { return valueForKeyPath(keyPath).isValid(); }
|
||||
|
||||
// these give access to anonymous/localhost/logged-in settings from the domain-server settings page
|
||||
bool haveStandardPermissionsForName(const QString& name) const { return _standardAgentPermissions.contains(name, 0); }
|
||||
|
@ -119,6 +117,8 @@ public:
|
|||
/// thread safe method to restore settings from a JSON object
|
||||
Q_INVOKABLE bool restoreSettingsFromObject(QJsonObject settingsToRestore, SettingsType settingsType);
|
||||
|
||||
bool recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, SettingsType settingsType);
|
||||
|
||||
signals:
|
||||
void updateNodePermissions();
|
||||
void settingsUpdated();
|
||||
|
@ -138,12 +138,13 @@ private:
|
|||
QStringList _argumentList;
|
||||
|
||||
QJsonArray filteredDescriptionArray(bool isContentSettings);
|
||||
bool recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject, SettingsType settingsType);
|
||||
|
||||
void updateSetting(const QString& key, const QJsonValue& newValue, QVariantMap& settingMap,
|
||||
const QJsonObject& settingDescription);
|
||||
QJsonObject settingDescriptionFromGroup(const QJsonObject& groupObject, const QString& settingName);
|
||||
void sortPermissions();
|
||||
|
||||
// you cannot be holding the _settingsLock when persisting to file from the same thread
|
||||
// since it may take either a read lock or write lock and recursive locking doesn't allow a change in type
|
||||
void persistToFile();
|
||||
|
||||
void splitSettingsDescription();
|
||||
|
@ -155,10 +156,10 @@ private:
|
|||
QJsonArray _contentSettingsDescription;
|
||||
QJsonObject _settingsMenuGroups;
|
||||
|
||||
// any method that calls _valueForKeyPath on this _configMap must get a write lock it keeps until it
|
||||
// is done with the returned QVariant*
|
||||
HifiConfigVariantMap _configMap;
|
||||
|
||||
friend class DomainServer;
|
||||
|
||||
// these cause calls to metaverse's group api
|
||||
void apiGetGroupID(const QString& groupName);
|
||||
void apiGetGroupRanks(const QUuid& groupID);
|
||||
|
@ -192,6 +193,9 @@ private:
|
|||
|
||||
// keep track of answers to api queries about which users are in which groups
|
||||
QHash<QString, QHash<QUuid, QUuid>> _groupMembership; // QHash<user-name, QHash<group-id, rank-id>>
|
||||
|
||||
/// guard read/write access from multiple threads to settings
|
||||
QReadWriteLock _settingsLock { QReadWriteLock::Recursive };
|
||||
};
|
||||
|
||||
#endif // hifi_DomainServerSettingsManager_h
|
||||
|
|
Loading…
Reference in a new issue