From ab75b183fbcda30ffbd4255a619ad0abcc4584df Mon Sep 17 00:00:00 2001 From: Haocen Xu Date: Sat, 17 Aug 2019 22:17:35 -0400 Subject: [PATCH 1/4] Fix click on new paste on clone paste editing view not removing custom attachment Fix cloning paste with attachment Update CSP in sample and default configuration Ensure clone paste also clone format Fix clone button hiding logic when paste is burn after read Remove attachment name when new paste clicked on Enable file operation only when editing --- cfg/conf.sample.php | 2 +- js/privatebin.js | 119 +++++++++++++++++++++++++++++++++++++++--- lib/Configuration.php | 2 +- tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 5 files changed, 117 insertions(+), 10 deletions(-) diff --git a/cfg/conf.sample.php b/cfg/conf.sample.php index 1c1d8d95..3decc5c8 100644 --- a/cfg/conf.sample.php +++ b/cfg/conf.sample.php @@ -70,7 +70,7 @@ languageselection = false ; Check the documentation at https://content-security-policy.com/ ; Note: If you use a bootstrap theme, you can remove the allow-popups from the sandbox restrictions. ; By default this disallows to load images from third-party servers, e.g. when they are embedded in pastes. If you wish to allow that, you can adjust the policy here. See https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-it-load-embedded-images for details. -; cspheader = "default-src 'none'; manifest-src 'self'; connect-src *; 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'; 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/js/privatebin.js b/js/privatebin.js index 29071d63..6c691911 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -1852,10 +1852,6 @@ jQuery.PrivateBin = (function($, RawDeflate) { Alert.showRemaining('FOR YOUR EYES ONLY. Don\'t close this window, this message can\'t be displayed again.'); $remainingTime.addClass('foryoureyesonly'); - - // discourage cloning (it cannot really be prevented) - TopNav.hideCloneButton(); - } else if (paste.getTimeToLive() > 0) { // display paste expiration let expiration = Helper.secondsToHuman(paste.getTimeToLive()), @@ -2225,6 +2221,18 @@ jQuery.PrivateBin = (function($, RawDeflate) { return $message.val(); }; + /** + * returns if status is editing + * + * @name Editor.isEditing + * @function + * @return {bool} + */ + me.isEditing = function() + { + return !$message.hasClass('hidden'); + }; + /** * init status manager * @@ -2598,6 +2606,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { $attachmentLink.removeAttr('download'); $attachmentLink.off('click'); $attachmentPreview.html(''); + $dragAndDropFileName.text(''); AttachmentViewer.removeAttachmentData(); }; @@ -2838,6 +2847,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { const handleDragEnterOrOver = function(event) { event.stopPropagation(); event.preventDefault(); + return false; }; const handleDrop = function(event) { @@ -2845,6 +2855,10 @@ jQuery.PrivateBin = (function($, RawDeflate) { evt.stopPropagation(); evt.preventDefault(); + if (!Editor.isEditing()) { + return false; + } + if ($fileInput) { const file = evt.dataTransfer.files[0]; //Clear the file input: @@ -2858,7 +2872,12 @@ jQuery.PrivateBin = (function($, RawDeflate) { }; $(document).draghover().on({ - 'draghoverstart': function() { + 'draghoverstart': function(e) { + if (!Editor.isEditing()) { + e.stopPropagation(); + e.preventDefault(); + return false; + } // show dropzone to indicate drop support $dropzone.removeClass('hidden'); }, @@ -2884,6 +2903,11 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ function addClipboardEventHandler() { $(document).on('paste', function (event) { + if (!Editor.isEditing()) { + 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') { @@ -3306,7 +3330,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { } /** - * set the format on bootstrap templates in dropdown + * set the format on bootstrap templates in dropdown from user interaction * * @name TopNav.updateFormat * @private @@ -3668,6 +3692,18 @@ jQuery.PrivateBin = (function($, RawDeflate) { $customAttachment.removeClass('hidden'); }; + /** + * hides the custom attachment + * + * @name TopNav.hideCustomAttachment + * @function + */ + me.hideCustomAttachment = function() + { + $customAttachment.addClass('hidden'); + $fileWrap.removeClass('hidden'); + }; + /** * collapses the navigation bar, only if expanded * @@ -3798,6 +3834,17 @@ jQuery.PrivateBin = (function($, RawDeflate) { }, 300); } + /** + * set the format on bootstrap templates in dropdown programmatically + * + * @name TopNav.setFormat + * @function + */ + me.setFormat = function(format) + { + $formatter.parent().find(`a[data-format="${format}"]`).click(); + } + /** * init navigation manager * @@ -4347,6 +4394,53 @@ jQuery.PrivateBin = (function($, RawDeflate) { let attachment = AttachmentViewer.getAttachment(); cipherMessage['attachment'] = attachment[0]; cipherMessage['attachment_name'] = attachment[1]; + + // we need to retrieve data from blob if browser already parsed it in memory + if (typeof attachment[0] === 'string' && attachment[0].startsWith('blob:')) { + Alert.showStatus( + [ + 'Retrieving cloned file \'%s\' from memory...', + attachment[1] + ], + 'copy' + ); + try { + const blobData = await $.ajax({ + type: 'GET', + url: `${attachment[0]}`, + processData: false, + timeout: 10000, + xhrFields: { + withCredentials: false, + responseType: 'blob' + } + }); + if (blobData instanceof window.Blob) { + const fileReading = new Promise(function(resolve, reject) { + const fileReader = new FileReader(); + fileReader.onload = function (event) { + resolve(event.target.result); + }; + fileReader.onerror = function (error) { + reject(error); + } + fileReader.readAsDataURL(blobData); + }); + cipherMessage['attachment'] = await fileReading; + } else { + Alert.showError( + I18n._('Cannot process attachment data.') + ); + throw new TypeError('Cannot process attachment data.'); + } + } catch (error) { + console.error(error); + Alert.showError( + I18n._('Cannot retrieve attachment.') + ); + throw error; + } + } } // encrypt message @@ -4587,6 +4681,11 @@ jQuery.PrivateBin = (function($, RawDeflate) { .then(() => { Alert.hideLoading(); TopNav.showViewButtons(); + + // discourage cloning (it cannot really be prevented) + if (paste.isBurnAfterReadingEnabled()) { + TopNav.hideCloneButton(); + } }) .catch((err) => { // wait for the user to type in the password, @@ -4799,6 +4898,12 @@ jQuery.PrivateBin = (function($, RawDeflate) { AttachmentViewer.removeAttachment(); TopNav.showCreateButtons(); + + // newPaste could be called when user is on paste clone editing view + TopNav.hideCustomAttachment(); + AttachmentViewer.clearDragAndDrop(); + AttachmentViewer.removeAttachmentData(); + Alert.hideLoading(); history.pushState({type: 'create'}, document.title, Helper.baseUri()); @@ -4914,6 +5019,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { } Editor.setText(PasteViewer.getText()); + // also clone the format + TopNav.setFormat(PasteViewer.getFormat()); PasteViewer.hide(); Editor.show(); diff --git a/lib/Configuration.php b/lib/Configuration.php index 6e0c2af0..67ecc234 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 *; 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\'; 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', diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index e775b7b5..55f1d689 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -71,7 +71,7 @@ if ($MARKDOWN): endif; ?> - + diff --git a/tpl/page.php b/tpl/page.php index 89973f21..6b48cee6 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -49,7 +49,7 @@ if ($MARKDOWN): endif; ?> - + From b912c07cd1db731ea884d6aeea5555d3e18ec75b Mon Sep 17 00:00:00 2001 From: Haocen Xu Date: Sun, 25 Aug 2019 02:15:58 -0400 Subject: [PATCH 2/4] 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 55f1d689..c685de23 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -71,7 +71,7 @@ if ($MARKDOWN): endif; ?> - + diff --git a/tpl/page.php b/tpl/page.php index 6b48cee6..ee7bf25c 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -49,7 +49,7 @@ if ($MARKDOWN): endif; ?> - + From ad096b80a1231c7b6d6b9b193209a34055e8d207 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sun, 25 Aug 2019 17:24:22 +0200 Subject: [PATCH 3/4] refactoring logic, to make intention more clear and reduce complexity --- js/privatebin.js | 30 +++++++++++++++--------------- tpl/bootstrap.php | 2 +- tpl/page.php | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/js/privatebin.js b/js/privatebin.js index 6c691911..6cde5dc0 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -2145,6 +2145,18 @@ jQuery.PrivateBin = (function($, RawDeflate) { return isPreview; }; + /** + * gets the visibility of the editor + * + * @name Editor.isHidden + * @function + * @return {bool} + */ + me.isHidden = function() + { + return $message.hasClass('hidden'); + }; + /** * reset the Editor view * @@ -2221,18 +2233,6 @@ jQuery.PrivateBin = (function($, RawDeflate) { return $message.val(); }; - /** - * returns if status is editing - * - * @name Editor.isEditing - * @function - * @return {bool} - */ - me.isEditing = function() - { - return !$message.hasClass('hidden'); - }; - /** * init status manager * @@ -2855,7 +2855,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { evt.stopPropagation(); evt.preventDefault(); - if (!Editor.isEditing()) { + if (Editor.isHidden()) { return false; } @@ -2873,7 +2873,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { $(document).draghover().on({ 'draghoverstart': function(e) { - if (!Editor.isEditing()) { + if (Editor.isHidden()) { e.stopPropagation(); e.preventDefault(); return false; @@ -2903,7 +2903,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ function addClipboardEventHandler() { $(document).on('paste', function (event) { - if (!Editor.isEditing()) { + if (Editor.isHidden()) { event.stopPropagation(); event.preventDefault(); return false; diff --git a/tpl/bootstrap.php b/tpl/bootstrap.php index c685de23..6d2fabac 100644 --- a/tpl/bootstrap.php +++ b/tpl/bootstrap.php @@ -71,7 +71,7 @@ if ($MARKDOWN): endif; ?> - + diff --git a/tpl/page.php b/tpl/page.php index ee7bf25c..30ec6e7a 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -49,7 +49,7 @@ if ($MARKDOWN): endif; ?> - + From 271d4b680a222330b0c64911b63761be66891947 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sun, 25 Aug 2019 17:29:52 +0200 Subject: [PATCH 4/4] updating changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4557f3e0..19eeab3f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ * CHANGED: Improved mobile UI - obscured send button and hard to click shortener button (#477) * CHANGED: Enhanced URL shortener integration (#479) * CHANGED: Improved file upload drag & drop UI (#317) + * FIXED: Cloning related issues (#489, #491, #493, #494) + * FIXED: Enable file operation only when editing (#497) * FIXED: Clicking 'New' on a previously submitted paste does not blank address bar (#354) * FIXED: Clear address bar when create new paste from existing paste (#479) * FIXED: Discussion section not hiding when new/clone paste is clicked on (#484)