Browse Source

Escape strings and encode URIs to mitigate possible DOM XSS.

pull/101/head
Matthew Petroff 9 years ago
parent
commit
e294e40b23
2 changed files with 34 additions and 24 deletions
  1. +3
    -3
      src/js/libpannellum.js
  2. +31
    -21
      src/js/pannellum.js

+ 3
- 3
src/js/libpannellum.js View File

@@ -175,9 +175,9 @@ function Renderer(container, image, imageType, video) {
faceImg.side = s; faceImg.side = s;
faceImg.onload = onLoad; faceImg.onload = onLoad;
if (imageType == 'multires') { if (imageType == 'multires') {
faceImg.src = path.replace('%s',sides[s]) + '.' + image.extension;
faceImg.src = encodeURI(path.replace('%s', sides[s]) + '.' + image.extension);
} else { } else {
faceImg.src = image[s].src;
faceImg.src = encodeURI(image[s].src);
} }
} }
@@ -934,7 +934,7 @@ function Renderer(container, image, imageType, video) {
node.textureLoaded = true; node.textureLoaded = true;
delete node.image; delete node.image;
}; };
node.image.src = node.path + '.' + image.extension;
node.image.src = encodeURI(node.path + '.' + image.extension);
} }
} }


+ 31
- 21
src/js/pannellum.js View File

