Sanitize SVG preview, preventing script execution in instance context, while dropping support for attachment download in IE
This commit is contained in:
parent
6c1f0dde0c
commit
2a4d572c1e
|
@ -10,11 +10,13 @@
|
||||||
* ADDED: Oracle database support (#868)
|
* ADDED: Oracle database support (#868)
|
||||||
* ADDED: Configuration option to limit paste creation and commenting to certain IPs (#883)
|
* ADDED: Configuration option to limit paste creation and commenting to certain IPs (#883)
|
||||||
* ADDED: Set CSP also as meta tag, to deal with misconfigured webservers mangling the HTTP header
|
* ADDED: Set CSP also as meta tag, to deal with misconfigured webservers mangling the HTTP header
|
||||||
|
* ADDED: Sanitize SVG preview, preventing script execution in instance context
|
||||||
* CHANGED: Language selection cookie only transmitted over HTTPS (#472)
|
* CHANGED: Language selection cookie only transmitted over HTTPS (#472)
|
||||||
* CHANGED: Upgrading libraries to: base-x 4.0.0, bootstrap 3.4.1 (JS), DOMpurify 2.3.6, ip-lib 1.18.0, jQuery 3.6.0, random_compat 2.0.21 & Showdown 2.0.0
|
* CHANGED: Upgrading libraries to: base-x 4.0.0, bootstrap 3.4.1 (JS), DOMpurify 2.3.6, ip-lib 1.18.0, jQuery 3.6.0, random_compat 2.0.21 & Showdown 2.0.0
|
||||||
* CHANGED: Removed automatic `.ini` configuration file migration (#808)
|
* CHANGED: Removed automatic `.ini` configuration file migration (#808)
|
||||||
* CHANGED: Removed configurable `dir` for `traffic` & `purge` limiters (#419)
|
* CHANGED: Removed configurable `dir` for `traffic` & `purge` limiters (#419)
|
||||||
* CHANGED: Server salt, traffic and purge limiter now stored in the storage backend (#419)
|
* CHANGED: Server salt, traffic and purge limiter now stored in the storage backend (#419)
|
||||||
|
* CHANGED: Drop support for attachment download in IE
|
||||||
* **1.3.5 (2021-04-05)**
|
* **1.3.5 (2021-04-05)**
|
||||||
* ADDED: Translations for Hebrew, Lithuanian, Indonesian and Catalan
|
* ADDED: Translations for Hebrew, Lithuanian, Indonesian and Catalan
|
||||||
* ADDED: Make the project info configurable (#681)
|
* ADDED: Make the project info configurable (#681)
|
||||||
|
|
118
js/privatebin.js
118
js/privatebin.js
|
@ -52,6 +52,31 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
||||||
*/
|
*/
|
||||||
let z;
|
let z;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DOMpurify settings for HTML content
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const purifyHtmlConfig = {
|
||||||
|
ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|magnet):)/i,
|
||||||
|
SAFE_FOR_JQUERY: true,
|
||||||
|
USE_PROFILES: {
|
||||||
|
html: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DOMpurify settings for SVG content
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
const purifySvgConfig = {
|
||||||
|
USE_PROFILES: {
|
||||||
|
svg: true,
|
||||||
|
svgFilters: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* CryptoData class
|
* CryptoData class
|
||||||
*
|
*
|
||||||
|
@ -409,7 +434,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
||||||
element.html().replace(
|
element.html().replace(
|
||||||
/(((https?|ftp):\/\/[\w?!=&.\/-;#@~%+*-]+(?![\w\s?!&.\/;#~%"=-]>))|((magnet):[\w?=&.\/-;#@~%+*-]+))/ig,
|
/(((https?|ftp):\/\/[\w?!=&.\/-;#@~%+*-]+(?![\w\s?!&.\/;#~%"=-]>))|((magnet):[\w?=&.\/-;#@~%+*-]+))/ig,
|
||||||
'<a href="$1" rel="nofollow noopener noreferrer">$1</a>'
|
'<a href="$1" rel="nofollow noopener noreferrer">$1</a>'
|
||||||
)
|
),
|
||||||
|
purifyHtmlConfig
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -2536,7 +2562,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
||||||
// let showdown convert the HTML and sanitize HTML *afterwards*!
|
// let showdown convert the HTML and sanitize HTML *afterwards*!
|
||||||
$plainText.html(
|
$plainText.html(
|
||||||
DOMPurify.sanitize(
|
DOMPurify.sanitize(
|
||||||
converter.makeHtml(text)
|
converter.makeHtml(text),
|
||||||
|
purifyHtmlConfig
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
// add table classes from bootstrap css
|
// add table classes from bootstrap css
|
||||||
|
@ -2752,6 +2779,34 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
||||||
$dropzone;
|
$dropzone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* get blob URL from string data and mime type
|
||||||
|
*
|
||||||
|
* @name AttachmentViewer.getBlobUrl
|
||||||
|
* @private
|
||||||
|
* @function
|
||||||
|
* @param {string} data - raw data of attachment
|
||||||
|
* @param {string} data - mime type of attachment
|
||||||
|
* @return {string} objectURL
|
||||||
|
*/
|
||||||
|
function getBlobUrl(data, mimeType)
|
||||||
|
{
|
||||||
|
// Transform into a Blob
|
||||||
|
const buf = new Uint8Array(data.length);
|
||||||
|
for (let i = 0; i < data.length; ++i) {
|
||||||
|
buf[i] = data.charCodeAt(i);
|
||||||
|
}
|
||||||
|
const blob = new window.Blob(
|
||||||
|
[buf],
|
||||||
|
{
|
||||||
|
type: mimeType
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get Blob URL
|
||||||
|
return window.URL.createObjectURL(blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
* sets the attachment but does not yet show it
|
* sets the attachment but does not yet show it
|
||||||
*
|
*
|
||||||
* @name AttachmentViewer.setAttachment
|
* @name AttachmentViewer.setAttachment
|
||||||
|
@ -2761,44 +2816,39 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
||||||
*/
|
*/
|
||||||
me.setAttachment = function(attachmentData, fileName)
|
me.setAttachment = function(attachmentData, fileName)
|
||||||
{
|
{
|
||||||
// data URI format: data:[<mediaType>][;base64],<data>
|
// data URI format: data:[<mimeType>][;base64],<data>
|
||||||
|
|
||||||
// position in data URI string of where data begins
|
// position in data URI string of where data begins
|
||||||
const base64Start = attachmentData.indexOf(',') + 1;
|
const base64Start = attachmentData.indexOf(',') + 1;
|
||||||
// position in data URI string of where mediaType ends
|
// position in data URI string of where mimeType ends
|
||||||
const mediaTypeEnd = attachmentData.indexOf(';');
|
const mimeTypeEnd = attachmentData.indexOf(';');
|
||||||
|
|
||||||
// extract mediaType
|
// extract mimeType
|
||||||
const mediaType = attachmentData.substring(5, mediaTypeEnd);
|
const mimeType = attachmentData.substring(5, mimeTypeEnd);
|
||||||
// extract data and convert to binary
|
// extract data and convert to binary
|
||||||
const rawData = attachmentData.substring(base64Start);
|
const rawData = attachmentData.substring(base64Start);
|
||||||
const decodedData = rawData.length > 0 ? atob(rawData) : '';
|
const decodedData = rawData.length > 0 ? atob(rawData) : '';
|
||||||
|
|
||||||
// Transform into a Blob
|
let blobUrl = getBlobUrl(decodedData, mimeType);
|
||||||
const buf = new Uint8Array(decodedData.length);
|
$attachmentLink.attr('href', blobUrl);
|
||||||
for (let i = 0; i < decodedData.length; ++i) {
|
|
||||||
buf[i] = decodedData.charCodeAt(i);
|
|
||||||
}
|
|
||||||
const blob = new window.Blob([ buf ], { type: mediaType });
|
|
||||||
|
|
||||||
// Get Blob URL
|
|
||||||
const blobUrl = window.URL.createObjectURL(blob);
|
|
||||||
|
|
||||||
// IE does not support setting a data URI on an a element
|
|
||||||
// Using msSaveBlob to download
|
|
||||||
if (window.Blob && navigator.msSaveBlob) {
|
|
||||||
$attachmentLink.off('click').on('click', function () {
|
|
||||||
navigator.msSaveBlob(blob, fileName);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
$attachmentLink.attr('href', blobUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof fileName !== 'undefined') {
|
if (typeof fileName !== 'undefined') {
|
||||||
$attachmentLink.attr('download', fileName);
|
$attachmentLink.attr('download', fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
me.handleBlobAttachmentPreview($attachmentPreview, blobUrl, mediaType);
|
// sanitize SVG preview
|
||||||
|
// prevents executing embedded scripts when CSP is not set and user
|
||||||
|
// right-clicks/long-taps and opens the SVG in a new tab - prevented
|
||||||
|
// in the preview by use of an img tag, which disables scripts, too
|
||||||
|
if (mimeType.match(/image\/svg/i)) {
|
||||||
|
const sanitizedData = DOMPurify.sanitize(
|
||||||
|
decodedData,
|
||||||
|
purifySvgConfig
|
||||||
|
);
|
||||||
|
blobUrl = getBlobUrl(sanitizedData, mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
me.handleBlobAttachmentPreview($attachmentPreview, blobUrl, mimeType);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3665,7 +3715,14 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
||||||
for (let i = 0; i < $head.length; ++i) {
|
for (let i = 0; i < $head.length; ++i) {
|
||||||
newDoc.write($head[i].outerHTML);
|
newDoc.write($head[i].outerHTML);
|
||||||
}
|
}
|
||||||
newDoc.write('</head><body><pre>' + DOMPurify.sanitize(Helper.htmlEntities(paste)) + '</pre></body></html>');
|
newDoc.write(
|
||||||
|
'</head><body><pre>' +
|
||||||
|
DOMPurify.sanitize(
|
||||||
|
Helper.htmlEntities(paste),
|
||||||
|
purifyHtmlConfig
|
||||||
|
) +
|
||||||
|
'</pre></body></html>'
|
||||||
|
);
|
||||||
newDoc.close();
|
newDoc.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5394,11 +5451,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
||||||
// first load translations
|
// first load translations
|
||||||
I18n.loadTranslations();
|
I18n.loadTranslations();
|
||||||
|
|
||||||
DOMPurify.setConfig({
|
|
||||||
ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|magnet):)/i,
|
|
||||||
SAFE_FOR_JQUERY: true
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add a hook to make all links open a new window
|
// Add a hook to make all links open a new window
|
||||||
DOMPurify.addHook('afterSanitizeAttributes', function(node) {
|
DOMPurify.addHook('afterSanitizeAttributes', function(node) {
|
||||||
// set all elements owning target to target=_blank
|
// set all elements owning target to target=_blank
|
||||||
|
|
|
@ -73,7 +73,7 @@ endif;
|
||||||
?>
|
?>
|
||||||
<script type="text/javascript" data-cfasync="false" src="js/purify-2.3.6.js" integrity="sha512-N1GGPjbqLbwK821ZN7C925WuTwU4aDxz2CEEOXQ6/s6m6MBwVj8fh5fugiE2hzsm0xud3q7jpjZQ4ILnpMREYQ==" crossorigin="anonymous"></script>
|
<script type="text/javascript" data-cfasync="false" src="js/purify-2.3.6.js" integrity="sha512-N1GGPjbqLbwK821ZN7C925WuTwU4aDxz2CEEOXQ6/s6m6MBwVj8fh5fugiE2hzsm0xud3q7jpjZQ4ILnpMREYQ==" crossorigin="anonymous"></script>
|
||||||
<script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LYos+qXHIRqFf5ZPNphvtTB0cgzHUizu2wwcOwcwz/VIpRv9lpcBgPYz4uq6jx0INwCAj6Fbnl5HoKiLufS2jg==" crossorigin="anonymous"></script>
|
<script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LYos+qXHIRqFf5ZPNphvtTB0cgzHUizu2wwcOwcwz/VIpRv9lpcBgPYz4uq6jx0INwCAj6Fbnl5HoKiLufS2jg==" crossorigin="anonymous"></script>
|
||||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-EdUms2nI12Cmtv014stIEBlyPjeKMHlkg7NiBJup1b7jJF5amKhev2RwTaldINXK4UaWbZtQ6hGuMPNvvNQZFA==" crossorigin="anonymous"></script>
|
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-5fNML95dptjIMzFG4KAGE2nNbORbyrCWq4ql9tkvoUF2HSnemlxzngQ5PlWhpi0J2ttKIEqfGMBjU5MywzzdWQ==" crossorigin="anonymous"></script>
|
||||||
<!-- icon -->
|
<!-- icon -->
|
||||||
<link rel="apple-touch-icon" href="<?php echo I18n::encode($BASEPATH); ?>img/apple-touch-icon.png" sizes="180x180" />
|
<link rel="apple-touch-icon" href="<?php echo I18n::encode($BASEPATH); ?>img/apple-touch-icon.png" sizes="180x180" />
|
||||||
<link rel="icon" type="image/png" href="img/favicon-32x32.png" sizes="32x32" />
|
<link rel="icon" type="image/png" href="img/favicon-32x32.png" sizes="32x32" />
|
||||||
|
|
|
@ -51,7 +51,7 @@ endif;
|
||||||
?>
|
?>
|
||||||
<script type="text/javascript" data-cfasync="false" src="js/purify-2.3.6.js" integrity="sha512-N1GGPjbqLbwK821ZN7C925WuTwU4aDxz2CEEOXQ6/s6m6MBwVj8fh5fugiE2hzsm0xud3q7jpjZQ4ILnpMREYQ==" crossorigin="anonymous"></script>
|
<script type="text/javascript" data-cfasync="false" src="js/purify-2.3.6.js" integrity="sha512-N1GGPjbqLbwK821ZN7C925WuTwU4aDxz2CEEOXQ6/s6m6MBwVj8fh5fugiE2hzsm0xud3q7jpjZQ4ILnpMREYQ==" crossorigin="anonymous"></script>
|
||||||
<script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LYos+qXHIRqFf5ZPNphvtTB0cgzHUizu2wwcOwcwz/VIpRv9lpcBgPYz4uq6jx0INwCAj6Fbnl5HoKiLufS2jg==" crossorigin="anonymous"></script>
|
<script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LYos+qXHIRqFf5ZPNphvtTB0cgzHUizu2wwcOwcwz/VIpRv9lpcBgPYz4uq6jx0INwCAj6Fbnl5HoKiLufS2jg==" crossorigin="anonymous"></script>
|
||||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-EdUms2nI12Cmtv014stIEBlyPjeKMHlkg7NiBJup1b7jJF5amKhev2RwTaldINXK4UaWbZtQ6hGuMPNvvNQZFA==" crossorigin="anonymous"></script>
|
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-5fNML95dptjIMzFG4KAGE2nNbORbyrCWq4ql9tkvoUF2HSnemlxzngQ5PlWhpi0J2ttKIEqfGMBjU5MywzzdWQ==" crossorigin="anonymous"></script>
|
||||||
<!-- icon -->
|
<!-- icon -->
|
||||||
<link rel="apple-touch-icon" href="img/apple-touch-icon.png?<?php echo rawurlencode($VERSION); ?>" sizes="180x180" />
|
<link rel="apple-touch-icon" href="img/apple-touch-icon.png?<?php echo rawurlencode($VERSION); ?>" sizes="180x180" />
|
||||||
<link rel="icon" type="image/png" href="img/favicon-32x32.png?<?php echo rawurlencode($VERSION); ?>" sizes="32x32" />
|
<link rel="icon" type="image/png" href="img/favicon-32x32.png?<?php echo rawurlencode($VERSION); ?>" sizes="32x32" />
|
||||||
|
|
Loading…
Reference in New Issue