Merge branch 'blob-uri'
This commit is contained in:
commit
cd72110ea4
6 changed files with 61 additions and 58 deletions
|
@ -70,7 +70,7 @@ languageselection = false
|
||||||
; Check the documentation at https://content-security-policy.com/
|
; 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.
|
; 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.
|
; 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:; media-src data:; object-src data:; Referrer-Policy: 'no-referrer'; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals"
|
; cspheader = "default-src 'none'; manifest-src 'self'; connect-src *; script-src 'self' 'unsafe-eval'; style-src 'self'; font-src 'self'; img-src 'self' blob:; media-src blob:; object-src blob:; Referrer-Policy: 'no-referrer'; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals"
|
||||||
|
|
||||||
; stay compatible with PrivateBin Alpha 0.19, less secure
|
; 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
|
; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of
|
||||||
|
|
|
@ -2101,8 +2101,11 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
||||||
// show preview
|
// show preview
|
||||||
PasteViewer.setText($message.val());
|
PasteViewer.setText($message.val());
|
||||||
if (AttachmentViewer.hasAttachmentData()) {
|
if (AttachmentViewer.hasAttachmentData()) {
|
||||||
let attachmentData = AttachmentViewer.getAttachmentData() || AttachmentViewer.getAttachmentLink().attr('href');
|
const attachment = AttachmentViewer.getAttachment();
|
||||||
AttachmentViewer.handleAttachmentPreview(AttachmentViewer.getAttachmentPreview(), attachmentData);
|
AttachmentViewer.handleBlobAttachmentPreview(
|
||||||
|
AttachmentViewer.getAttachmentPreview(),
|
||||||
|
attachment[0], attachment[1]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
PasteViewer.run();
|
PasteViewer.run();
|
||||||
|
|
||||||
|
@ -2514,39 +2517,43 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
||||||
*/
|
*/
|
||||||
me.setAttachment = function(attachmentData, fileName)
|
me.setAttachment = function(attachmentData, fileName)
|
||||||
{
|
{
|
||||||
|
// data URI format: data:[<mediaType>][;base64],<data>
|
||||||
|
|
||||||
|
// position in data URI string of where data begins
|
||||||
|
const base64Start = attachmentData.indexOf(',') + 1;
|
||||||
|
// position in data URI string of where mediaType ends
|
||||||
|
const mediaTypeEnd = attachmentData.indexOf(';');
|
||||||
|
|
||||||
|
// extract mediaType
|
||||||
|
const mediaType = attachmentData.substring(5, mediaTypeEnd);
|
||||||
|
// extract data and convert to binary
|
||||||
|
const decodedData = atob(attachmentData.substring(base64Start));
|
||||||
|
|
||||||
|
// Transform into a Blob
|
||||||
|
const buf = new Uint8Array(decodedData.length);
|
||||||
|
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
|
// IE does not support setting a data URI on an a element
|
||||||
// Convert dataURI to a Blob and use msSaveBlob to download
|
// Using msSaveBlob to download
|
||||||
if (window.Blob && navigator.msSaveBlob) {
|
if (window.Blob && navigator.msSaveBlob) {
|
||||||
$attachmentLink.off('click').on('click', function () {
|
$attachmentLink.off('click').on('click', function () {
|
||||||
// data URI format: data:[<mediaType>][;base64],<data>
|
|
||||||
|
|
||||||
// position in data URI string of where data begins
|
|
||||||
const base64Start = attachmentData.indexOf(',') + 1;
|
|
||||||
// position in data URI string of where mediaType ends
|
|
||||||
const mediaTypeEnd = attachmentData.indexOf(';');
|
|
||||||
|
|
||||||
// extract mediaType
|
|
||||||
const mediaType = attachmentData.substring(5, mediaTypeEnd);
|
|
||||||
// extract data and convert to binary
|
|
||||||
const decodedData = atob(attachmentData.substring(base64Start));
|
|
||||||
|
|
||||||
// Transform into a Blob
|
|
||||||
const buf = new Uint8Array(decodedData.length);
|
|
||||||
for (let i = 0; i < decodedData.length; ++i) {
|
|
||||||
buf[i] = decodedData.charCodeAt(i);
|
|
||||||
}
|
|
||||||
const blob = new window.Blob([ buf ], { type: mediaType });
|
|
||||||
navigator.msSaveBlob(blob, fileName);
|
navigator.msSaveBlob(blob, fileName);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
$attachmentLink.attr('href', attachmentData);
|
$attachmentLink.attr('href', blobUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof fileName !== 'undefined') {
|
if (typeof fileName !== 'undefined') {
|
||||||
$attachmentLink.attr('download', fileName);
|
$attachmentLink.attr('download', fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
me.handleAttachmentPreview($attachmentPreview, attachmentData);
|
me.handleBlobAttachmentPreview($attachmentPreview, blobUrl, mediaType);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2739,7 +2746,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
||||||
attachmentData = dataURL;
|
attachmentData = dataURL;
|
||||||
|
|
||||||
if (Editor.isPreview()) {
|
if (Editor.isPreview()) {
|
||||||
me.handleAttachmentPreview($attachmentPreview, dataURL);
|
me.setAttachment(dataURL, loadedFile.name || '');
|
||||||
$attachmentPreview.removeClass('hidden');
|
$attachmentPreview.removeClass('hidden');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -2747,26 +2754,21 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* handle the preview of files that can either be an image, video, audio or pdf element
|
* handle the preview of files decoded to blob that can either be an image, video, audio or pdf element
|
||||||
*
|
*
|
||||||
* @name AttachmentViewer.handleAttachmentPreview
|
* @name AttachmentViewer.handleBlobAttachmentPreview
|
||||||
* @function
|
* @function
|
||||||
* @argument {jQuery} $targetElement element where the preview should be appended
|
* @argument {jQuery} $targetElement element where the preview should be appended
|
||||||
* @argument {string} file as a data URL
|
* @argument {string} file as a blob URL
|
||||||
|
* @argument {string} mime type
|
||||||
*/
|
*/
|
||||||
me.handleAttachmentPreview = function ($targetElement, data) {
|
me.handleBlobAttachmentPreview = function ($targetElement, blobUrl, mimeType) {
|
||||||
if (data) {
|
if (blobUrl) {
|
||||||
// source: https://developer.mozilla.org/en-US/docs/Web/API/FileReader#readAsDataURL()
|
|
||||||
const mimeType = data.slice(
|
|
||||||
data.indexOf('data:') + 5,
|
|
||||||
data.indexOf(';base64,')
|
|
||||||
);
|
|
||||||
|
|
||||||
attachmentHasPreview = true;
|
attachmentHasPreview = true;
|
||||||
if (mimeType.match(/image\//i)) {
|
if (mimeType.match(/image\//i)) {
|
||||||
$targetElement.html(
|
$targetElement.html(
|
||||||
$(document.createElement('img'))
|
$(document.createElement('img'))
|
||||||
.attr('src', data)
|
.attr('src', blobUrl)
|
||||||
.attr('class', 'img-thumbnail')
|
.attr('class', 'img-thumbnail')
|
||||||
);
|
);
|
||||||
} else if (mimeType.match(/video\//i)) {
|
} else if (mimeType.match(/video\//i)) {
|
||||||
|
@ -2778,7 +2780,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
||||||
|
|
||||||
.append($(document.createElement('source'))
|
.append($(document.createElement('source'))
|
||||||
.attr('type', mimeType)
|
.attr('type', mimeType)
|
||||||
.attr('src', data))
|
.attr('src', blobUrl))
|
||||||
);
|
);
|
||||||
} else if (mimeType.match(/audio\//i)) {
|
} else if (mimeType.match(/audio\//i)) {
|
||||||
$targetElement.html(
|
$targetElement.html(
|
||||||
|
@ -2788,26 +2790,15 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
||||||
|
|
||||||
.append($(document.createElement('source'))
|
.append($(document.createElement('source'))
|
||||||
.attr('type', mimeType)
|
.attr('type', mimeType)
|
||||||
.attr('src', data))
|
.attr('src', blobUrl))
|
||||||
);
|
);
|
||||||
} else if (mimeType.match(/\/pdf/i)) {
|
} else if (mimeType.match(/\/pdf/i)) {
|
||||||
// PDFs are only displayed if the filesize is smaller than about 1MB (after base64 encoding).
|
|
||||||
// Bigger filesizes currently cause crashes in various browsers.
|
|
||||||
// See also: https://code.google.com/p/chromium/issues/detail?id=69227
|
|
||||||
|
|
||||||
// Firefox crashes with files that are about 1.5MB
|
|
||||||
// The performance with 1MB files is bearable
|
|
||||||
if (data.length > 1398488) {
|
|
||||||
Alert.showError('File too large, to display a preview. Please download the attachment.'); //TODO: is this error really neccessary?
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback for browsers, that don't support the vh unit
|
// Fallback for browsers, that don't support the vh unit
|
||||||
const clientHeight = $(window).height();
|
var clientHeight = $(window).height();
|
||||||
|
|
||||||
$targetElement.html(
|
$targetElement.html(
|
||||||
$(document.createElement('embed'))
|
$(document.createElement('embed'))
|
||||||
.attr('src', data)
|
.attr('src', blobUrl)
|
||||||
.attr('type', 'application/pdf')
|
.attr('type', 'application/pdf')
|
||||||
.attr('class', 'pdfPreview')
|
.attr('class', 'pdfPreview')
|
||||||
.css('height', clientHeight)
|
.css('height', clientHeight)
|
||||||
|
|
|
@ -11,13 +11,13 @@ describe('AttachmentViewer', function () {
|
||||||
jsc.property(
|
jsc.property(
|
||||||
'displays & hides data as requested',
|
'displays & hides data as requested',
|
||||||
common.jscMimeTypes(),
|
common.jscMimeTypes(),
|
||||||
jsc.nearray(common.jscBase64String()),
|
|
||||||
'string',
|
'string',
|
||||||
'string',
|
'string',
|
||||||
'string',
|
'string',
|
||||||
function (mimeType, base64, filename, prefix, postfix) {
|
'string',
|
||||||
|
function (mimeType, rawdata, filename, prefix, postfix) {
|
||||||
var clean = jsdom(),
|
var clean = jsdom(),
|
||||||
data = 'data:' + mimeType + ';base64,' + base64.join(''),
|
data = 'data:' + mimeType + ';base64,' + btoa(rawdata),
|
||||||
previewSupported = (
|
previewSupported = (
|
||||||
mimeType.substring(0, 6) === 'image/' ||
|
mimeType.substring(0, 6) === 'image/' ||
|
||||||
mimeType.substring(0, 6) === 'audio/' ||
|
mimeType.substring(0, 6) === 'audio/' ||
|
||||||
|
@ -34,6 +34,16 @@ describe('AttachmentViewer', function () {
|
||||||
'Download attachment</a></div><div id="attachmentPrevie' +
|
'Download attachment</a></div><div id="attachmentPrevie' +
|
||||||
'w" class="hidden"></div>'
|
'w" class="hidden"></div>'
|
||||||
);
|
);
|
||||||
|
// mock createObjectURL for jsDOM
|
||||||
|
if (typeof window.URL.createObjectURL === 'undefined') {
|
||||||
|
Object.defineProperty(
|
||||||
|
window.URL,
|
||||||
|
'createObjectURL',
|
||||||
|
{value: function(blob) {
|
||||||
|
return 'blob:' + location.origin + '/1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed';
|
||||||
|
}}
|
||||||
|
)
|
||||||
|
}
|
||||||
$.PrivateBin.AttachmentViewer.init();
|
$.PrivateBin.AttachmentViewer.init();
|
||||||
results.push(
|
results.push(
|
||||||
!$.PrivateBin.AttachmentViewer.hasAttachment() &&
|
!$.PrivateBin.AttachmentViewer.hasAttachment() &&
|
||||||
|
@ -45,6 +55,8 @@ describe('AttachmentViewer', function () {
|
||||||
} else {
|
} else {
|
||||||
$.PrivateBin.AttachmentViewer.setAttachment(data);
|
$.PrivateBin.AttachmentViewer.setAttachment(data);
|
||||||
}
|
}
|
||||||
|
// beyond this point we will get the blob URL instead of the data
|
||||||
|
data = window.URL.createObjectURL(data);
|
||||||
var attachment = $.PrivateBin.AttachmentViewer.getAttachment();
|
var attachment = $.PrivateBin.AttachmentViewer.getAttachment();
|
||||||
results.push(
|
results.push(
|
||||||
$.PrivateBin.AttachmentViewer.hasAttachment() &&
|
$.PrivateBin.AttachmentViewer.hasAttachment() &&
|
||||||
|
|
|
@ -53,7 +53,7 @@ class Configuration
|
||||||
'urlshortener' => '',
|
'urlshortener' => '',
|
||||||
'qrcode' => true,
|
'qrcode' => true,
|
||||||
'icon' => 'identicon',
|
'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:; media-src data:; object-src data:; Referrer-Policy: \'no-referrer\'; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals',
|
'cspheader' => 'default-src \'none\'; manifest-src \'self\'; connect-src *; script-src \'self\' \'unsafe-eval\'; style-src \'self\'; font-src \'self\'; img-src \'self\' blob:; media-src blob:; object-src blob:; Referrer-Policy: \'no-referrer\'; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals',
|
||||||
'zerobincompatibility' => false,
|
'zerobincompatibility' => false,
|
||||||
),
|
),
|
||||||
'expire' => array(
|
'expire' => array(
|
||||||
|
|
|
@ -72,7 +72,7 @@ if ($MARKDOWN):
|
||||||
endif;
|
endif;
|
||||||
?>
|
?>
|
||||||
<script type="text/javascript" data-cfasync="false" src="js/purify-1.0.7.js" integrity="sha512-VnKJHLosO8z2ojNvWk9BEKYqnhZyWK9rM90FgZUUEp/PRnUqR5OLLKE0a3BkVmn7YgB7LXRrjHgFHQYKd6DAIA==" crossorigin="anonymous"></script>
|
<script type="text/javascript" data-cfasync="false" src="js/purify-1.0.7.js" integrity="sha512-VnKJHLosO8z2ojNvWk9BEKYqnhZyWK9rM90FgZUUEp/PRnUqR5OLLKE0a3BkVmn7YgB7LXRrjHgFHQYKd6DAIA==" crossorigin="anonymous"></script>
|
||||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-kjbmxiSF8+OGm+5u/09c+YYlfMJBa9+i5bH7/2cd184aBxKDZsB9zc11XjFeYx5by2ZfaqhPBHNtWe2YBzCAuQ==" crossorigin="anonymous"></script>
|
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-RE9PlksCFEcNHrU0eXzMBdNahXuwzbJHdzmCFNR5LlXMK+bSE5f07qniZJcszcW8L0imdN7MFSsBHxXxVdaqqg==" crossorigin="anonymous"></script>
|
||||||
<!--[if lt IE 10]>
|
<!--[if lt IE 10]>
|
||||||
<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
|
<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
|
|
|
@ -50,7 +50,7 @@ if ($MARKDOWN):
|
||||||
endif;
|
endif;
|
||||||
?>
|
?>
|
||||||
<script type="text/javascript" data-cfasync="false" src="js/purify-1.0.7.js" integrity="sha512-VnKJHLosO8z2ojNvWk9BEKYqnhZyWK9rM90FgZUUEp/PRnUqR5OLLKE0a3BkVmn7YgB7LXRrjHgFHQYKd6DAIA==" crossorigin="anonymous"></script>
|
<script type="text/javascript" data-cfasync="false" src="js/purify-1.0.7.js" integrity="sha512-VnKJHLosO8z2ojNvWk9BEKYqnhZyWK9rM90FgZUUEp/PRnUqR5OLLKE0a3BkVmn7YgB7LXRrjHgFHQYKd6DAIA==" crossorigin="anonymous"></script>
|
||||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-kjbmxiSF8+OGm+5u/09c+YYlfMJBa9+i5bH7/2cd184aBxKDZsB9zc11XjFeYx5by2ZfaqhPBHNtWe2YBzCAuQ==" crossorigin="anonymous"></script>
|
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-RE9PlksCFEcNHrU0eXzMBdNahXuwzbJHdzmCFNR5LlXMK+bSE5f07qniZJcszcW8L0imdN7MFSsBHxXxVdaqqg==" crossorigin="anonymous"></script>
|
||||||
<!--[if lt IE 10]>
|
<!--[if lt IE 10]>
|
||||||
<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
|
<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
|
||||||
<![endif]-->
|
<![endif]-->
|
||||||
|
|
Loading…
Reference in a new issue