Skip to content

Commit

Permalink
sanitize user input when passing it to innerHTML in the UI
Browse files Browse the repository at this point in the history
* use dompurify library for that
* replaced many `innerHTML` assignments with `textContent`

Signed-off-by: Thomas Jäckle <thomas.jaeckle@beyonnex.io>
  • Loading branch information
thjaeckle committed May 17, 2024
1 parent aba53ad commit cce2e96
Show file tree
Hide file tree
Showing 17 changed files with 66 additions and 68 deletions.
12 changes: 6 additions & 6 deletions ui/modules/connections/connections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
/* eslint-disable require-jsdoc */
import * as API from '../api.js';
import * as Utils from '../utils.js';
import {TabHandler} from '../utils/tabHandler.js';
import { TabHandler } from '../utils/tabHandler.js';
import connectionsHTML from './connections.html';

const observers = [];
Expand Down Expand Up @@ -57,7 +57,7 @@ export function setConnection(connection, isNewConnection = false) {
}

export function loadConnections() {
dom.tbodyConnections.innerHTML = '';
dom.tbodyConnections.textContent = '';
let connectionSelected = false;
API.callConnectionsAPI('listConnections', (connections) => {
connections.forEach((connection) => {
Expand All @@ -66,15 +66,15 @@ export function loadConnections() {
row.id = id;
if (API.env() === 'ditto_2') {
API.callConnectionsAPI('retrieveConnection', (dittoConnection) => {
row.insertCell(0).innerHTML = dittoConnection.name;
row.insertCell(0).textContent = dittoConnection.name;
},
id);
} else {
row.insertCell(0).innerHTML = connection.name ? connection.name : id;
row.insertCell(0).textContent = connection.name ? connection.name : id;
}
API.callConnectionsAPI('retrieveStatus', (status) => {
row.insertCell(-1).innerHTML = status.liveStatus;
row.insertCell(-1).innerHTML = status.recoveryStatus;
row.insertCell(-1).textContent = status.liveStatus;
row.insertCell(-1).textContent = status.recoveryStatus;
},
id);
if (id === selectedConnectionId) {
Expand Down
6 changes: 3 additions & 3 deletions ui/modules/connections/connectionsMonitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ function onEnableConnectionLogsClick() {

function retrieveConnectionMetrics() {
Utils.assert(selectedConnectionId, 'Please select a connection', dom.tableValidationConnections);
dom.tbodyConnectionMetrics.innerHTML = '';
dom.tbodyConnectionMetrics.textContent = '';
API.callConnectionsAPI('retrieveConnectionMetrics', (response) => {
if (response.connectionMetrics) {
Object.keys(response.connectionMetrics).forEach((direction) => {
Expand Down Expand Up @@ -149,8 +149,8 @@ function onConnectionChange(connection, isNewConnection = true) {
selectedConnectionId = connection ? connection.id : null;
connectionStatusDetail.setValue('');
connectionLogDetail.setValue('');
dom.tbodyConnectionMetrics.innerHTML = '';
dom.tbodyConnectionLogs.innerHTML = '';
dom.tbodyConnectionMetrics.textContent = '';
dom.tbodyConnectionLogs.textContent = '';
if (!isNewConnection && connection && connection.id) {
retrieveConnectionLogs();
}
Expand Down
6 changes: 3 additions & 3 deletions ui/modules/environments/environments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
* SPDX-License-Identifier: EPL-2.0
*/

import * as Utils from '../utils.js';
/* eslint-disable arrow-parens */
/* eslint-disable prefer-const */
/* eslint-disable require-jsdoc */
import * as Authorization from './authorization.js';
import * as Utils from '../utils.js';
import defaultTemplates from './environmentTemplates.json';
import environmentsHTML from './environments.html';
import defaultTemplates from './environmentTemplates.json';


const URL_PRIMARY_ENVIRONMENT_NAME = 'primaryEnvironmentName';
Expand Down Expand Up @@ -222,7 +222,7 @@ export function environmentsJsonChanged(modifiedField = null) {
}

function updateEnvTable() {
dom.tbodyEnvironments.innerHTML = '';
dom.tbodyEnvironments.textContent = '';
Object.keys(environments).forEach((key) => {
Utils.addTableRow(dom.tbodyEnvironments, key, key === selectedEnvName);
});
Expand Down
4 changes: 2 additions & 2 deletions ui/modules/operations/operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ function loadAllLogLevels() {
API.callDittoREST('GET', '/devops/logging', null, null, false, true)
.then((result) => createLoggerView(result))
.catch((error) => {
dom.divLoggers.innerHTML = '';
dom.divLoggers.textContent = '';
});
}

function createLoggerView(allLogLevels) {
dom.divLoggers.innerHTML = '';
dom.divLoggers.textContent = '';

type LogLevel = {
loggerConfigs?: object[]
Expand Down
2 changes: 1 addition & 1 deletion ui/modules/policies/policies.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ function onThingChanged(thing) {
}

function refreshWhoAmI() {
dom.tbodyWhoami.innerHTML = '';
dom.tbodyWhoami.textContent = '';
API.callDittoREST('GET', '/whoami')
.then((whoamiResult) => {
whoamiResult.subjects.forEach((subject) => {
Expand Down
2 changes: 1 addition & 1 deletion ui/modules/things/attributes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ function refreshAttribute(thing, attributePath = null) {
function onThingChanged(thing) {
dom.crudAttribute.editDisabled = (thing === null);

dom.tbodyAttributes.innerHTML = '';
dom.tbodyAttributes.textContent = '';
let count = 0;
let thingHasAttribute = false;
if (thing && thing.attributes) {
Expand Down
4 changes: 2 additions & 2 deletions ui/modules/things/featureMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,11 @@ function clearAllFields() {
dom.inputMessageTimeout.value = '10';
acePayload.setValue('');
aceResponse.setValue('');
dom.ulMessageTemplates.innerHTML = '';
dom.ulMessageTemplates.textContent = '';
}

function refillTemplates() {
dom.ulMessageTemplates.innerHTML = '';
dom.ulMessageTemplates.textContent = '';
Utils.addDropDownEntries(dom.ulMessageTemplates, ['Saved message templates'], true);
if (theFeatureId && Environments.current().messageTemplates[theFeatureId]) {
Utils.addDropDownEntries(
Expand Down
2 changes: 1 addition & 1 deletion ui/modules/things/features.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ function refreshFeature(thing, featureId = null) {
function onThingChanged(thing) {
dom.crudFeature.editDisabled = (thing === null);
// Update features table
dom.tbodyFeatures.innerHTML = '';
dom.tbodyFeatures.textContent = '';
let count = 0;
let thingHasFeature = false;
if (thing && thing.features) {
Expand Down
8 changes: 4 additions & 4 deletions ui/modules/things/fields.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
import {Modal} from 'bootstrap';
import { Modal } from 'bootstrap';

import * as Environments from '../environments/environments.js';
import * as Utils from '../utils.js';
Expand Down Expand Up @@ -165,14 +165,14 @@ function onEnvironmentChanged() {
* (Re-)Initializes the fieldlist in the UI
*/
function updateFieldList() {
dom.fieldList.innerHTML = '';
dom.fieldList.textContent = '';
theFieldIndex = -1;
Environments.current().fieldList.forEach((field, i) => {
const fieldSelected = dom.fieldPath.value === field.path;
const row = dom.fieldList.insertRow();
Utils.addCheckboxToRow(row, i, field.active, toggleFieldActiveEventHandler);
row.insertCell(-1).innerHTML = field.path;
row.insertCell(-1).innerHTML = field['label'] ? field.label : null;
row.insertCell(-1).textContent = field.path;
row.insertCell(-1).textContent = field['label'] ? field.label : null;
if (fieldSelected) {
theFieldIndex = i;
row.classList.add('table-active');
Expand Down
2 changes: 1 addition & 1 deletion ui/modules/things/messagesIncoming.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function onMessageTableClick(event) {
function onResetMessagesClick() {
messages = [];
dom.badgeMessageIncomingCount.textContent = '';
dom.tbodyMessagesIncoming.innerHTML = '';
dom.tbodyMessagesIncoming.textContent = '';
messageDetail.setValue('');
}

Expand Down
8 changes: 3 additions & 5 deletions ui/modules/things/searchFilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,7 @@ export async function ready() {
});

dom.searchThings.onclick = () => {
fillHistory(dom.searchFilterEdit.value);
ThingsSearch.searchTriggered(dom.searchFilterEdit.value);
ThingsSearch.searchTriggered(dom.searchFilterEdit.value, () => fillHistory(dom.searchFilterEdit.value));
};

dom.searchFavorite.onclick = () => {
Expand All @@ -74,8 +73,7 @@ export async function ready() {

dom.searchFilterEdit.onkeyup = (event) => {
if ((event.key === 'Enter' || event.code === 13) && dom.searchFilterEdit.value.indexOf(FILTER_PLACEHOLDER) < 0) {
fillHistory(dom.searchFilterEdit.value);
ThingsSearch.searchTriggered(dom.searchFilterEdit.value);
ThingsSearch.searchTriggered(dom.searchFilterEdit.value, () => fillHistory(dom.searchFilterEdit.value));
} else {
clearTimeout(keyStrokeTimeout);
keyStrokeTimeout = setTimeout(checkIfFavorite, 1000);
Expand Down Expand Up @@ -107,7 +105,7 @@ function fillSearchFilterEdit(fillString) {
checkIfFavorite();
const filterEditNeeded = checkAndMarkParameter();
if (!filterEditNeeded) {
ThingsSearch.searchTriggered(dom.searchFilterEdit.value);
ThingsSearch.searchTriggered(dom.searchFilterEdit.value, () => null);
}
}

Expand Down
4 changes: 2 additions & 2 deletions ui/modules/things/thingMessages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,11 +152,11 @@ function clearAllFields() {
dom.inputThingMessageTimeout.value = '10';
acePayload.setValue('');
aceResponse.setValue('');
dom.ulThingMessageTemplates.innerHTML = '';
dom.ulThingMessageTemplates.textContent = '';
}

function refillTemplates() {
dom.ulThingMessageTemplates.innerHTML = '';
dom.ulThingMessageTemplates.textContent = '';
Utils.addDropDownEntries(dom.ulThingMessageTemplates, ['Saved message templates'], true);
if (Environments.current().messageTemplates['/']) {
Utils.addDropDownEntries(
Expand Down
2 changes: 1 addition & 1 deletion ui/modules/things/thingsCRUD.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ function onThingChanged(thingJson) {
updateThingJsonEditor();

function updateThingDetailsTable() {
dom.tbodyThingDetails.innerHTML = '';
dom.tbodyThingDetails.textContent = '';
if (thingJson) {
Utils.addTableRow(dom.tbodyThingDetails, 'thingId', false, true, thingJson.thingId);
Utils.addTableRow(dom.tbodyThingDetails, 'policyId', false, true, thingJson.policyId);
Expand Down
20 changes: 11 additions & 9 deletions ui/modules/things/thingsSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import { JSONPath } from 'jsonpath-plus';

import * as API from '../api.js';
import * as Environments from '../environments/environments.js';

import * as Utils from '../utils.js';
import { sanitizeHTML } from '../utils.js';
import * as Fields from './fields.js';
import * as Things from './things.js';
import * as ThingsSSE from './thingsSSE.js';
Expand Down Expand Up @@ -75,12 +75,14 @@ function onThingsTableClicked(event) {
/**
* Tests if the search filter is an RQL. If yes, things search is called otherwise just things get
* @param {String} filter search filter string containing an RQL or a thingId
* @param rqlFilterCallback a callback to invoke when the passed `filter` was a valid RQL statement
*/
export function searchTriggered(filter) {
export function searchTriggered(filter: string, rqlFilterCallback: () => void) {
lastSearch = filter;
const regex = /^(eq\(|ne\(|gt\(|ge\(|lt\(|le\(|in\(|like\(|ilike\(|exists\(|and\(|or\(|not\().*/;
if (filter === '' || regex.test(filter)) {
searchThings(filter);
rqlFilterCallback();
} else {
getThings([filter]);
}
Expand All @@ -104,7 +106,7 @@ export function performLastSearch() {
if (lastSearch === 'pinned') {
pinnedTriggered();
} else {
searchTriggered(lastSearch);
searchTriggered(lastSearch, () => null);
}
}

Expand All @@ -113,7 +115,7 @@ export function performLastSearch() {
* @param {Array} thingIds Array of thingIds
*/
export function getThings(thingIds) {
dom.thingsTableBody.innerHTML = '';
dom.thingsTableBody.textContent = '';
const fieldsQueryParameter = Fields.getQueryParameter();
if (thingIds.length > 0) {
API.callDittoREST('GET',
Expand All @@ -134,8 +136,8 @@ export function getThings(thingIds) {

function resetAndClearViews(retainThing = false) {
theSearchCursor = null;
dom.thingsTableHead.innerHTML = '';
dom.thingsTableBody.innerHTML = '';
dom.thingsTableHead.textContent = '';
dom.thingsTableBody.textContent = '';
if (!retainThing) {
Things.setTheThing(null);
}
Expand Down Expand Up @@ -187,7 +189,7 @@ function searchThings(filter, isMore = false) {

function addMoreToThingList() {
const moreCell = dom.thingsTableBody.insertRow().insertCell(-1);
moreCell.innerHTML = 'load more...';
moreCell.textContent = 'load more...';
moreCell.colSpan = dom.thingsTableBody.rows[0].childElementCount;
moreCell.style.textAlign = 'center';
moreCell.style.cursor = 'pointer';
Expand Down Expand Up @@ -225,7 +227,7 @@ function fillThingsTable(thingsList) {
}

function fillHeaderRow() {
dom.thingsTableHead.innerHTML = '';
dom.thingsTableHead.textContent = '';
// Utils.addCheckboxToRow(dom.thingsTableHead, 'checkboxHead', false, null);
Utils.insertHeaderCell(dom.thingsTableHead, '');
Utils.insertHeaderCell(dom.thingsTableHead, 'Thing ID');
Expand Down Expand Up @@ -302,7 +304,7 @@ export function updateTableRow(thingUpdateJson) {
path: path,
});
if (elem.length !== 0) {
cell.innerHTML = elem[0];
cell.innerHTML = sanitizeHTML(elem[0]);
}
}
});
Expand Down
Loading

0 comments on commit cce2e96

Please sign in to comment.