Merge branch 'master' of github.com:highfidelity/hifi into qt-launcher

This commit is contained in:
danteruiz 2019-10-02 16:44:00 -07:00
commit 97644eb335
440 changed files with 14261 additions and 7321 deletions

View file

@ -71,9 +71,13 @@ RUN mkdir "$HIFI_BASE" && \
mkdir "$HIFI_VCPKG_BASE" && \
mkdir "$HIFI_ANDROID_PRECOMPILED"
RUN git clone https://github.com/jherico/hifi.git && \
# Checkout a relatively recent commit from the main repository and use it to cache the
# gradle and vcpkg dependencies
# This commit ID should be updated whenever someone changes the dependency list
# in cmake/ports
RUN git clone https://github.com/highfidelity/hifi.git && \
cd ~/hifi && \
git checkout quest/build
git checkout 796bfb5d6715ff14c2e60f3ee8fac1465b7578c6
WORKDIR /home/jenkins/hifi

View file

@ -84,7 +84,7 @@ Agent::Agent(ReceivedMessage& message) :
DependencyManager::get<EntityScriptingInterface>()->setPacketSender(&_entityEditSender);
DependencyManager::set<ResourceManager>();
DependencyManager::set<PluginManager>();
DependencyManager::set<PluginManager>()->instantiate();
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
@ -433,7 +433,7 @@ void Agent::executeScript() {
using namespace recording;
static const FrameType AUDIO_FRAME_TYPE = Frame::registerFrameType(AudioConstants::getAudioFrameName());
Frame::registerFrameHandler(AUDIO_FRAME_TYPE, [this, &scriptedAvatar](Frame::ConstPointer frame) {
Frame::registerFrameHandler(AUDIO_FRAME_TYPE, [this, &player, &scriptedAvatar](Frame::ConstPointer frame) {
if (_shouldMuteRecordingAudio) {
return;
}
@ -442,9 +442,18 @@ void Agent::executeScript() {
QByteArray audio(frame->data);
int16_t* samples = reinterpret_cast<int16_t*>(audio.data());
int numSamples = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL;
auto volume = player->getVolume();
if (volume >= 0.0f && volume < 1.0f) {
int32_t fract = (int32_t)(volume * (float)(1 << 16)); // Q16
for (int i = 0; i < numSamples; i++) {
samples[i] = (fract * (int32_t)samples[i]) >> 16;
}
}
if (_isNoiseGateEnabled) {
int16_t* samples = reinterpret_cast<int16_t*>(audio.data());
int numSamples = AudioConstants::NETWORK_FRAME_SAMPLES_PER_CHANNEL;
_audioGate.render(samples, samples, numSamples);
}
@ -511,6 +520,7 @@ void Agent::executeScript() {
DependencyManager::set<AssignmentParentFinder>(_entityViewer.getTree());
DependencyManager::get<ScriptEngines>()->runScriptInitializers(_scriptEngine);
_scriptEngine->run();
Frame::clearFrameHandler(AUDIO_FRAME_TYPE);

View file

@ -22,6 +22,7 @@
#include <AccountManager.h>
#include <AddressManager.h>
#include <Assignment.h>
#include <CrashAnnotations.h>
#include <LogHandler.h>
#include <LogUtils.h>
#include <LimitedNodeList.h>
@ -144,6 +145,7 @@ AssignmentClient::~AssignmentClient() {
}
void AssignmentClient::aboutToQuit() {
crash::annotations::setShutdownState(true);
stopAssignmentClient();
}
@ -173,6 +175,7 @@ void AssignmentClient::sendStatusPacketToACM() {
void AssignmentClient::sendAssignmentRequest() {
if (!_currentAssignment && !_isAssigned) {
crash::annotations::setShutdownState(false);
auto nodeList = DependencyManager::get<NodeList>();
@ -289,6 +292,8 @@ void AssignmentClient::handleAuthenticationRequest() {
}
void AssignmentClient::assignmentCompleted() {
crash::annotations::setShutdownState(true);
// we expect that to be here the previous assignment has completely cleaned up
assert(_currentAssignment.isNull());

View file

@ -22,6 +22,7 @@
#include <HifiConfigVariantMap.h>
#include <SharedUtil.h>
#include <ShutdownEventListener.h>
#include <shared/ScriptInitializerMixin.h>
#include "Assignment.h"
#include "AssignmentClient.h"
@ -239,7 +240,11 @@ AssignmentClientApp::AssignmentClientApp(int argc, char* argv[]) :
QThread::currentThread()->setObjectName("main thread");
LogHandler::getInstance().moveToThread(thread());
LogHandler::getInstance().setupRepeatedMessageFlusher();
DependencyManager::registerInheritance<LimitedNodeList, NodeList>();
DependencyManager::set<ScriptInitializers>();
if (numForks || minForks || maxForks) {
AssignmentClientMonitor* monitor = new AssignmentClientMonitor(numForks, minForks, maxForks,

View file

@ -499,6 +499,8 @@ void AvatarMixer::handleAvatarKilled(SharedNodePointer avatarNode) {
} else {
_sessionDisplayNames.erase(displayNameIter);
}
nodeData->getAvatar().stopChallengeTimer();
}
std::unique_ptr<NLPacket> killPacket;

View file

@ -33,12 +33,12 @@ MixerAvatar::MixerAvatar() {
_challengeTimer.setSingleShot(true);
_challengeTimer.setInterval(CHALLENGE_TIMEOUT_MS);
_challengeTimer.callOnTimeout([this]() {
_challengeTimer.callOnTimeout(this, [this]() {
if (_verifyState == challengeClient) {
_pendingEvent = false;
_verifyState = verificationFailed;
_needsIdentityUpdate = true;
qCDebug(avatars) << "Dynamic verification TIMED-OUT for " << getDisplayName() << getSessionUUID();
qCDebug(avatars) << "Dynamic verification TIMED-OUT for" << getDisplayName() << getSessionUUID();
} else {
qCDebug(avatars) << "Ignoring timeout of avatar challenge";
}
@ -287,7 +287,7 @@ void MixerAvatar::processCertifyEvents() {
<< ":" << _dynamicMarketResponse;
}
} else {
qCDebug(avatars) << "Get owner status failed for " << getDisplayName() << _marketplaceIdFromURL <<
qCDebug(avatars) << "Get owner status failed for" << getDisplayName() << _marketplaceIdFromURL <<
"message:" << responseJson["message"].toString();
_verifyState = error;
}
@ -332,7 +332,7 @@ void MixerAvatar::sendOwnerChallenge() {
void MixerAvatar::processChallengeResponse(ReceivedMessage& response) {
QByteArray avatarID;
QMutexLocker certifyLocker(&_avatarCertifyLock);
QMetaObject::invokeMethod(&_challengeTimer, &QTimer::stop);
stopChallengeTimer();
if (_verifyState == challengeClient) {
QByteArray responseData = response.readAll();
if (responseData.length() < 8) {
@ -356,7 +356,7 @@ void MixerAvatar::processChallengeResponse(ReceivedMessage& response) {
_verifyState = challengeResult ? verificationSucceeded : verificationFailed;
_needsIdentityUpdate = true;
if (_verifyState == verificationFailed) {
qCDebug(avatars) << "Dynamic verification FAILED for " << getDisplayName() << getSessionUUID();
qCDebug(avatars) << "Dynamic verification FAILED for" << getDisplayName() << getSessionUUID();
} else {
qCDebug(avatars) << "Dynamic verification SUCCEEDED for" << getDisplayName() << getSessionUUID();
}
@ -365,3 +365,11 @@ void MixerAvatar::processChallengeResponse(ReceivedMessage& response) {
qCDebug(avatars) << "WARNING: Unexpected avatar challenge-response in state" << stateToName(_verifyState);
}
}
void MixerAvatar::stopChallengeTimer() {
if (QThread::currentThread() == thread()) {
_challengeTimer.stop();
} else {
QMetaObject::invokeMethod(&_challengeTimer, &QTimer::stop);
}
}

View file

@ -34,6 +34,8 @@ public:
void processCertifyEvents();
void processChallengeResponse(ReceivedMessage& response);
void stopChallengeTimer();
// Avatar certification/verification:
enum VerifyState {
nonCertified, requestingFST, receivedFST, staticValidation, requestingOwner, ownerResponse,

View file

@ -17,9 +17,9 @@
#include <QJsonDocument>
#include <EntityTree.h>
#include <SimpleEntitySimulation.h>
#include <ResourceCache.h>
#include <ScriptCache.h>
#include <plugins/PluginManager.h>
#include <EntityEditFilters.h>
#include <NetworkingConstants.h>
#include <hfm/ModelFormatRegistry.h>
@ -36,12 +36,13 @@ const char* LOCAL_MODELS_PERSIST_FILE = "resources/models.svo";
EntityServer::EntityServer(ReceivedMessage& message) :
OctreeServer(message),
_entitySimulation(NULL),
_entitySimulation(nullptr),
_dynamicDomainVerificationTimer(this)
{
DependencyManager::set<ResourceManager>();
DependencyManager::set<ResourceCacheSharedItems>();
DependencyManager::set<ScriptCache>();
DependencyManager::set<PluginManager>()->instantiate();
DependencyManager::registerInheritance<EntityDynamicFactoryInterface, AssignmentDynamicFactory>();
DependencyManager::set<AssignmentDynamicFactory>();

View file

@ -16,9 +16,11 @@
#include <memory>
#include "EntityItem.h"
#include <EntityItem.h>
#include <EntityTree.h>
#include <SimpleEntitySimulation.h>
#include "EntityServerConsts.h"
#include "EntityTree.h"
/// Handles assignments of type EntityServer - sending entities to various clients.
@ -27,9 +29,6 @@ struct ViewerSendingStats {
quint64 lastEdited;
};
class SimpleEntitySimulation;
using SimpleEntitySimulationPointer = std::shared_ptr<SimpleEntitySimulation>;
class EntityServer : public OctreeServer, public NewlyCreatedEntityHook {
Q_OBJECT
public:

View file

@ -64,7 +64,7 @@ EntityScriptServer::EntityScriptServer(ReceivedMessage& message) : ThreadedAssig
DependencyManager::set<ResourceScriptingInterface>();
DependencyManager::set<ResourceManager>();
DependencyManager::set<PluginManager>();
DependencyManager::set<PluginManager>()->instantiate();
DependencyManager::registerInheritance<SpatialParentFinder, AssignmentParentFinder>();
@ -301,10 +301,17 @@ void EntityScriptServer::run() {
entityScriptingInterface->setEntityTree(_entityViewer.getTree());
DependencyManager::set<AssignmentParentFinder>(_entityViewer.getTree());
auto treePtr = _entityViewer.getTree();
DependencyManager::set<AssignmentParentFinder>(treePtr);
if (!_entitySimulation) {
SimpleEntitySimulationPointer simpleSimulation { new SimpleEntitySimulation() };
simpleSimulation->setEntityTree(treePtr);
treePtr->setSimulation(simpleSimulation);
_entitySimulation = simpleSimulation;
}
auto tree = _entityViewer.getTree().get();
auto tree = treePtr.get();
connect(tree, &EntityTree::deletingEntity, this, &EntityScriptServer::deletingEntity, Qt::QueuedConnection);
connect(tree, &EntityTree::addingEntity, this, &EntityScriptServer::addingEntity, Qt::QueuedConnection);
connect(tree, &EntityTree::entityServerScriptChanging, this, &EntityScriptServer::entityServerScriptChanging, Qt::QueuedConnection);
@ -451,10 +458,11 @@ void EntityScriptServer::resetEntitiesScriptEngine() {
connect(newEngine.data(), &ScriptEngine::update, this, [this] {
_entityViewer.queryOctree();
_entityViewer.getTree()->preUpdate();
_entityViewer.getTree()->update();
});
scriptEngines->runScriptInitializers(newEngine);
newEngine->runInThread();
auto newEngineSP = qSharedPointerCast<EntitiesScriptEngineProvider>(newEngine);
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(newEngineSP);

View file

@ -21,6 +21,7 @@
#include <EntityEditPacketSender.h>
#include <plugins/CodecPlugin.h>
#include <ScriptEngine.h>
#include <SimpleEntitySimulation.h>
#include <ThreadedAssignment.h>
#include "../entities/EntityTreeHeadlessViewer.h"
@ -75,6 +76,7 @@ private:
static int _entitiesScriptEngineCount;
ScriptEnginePointer _entitiesScriptEngine;
SimpleEntitySimulationPointer _entitySimulation;
EntityEditPacketSender _entityEditSender;
EntityTreeHeadlessViewer _entityViewer;

View file

@ -34,7 +34,7 @@ if (WIN32)
list(APPEND CMAKE_PREFIX_PATH "${WINDOW_SDK_PATH}")
# /wd4351 disables warning C4351: new behavior: elements of array will be default initialized
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /wd4351")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP${HIFI_MAX_BUILD_CORES} /wd4351")
# /LARGEADDRESSAWARE enables 32-bit apps to use more than 2GB of memory.
# Caveats: http://stackoverflow.com/questions/2288728/drawbacks-of-using-largeaddressaware-for-32-bit-windows-executables
# TODO: Remove when building 64-bit.

View file

@ -38,7 +38,7 @@ macro(SET_PACKAGING_PARAMETERS)
set(BUILD_ORGANIZATION "High Fidelity")
set(HIGH_FIDELITY_PROTOCOL "hifi")
set(HIGH_FIDELITY_APP_PROTOCOL "hifiapp")
set(INTERFACE_BUNDLE_NAME "Interface")
set(INTERFACE_BUNDLE_NAME "interface")
set(INTERFACE_ICON_PREFIX "interface")
# add definition for this release type
@ -61,7 +61,7 @@ macro(SET_PACKAGING_PARAMETERS)
set(PR_BUILD 1)
set(BUILD_VERSION "PR${RELEASE_NUMBER}")
set(BUILD_ORGANIZATION "High Fidelity - PR${RELEASE_NUMBER}")
set(INTERFACE_BUNDLE_NAME "Interface")
set(INTERFACE_BUNDLE_NAME "interface")
set(INTERFACE_ICON_PREFIX "interface-beta")
# add definition for this release type
@ -70,7 +70,7 @@ macro(SET_PACKAGING_PARAMETERS)
set(DEV_BUILD 1)
set(BUILD_VERSION "dev")
set(BUILD_ORGANIZATION "High Fidelity - ${BUILD_VERSION}")
set(INTERFACE_BUNDLE_NAME "Interface")
set(INTERFACE_BUNDLE_NAME "interface")
set(INTERFACE_ICON_PREFIX "interface-beta")
# add definition for this release type
@ -192,12 +192,12 @@ macro(SET_PACKAGING_PARAMETERS)
# shortcut names
if (PRODUCTION_BUILD)
set(INTERFACE_SHORTCUT_NAME "High Fidelity Interface")
set(INTERFACE_SHORTCUT_NAME "High Fidelity")
set(CONSOLE_SHORTCUT_NAME "Console")
set(SANDBOX_SHORTCUT_NAME "Sandbox")
set(APP_USER_MODEL_ID "com.highfidelity.console")
else ()
set(INTERFACE_SHORTCUT_NAME "High Fidelity Interface - ${BUILD_VERSION_NO_SHA}")
set(INTERFACE_SHORTCUT_NAME "High Fidelity - ${BUILD_VERSION_NO_SHA}")
set(CONSOLE_SHORTCUT_NAME "Console - ${BUILD_VERSION_NO_SHA}")
set(SANDBOX_SHORTCUT_NAME "Sandbox - ${BUILD_VERSION_NO_SHA}")
endif ()

View file

@ -7,7 +7,8 @@
#
macro(SETUP_HIFI_CLIENT_SERVER_PLUGIN)
set(${TARGET_NAME}_SHARED 1)
setup_hifi_library(${ARGV})
set(PLUGIN_SUBFOLDER ${ARGN})
setup_hifi_library()
if (BUILD_CLIENT)
add_dependencies(interface ${TARGET_NAME})
@ -27,6 +28,11 @@ macro(SETUP_HIFI_CLIENT_SERVER_PLUGIN)
set(SERVER_PLUGIN_PATH "plugins")
endif()
if (PLUGIN_SUBFOLDER)
set(CLIENT_PLUGIN_PATH "${CLIENT_PLUGIN_PATH}/${PLUGIN_SUBFOLDER}")
set(SERVER_PLUGIN_PATH "${SERVER_PLUGIN_PATH}/${PLUGIN_SUBFOLDER}")
endif()
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_GENERATOR STREQUAL "Unix Makefiles")
set(CLIENT_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/interface/${CLIENT_PLUGIN_PATH}/")
set(SERVER_PLUGIN_FULL_PATH "${CMAKE_BINARY_DIR}/assignment-client/${SERVER_PLUGIN_PATH}/")

View file

@ -20,7 +20,7 @@ macro(SETUP_HIFI_LIBRARY)
foreach(SRC ${AVX_SRCS})
if (WIN32)
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS /arch:AVX)
elseif (APPLE OR UNIX)
elseif (APPLE OR (UNIX AND NOT ANDROID))
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS -mavx)
endif()
endforeach()
@ -30,7 +30,7 @@ macro(SETUP_HIFI_LIBRARY)
foreach(SRC ${AVX2_SRCS})
if (WIN32)
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS /arch:AVX2)
elseif (APPLE OR UNIX)
elseif (APPLE OR (UNIX AND NOT ANDROID))
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS "-mavx2 -mfma")
endif()
endforeach()
@ -44,7 +44,7 @@ macro(SETUP_HIFI_LIBRARY)
if (COMPILER_SUPPORTS_AVX512)
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS /arch:AVX512)
endif()
elseif (APPLE OR UNIX)
elseif (APPLE OR (UNIX AND NOT ANDROID))
check_cxx_compiler_flag("-mavx512f" COMPILER_SUPPORTS_AVX512)
if (COMPILER_SUPPORTS_AVX512)
set_source_files_properties(${SRC} PROPERTIES COMPILE_FLAGS -mavx512f)

View file

@ -15,9 +15,11 @@ macro(TARGET_WEBRTC)
# select_library_configurations(WEBRTC)
else()
set(WEBRTC_INCLUDE_DIRS "${VCPKG_INSTALL_ROOT}/include/webrtc")
find_library(WEBRTC_LIBRARY NAMES webrtc PATHS ${VCPKG_INSTALL_ROOT}/lib/ NO_DEFAULT_PATH)
target_include_directories(${TARGET_NAME} SYSTEM PUBLIC ${WEBRTC_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} ${WEBRTC_LIBRARY})
find_library(WEBRTC_LIBRARY_RELEASE webrtc PATHS ${VCPKG_INSTALL_ROOT}/lib NO_DEFAULT_PATH)
find_library(WEBRTC_LIBRARY_DEBUG webrtc PATHS ${VCPKG_INSTALL_ROOT}/debug/lib NO_DEFAULT_PATH)
select_library_configurations(WEBRTC)
target_link_libraries(${TARGET_NAME} ${WEBRTC_LIBRARIES})
endif()

View file

@ -1,38 +0,0 @@
#
# FindiViewHMD.cmake
#
# Try to find the SMI iViewHMD eye tracker library
#
# You must provide a IVIEWHMD_ROOT_DIR which contains 3rdParty, include, and libs directories
#
# Once done this will define
#
# IVIEWHMD_FOUND - system found iViewHMD
# IVIEWHMD_INCLUDE_DIRS - the iViewHMD include directory
# IVIEWHMD_LIBRARIES - link this to use iViewHMD
#
# Created on 27 Jul 2015 by David Rowe
# Copyright 2015 High Fidelity, Inc.
#
if (WIN32)
include("${MACRO_DIR}/HifiLibrarySearchHints.cmake")
hifi_library_search_hints("iViewHMD")
find_path(IVIEWHMD_INCLUDE_DIRS iViewHMDAPI.h PATH_SUFFIXES include HINTS ${IVIEWHMD_SEARCH_DIRS})
find_library(IVIEWHMD_LIBRARIES NAMES iViewHMDAPI PATH_SUFFIXES libs/x86 HINTS ${IVIEWHMD_SEARCH_DIRS})
find_path(IVIEWHMD_API_DLL_PATH iViewHMDAPI.dll PATH_SUFFIXES libs/x86 HINTS ${IVIEWHMD_SEARCH_DIRS})
list(APPEND IVIEWHMD_REQUIREMENTS IVIEWHMD_INCLUDE_DIRS IVIEWHMD_LIBRARIES IVIEWHMD_API_DLL_PATH)
find_path(IVIEWHMD_DLL_PATH_3RD_PARTY libiViewNG.dll PATH_SUFFIXES 3rdParty HINTS ${IVIEWHMD_SEARCH_DIRS})
list(APPEND IVIEWHMD_REQUIREMENTS IVIEWHMD_DLL_PATH_3RD_PARTY)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(IVIEWHMD DEFAULT_MSG ${IVIEWHMD_REQUIREMENTS})
add_paths_to_fixup_libs(${IVIEWHMD_API_DLL_PATH} ${IVIEWHMD_DLL_PATH_3RD_PARTY})
mark_as_advanced(IVIEWHMD_INCLUDE_DIRS IVIEWHMD_LIBRARIES IVIEWHMD_SEARCH_DIRS)
endif()

View file

@ -1156,7 +1156,17 @@ FunctionEnd
Section "-Core installation"
;The following delete blocks are temporary and can be removed once users who had the initial installer have updated
; 2016-02-25 - The following delete blocks are temporary and can be removed once users who had the initial installer have updated
; 2019-09-10 - (3 and a half years later) Sure they are buddy. Sure they are.
; MessageBox MB_OK|MB_ICONEXCLAMATION "installer type is @INSTALLER_TYPE@"
;Delete any server executables that might have been installed by bad versions of the client-only installer, but ONLY if we are a client-only installer
${If} "@INSTALLER_TYPE@" == "client_only"
; MessageBox MB_OK|MB_ICONEXCLAMATION "trying to delete server binaries"
Delete "$INSTDIR\assignment-client.exe"
Delete "$INSTDIR\domain-server.exe"
${EndIf}
;Delete any server-console files installed before it was placed in sub-folder
Delete "$INSTDIR\server-console.exe"

View file

@ -1,5 +1,5 @@
{
"version": 2.3,
"version": 2.4,
"settings": [
{
"name": "metaverse",
@ -1705,6 +1705,114 @@
}
]
},
{
"name": "oauth",
"label": "OAuth",
"show_on_enable": true,
"settings": [
{
"name": "enable",
"type": "checkbox",
"default": false,
"hidden": true
},
{
"name": "admin-users",
"label": "Admin Users",
"type": "table",
"can_add_new_rows": true,
"help": "Any of these users can administer the domain.",
"numbered": false,
"backup": false,
"advanced": false,
"columns": [
{
"name": "username",
"label": "Username",
"can_set": true
}
]
},
{
"name": "admin-roles",
"label": "Admin Roles",
"type": "table",
"can_add_new_rows": true,
"help": "Any user with any of these metaverse roles can administer the domain.",
"numbered": false,
"backup": false,
"advanced": true,
"columns": [
{
"name": "role",
"label": "Role",
"can_set": true
}
]
},
{
"name": "client-id",
"label": "Client ID",
"help": "OAuth client ID.",
"default": "",
"advanced": true,
"backup": false
},
{
"name": "client-secret",
"label": "Client Secret",
"help": "OAuth client secret.",
"type": "password",
"password_placeholder": "******",
"value-hidden": true,
"advanced": true,
"backup": false
},
{
"name": "provider",
"label": "Provider",
"help": "OAuth provider URL.",
"default": "https://metaverse.highfidelity.com",
"advanced": true,
"backup": false
},
{
"name": "hostname",
"label": "Hostname",
"help": "OAuth hostname.",
"default": "",
"advanced": true,
"backup": false
},
{
"name": "key-passphrase",
"label": "SSL Private Key Passphrase",
"help": "SSL Private Key Passphrase",
"type": "password",
"password_placeholder": "******",
"value-hidden": true,
"advanced": true,
"backup": false
},
{
"name": "cert-fingerprint",
"type": "hidden",
"readonly": true,
"advanced": true,
"backup": false
},
{
"name": "cert",
"advanced": true,
"backup": false
},
{
"name": "key",
"advanced": true,
"backup": false
}
]
},
{
"name": "automatic_content_archives",
"label": "Automatic Content Archives",

View file

@ -2,6 +2,9 @@ var DomainInfo = null;
var viewHelpers = {
getFormGroup: function(keypath, setting, values, isAdvanced) {
if (setting.hidden) {
return "";
}
form_group = "<div class='form-group " +
(isAdvanced ? Settings.ADVANCED_CLASS : "") + " " +
(setting.deprecated ? Settings.DEPRECATED_CLASS : "" ) + "' " +
@ -82,8 +85,9 @@ var viewHelpers = {
"placeholder='" + (_.has(setting, 'placeholder') ? setting.placeholder : "") +
"' value='" + (_.has(setting, 'password_placeholder') ? setting.password_placeholder : setting_value) + "'/>"
}
form_group += "<span class='help-block'>" + setting.help + "</span>"
if (setting.help) {
form_group += "<span class='help-block'>" + setting.help + "</span>"
}
}
}
@ -114,12 +118,17 @@ function reloadSettings(callback) {
data.descriptions.push(Settings.extraGroupsAtEnd[endGroupIndex]);
}
data.descriptions = data.descriptions.map(function(x) {
x.hidden = x.hidden || (x.show_on_enable && data.values[x.name] && !data.values[x.name].enable);
return x;
});
$('#panels').html(Settings.panelsTemplate(data));
Settings.data = data;
Settings.initialValues = form2js('settings-form', ".", false, cleanupFormValues, true);
Settings.afterReloadActions();
Settings.afterReloadActions(data);
// setup any bootstrap switches
$('.toggle-checkbox').bootstrapSwitch();
@ -129,10 +138,14 @@ function reloadSettings(callback) {
Settings.pendingChanges = 0;
// call the callback now that settings are loaded
callback(true);
if (callback) {
callback(true);
}
}).fail(function() {
// call the failure object since settings load faild
callback(false)
if (callback) {
callback(false);
}
});
}
@ -237,14 +250,14 @@ $(document).ready(function(){
// set focus to the first input in the new row
$target.closest('table').find('tr.inputs input:first').focus();
}
} else {
var tableRows = sibling.parent();
var tableBody = tableRows.parent();
var tableRows = sibling.parent();
var tableBody = tableRows.parent();
// if theres no more siblings, we should jump to a new row
if (sibling.next().length == 0 && tableRows.nextAll().length == 1) {
tableBody.find("." + Settings.ADD_ROW_BUTTON_CLASS).click();
// if theres no more siblings, we should jump to a new row
if (sibling.next().length == 0 && tableRows.nextAll().length == 1) {
tableBody.find("." + Settings.ADD_ROW_BUTTON_CLASS).click();
}
}
}

View file

@ -18,7 +18,19 @@ $(document).ready(function(){
Settings.extraGroupsAtIndex = Settings.extraDomainGroupsAtIndex;
var METAVERSE_URL = URLs.METAVERSE_URL;
Settings.afterReloadActions = function() {
var SSL_PRIVATE_KEY_FILE_ID = 'ssl-private-key-file';
var SSL_PRIVATE_KEY_CONTENTS_ID = 'key-contents';
var SSL_PRIVATE_KEY_CONTENTS_NAME = 'oauth.key-contents';
var SSL_CERT_UPLOAD_ID = 'ssl-cert-button';
var SSL_CERT_FILE_ID = 'ssl-cert-file';
var SSL_CERT_FINGERPRINT_ID = 'cert-fingerprint';
var SSL_CERT_FINGERPRINT_SPAN_ID = 'cert-fingerprint-span-id';
var SSL_CERT_CONTENTS_ID = 'cert-contents';
var SSL_CERT_CONTENTS_NAME = 'oauth.cert-contents';
var SSL_PRIVATE_KEY_PATH = 'oauth.key';
var SSL_CERT_PATH = 'oauth.cert';
Settings.afterReloadActions = function(data) {
getMetaverseUrl(function(metaverse_url) {
METAVERSE_URL = metaverse_url;
@ -32,6 +44,8 @@ $(document).ready(function(){
setupDomainNetworkingSettings();
// setupDomainLabelSetting();
setupSettingsOAuth(data);
setupSettingsBackup();
if (domainIDIsSet()) {
@ -124,6 +138,48 @@ $(document).ready(function(){
}
}
if (formJSON["oauth"]) {
var private_key = formJSON["oauth"]["key-contents"];
var cert = formJSON["oauth"]["cert-contents"];
var oauthErrors = "";
if (private_key != undefined) {
var pattern = /-+BEGIN PRIVATE KEY-+[A-Za-z0-9+/\n=]*-+END PRIVATE KEY-+/m;
if (!pattern.test(private_key)) {
oauthErrors += "Private key must be in PEM format<BR/>";
}
}
if (cert != undefined) {
var pattern = /-+BEGIN CERTIFICATE-+[A-Za-z0-9+/\n=]*-+END CERTIFICATE-+/m;
if (!pattern.test(cert)) {
oauthErrors += "Certificate must be in PEM format<BR/>";
}
}
if ($('#oauth.panel').length) {
if (!$('input[name="oauth.client-id"]').val()) {
oauthErrors += "OAuth requires a client Id.<BR/>";
}
if (!$('input[name="oauth.provider"]').val()) {
oauthErrors += "OAuth requires a provider.<BR/>";
}
if (!$('input[name="oauth.hostname"]').val()) {
oauthErrors += "OAuth requires a hostname.<BR/>";
}
if (!$('input[name="' + SSL_PRIVATE_KEY_PATH + '"]').val() && !$('input[name="' + SSL_PRIVATE_KEY_CONTENTS_NAME + '"]').val()) {
oauthErrors += "OAuth requires an SSL Private Key.<BR/>";
}
if (!$('input[name="' + SSL_CERT_PATH + '"]').val() && !$('input[name="' + SSL_CERT_CONTENTS_NAME + '"]').val()) {
oauthErrors += "OAuth requires an SSL Certificate.<BR/>";
}
if (!$("table[name='oauth.admin-users'] tr.value-row").length &&
!$("table[name='oauth.admin-roles'] tr.value-row").length) {
oauthErrors += "OAuth must have at least one admin user or admin role.<BR/>";
}
}
if (oauthErrors) {
bootbox.alert({ "message": oauthErrors, "title": "OAuth Configuration Error" });
return false;
}
}
postSettings(formJSON);
};
@ -1035,6 +1091,67 @@ $(document).ready(function(){
});
}
function setupSettingsOAuth(data) {
// construct the HTML needed for the settings backup panel
var html = "<div class='form-group undefined'>";
html += "<label class='control-label'>SSL Private Key</label><BR/>";
html += "<label id='key-path-label'class='control-label'>Path</label>";
html += "<input id='" + SSL_PRIVATE_KEY_FILE_ID + "' type='file' accept='.key'/>";
html += "<input id='" + SSL_PRIVATE_KEY_CONTENTS_ID + "' name='" + SSL_PRIVATE_KEY_CONTENTS_NAME + "' type='hidden'/>";
html += "</div>";
html += "<div class='form-group undefined'>";
html += "<label class='control-label'>SSL Cert</label>";
html += "<div id='cert-fingerprint'><b>Fingerprint:</b><span id='" + SSL_CERT_FINGERPRINT_SPAN_ID + "'>" + data.values.oauth["cert-fingerprint"] + "</span></div>";
html += "<label id='cert-path-label' class='control-label'>Path</label>";
html += "<input id='" + SSL_CERT_FILE_ID + "' type='file' accept='.cer,.crt'/>";
html += "<input id='" + SSL_CERT_CONTENTS_ID + "' name='" + SSL_CERT_CONTENTS_NAME + "' type='hidden'/>";
html += "</div>";
$('#oauth-advanced').append(html);
$('#key-path-label').after($('[data-keypath="' + SSL_PRIVATE_KEY_PATH + '"]'));
$('#cert-path-label').after($('[data-keypath="' + SSL_CERT_PATH + '"]'));
$('[name="' + SSL_PRIVATE_KEY_PATH + '"]').val(data.values.oauth.key);
$('[name="' + SSL_CERT_PATH + '"]').val(data.values.oauth.cert);
$('body').on('change input propertychange', '#' + SSL_PRIVATE_KEY_FILE_ID, function(e){
var f = e.target.files[0];
var reader = new FileReader();
reader.onload = function(e) {
$('#' + SSL_PRIVATE_KEY_CONTENTS_ID).val(reader.result);
$('#' + SSL_PRIVATE_KEY_CONTENTS_ID).attr('data-changed', true);
$('[name="' + SSL_PRIVATE_KEY_PATH + '"]').val('');
badgeForDifferences($('#' + SSL_PRIVATE_KEY_CONTENTS_ID));
}
reader.readAsText(f);
});
$('body').on('change input propertychange', '#' + SSL_CERT_FILE_ID, function(e){
var f = e.target.files[0];
var reader = new FileReader();
reader.onload = function(e) {
$('#' + SSL_CERT_CONTENTS_ID).val(reader.result);
$('#' + SSL_CERT_CONTENTS_ID).attr('data-changed', true);
$('[name="' + SSL_CERT_PATH + '"]').val('');
$('#' + SSL_CERT_FINGERPRINT_SPAN_ID).text('');
badgeForDifferences($('#' + SSL_CERT_CONTENTS_ID));
}
reader.readAsText(f);
});
$('body').on('change input propertychange', '[name="' + SSL_PRIVATE_KEY_PATH + '"]', function(e){
$('#' + SSL_PRIVATE_KEY_FILE_ID).val('');
$('#' + SSL_PRIVATE_KEY_CONTENTS_ID).val('');
badgeForDifferences($('[name="' + SSL_PRIVATE_KEY_PATH + '"]').attr('data-changed', true));
});
$('body').on('change input propertychange', '[name="' + SSL_CERT_PATH + '"]', function(e){
$('#' + SSL_CERT_FILE_ID).val('');
$('#' + SSL_CERT_CONTENTS_ID).val('');
$('#' + SSL_CERT_FINGERPRINT_SPAN_ID).text('');
badgeForDifferences($('[name="' + SSL_CERT_PATH + '"]').attr('data-changed', true));
});
}
var RESTORE_SETTINGS_UPLOAD_ID = 'restore-settings-button';
var RESTORE_SETTINGS_FILE_ID = 'restore-settings-file';

View file

@ -32,6 +32,7 @@
#include <AccountManager.h>
#include <AssetClient.h>
#include <BuildInfo.h>
#include <CrashAnnotations.h>
#include <DependencyManager.h>
#include <HifiConfigVariantMap.h>
#include <HTTPConnection.h>
@ -174,6 +175,9 @@ DomainServer::DomainServer(int argc, char* argv[]) :
LogUtils::init();
LogHandler::getInstance().moveToThread(thread());
LogHandler::getInstance().setupRepeatedMessageFlusher();
qDebug() << "Setting up domain-server";
qDebug() << "[VERSION] Build sequence:" << qPrintable(applicationVersion());
qDebug() << "[VERSION] MODIFIED_ORGANIZATION:" << BuildInfo::MODIFIED_ORGANIZATION;
@ -182,6 +186,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
qDebug() << "[VERSION] BUILD_GLOBAL_SERVICES:" << BuildInfo::BUILD_GLOBAL_SERVICES;
qDebug() << "[VERSION] We will be using this name to find ICE servers:" << _iceServerAddr;
connect(this, &QCoreApplication::aboutToQuit, this, &DomainServer::aboutToQuit);
// make sure we have a fresh AccountManager instance
// (need this since domain-server can restart itself and maintain static variables)
@ -226,9 +231,10 @@ DomainServer::DomainServer(int argc, char* argv[]) :
setupGroupCacheRefresh();
// if we were given a certificate/private key or oauth credentials they must succeed
if (!(optionallyReadX509KeyAndCertificate() && optionallySetupOAuth())) {
return;
optionallySetupOAuth();
if (_oauthEnable) {
_oauthEnable = optionallyReadX509KeyAndCertificate();
}
_settingsManager.apiRefreshGroupInformation();
@ -319,7 +325,7 @@ DomainServer::DomainServer(int argc, char* argv[]) :
connect(_contentManager.get(), &DomainContentBackupManager::recoveryCompleted, this, &DomainServer::restart);
static const int NODE_PING_MONITOR_INTERVAL_MSECS = 1 * MSECS_PER_SECOND;
static const int NODE_PING_MONITOR_INTERVAL_MSECS = 1 * MSECS_PER_SECOND;
_nodePingMonitorTimer = new QTimer{ this };
connect(_nodePingMonitorTimer, &QTimer::timeout, this, &DomainServer::nodePingMonitor);
_nodePingMonitorTimer->start(NODE_PING_MONITOR_INTERVAL_MSECS);
@ -428,6 +434,10 @@ DomainServer::~DomainServer() {
DependencyManager::destroy<LimitedNodeList>();
}
void DomainServer::aboutToQuit() {
crash::annotations::setShutdownState(true);
}
void DomainServer::queuedQuit(QString quitMessage, int exitCode) {
if (!quitMessage.isEmpty()) {
qWarning() << qPrintable(quitMessage);
@ -447,8 +457,9 @@ QUuid DomainServer::getID() {
}
bool DomainServer::optionallyReadX509KeyAndCertificate() {
const QString X509_CERTIFICATE_OPTION = "cert";
const QString X509_PRIVATE_KEY_OPTION = "key";
const QString X509_CERTIFICATE_OPTION = "oauth.cert";
const QString X509_PRIVATE_KEY_OPTION = "oauth.key";
const QString X509_PRIVATE_KEY_PASSPHRASE_OPTION = "oauth.key-passphrase";
const QString X509_KEY_PASSPHRASE_ENV = "DOMAIN_SERVER_KEY_PASSPHRASE";
QString certPath = _settingsManager.valueForKeyPath(X509_CERTIFICATE_OPTION).toString();
@ -459,7 +470,12 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() {
// this is used for Oauth callbacks when authorizing users against a data server
// let's make sure we can load the key and certificate
QString keyPassphraseString = QProcessEnvironment::systemEnvironment().value(X509_KEY_PASSPHRASE_ENV);
QString keyPassphraseEnv = QProcessEnvironment::systemEnvironment().value(X509_KEY_PASSPHRASE_ENV);
QString keyPassphraseString = _settingsManager.valueForKeyPath(X509_PRIVATE_KEY_PASSPHRASE_OPTION).toString();
if (!keyPassphraseEnv.isEmpty()) {
keyPassphraseString = keyPassphraseEnv;
}
qDebug() << "Reading certificate file at" << certPath << "for HTTPS.";
qDebug() << "Reading key file at" << keyPath << "for HTTPS.";
@ -473,16 +489,15 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() {
QSslCertificate sslCertificate(&certFile);
QSslKey privateKey(&keyFile, QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, keyPassphraseString.toUtf8());
if (privateKey.isNull()) {
qCritical() << "SSL Private Key Not Loading. Bad password or key format?";
}
_httpsManager.reset(new HTTPSManager(QHostAddress::AnyIPv4, DOMAIN_SERVER_HTTPS_PORT, sslCertificate, privateKey, QString(), this));
qDebug() << "TCP server listening for HTTPS connections on" << DOMAIN_SERVER_HTTPS_PORT;
} else if (!certPath.isEmpty() || !keyPath.isEmpty()) {
static const QString MISSING_CERT_ERROR_MSG = "Missing certificate or private key. domain-server will now quit.";
static const int MISSING_CERT_ERROR_CODE = 3;
QMetaObject::invokeMethod(this, "queuedQuit", Qt::QueuedConnection,
Q_ARG(QString, MISSING_CERT_ERROR_MSG), Q_ARG(int, MISSING_CERT_ERROR_CODE));
return false;
}
@ -490,10 +505,12 @@ bool DomainServer::optionallyReadX509KeyAndCertificate() {
}
bool DomainServer::optionallySetupOAuth() {
const QString OAUTH_PROVIDER_URL_OPTION = "oauth-provider";
const QString OAUTH_CLIENT_ID_OPTION = "oauth-client-id";
const QString OAUTH_ENABLE_OPTION = "oauth.enable";
const QString OAUTH_PROVIDER_URL_OPTION = "oauth.provider";
const QString OAUTH_CLIENT_ID_OPTION = "oauth.client-id";
const QString OAUTH_CLIENT_SECRET_ENV = "DOMAIN_SERVER_CLIENT_SECRET";
const QString REDIRECT_HOSTNAME_OPTION = "hostname";
const QString OAUTH_CLIENT_SECRET_OPTION = "oauth.client-secret";
const QString REDIRECT_HOSTNAME_OPTION = "oauth.hostname";
_oauthProviderURL = QUrl(_settingsManager.valueForKeyPath(OAUTH_PROVIDER_URL_OPTION).toString());
@ -502,22 +519,24 @@ bool DomainServer::optionallySetupOAuth() {
_oauthProviderURL = NetworkingConstants::METAVERSE_SERVER_URL();
}
_oauthClientSecret = QProcessEnvironment::systemEnvironment().value(OAUTH_CLIENT_SECRET_ENV);
if (_oauthClientSecret.isEmpty()) {
_oauthClientSecret = _settingsManager.valueForKeyPath(OAUTH_CLIENT_SECRET_OPTION).toString();
}
auto accountManager = DependencyManager::get<AccountManager>();
accountManager->setAuthURL(_oauthProviderURL);
_oauthClientID = _settingsManager.valueForKeyPath(OAUTH_CLIENT_ID_OPTION).toString();
_oauthClientSecret = QProcessEnvironment::systemEnvironment().value(OAUTH_CLIENT_SECRET_ENV);
_hostname = _settingsManager.valueForKeyPath(REDIRECT_HOSTNAME_OPTION).toString();
if (!_oauthClientID.isEmpty()) {
_oauthEnable = _settingsManager.valueForKeyPath(OAUTH_ENABLE_OPTION).toBool();
if (_oauthEnable) {
if (_oauthProviderURL.isEmpty()
|| _hostname.isEmpty()
|| _oauthClientID.isEmpty()
|| _oauthClientSecret.isEmpty()) {
static const QString MISSING_OAUTH_INFO_MSG = "Missing OAuth provider URL, hostname, client ID, or client secret. domain-server will now quit.";
static const int MISSING_OAUTH_INFO_ERROR_CODE = 4;
QMetaObject::invokeMethod(this, "queuedQuit", Qt::QueuedConnection,
Q_ARG(QString, MISSING_OAUTH_INFO_MSG), Q_ARG(int, MISSING_OAUTH_INFO_ERROR_CODE));
_oauthEnable = false;
return false;
} else {
qDebug() << "OAuth will be used to identify clients using provider at" << _oauthProviderURL.toString();
@ -1746,8 +1765,8 @@ void DomainServer::nodePingMonitor() {
}
void DomainServer::processOctreeDataPersistMessage(QSharedPointer<ReceivedMessage> message) {
qDebug() << "Received octree data persist message";
auto data = message->readAll();
qDebug() << "Received octree data persist message" << (data.size() / 1000) << "kbytes.";
auto filePath = getEntitiesFilePath();
QDir dir(getEntitiesDirPath());
@ -1759,12 +1778,16 @@ void DomainServer::processOctreeDataPersistMessage(QSharedPointer<ReceivedMessag
QFile f(filePath);
if (f.open(QIODevice::WriteOnly)) {
f.write(data);
#ifdef EXPENSIVE_NETWORK_DIAGNOSTICS
// These diagnostics take take more than 200ms (depending on content size),
// causing Socket::readPendingDatagrams to overrun its timebox.
OctreeUtils::RawEntityData entityData;
if (entityData.readOctreeDataInfoFromData(data)) {
qCDebug(domain_server) << "Wrote new entities file" << entityData.id << entityData.dataVersion;
} else {
qCDebug(domain_server) << "Failed to read new octree data info";
}
#endif
} else {
qCDebug(domain_server) << "Failed to write new entities file:" << filePath;
}
@ -2689,8 +2712,8 @@ void DomainServer::profileRequestFinished() {
std::pair<bool, QString> DomainServer::isAuthenticatedRequest(HTTPConnection* connection) {
static const QByteArray HTTP_COOKIE_HEADER_KEY = "Cookie";
static const QString ADMIN_USERS_CONFIG_KEY = "admin-users";
static const QString ADMIN_ROLES_CONFIG_KEY = "admin-roles";
static const QString ADMIN_USERS_CONFIG_KEY = "oauth.admin-users";
static const QString ADMIN_ROLES_CONFIG_KEY = "oauth.admin-roles";
static const QString BASIC_AUTH_USERNAME_KEY_PATH = "security.http_username";
static const QString BASIC_AUTH_PASSWORD_KEY_PATH = "security.http_password";
const QString COOKIE_UUID_REGEX_STRING = HIFI_SESSION_COOKIE_KEY + "=([\\d\\w-]+)($|;)";
@ -2700,8 +2723,7 @@ std::pair<bool, QString> DomainServer::isAuthenticatedRequest(HTTPConnection* c
QVariant adminUsersVariant = _settingsManager.valueForKeyPath(ADMIN_USERS_CONFIG_KEY);
QVariant adminRolesVariant = _settingsManager.valueForKeyPath(ADMIN_ROLES_CONFIG_KEY);
if (!_oauthProviderURL.isEmpty()
&& (adminUsersVariant.isValid() || adminRolesVariant.isValid())) {
if (_oauthEnable) {
QString cookieString = connection->requestHeader(HTTP_COOKIE_HEADER_KEY);
QRegExp cookieUUIDRegex(COOKIE_UUID_REGEX_STRING);

View file

@ -136,6 +136,8 @@ private slots:
void tokenGrantFinished();
void profileRequestFinished();
void aboutToQuit();
signals:
void iceServerChanged();
void userConnected();
@ -236,6 +238,7 @@ private:
bool _isUsingDTLS { false };
bool _oauthEnable { false };
QUrl _oauthProviderURL;
QString _oauthClientID;
QString _oauthClientSecret;

View file

@ -22,7 +22,9 @@
#include <QtCore/QThread>
#include <QtCore/QUrl>
#include <QtCore/QUrlQuery>
#include <QtNetwork/QSslKey>
#include <QSaveFile>
#include <QPair>
#include <AccountManager.h>
#include <Assignment.h>
@ -46,10 +48,14 @@ const QString DESCRIPTION_SETTINGS_KEY = "settings";
const QString SETTING_DEFAULT_KEY = "default";
const QString DESCRIPTION_NAME_KEY = "name";
const QString DESCRIPTION_GROUP_LABEL_KEY = "label";
const QString DESCRIPTION_GROUP_SHOW_ON_ENABLE_KEY = "show_on_enable";
const QString DESCRIPTION_ENABLE_KEY = "enable";
const QString DESCRIPTION_BACKUP_FLAG_KEY = "backup";
const QString SETTING_DESCRIPTION_TYPE_KEY = "type";
const QString DESCRIPTION_COLUMNS_KEY = "columns";
const QString CONTENT_SETTING_FLAG_KEY = "content_setting";
static const QString SPLIT_MENU_GROUPS_DOMAIN_SETTINGS_KEY = "domain_settings";
static const QString SPLIT_MENU_GROUPS_CONTENT_SETTINGS_KEY = "content_settings";
const QString SETTINGS_VIEWPOINT_KEY = "viewpoint";
@ -136,6 +142,10 @@ void DomainServerSettingsManager::splitSettingsDescription() {
settingsDropdownGroup[DESCRIPTION_GROUP_LABEL_KEY] = groupObject[DESCRIPTION_GROUP_LABEL_KEY];
if (groupObject.contains(DESCRIPTION_GROUP_SHOW_ON_ENABLE_KEY)) {
settingsDropdownGroup[DESCRIPTION_GROUP_SHOW_ON_ENABLE_KEY] = groupObject[DESCRIPTION_GROUP_SHOW_ON_ENABLE_KEY];
}
static const QString DESCRIPTION_GROUP_HTML_ID_KEY = "html_id";
if (groupObject.contains(DESCRIPTION_GROUP_HTML_ID_KEY)) {
settingsDropdownGroup[DESCRIPTION_GROUP_HTML_ID_KEY] = groupObject[DESCRIPTION_GROUP_HTML_ID_KEY];
@ -170,9 +180,6 @@ void DomainServerSettingsManager::splitSettingsDescription() {
// populate the settings menu groups with what we've collected
static const QString SPLIT_MENU_GROUPS_DOMAIN_SETTINGS_KEY = "domain_settings";
static const QString SPLIT_MENU_GROUPS_CONTENT_SETTINGS_KEY = "content_settings";
_settingsMenuGroups[SPLIT_MENU_GROUPS_DOMAIN_SETTINGS_KEY] = domainSettingsMenuGroups;
_settingsMenuGroups[SPLIT_MENU_GROUPS_CONTENT_SETTINGS_KEY] = contentSettingsMenuGroups;
}
@ -448,6 +455,77 @@ void DomainServerSettingsManager::setupConfigMap(const QString& userConfigFilena
packPermissions();
}
if (oldVersion < 2.4) {
// migrate oauth settings to their own group
const QString ADMIN_USERS = "admin-users";
const QString OAUTH_ADMIN_USERS = "oauth.admin-users";
const QString OAUTH_CLIENT_ID = "oauth.client-id";
const QString ALT_ADMIN_USERS = "admin.users";
const QString ADMIN_ROLES = "admin-roles";
const QString OAUTH_ADMIN_ROLES = "oauth.admin-roles";
const QString OAUTH_ENABLE = "oauth.enable";
QVector<QPair<const char*, const char*> > conversionMap = {
{"key", "oauth.key"},
{"cert", "oauth.cert"},
{"hostname", "oauth.hostname"},
{"oauth-client-id", "oauth.client-id"},
{"oauth-provider", "oauth.provider"}
};
for (auto & conversion : conversionMap) {
QVariant* prevValue = _configMap.valueForKeyPath(conversion.first);
if (prevValue) {
auto newValue = _configMap.valueForKeyPath(conversion.second, true);
*newValue = *prevValue;
}
}
QVariant* client_id = _configMap.valueForKeyPath(OAUTH_CLIENT_ID);
if (client_id) {
QVariant* oauthEnable = _configMap.valueForKeyPath(OAUTH_ENABLE, true);
*oauthEnable = QVariant(true);
}
QVariant* oldAdminUsers = _configMap.valueForKeyPath(ADMIN_USERS);
QVariant* newAdminUsers = _configMap.valueForKeyPath(OAUTH_ADMIN_USERS, true);
QVariantList adminUsers(newAdminUsers->toList());
if (oldAdminUsers) {
QStringList adminUsersList = oldAdminUsers->toStringList();
for (auto & user : adminUsersList) {
if (!adminUsers.contains(user)) {
adminUsers.append(user);
}
}
}
QVariant* altAdminUsers = _configMap.valueForKeyPath(ALT_ADMIN_USERS);
if (altAdminUsers) {
QStringList adminUsersList = altAdminUsers->toStringList();
for (auto & user : adminUsersList) {
if (!adminUsers.contains(user)) {
adminUsers.append(user);
}
}
}
*newAdminUsers = adminUsers;
QVariant* oldAdminRoles = _configMap.valueForKeyPath(ADMIN_ROLES);
QVariant* newAdminRoles = _configMap.valueForKeyPath(OAUTH_ADMIN_ROLES, true);
QVariantList adminRoles(newAdminRoles->toList());
if (oldAdminRoles) {
QStringList adminRoleList = oldAdminRoles->toStringList();
for (auto & role : adminRoleList) {
if (!adminRoles.contains(role)) {
adminRoles.append(role);
}
}
}
*newAdminRoles = adminRoles;
}
// write the current description version to our settings
*versionVariant = _descriptionVersion;
@ -1185,7 +1263,24 @@ bool DomainServerSettingsManager::handleAuthenticatedHTTPRequest(HTTPConnection
return true;
} else if (url.path() == SETTINGS_MENU_GROUPS_PATH) {
connection->respond(HTTPConnection::StatusCode200, QJsonDocument(_settingsMenuGroups).toJson(), "application/json");
QJsonObject settings;
for (auto & key : _settingsMenuGroups.keys()) {
const QJsonArray& settingGroups = _settingsMenuGroups[key].toArray();
QJsonArray groups;
foreach (const QJsonValue& group, settingGroups) {
QJsonObject groupObject = group.toObject();
QVariant* enableKey = _configMap.valueForKeyPath(groupObject[DESCRIPTION_NAME_KEY].toString() + "." + DESCRIPTION_ENABLE_KEY);
if (!groupObject.contains(DESCRIPTION_GROUP_SHOW_ON_ENABLE_KEY)
|| (groupObject[DESCRIPTION_GROUP_SHOW_ON_ENABLE_KEY].toBool() && enableKey && enableKey->toBool() )) {
groups.append(groupObject);
}
}
settings[key] = groups;
}
connection->respond(HTTPConnection::StatusCode200, QJsonDocument(settings).toJson(), "application/json");
return true;
} else if (url.path() == SETTINGS_BACKUP_PATH) {
@ -1446,6 +1541,28 @@ QJsonObject DomainServerSettingsManager::settingsResponseObjectForType(const QSt
}
}
// add 'derived' values used primarily for UI
const QString X509_CERTIFICATE_OPTION = "oauth.cert";
QString certPath = valueForKeyPath(X509_CERTIFICATE_OPTION).toString();
if (!certPath.isEmpty()) {
// the user wants to use the following cert and key for HTTPS
// this is used for Oauth callbacks when authorizing users against a data server
// let's make sure we can load the key and certificate
qDebug() << "Reading certificate file at" << certPath << "for HTTPS.";
QFile certFile(certPath);
certFile.open(QIODevice::ReadOnly);
QSslCertificate sslCertificate(&certFile);
QString digest = sslCertificate.digest().toHex(':');
auto groupObject = responseObject["oauth"].toObject();
groupObject["cert-fingerprint"] = digest;
responseObject["oauth"] = groupObject;
}
return responseObject;
}
@ -1551,23 +1668,65 @@ QJsonObject DomainServerSettingsManager::settingDescriptionFromGroup(const QJson
return QJsonObject();
}
bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedObject,
bool DomainServerSettingsManager::recurseJSONObjectAndOverwriteSettings(const QJsonObject& postedSettingsObject,
SettingsType settingsType) {
// take a write lock since we're about to overwrite settings in the config map
QWriteLocker locker(&_settingsLock);
QJsonObject postedObject(postedSettingsObject);
static const QString SECURITY_ROOT_KEY = "security";
static const QString AC_SUBNET_WHITELIST_KEY = "ac_subnet_whitelist";
static const QString BROADCASTING_KEY = "broadcasting";
static const QString WIZARD_KEY = "wizard";
static const QString DESCRIPTION_ROOT_KEY = "descriptors";
static const QString OAUTH_ROOT_KEY = "oauth";
static const QString OAUTH_KEY_CONTENTS = "key-contents";
static const QString OAUTH_CERT_CONTENTS = "cert-contents";
static const QString OAUTH_CERT_PATH = "cert";
static const QString OAUTH_KEY_PASSPHRASE = "key-passphrase";
static const QString OAUTH_KEY_PATH = "key";
auto& settingsVariant = _configMap.getConfig();
bool needRestart = false;
auto& filteredDescriptionArray = settingsType == DomainSettings ? _domainSettingsDescription : _contentSettingsDescription;
auto oauthObject = postedObject[OAUTH_ROOT_KEY].toObject();
if (oauthObject.contains(OAUTH_CERT_CONTENTS)) {
QSslCertificate cert(oauthObject[OAUTH_CERT_CONTENTS].toString().toUtf8());
if (!cert.isNull()) {
static const QString CERT_FILE_NAME = "certificate.crt";
auto certPath = PathUtils::getAppDataFilePath(CERT_FILE_NAME);
QFile file(certPath);
if (file.open(QFile::WriteOnly)) {
file.write(cert.toPem());
file.close();
}
oauthObject[OAUTH_CERT_PATH] = certPath;
}
oauthObject.remove(OAUTH_CERT_CONTENTS);
}
if (oauthObject.contains(OAUTH_KEY_CONTENTS)) {
QString keyPassphraseString = oauthObject[OAUTH_KEY_PASSPHRASE].toString();
QSslKey key(oauthObject[OAUTH_KEY_CONTENTS].toString().toUtf8(), QSsl::Rsa, QSsl::Pem, QSsl::PrivateKey, keyPassphraseString.toUtf8());
if (!key.isNull()) {
static const QString KEY_FILE_NAME = "certificate.key";
auto keyPath = PathUtils::getAppDataFilePath(KEY_FILE_NAME);
QFile file(keyPath);
if (file.open(QFile::WriteOnly)) {
file.write(key.toPem());
file.close();
file.setPermissions(QFile::ReadOwner | QFile::WriteOwner);
}
oauthObject[OAUTH_KEY_PATH] = keyPath;
}
oauthObject.remove(OAUTH_KEY_CONTENTS);
}
postedObject[OAUTH_ROOT_KEY] = oauthObject;
// Iterate on the setting groups
foreach(const QString& rootKey, postedObject.keys()) {
const QJsonValue& rootValue = postedObject[rootKey];
@ -1752,6 +1911,8 @@ void DomainServerSettingsManager::persistToFile() {
_configMap.loadConfig();
return; // defend against future code
}
QFile(settingsFilename).setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner);
}
QStringList DomainServerSettingsManager::getAllKnownGroupNames() {

View file

@ -15,9 +15,10 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include <BuildInfo.h>
#include <CrashAnnotations.h>
#include <LogHandler.h>
#include <SharedUtil.h>
#include <BuildInfo.h>
#include "DomainServer.h"
@ -32,6 +33,7 @@ int main(int argc, char* argv[]) {
// use a do-while to handle domain-server restart
do {
crash::annotations::setShutdownState(false);
DomainServer domainServer(argc, argv);
currentExitCode = domainServer.exec();
} while (currentExitCode == DomainServer::EXIT_CODE_REBOOT);
@ -39,4 +41,3 @@ int main(int argc, char* argv[]) {
qInfo() << "Quitting.";
return currentExitCode;
}

View file

@ -70,12 +70,16 @@ file(GLOB_RECURSE INTERFACE_SRCS "src/*.cpp" "src/*.h")
GroupSources("src")
list(APPEND INTERFACE_SRCS ${RESOURCES_RCC})
# grab the Objective-C sources on OS X
if (APPLE)
file(GLOB_RECURSE INTERFACE_OBJCPP_SRCS "src/*.m" "src/*.mm")
list(APPEND INTERFACE_SRCS ${INTERFACE_OBJCPP_SRCS})
endif ()
# Add SpeechRecognizer if on Windows or OS X, otherwise remove
if (WIN32)
# Use .cpp and .h files as is.
elseif (APPLE)
file(GLOB INTERFACE_OBJCPP_SRCS "src/SpeechRecognizer.mm")
set(INTERFACE_SRCS ${INTERFACE_SRCS} ${INTERFACE_OBJCPP_SRCS})
get_filename_component(SPEECHRECOGNIZER_CPP "src/SpeechRecognizer.cpp" ABSOLUTE)
list(REMOVE_ITEM INTERFACE_SRCS ${SPEECHRECOGNIZER_CPP})
else ()
@ -117,6 +121,7 @@ if (APPLE)
# configure CMake to use a custom Info.plist
set_target_properties(${this_target} PROPERTIES MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.in)
set(MACOSX_BUNDLE_BUNDLE_NAME "High Fidelity")
if (PRODUCTION_BUILD)
set(MACOSX_BUNDLE_GUI_IDENTIFIER com.highfidelity.interface)
else ()
@ -151,7 +156,7 @@ elseif (WIN32)
set(CONFIGURE_ICON_RC_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/Icon.rc")
configure_file("${HF_CMAKE_DIR}/templates/Icon.rc.in" ${CONFIGURE_ICON_RC_OUTPUT})
set(APP_FULL_NAME "High Fidelity Interface")
set(APP_FULL_NAME "High Fidelity")
set(CONFIGURE_VERSION_INFO_RC_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/VersionInfo.rc")
configure_file("${HF_CMAKE_DIR}/templates/VersionInfo.rc.in" ${CONFIGURE_VERSION_INFO_RC_OUTPUT})

View file

@ -1,14 +0,0 @@
Instructions for adding SMI HMD Eye Tracking to Interface on Windows
David Rowe, 27 Jul 2015.
1. Download and install the SMI HMD Eye Tracking software from http://update.smivision.com/iViewNG-HMD.exe.
2. Copy the SDK folders (3rdParty, include, libs) from the SDK installation folder C:\Program Files (x86)\SMI\iViewNG-HMD\SDK
into the interface/externals/iViewHMD folder. This readme.txt should be there as well.
You may optionally choose to copy the SDK folders to a location outside the repository (so you can re-use with different
checkouts and different projects). If so, set the ENV variable "HIFI_LIB_DIR" to a directory containing a subfolder
"iViewHMD" that contains the folders mentioned above.
3. Clear your build directory, run cmake and build, and you should be all set.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.application-groups</key>
<array>
<string>high-fidelity.hifi</string>
</array>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.device.audio-input</key>
<true/>
<key>com.apple.security.network.client</key>
<true/>
<key>com.apple.security.network.server</key>
<true/>
</dict>
</plist>

Some files were not shown because too many files have changed in this diff Show more