mirror of
https://github.com/overte-org/overte.git
synced 2025-08-05 23:39:26 +02:00
Merge pull request #112 from kasenvr/fix/whitelist-qml-adds
Whitelist disabled by default, now has a toggle
This commit is contained in:
commit
900e66ac01
3 changed files with 183 additions and 141 deletions
|
@ -8,7 +8,7 @@
|
||||||
// Distributed under the Apache License, Version 2.0.
|
// Distributed under the Apache License, Version 2.0.
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
// Security Settings for the Entity Script Whitelist
|
// Security Settings for the Entity Script QML Whitelist
|
||||||
|
|
||||||
import Hifi 1.0 as Hifi
|
import Hifi 1.0 as Hifi
|
||||||
import QtQuick 2.8
|
import QtQuick 2.8
|
||||||
|
@ -21,145 +21,186 @@ import "../../../windows"
|
||||||
|
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
id: parentBody;
|
||||||
function getWhitelistAsText() {
|
|
||||||
var whitelist = Settings.getValue("private/settingsSafeURLS");
|
|
||||||
var arrayWhitelist = whitelist.split(",");
|
|
||||||
var whitelistText = arrayWhitelist.join("\n");
|
|
||||||
return whitelistText;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setWhitelistAsText(whitelistText) {
|
|
||||||
Settings.setValue("private/settingsSafeURLS", whitelistText.text);
|
|
||||||
|
|
||||||
var originalSetString = whitelistText.text;
|
|
||||||
var originalSet = originalSetString.split(' ').join('');
|
|
||||||
|
|
||||||
var check = Settings.getValue("private/settingsSafeURLS");
|
|
||||||
var arrayCheck = check.split(",");
|
|
||||||
var textCheck = arrayCheck.join("\n");
|
|
||||||
|
|
||||||
if(textCheck == originalSet) {
|
|
||||||
setWhitelistSuccess(true);
|
|
||||||
} else {
|
|
||||||
setWhitelistSuccess(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function setWhitelistSuccess(success) {
|
|
||||||
if(success) {
|
|
||||||
notificationText.text = "Successfully saved settings.";
|
|
||||||
} else {
|
|
||||||
notificationText.text = "Error! Settings not saved.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
width: parent.width;
|
|
||||||
height: 120;
|
|
||||||
color: "#80010203";
|
|
||||||
|
|
||||||
HifiStylesUit.RalewayRegular {
|
function getWhitelistAsText() {
|
||||||
id: titleText;
|
var whitelist = Settings.getValue("private/settingsSafeURLS");
|
||||||
text: "Entity Script Whitelist"
|
var arrayWhitelist = whitelist.split(",").join("\n");
|
||||||
// Text size
|
return arrayWhitelist;
|
||||||
size: 24;
|
}
|
||||||
// Style
|
|
||||||
color: "white";
|
function setWhitelistAsText(whitelistText) {
|
||||||
elide: Text.ElideRight;
|
Settings.setValue("private/settingsSafeURLS", whitelistText.text);
|
||||||
// Anchors
|
|
||||||
anchors.top: parent.top;
|
var originalSetString = whitelistText.text;
|
||||||
anchors.left: parent.left;
|
var originalSet = originalSetString.split(' ').join('');
|
||||||
anchors.leftMargin: 20;
|
|
||||||
anchors.right: parent.right;
|
var check = Settings.getValue("private/settingsSafeURLS");
|
||||||
anchors.rightMargin: 20;
|
var arrayCheck = check.split(",").join("\n");
|
||||||
height: 60;
|
|
||||||
}
|
setWhitelistSuccess(arrayCheck === originalSet);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setWhitelistSuccess(success) {
|
||||||
|
if (success) {
|
||||||
|
notificationText.text = "Successfully saved settings.";
|
||||||
|
} else {
|
||||||
|
notificationText.text = "Error! Settings not saved.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleWhitelist(enabled) {
|
||||||
|
Settings.setValue("private/whitelistEnabled", enabled);
|
||||||
|
console.info("Toggling Whitelist to:", enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
function initCheckbox() {
|
||||||
|
var check = Settings.getValue("private/whitelistEnabled", false);
|
||||||
|
|
||||||
|
if (check) {
|
||||||
|
whitelistEnabled.toggle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: textAreaRectangle;
|
anchors.fill: parent
|
||||||
color: "black";
|
|
||||||
width: parent.width;
|
width: parent.width;
|
||||||
height: 250;
|
height: 120;
|
||||||
anchors.top: titleText.bottom;
|
color: "#80010203";
|
||||||
|
|
||||||
ScrollView {
|
|
||||||
id: textAreaScrollView
|
|
||||||
anchors.fill: parent;
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
contentWidth: parent.width
|
|
||||||
contentHeight: parent.height
|
|
||||||
clip: false;
|
|
||||||
|
|
||||||
TextArea {
|
|
||||||
id: whitelistTextArea
|
|
||||||
text: getWhitelistAsText();
|
|
||||||
onTextChanged: notificationText.text = "";
|
|
||||||
width: parent.width;
|
|
||||||
height: parent.height;
|
|
||||||
font.family: "Ubuntu";
|
|
||||||
font.pointSize: 12;
|
|
||||||
color: "white";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: saveChanges
|
|
||||||
anchors.topMargin: 5;
|
|
||||||
anchors.leftMargin: 20;
|
|
||||||
anchors.rightMargin: 20;
|
|
||||||
x: textAreaRectangle.x + textAreaRectangle.width - width - 15;
|
|
||||||
y: textAreaRectangle.y + textAreaRectangle.height - height;
|
|
||||||
contentItem: Text {
|
|
||||||
text: saveChanges.text
|
|
||||||
font.family: "Ubuntu";
|
|
||||||
font.pointSize: 12;
|
|
||||||
opacity: enabled ? 1.0 : 0.3
|
|
||||||
color: "black"
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
text: "Save Changes"
|
|
||||||
onClicked: setWhitelistAsText(whitelistTextArea)
|
|
||||||
|
|
||||||
HifiStylesUit.RalewayRegular {
|
|
||||||
id: notificationText;
|
|
||||||
text: ""
|
|
||||||
// Text size
|
|
||||||
size: 14;
|
|
||||||
// Style
|
|
||||||
color: "white";
|
|
||||||
elide: Text.ElideLeft;
|
|
||||||
// Anchors
|
|
||||||
anchors.right: parent.right;
|
|
||||||
anchors.rightMargin: 130;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
HifiStylesUit.RalewayRegular {
|
HifiStylesUit.RalewayRegular {
|
||||||
id: descriptionText;
|
id: titleText;
|
||||||
text: "Separate your URLs by line, not commas. Example:
|
text: "Entity Script / QML Whitelist"
|
||||||
https://google.com/
|
|
||||||
https://bing.com/
|
|
||||||
https://mydomain.here/
|
|
||||||
\nEnsure there are no spaces or whitespace.
|
|
||||||
\nFor QML files, you can only whitelist each file individually
|
|
||||||
ending with '.qml'."
|
|
||||||
// Text size
|
// Text size
|
||||||
size: 16;
|
size: 24;
|
||||||
// Style
|
// Style
|
||||||
color: "white";
|
color: "white";
|
||||||
elide: Text.ElideRight;
|
elide: Text.ElideRight;
|
||||||
// Anchors
|
// Anchors
|
||||||
anchors.top: parent.bottom;
|
anchors.top: parent.top;
|
||||||
anchors.topMargin: 90;
|
|
||||||
anchors.left: parent.left;
|
anchors.left: parent.left;
|
||||||
anchors.leftMargin: 20;
|
anchors.leftMargin: 20;
|
||||||
anchors.right: parent.right;
|
anchors.right: parent.right;
|
||||||
anchors.rightMargin: 20;
|
anchors.rightMargin: 20;
|
||||||
|
height: 60;
|
||||||
|
|
||||||
|
CheckBox {
|
||||||
|
Component.onCompleted: {
|
||||||
|
initCheckbox();
|
||||||
|
}
|
||||||
|
|
||||||
|
id: whitelistEnabled;
|
||||||
|
|
||||||
|
anchors.right: parent.right;
|
||||||
|
anchors.top: parent.top;
|
||||||
|
anchors.topMargin: 10;
|
||||||
|
onToggled: {
|
||||||
|
toggleWhitelist(whitelistEnabled.checked)
|
||||||
|
}
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: "Enabled"
|
||||||
|
color: "white"
|
||||||
|
font.pixelSize: 18;
|
||||||
|
anchors.right: parent.left;
|
||||||
|
anchors.top: parent.top;
|
||||||
|
anchors.topMargin: 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
Rectangle {
|
||||||
|
id: textAreaRectangle;
|
||||||
|
color: "black";
|
||||||
|
width: parent.width;
|
||||||
|
height: 250;
|
||||||
|
anchors.top: titleText.bottom;
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
id: textAreaScrollView
|
||||||
|
anchors.fill: parent;
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
|
contentWidth: parent.width
|
||||||
|
contentHeight: parent.height
|
||||||
|
clip: false;
|
||||||
|
|
||||||
|
TextArea {
|
||||||
|
id: whitelistTextArea
|
||||||
|
text: getWhitelistAsText();
|
||||||
|
onTextChanged: notificationText.text = "";
|
||||||
|
width: parent.width;
|
||||||
|
height: parent.height;
|
||||||
|
font.family: "Ubuntu";
|
||||||
|
font.pointSize: 12;
|
||||||
|
color: "white";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
id: saveChanges
|
||||||
|
anchors.topMargin: 5;
|
||||||
|
anchors.leftMargin: 20;
|
||||||
|
anchors.rightMargin: 20;
|
||||||
|
x: textAreaRectangle.x + textAreaRectangle.width - width - 15;
|
||||||
|
y: textAreaRectangle.y + textAreaRectangle.height - height;
|
||||||
|
contentItem: Text {
|
||||||
|
text: saveChanges.text
|
||||||
|
font.family: "Ubuntu";
|
||||||
|
font.pointSize: 12;
|
||||||
|
opacity: enabled ? 1.0 : 0.3
|
||||||
|
color: "black"
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
text: "Save Changes"
|
||||||
|
onClicked: setWhitelistAsText(whitelistTextArea)
|
||||||
|
|
||||||
|
HifiStylesUit.RalewayRegular {
|
||||||
|
id: notificationText;
|
||||||
|
text: ""
|
||||||
|
// Text size
|
||||||
|
size: 16;
|
||||||
|
// Style
|
||||||
|
color: "white";
|
||||||
|
elide: Text.ElideLeft;
|
||||||
|
// Anchors
|
||||||
|
anchors.right: parent.left;
|
||||||
|
anchors.rightMargin: 10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HifiStylesUit.RalewayRegular {
|
||||||
|
id: descriptionText;
|
||||||
|
text:
|
||||||
|
"The whitelist checks scripts and QML as they are loaded.<br/>
|
||||||
|
Therefore, if a script is cached or has no reason to load again,<br/>
|
||||||
|
removing it from the whitelist will have no effect until<br/>
|
||||||
|
it is reloaded.<br/>
|
||||||
|
Separate your whitelisted domains by line, not commas. e.g.
|
||||||
|
<blockquote>
|
||||||
|
<b>https://google.com/</b><br/>
|
||||||
|
<b>hifi://the-spot/</b><br/>
|
||||||
|
<b>127.0.0.1</b><br/>
|
||||||
|
<b>https://mydomain.here/</b>
|
||||||
|
</blockquote>
|
||||||
|
Ensure there are no spaces or whitespace.<br/><br/>
|
||||||
|
For QML files, you can only whitelist each file individually<br/>
|
||||||
|
ending with '.qml'."
|
||||||
|
// Text size
|
||||||
|
size: 16;
|
||||||
|
// Style
|
||||||
|
color: "white";
|
||||||
|
elide: Text.ElideRight;
|
||||||
|
textFormat: Text.RichText;
|
||||||
|
// Anchors
|
||||||
|
anchors.top: parent.bottom;
|
||||||
|
anchors.topMargin: 90;
|
||||||
|
anchors.left: parent.left;
|
||||||
|
anchors.leftMargin: 20;
|
||||||
|
anchors.right: parent.right;
|
||||||
|
anchors.rightMargin: 20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -287,7 +287,7 @@ Menu::Menu() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Settings > Entity Script Whitelist
|
// Settings > Entity Script / QML Whitelist
|
||||||
action = addActionToQMenuAndActionHash(settingsMenu, "Entity Script / QML Whitelist");
|
action = addActionToQMenuAndActionHash(settingsMenu, "Entity Script / QML Whitelist");
|
||||||
connect(action, &QAction::triggered, [] {
|
connect(action, &QAction::triggered, [] {
|
||||||
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
|
auto tablet = DependencyManager::get<TabletScriptingInterface>()->getTablet("com.highfidelity.interface.tablet.system");
|
||||||
|
|
|
@ -2369,34 +2369,35 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
|
||||||
QList<QString> safeURLPrefixes = { "file:///", "atp:", "cache:" };
|
QList<QString> safeURLPrefixes = { "file:///", "atp:", "cache:" };
|
||||||
safeURLPrefixes += qEnvironmentVariable("EXTRA_WHITELIST").trimmed().split(QRegExp("\\s*,\\s*"), QString::SkipEmptyParts);
|
safeURLPrefixes += qEnvironmentVariable("EXTRA_WHITELIST").trimmed().split(QRegExp("\\s*,\\s*"), QString::SkipEmptyParts);
|
||||||
|
|
||||||
// IF WHITELIST IS DISABLED IN SETTINGS
|
// Entity Script Whitelist toggle check.
|
||||||
bool whitelistEnabled = Setting::Handle<bool>("private/whitelistEnabled", true).get();
|
Setting::Handle<bool> whitelistEnabled {"private/whitelistEnabled", false };
|
||||||
if (!whitelistEnabled) {
|
|
||||||
|
if (!whitelistEnabled.get()) {
|
||||||
passList = true;
|
passList = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// PULL SAFEURLS FROM INTERFACE.JSON Settings
|
// Pull SAFEURLS from the Interface.JSON settings.
|
||||||
QVariant raw = Setting::Handle<QVariant>("private/settingsSafeURLS").get();
|
QVariant raw = Setting::Handle<QVariant>("private/settingsSafeURLS").get();
|
||||||
QStringList settingsSafeURLS = raw.toString().trimmed().split(QRegExp("\\s*[,\r\n]+\\s*"), QString::SkipEmptyParts);
|
QStringList settingsSafeURLS = raw.toString().trimmed().split(QRegExp("\\s*[,\r\n]+\\s*"), QString::SkipEmptyParts);
|
||||||
safeURLPrefixes += settingsSafeURLS;
|
safeURLPrefixes += settingsSafeURLS;
|
||||||
// END PULL SAFEURLS FROM INTERFACE.JSON Settings
|
// END Pull SAFEURLS from the Interface.JSON settings.
|
||||||
|
|
||||||
// GET CURRENT DOMAIN WHITELIST BYPASS, IN CASE AN ENTIRE DOMAIN IS WHITELISTED
|
// Get current domain whitelist bypass, in case an entire domain is whitelisted.
|
||||||
QString currentDomain = DependencyManager::get<AddressManager>()->getDomainURL().host();
|
QString currentDomain = DependencyManager::get<AddressManager>()->getDomainURL().host();
|
||||||
|
|
||||||
QString domainSafeIP = nodeList->getDomainHandler().getHostname();
|
QString domainSafeIP = nodeList->getDomainHandler().getHostname();
|
||||||
QString domainSafeURL = URL_SCHEME_HIFI + "://" + currentDomain;
|
QString domainSafeURL = URL_SCHEME_HIFI + "://" + currentDomain;
|
||||||
for (const auto& str : safeURLPrefixes) {
|
for (const auto& str : safeURLPrefixes) {
|
||||||
if (domainSafeURL.startsWith(str) || domainSafeIP.startsWith(str)) {
|
if (domainSafeURL.startsWith(str) || domainSafeIP.startsWith(str)) {
|
||||||
qCDebug(scriptengine) << whitelistPrefix << "Whitelist Bypassed. Current Domain Host: "
|
qCDebug(scriptengine) << whitelistPrefix << "Whitelist Bypassed, entire domain is whitelisted. Current Domain Host: "
|
||||||
<< nodeList->getDomainHandler().getHostname()
|
<< nodeList->getDomainHandler().getHostname()
|
||||||
<< "Current Domain: " << currentDomain;
|
<< "Current Domain: " << currentDomain;
|
||||||
passList = true;
|
passList = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// END CURRENT DOMAIN WHITELIST BYPASS
|
// END bypass whitelist based on current domain.
|
||||||
|
|
||||||
// START CHECKING AGAINST THE WHITELIST
|
// Start processing scripts through the whitelist.
|
||||||
if (ScriptEngine::getContext() == "entity_server") { // If running on the server, do not engage whitelist.
|
if (ScriptEngine::getContext() == "entity_server") { // If running on the server, do not engage whitelist.
|
||||||
passList = true;
|
passList = true;
|
||||||
} else if (!passList) { // If waved through, do not engage whitelist.
|
} else if (!passList) { // If waved through, do not engage whitelist.
|
||||||
|
@ -2406,11 +2407,11 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co
|
||||||
if (!str.isEmpty() && scriptOrURL.startsWith(str)) {
|
if (!str.isEmpty() && scriptOrURL.startsWith(str)) {
|
||||||
passList = true;
|
passList = true;
|
||||||
qCDebug(scriptengine) << whitelistPrefix << "Script approved.";
|
qCDebug(scriptengine) << whitelistPrefix << "Script approved.";
|
||||||
break; // bail early since we found a match
|
break; // Bail early since we found a match.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// END CHECKING AGAINST THE WHITELIST
|
// END processing of scripts through the whitelist.
|
||||||
|
|
||||||
if (!passList) { // If the entity failed to pass for any reason, it's blocked and an error is thrown.
|
if (!passList) { // If the entity failed to pass for any reason, it's blocked and an error is thrown.
|
||||||
qCDebug(scriptengine) << whitelistPrefix << "(disabled entity script)" << entityID.toString() << scriptOrURL;
|
qCDebug(scriptengine) << whitelistPrefix << "(disabled entity script)" << entityID.toString() << scriptOrURL;
|
||||||
|
|
Loading…
Reference in a new issue