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;
?>
-
+