Commit 3b2ce9e8 authored by Piotr Gawron's avatar Piotr Gawron
Browse files

Merge branch '276-xss-vulnerability' into 'master'

xss vulnerability

Closes #274

See merge request piotr.gawron/minerva!188
parents 41517275 61181a7d
Pipeline #3362 passed with stage
in 57 seconds
......@@ -6,6 +6,8 @@ var Promise = require("bluebird");
var logger = require('./logger');
var xss = require('xss');
var Functions = {};
/**
......@@ -253,7 +255,15 @@ Functions.createElement = function (params) {
result.type = params.inputType;
}
if (params.content !== null && params.content !== undefined) {
result.innerHTML = params.content;
if (params.xss !== false) {
var content = xss(params.content);
if (content !== params.content) {
logger.warn("XSS changed content: " + params.content);
}
result.innerHTML = content;
} else {
result.innerHTML = params.content;
}
}
if (params.style !== null && params.style !== undefined) {
result.style.cssText = params.style;
......
......@@ -11,6 +11,7 @@ var OptionsMenu = require('./OptionsMenu');
var Promise = require("bluebird");
var logger = require('../logger');
var xss = require('xss');
function Header(params) {
AbstractGuiElement.call(this, params);
......@@ -35,7 +36,7 @@ Header.prototype._createHeaderGui = function (guiParams) {
self.getElement().className = "minerva-header";
var projectId = self.getProject().getProjectId();
var projectName = self.getProject().getName();
var projectName = xss(self.getProject().getName());
var loadingDiv = Functions.createElement({
type: "div",
......@@ -55,7 +56,8 @@ Header.prototype._createHeaderGui = function (guiParams) {
var link = Functions.createElement({
type: "a",
style: "padding-right:15px; float:right",
content: '<i class="fa fa-lock" style="font-size:17px"></i>&nbsp;'
content: '<i class="fa fa-lock" style="font-size:17px"></i>&nbsp;',
xss: false
});
link.href = ServerConnector.getServerBaseUrl() + "admin.xhtml?id=" + projectId;
self.getElement().appendChild(link);
......@@ -84,7 +86,8 @@ Header.prototype._createHeaderGui = function (guiParams) {
var bottom = top + link.outerHeight();
return self._optionsMenu.open(left, bottom, e.timeStamp);
}
},
xss: false
});
self.getElement().appendChild(menuLink);
}
......@@ -93,7 +96,8 @@ Header.prototype._createHeaderGui = function (guiParams) {
var homeLink = Functions.createElement({
type: "a",
content: '<i class="fa fa-home" style="font-size:17px"></i> ' + projectName
content: '<i class="fa fa-home" style="font-size:17px"></i> ' + projectName,
xss: false
});
homeLink.href = ServerConnector.getServerBaseUrl() + "?id=" + projectId;
self.getElement().appendChild(homeLink);
......
......@@ -18,60 +18,62 @@ function Legend(params) {
Legend.prototype = Object.create(AbstractGuiElement.prototype);
Legend.prototype.constructor = Legend;
Legend.prototype._initializeGui = function() {
Legend.prototype._initializeGui = function () {
var self = this;
var legendDiv = Functions.createElement({
type : "div",
id : "legend-div",
className : "carousel slide",
type: "div",
id: "legend-div",
className: "carousel slide",
});
self.getElement().appendChild(legendDiv);
var indicators = Functions.createElement({
type : "ol",
name : "indicators",
className : "carousel-indicators",
type: "ol",
name: "indicators",
className: "carousel-indicators",
});
legendDiv.appendChild(indicators);
self.setControlElement(PanelControlElementType.LEGEND_INDICATORS_OL, indicators);
var slidesDiv = Functions.createElement({
type : "div",
name : "slides",
className : "carousel-inner",
role : "listbox",
type: "div",
name: "slides",
className: "carousel-inner",
role: "listbox",
});
legendDiv.appendChild(slidesDiv);
self.setControlElement(PanelControlElementType.LEGEND_SLIDES_DIV, slidesDiv);
var leftButton = Functions
.createElement({
type : "a",
className : "left carousel-control",
role : "button",
href : "#legend-div",
content : '<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span><span class="sr-only">Previous</span>',
});
.createElement({
type: "a",
className: "left carousel-control",
role: "button",
href: "#legend-div",
content: '<span class="glyphicon glyphicon-chevron-left" aria-hidden="true"></span><span class="sr-only">Previous</span>',
xss: false
});
leftButton.setAttribute("data-slide", "prev");
legendDiv.appendChild(leftButton);
var rightButton = Functions
.createElement({
type : "a",
className : "right carousel-control",
role : "button",
href : "#legend-div",
content : '<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span><span class="sr-only">Next</span>',
});
.createElement({
type: "a",
className: "right carousel-control",
role: "button",
href: "#legend-div",
content: '<span class="glyphicon glyphicon-chevron-right" aria-hidden="true"></span><span class="sr-only">Next</span>',
xss: false
});
rightButton.setAttribute("data-slide", "next");
legendDiv.appendChild(rightButton);
};
Legend.prototype.hide = function() {
Legend.prototype.hide = function () {
this.getElement().style.display = "none";
};
Legend.prototype.show = function() {
Legend.prototype.show = function () {
this.getElement().style.display = "block";
};
......@@ -98,12 +100,12 @@ function createLegendSlide(file, index) {
return result;
}
Legend.prototype.init = function() {
Legend.prototype.init = function () {
var self = this;
var element = self.getElement();
var menu = self.getControlElement(PanelControlElementType.LEGEND_INDICATORS_OL);
var slides = self.getControlElement(PanelControlElementType.LEGEND_SLIDES_DIV);
return ServerConnector.getConfigurationParam(ConfigurationType.LEGEND_FILES).then(function(legendFiles) {
return ServerConnector.getConfigurationParam(ConfigurationType.LEGEND_FILES).then(function (legendFiles) {
for (var i = 0; i < legendFiles.length; i++) {
var legendFile = legendFiles[i];
menu.appendChild(createLegendIndicator(legendFile, i));
......
......@@ -9,6 +9,7 @@ var PanelControlElementType = require('./PanelControlElementType');
var Functions = require('../Functions');
var logger = require('../logger');
var xss = require('xss');
function Panel(params) {
AbstractGuiElement.call(this, params);
......@@ -57,11 +58,12 @@ Panel.prototype.createHelpButton = function () {
type: "button",
className: "minerva-help-button",
content: '<span class="ui-icon ui-icon-help" style="margin-left: -0.5em;"/>',
xss: false
});
helpTipButton.onclick = function () {
var helpDialogDiv = Functions.createElement({
type: "div",
content: self.getHelpTip(),
content: xss(self.getHelpTip())
});
$(helpDialogDiv).dialog({
close: function () {
......
"use strict";
/* exported logger */
var Promise = require("bluebird");
var JSZip = require("jszip");
var xss = require('xss');
var AbstractGuiElement = require('../AbstractGuiElement');
var ChooseAnnotatorsDialog = require('./ChooseAnnotatorsDialog');
......@@ -12,6 +12,7 @@ var OverlayParser = require('../../map/OverlayParser');
var ZipEntry = require('./ZipEntry');
var Functions = require('../../Functions');
// noinspection JSUnusedLocalSymbols
var logger = require('../../logger');
var guiUtils = new (require('../leftPanel/GuiUtils'))();
......@@ -228,7 +229,8 @@ AddProjectDialog.prototype.createGeneralTabContent = function () {
return self.onSaveClicked().then(function () {
return self.close();
}, GuiConnector.alert);
}
},
xss: false
});
var cancelButton = Functions.createElement({
type: "button",
......@@ -236,7 +238,8 @@ AddProjectDialog.prototype.createGeneralTabContent = function () {
content: '<span class="ui-icon ui-icon-cancel"></span>&nbsp;CANCEL',
onclick: function () {
return self.close();
}
},
xss: false
});
var menuRow = Functions.createElement({
type: "div",
......@@ -253,12 +256,13 @@ AddProjectDialog.prototype.createInputRow = function (labelName, defaultValue, i
var label = new Functions.createElement({
type: "div",
style: "display:table-cell",
content: labelName
content: xss(labelName)
});
var input = new Functions.createElement({
type: "div",
style: "display:table-cell",
content: "<input name='" + inputName + "' value='" + defaultValue + "'/>"
content: "<input name='" + xss(inputName) + "' value='" + xss(defaultValue) + "'/>",
xss: false
});
return this.createRow([label, input]);
};
......@@ -267,7 +271,7 @@ AddProjectDialog.prototype.createCheckboxRow = function (labelName, defaultValue
var label = new Functions.createElement({
type: "div",
style: "display:table-cell",
content: labelName
content: xss(labelName)
});
var checked = "";
if (defaultValue) {
......@@ -276,7 +280,8 @@ AddProjectDialog.prototype.createCheckboxRow = function (labelName, defaultValue
var checkbox = new Functions.createElement({
type: "div",
style: "display:table-cell",
content: "<input type='checkbox' name='" + inputName + "' " + checked + "/>"
content: "<input type='checkbox' name='" + xss(inputName) + "' " + checked + "/>",
xss: false
});
var rowElements = [label, checkbox];
if (elements !== undefined) {
......@@ -854,7 +859,7 @@ AddProjectDialog.prototype.checkValidity = function () {
isValid = false;
}
var projectId = self.getProjectId();
if (!(/^[a-z0-9A-Z\-\_]+$/.test(projectId))){
if (!(/^[a-z0-9A-Z\-\_]+$/.test(projectId))) {
error += "<li>projectId can contain only alphanumeric characters and -_</li>";
isValid = false;
}
......
......@@ -30,13 +30,15 @@ ChooseAnnotatorsDialog.prototype.createGui = function () {
content.appendChild(Functions.createElement({
type: "div",
style: "display:table-cell",
content: "<div name='elementTree'/>"
content: "<div name='elementTree'/>",
xss: false
}));
content.appendChild(Functions.createElement({
type: "div",
style: "display:table-cell",
content: "<div name='annotatorListBox'/>"
content: "<div name='annotatorListBox'/>",
xss: false
}));
self.getElement().appendChild(content);
......
......@@ -30,13 +30,15 @@ ChooseValidatorsDialog.prototype.createGui = function () {
content.appendChild(Functions.createElement({
type: "div",
style: "display:table-cell",
content: "<div name='elementTree'/>"
content: "<div name='elementTree'/>",
xss: false
}));
content.appendChild(Functions.createElement({
type: "div",
style: "display:table-cell",
content: "<div name='annotatorListBox'/>"
content: "<div name='annotatorListBox'/>",
xss: false
}));
self.getElement().appendChild(content);
......
"use strict";
/* exported Promise*/
/* exported logger */
var AbstractAdminPanel = require('./AbstractAdminPanel');
var Functions = require('../../Functions');
// noinspection JSUnusedLocalSymbols
var logger = require('../../logger');
var Promise = require("bluebird");
var xss = require('xss');
function CommentsAdminPanel(params) {
AbstractAdminPanel.call(this, params);
......@@ -22,19 +21,19 @@ CommentsAdminPanel.prototype.constructor = CommentsAdminPanel;
CommentsAdminPanel.prototype._createGui = function () {
var self = this;
var projectsDiv = Functions.createElement({
type: "div",
type: "div"
});
self.getElement().appendChild(projectsDiv);
var dataDiv = Functions.createElement({
type: "div",
style: "display:table",
style: "display:table"
});
projectsDiv.appendChild(dataDiv);
var commentsCell = Functions.createElement({
type: "div",
style: "display:table-cell;width:100%;vertical-align:top",
style: "display:table-cell;width:100%;vertical-align:top"
});
projectsDiv.appendChild(commentsCell);
......@@ -42,37 +41,37 @@ CommentsAdminPanel.prototype._createGui = function () {
type: "table",
name: "commentsTable",
className: "display",
style: "width:100%",
style: "width:100%"
});
commentsCell.appendChild(commentsTable);
$(commentsTable).DataTable({
columns: [{
title: 'Id',
title: 'Id'
}, {
title: 'Title',
title: 'Title'
}, {
title: 'Author',
title: 'Author'
}, {
title: 'Email',
title: 'Email'
}, {
title: 'Content',
title: 'Content'
}, {
title: 'Removed',
title: 'Removed'
}, {
title: 'Pinned',
},],
title: 'Pinned'
}]
});
var projectsCell = Functions.createElement({
type: "div",
style: "display:table-cell",
style: "display:table-cell"
});
projectsDiv.appendChild(projectsCell);
var selectProject = Functions.createElement({
type: "select",
name: "projectSelect",
name: "projectSelect"
});
selectProject.size = "12";
selectProject.onchange = function () {
......@@ -81,7 +80,7 @@ CommentsAdminPanel.prototype._createGui = function () {
projectsCell.appendChild(Functions.createElement({
type: "h3",
content: "Project",
content: "Project"
}));
projectsCell.appendChild(selectProject);
};
......@@ -195,10 +194,10 @@ CommentsAdminPanel.prototype.commentToTableRow = function (comment) {
}
var row = [comment.getId(), //
title, //
author, //
email, //
comment.getContent(), //
xss(title), //
xss(author), //
xss(email), //
xss(comment.getContent()), //
remove, //
toYesNo(comment.isPinned())];
return row;
......
......@@ -13,6 +13,7 @@ var Functions = require('../../Functions');
var logger = require('../../logger');
var guiUtils = new (require('../leftPanel/GuiUtils'))();
var xss = require('xss');
function EditProjectDialog(params) {
AbstractGuiElement.call(this, params);
......@@ -130,7 +131,8 @@ EditProjectDialog.prototype.createGeneralTabContent = function () {
nameRow.appendChild(new Functions.createElement({
type: "div",
style: "display:table-cell",
content: "<input name='projectName' value='" + project.getName() + "'/>"
content: "<input name='projectName' value='" + xss(project.getName()) + "'/>",
xss: false
}));
var versionRow = new Functions.createElement({
......@@ -146,7 +148,8 @@ EditProjectDialog.prototype.createGeneralTabContent = function () {
versionRow.appendChild(new Functions.createElement({
type: "div",
style: "display:table-cell",
content: "<input name='projectVersion' value='" + project.getVersion() + "'/>"
content: "<input name='projectVersion' value='" + xss(project.getVersion()) + "'/>",
xss: false
}));
var diseaseRow = new Functions.createElement({
......@@ -161,12 +164,13 @@ EditProjectDialog.prototype.createGeneralTabContent = function () {
}));
var disease = "";
if (project.getDisease() !== undefined) {
disease = project.getDisease().getResource();
disease = xss(project.getDisease().getResource());
}
diseaseRow.appendChild(new Functions.createElement({
type: "div",
style: "display:table-cell",
content: "<input name='projectDisease' value='" + disease + "'/>"
content: "<input name='projectDisease' value='" + disease + "'/>",
xss: false
}));
var organismRow = new Functions.createElement({
......@@ -181,12 +185,13 @@ EditProjectDialog.prototype.createGeneralTabContent = function () {
}));
var organism = "";
if (project.getOrganism() !== undefined) {
organism = project.getOrganism().getResource();
organism = xss(project.getOrganism().getResource());
}
organismRow.appendChild(new Functions.createElement({
type: "div",
style: "display:table-cell",
content: "<input name='projectOrganism' value='" + organism + "'/>"
content: "<input name='projectOrganism' value='" + organism + "'/>",
xss: false
}));
var emailRow = new Functions.createElement({
......@@ -201,12 +206,13 @@ EditProjectDialog.prototype.createGeneralTabContent = function () {
}));
var email = "";
if (project.getNotifyEmail() !== undefined) {
email = project.getNotifyEmail();
email = xss(project.getNotifyEmail());
}
emailRow.appendChild(new Functions.createElement({
type: "div",
style: "display:table-cell",
content: "<input name='projectNotifyEmail' value='" + email + "'/>"
content: "<input name='projectNotifyEmail' value='" + email + "'/>",
xss: false
}));
var menuRow = Functions.createElement({
......@@ -224,7 +230,8 @@ EditProjectDialog.prototype.createGeneralTabContent = function () {
return self.onSaveClicked().then(function () {
return self.close();
}, GuiConnector.alert);
}
},
xss: false
});
var cancelButton = Functions.createElement({
type: "button",
......@@ -232,7 +239,8 @@ EditProjectDialog.prototype.createGeneralTabContent = function () {
content: '<span class="ui-icon ui-icon-cancel"></span>&nbsp;CANCEL',
onclick: function () {
return self.close();
}
},
xss: false
});
menuRow.appendChild(saveProjectButton);
menuRow.appendChild(cancelButton);
......
"use strict";
/* exported logger */
var Promise = require("bluebird");
var xss = require('xss');
var AbstractGuiElement = require('../AbstractGuiElement');
var GuiConnector = require('../../GuiConnector');
......@@ -128,7 +128,7 @@ function getStringIfDefined(value) {
if (value === undefined) {
return "";
}
return value;
return xss(value);
}
EditUserDialog.prototype.createGeneralTabContent = function () {
......@@ -159,13 +159,15 @@ EditUserDialog.prototype.createGeneralTabContent = function () {
loginRow.appendChild(new Functions.createElement({
type: "div",
style: "display:table-cell",
content: "<input name='userLogin' value=''/>"
content: "<input name='userLogin' value=''/>",
xss: false
}));
} else {
loginRow.appendChild(new Functions.createElement({
type: "div",
style: "display:table-cell",
content: "<input name='userLogin' value='" + getStringIfDefined(user.getLogin()) + "' readonly/>"
content: "<input name='userLogin' value='" + getStringIfDefined(user.getLogin()) + "' readonly/>",
xss: false
}));
}
......@@ -182,7 +184,8 @@ EditUserDialog.prototype.createGeneralTabContent = function () {
passwordRow.appendChild(new Functions.createElement({
type: "div",
style: "display:table-cell",
content: "<input type=\"password\" name='userPassword' value=''/>"
content: "<input type=\"password\" name='userPassword' value=''/>",
xss: false
}));
var passwordRow2 = new Functions.createElement({
......@@ -198,7 +201,8 @@ EditUserDialog.prototype.createGeneralTabContent = function () {
passwordRow2.appendChild(new Functions.createElement({
type: "div",
style: "display:table-cell",
content: "<input type=\"password\" name='userPassword2' value=''/>"
content: "<input type=\"password\" name='userPassword2' value=''/>",
xss: false
}));
var nameRow = new Functions.createElement({
......@@ -214,7 +218,8 @@ EditUserDialog.prototype.createGeneralTabContent = function () {
nameRow.appendChild(new Functions.createElement({
type: "div",
style: "display:table-cell",
content: "<input name='userName' value='" + getStringIfDefined(user.getName()) + "'/>"
content: "<input name='userName' value='" + getStringIfDefined(user.getName()) + "'/>",
xss: false
}));
var surnameRow = new Functions.createElement({
......@@ -230,7 +235,9 @@ EditUserDialog.prototype.createGeneralTabContent = function () {
surnameRow.appendChild(new Functions.createElement({
type: "div",
style: "display:table-cell",
content: "<input name='userSurname' value='" + getStringIfDefined(user.getSurname()) + "'/>"
content: "<input name='userSurname' value='" + getStringIfDefined(user.getSurname()) + "'/>",
xss: false