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) 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..6cde5dc0 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()), @@ -2149,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 * @@ -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.isHidden()) { + 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.isHidden()) { + 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.isHidden()) { + 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..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 89973f21..30ec6e7a 100644 --- a/tpl/page.php +++ b/tpl/page.php @@ -49,7 +49,7 @@ if ($MARKDOWN): endif; ?> - +