@@ -290,7 +290,7 @@ function init() {
if (config.basePath && !absoluteURL(p)) { if (config.basePath && !absoluteURL(p)) {
p = config.basePath + p; p = config.basePath + p;
} }
panoImage[i].src = p;
panoImage[i].src = encodeURI(p);
} }
} else if (config.type == 'multires') { } else if (config.type == 'multires') {
onImageLoad(); onImageLoad();
@@ -308,7 +308,7 @@ function init() {
for (i = 0; i < config.panoramas.length; i++) { for (i = 0; i < config.panoramas.length; i++) {
if (panoImage.canPlayType(config.panoramas[i].type).length > 0) { if (panoImage.canPlayType(config.panoramas[i].type).length > 0) {
panoImage.crossOrigin = 'anonymous'; panoImage.crossOrigin = 'anonymous';
panoImage.src = absoluteURL(config.panoramas[i].file) ? config.panoramas[i].file : p + config.panoramas[i].file;
panoImage.src = encodeURI(absoluteURL(config.panoramas[i].file) ? config.panoramas[i].file : p + config.panoramas[i].file);
break; break;
} }
} }
@@ -333,7 +333,7 @@ function init() {
if (xhr.status != 200) { if (xhr.status != 200) {
// Display error if image can't be loaded // Display error if image can't be loaded
var a = document.createElement('a'); var a = document.createElement('a');
a.href = p;
a.href = encodeURI(p);
a.innerHTML = a.href; a.innerHTML = a.href;
anError('The file ' + a.outerHTML + ' could not be accessed.'); anError('The file ' + a.outerHTML + ' could not be accessed.');
} }
@@ -1120,15 +1120,15 @@ function createHotSpots() {
}); });
config.hotSpots.forEach(function(hs) { config.hotSpots.forEach(function(hs) {
var div = document.createElement('div'); var div = document.createElement('div');
div.className = 'pnlm-hotspot pnlm-tooltip pnlm-sprite pnlm-' + hs.type;
div.className = 'pnlm-hotspot pnlm-tooltip pnlm-sprite pnlm-' + escapeHTML(hs.type);
var span = document.createElement('span'); var span = document.createElement('span');
span.innerHTML = hs.text;
span.innerHTML = escapeHTML(hs.text);
var a; var a;
if (hs.URL) { if (hs.URL) {
a = document.createElement('a'); a = document.createElement('a');
a.setAttribute('href', hs.URL);
a.setAttribute('href', encodeURI(hs.URL));
a.setAttribute('target', '_blank'); a.setAttribute('target', '_blank');
renderContainer.appendChild(a); renderContainer.appendChild(a);
div.style.cursor = 'pointer'; div.style.cursor = 'pointer';
@@ -1136,19 +1136,19 @@ function createHotSpots() {
a.appendChild(div); a.appendChild(div);
} else if (hs.video) { } else if (hs.video) {
var video = document.createElement('video'); var video = document.createElement('video');
video.setAttribute('src',hs.video);
video.setAttribute('controls',true);
video.setAttribute('style','width:' + hs.width + 'px');
video.setAttribute('src', encodeURI(hs.video));
video.setAttribute('controls', true);
video.setAttribute('style', 'width:' + hs.width + 'px');
renderContainer.appendChild(div); renderContainer.appendChild(div);
span.appendChild(video); span.appendChild(video);
} else if (hs.image) { } else if (hs.image) {
a = document.createElement('a'); a = document.createElement('a');
a.setAttribute('href', hs.image);
a.setAttribute('href', encodeURI(hs.image));
a.setAttribute('target', '_blank'); a.setAttribute('target', '_blank');
span.appendChild(a); span.appendChild(a);
var image = document.createElement('img'); var image = document.createElement('img');
image.setAttribute('src',hs.image);
image.setAttribute('style','width:' + hs.width + 'px');
image.setAttribute('src', encodeURI(hs.image));
image.setAttribute('style', 'width:' + hs.width + 'px');
renderContainer.appendChild(div); renderContainer.appendChild(div);
a.appendChild(image); a.appendChild(image);
@@ -1300,7 +1300,7 @@ function processOptions() {
preview = new Image(); preview = new Image();
preview.crossOrigin = 'anonymous'; preview.crossOrigin = 'anonymous';
preview.src = p;
preview.src = encodeURI(p);
preview.className = 'pnlm-preview-img'; preview.className = 'pnlm-preview-img';
renderContainer.appendChild(preview); renderContainer.appendChild(preview);
} }
@@ -1310,17 +1310,17 @@ function processOptions() {
if (config.hasOwnProperty(key)) { if (config.hasOwnProperty(key)) {
switch(key) { switch(key) {
case 'title': case 'title':
infoDisplay.title.innerHTML = config[key];
infoDisplay.title.innerHTML = escapeHTML(config[key]);
infoDisplay.container.style.display = 'inline'; infoDisplay.container.style.display = 'inline';
break; break;
case 'author': case 'author':
infoDisplay.author.innerHTML = 'by ' + config[key];
infoDisplay.author.innerHTML = 'by ' + escapeHTML(config[key]);
infoDisplay.container.style.display = 'inline'; infoDisplay.container.style.display = 'inline';
break; break;
case 'fallback': case 'fallback':
infoDisplay.errorMsg.innerHTML = '<p>Your browser does not support WebGL.<br><a href="' + config[key] + '" target="_blank">Click here to view this panorama in an alternative viewer.</a></p>';
infoDisplay.errorMsg.innerHTML = '<p>Your browser does not support WebGL.<br><a href="' + encodeURI(config[key]) + '" target="_blank">Click here to view this panorama in an alternative viewer.</a></p>';
break; break;
case 'hfov': case 'hfov':
@@ -1358,11 +1358,6 @@ function processOptions() {
config.autoRotateStopDelay = config[key]; config.autoRotateStopDelay = config[key];
break; break;
case 'header':
// Add contents to header
document.getElementsByTagName('head')[0].innerHTML += config[key];
break;
case 'showZoomCtrl': case 'showZoomCtrl':
if (config[key]) { if (config[key]) {
// Show zoom controls // Show zoom controls
@@ -1549,6 +1544,21 @@ function loadScene(sceneId, targetPitch, targetYaw) {
} }


/** /**
* Escapes HTML string (to mitigate possible DOM XSS attacks).
* @private
* @param {string} s - String to escape
* @returns {string} Escaped string
*/
function escapeHTML(s) {
return String(s).replace(/&/g, '&amp;')
.replace('"', '&quot;')
.replace("'", '&#39;')
.replace('<', '&lt;')
.replace('>', '&gt;')
.replace('/', '&#x2f;');
}

/**
* Returns the pitch of the center of the view. * Returns the pitch of the center of the view.
* @memberof Viewer * @memberof Viewer
* @instance * @instance


Loading…
Cancel
Save