From bb9a5772bce85cd55e255c7e56f7e265d29ad666 Mon Sep 17 00:00:00 2001 From: Haocen Xu Date: Wed, 20 May 2020 21:25:16 -0400 Subject: [PATCH 01/15] Add resource: to script-src cspheader to allowed rendering of pdf in Firefox --- cfg/conf.sample.php | 2 +- lib/Configuration.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cfg/conf.sample.php b/cfg/conf.sample.php index d2d285dec..863974a23 100644 --- a/cfg/conf.sample.php +++ b/cfg/conf.sample.php @@ -79,7 +79,7 @@ ; async functions and display an error if not and for Chrome to enable ; webassembly support (used for zlib compression). You can remove it if Chrome ; doesn't need to be supported and old browsers don't need to be warned. -; cspheader = "default-src 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'unsafe-eval'; style-src 'self'; font-src 'self'; img-src 'self' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals" +; cspheader = "default-src 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'unsafe-eval' resource:; style-src 'self'; font-src 'self'; img-src 'self' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals" ; stay compatible with PrivateBin Alpha 0.19, less secure ; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of diff --git a/lib/Configuration.php b/lib/Configuration.php index 06edf68ba..4df121f47 100644 --- a/lib/Configuration.php +++ b/lib/Configuration.php @@ -53,7 +53,7 @@ class Configuration 'urlshortener' => '', 'qrcode' => true, 'icon' => 'identicon', - 'cspheader' => 'default-src \'none\'; manifest-src \'self\'; connect-src * blob:; script-src \'self\' \'unsafe-eval\'; style-src \'self\'; font-src \'self\'; img-src \'self\' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals', + 'cspheader' => 'default-src \'none\'; manifest-src \'self\'; connect-src * blob:; script-src \'self\' \'unsafe-eval\' resource:; style-src \'self\'; font-src \'self\'; img-src \'self\' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals', 'zerobincompatibility' => false, 'httpwarning' => true, 'compression' => 'zlib', From 7eb96eb3cbb0f29b7b09954308518caa99c3c5dc Mon Sep 17 00:00:00 2001 From: Haocen Xu Date: Sun, 17 May 2020 01:35:19 -0400 Subject: [PATCH 02/15] Avoid handling clipboard data item if it is not file type --- js/privatebin.js | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index 23344dd84..56e1384b1 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -3110,19 +3110,15 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ function addClipboardEventHandler() { $(document).on('paste', function (event) { - if (TopNav.isAttachmentReadonly()) { - event.stopPropagation(); - event.preventDefault(); - return false; - } const items = (event.clipboardData || event.originalEvent.clipboardData).items; - for (let i = 0; i < items.length; ++i) { - if (items[i].kind === 'file') { - //Clear the file input: - $fileInput.wrap('
').closest('form').get(0).reset(); - $fileInput.unwrap(); - - readFileData(items[i].getAsFile()); + const lastItem = items[items.length - 1]; + if (lastItem.kind === 'file') { + if (TopNav.isAttachmentReadonly()) { + event.stopPropagation(); + event.preventDefault(); + return false; + } else { + readFileData(lastItem.getAsFile()); } } }); From d6b06269a4bcc5245a666414a1ee836e0057f755 Mon Sep 17 00:00:00 2001 From: Haocen Xu Date: Sat, 30 May 2020 05:47:33 -0400 Subject: [PATCH 03/15] Fix Editor.hide typo --- js/privatebin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/privatebin.js b/js/privatebin.js index 56e1384b1..927993798 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -2404,7 +2404,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { /** * hides the Editor * - * @name Editor.reset + * @name Editor.hide * @function */ me.hide = function() From 4984194c335591d9b0273d38f0914422aa3e6136 Mon Sep 17 00:00:00 2001 From: Haocen Xu Date: Sat, 30 May 2020 05:48:15 -0400 Subject: [PATCH 04/15] Avoid dropzone appearing when it should not by fixing TopNav.isAttachmentReadonly logic --- js/privatebin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/privatebin.js b/js/privatebin.js index 927993798..9708a525a 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -4276,7 +4276,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ me.isAttachmentReadonly = function() { - return createButtonsDisplayed && $attach.hasClass('hidden'); + return !createButtonsDisplayed || $attach.hasClass('hidden'); } /** From 74551f58d721b4e9064300e99fe0fb182d9a42fc Mon Sep 17 00:00:00 2001 From: Haocen Xu Date: Sat, 30 May 2020 05:52:15 -0400 Subject: [PATCH 05/15] Avoid DOMPurify mess with forward slash in expirationDateString --- js/privatebin.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index 9708a525a..57995bdea 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -3748,8 +3748,12 @@ jQuery.PrivateBin = (function($, RawDeflate) { if (expirationDateString !== null) { emailBody += EOL; emailBody += BULLET; - emailBody += I18n._( - 'This link will expire after %s.', + // avoid DOMPurify mess with forward slash in expirationDateString + emailBody += Helper.sprintf( + I18n._( + 'This link will expire after %s.', + '%s' + ), expirationDateString ); } From afcece17dd38d6f99aa76165771efe18d694e812 Mon Sep 17 00:00:00 2001 From: Haocen Xu Date: Sat, 30 May 2020 05:55:41 -0400 Subject: [PATCH 06/15] Fix broken Helper.durationToSeconds, as it doesn't handle weeks --- js/privatebin.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/js/privatebin.js b/js/privatebin.js index 57995bdea..d80ae7524 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -243,6 +243,18 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ const day = 86400; + /** + * number of seconds in a week + * + * = 60 * 60 * 24 * 7 seconds + * + * @name Helper.week + * @private + * @enum {number} + * @readonly + */ + const week = 604800; + /** * number of seconds in a month (30 days, an approximation) * @@ -326,7 +338,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ me.durationToSeconds = function(duration) { - let pieces = duration.split(/\d+/), + let pieces = duration.split(/(\D+)/), factor = pieces[0] || 0, timespan = pieces[1] || pieces[0]; switch (timespan) @@ -337,6 +349,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { return factor * hour; case 'day': return factor * day; + case 'week': + return factor * week; case 'month': return factor * month; case 'year': From e298c3d10c9254b0677eb1f9618ca395b5e9ecc1 Mon Sep 17 00:00:00 2001 From: Haocen Xu Date: Sat, 30 May 2020 05:57:27 -0400 Subject: [PATCH 07/15] Reload page when back button in browser pressed, avoid reading burn after read paste from cache --- js/privatebin.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/js/privatebin.js b/js/privatebin.js index d80ae7524..98d9c9a41 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -5386,6 +5386,10 @@ jQuery.PrivateBin = (function($, RawDeflate) { if (Model.hasDeleteToken()) { return; } + // always reload on back button to invalidate cache(protect burn after read paste) + window.addEventListener('popstate', () => { + window.location.reload(); + }); // display an existing paste return me.showPaste(); From 25a39148a81deaf50fab50bb53aa7c587c276408 Mon Sep 17 00:00:00 2001 From: Haocen Xu Date: Sat, 30 May 2020 06:00:17 -0400 Subject: [PATCH 08/15] Change order of execution to detect delete token properly --- js/privatebin.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index 98d9c9a41..29265771d 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -5373,6 +5373,12 @@ jQuery.PrivateBin = (function($, RawDeflate) { } me.initZ(); + // if delete token is passed (i.e. paste has been deleted by this + // access), there is nothing more to do + if (Model.hasDeleteToken()) { + return; + } + // check whether existing paste needs to be shown try { Model.getPasteId(); @@ -5381,11 +5387,6 @@ jQuery.PrivateBin = (function($, RawDeflate) { return me.newPaste(); } - // if delete token is passed (i.e. paste has been deleted by this - // access), there is nothing more to do - if (Model.hasDeleteToken()) { - return; - } // always reload on back button to invalidate cache(protect burn after read paste) window.addEventListener('popstate', () => { window.location.reload(); From 5f0011b0f6ffc036041873daf50a08089e648bc4 Mon Sep 17 00:00:00 2001 From: Haocen Xu Date: Sat, 30 May 2020 06:05:20 -0400 Subject: [PATCH 09/15] Sanitize output from Helper.urls2links --- js/privatebin.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index 29265771d..b9f25b9e5 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -405,9 +405,11 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.urls2links = function(element) { element.html( - element.html().replace( - /(((https?|ftp):\/\/[\w?!=&.\/-;#@~%+*-]+(?![\w\s?!&.\/;#~%"=-]>))|((magnet):[\w?=&.\/-;#@~%+*-]+))/ig, - '$1' + DOMPurify.sanitize( + element.html().replace( + /(((https?|ftp):\/\/[\w?!=&.\/-;#@~%+*-]+(?![\w\s?!&.\/;#~%"=-]>))|((magnet):[\w?=&.\/-;#@~%+*-]+))/ig, + '$1' + ) ) ); }; From dd98af0775856fddef48d09b8a88b20de8352385 Mon Sep 17 00:00:00 2001 From: Haocen Xu Date: Sat, 30 May 2020 06:07:47 -0400 Subject: [PATCH 10/15] Avoid recreation of existing pasteurl element when calling URL shortener --- js/privatebin.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index b9f25b9e5..47aa24859 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -1991,15 +1991,11 @@ jQuery.PrivateBin = (function($, RawDeflate) { return a.length - b.length; })[0]; if (typeof shortUrl === 'string' && shortUrl.length > 0) { - I18n._( - $('#pastelink'), - 'Your paste is %s (Hit [Ctrl]+[c] to copy)', - shortUrl, shortUrl - ); // we disable the button to avoid calling shortener again $shortenButton.addClass('buttondisabled'); - // save newly created element - $pasteUrl = $('#pasteurl'); + // update link + $pasteUrl.text(shortUrl); + $pasteUrl.prop('href', shortUrl); // we pre-select the link so that the user only has to [Ctrl]+[c] the link Helper.selectText($pasteUrl[0]); return; From 420f0d6634b456d906dfb31e98793ac8d764fe98 Mon Sep 17 00:00:00 2001 From: Haocen Xu Date: Sat, 30 May 2020 06:22:35 -0400 Subject: [PATCH 11/15] Update SRI --- tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index 0b2d95a3c..a45258848 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -72,7 +72,7 @@ ?> - + diff --git a/tpl/page.php b/tpl/page.php index 947850e50..41ae076d9 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -50,7 +50,7 @@ ?> - + From 903ea5ea68011ed0788ecf3ba5065f66fa88f4e1 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 1 Jun 2020 02:33:22 +0800 Subject: [PATCH 12/15] Open all links in new window --- js/privatebin.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/js/privatebin.js b/js/privatebin.js index 47aa24859..1170804ad 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -5340,6 +5340,23 @@ jQuery.PrivateBin = (function($, RawDeflate) { SAFE_FOR_JQUERY: true }); + // Add a hook to make all links open a new window + DOMPurify.addHook('afterSanitizeAttributes', function(node) { + // set all elements owning target to target=_blank + if ('target' in node && node.id !== 'pasteurl') { + node.setAttribute('target', '_blank'); + } + // set non-HTML/MathML links to xlink:show=new + if (!node.hasAttribute('target') + && (node.hasAttribute('xlink:href') + || node.hasAttribute('href'))) { + node.setAttribute('xlink:show', 'new'); + } + if ('rel' in node) { + node.setAttribute('rel', 'nofollow noopener noreferrer'); + } + }); + // center all modals $('.modal').on('show.bs.modal', function(e) { $(e.target).css({ From 9b138fd5fdbddb2fb8cf5ee905907019bd76a00f Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 1 Jun 2020 02:35:06 +0800 Subject: [PATCH 13/15] Update SRI --- tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index a45258848..9a8548c10 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -72,7 +72,7 @@ ?> - + diff --git a/tpl/page.php b/tpl/page.php index 41ae076d9..87ecd1a28 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -50,7 +50,7 @@ ?> - + From 65011019b7c7dc604271976c3dc61e94d6a202b0 Mon Sep 17 00:00:00 2001 From: Haocen Xu Date: Tue, 2 Jun 2020 08:50:14 -0400 Subject: [PATCH 14/15] Fix urls2links unit test --- js/privatebin.js | 2 +- js/test/Helper.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index 1170804ad..6826da4a9 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -408,7 +408,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { DOMPurify.sanitize( element.html().replace( /(((https?|ftp):\/\/[\w?!=&.\/-;#@~%+*-]+(?![\w\s?!&.\/;#~%"=-]>))|((magnet):[\w?=&.\/-;#@~%+*-]+))/ig, - '$1' + '$1' ) ) ); diff --git a/js/test/Helper.js b/js/test/Helper.js index f58d73abb..2382c83c4 100644 --- a/js/test/Helper.js +++ b/js/test/Helper.js @@ -125,7 +125,7 @@ describe('Helper', function () { let result = e.html(); clean(); url = $('
').text(url).html(); - return $('
').text(prefix).html() + '' + url + '' + $('
').text(postfix).html() === result; + return $('
').text(prefix).html() + '' + url + '' + $('
').text(postfix).html() === result; } ); jsc.property( @@ -145,7 +145,7 @@ describe('Helper', function () { let result = e.html(); clean(); url = $('
').text(url).html(); - return $('
').text(prefix).html() + '' + url + '' + $('
').text(postfix).html() === result; + return $('
').text(prefix).html() + '' + url + '' + $('
').text(postfix).html() === result; } ); }); From f1d4792d3efd4060e990ea66d29c7a0b69e34cc8 Mon Sep 17 00:00:00 2001 From: Haocen Xu Date: Tue, 2 Jun 2020 09:06:12 -0400 Subject: [PATCH 15/15] Update SRI --- tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index 9a8548c10..71da5a66e 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -72,7 +72,7 @@ ?> - + diff --git a/tpl/page.php b/tpl/page.php index 87ecd1a28..fd13cc1bb 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -50,7 +50,7 @@ ?> - +