Quellcode durchsuchen

Merge branch 'blob-uri'

El RIDO vor 7 Jahren
Ursprung
Commit
cd72110ea4
6 geänderte Dateien mit 62 neuen und 59 gelöschten Zeilen
  1. 1 1
      cfg/conf.sample.php
  2. 43 52
      js/privatebin.js
  3. 15 3
      js/test/AttachmentViewer.js
  4. 1 1
      lib/Configuration.php
  5. 1 1
      tpl/bootstrap.php
  6. 1 1
      tpl/page.php

+ 1 - 1
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:; 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
 ; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of

+ 43 - 52
js/privatebin.js

@@ -2101,8 +2101,11 @@ jQuery.PrivateBin = (function($, RawDeflate) {
             // show preview
             PasteViewer.setText($message.val());
             if (AttachmentViewer.hasAttachmentData()) {
-                let attachmentData = AttachmentViewer.getAttachmentData() || AttachmentViewer.getAttachmentLink().attr('href');
-                AttachmentViewer.handleAttachmentPreview(AttachmentViewer.getAttachmentPreview(), attachmentData);
+                const attachment = AttachmentViewer.getAttachment();
+                AttachmentViewer.handleBlobAttachmentPreview(
+                    AttachmentViewer.getAttachmentPreview(),
+                    attachment[0], attachment[1]
+                );
             }
             PasteViewer.run();
 
@@ -2514,39 +2517,43 @@ jQuery.PrivateBin = (function($, RawDeflate) {
          */
         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
-            // Convert dataURI to a Blob and use msSaveBlob to download
+            // Using msSaveBlob to download
             if (window.Blob && navigator.msSaveBlob) {
                 $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);
                 });
             } else {
-                $attachmentLink.attr('href', attachmentData);
+                $attachmentLink.attr('href', blobUrl);
             }
 
             if (typeof fileName !== 'undefined') {
                 $attachmentLink.attr('download', fileName);
             }
 
-            me.handleAttachmentPreview($attachmentPreview, attachmentData);
+            me.handleBlobAttachmentPreview($attachmentPreview, blobUrl, mediaType);
         };
 
         /**
@@ -2739,7 +2746,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
                 attachmentData = dataURL;
 
                 if (Editor.isPreview()) {
-                    me.handleAttachmentPreview($attachmentPreview, dataURL);
+                    me.setAttachment(dataURL, loadedFile.name || '');
                     $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
          * @argument {jQuery} $targetElement element where the preview should be appended
-         * @argument {string} file as a data URL
-         */
-        me.handleAttachmentPreview = function ($targetElement, data) {
-            if (data) {
-                // source: https://developer.mozilla.org/en-US/docs/Web/API/FileReader#readAsDataURL()
-                const mimeType = data.slice(
-                    data.indexOf('data:') + 5,
-                    data.indexOf(';base64,')
-                );
-
+         * @argument {string} file as a blob URL
+         * @argument {string} mime type
+         */
+        me.handleBlobAttachmentPreview = function ($targetElement, blobUrl, mimeType) {
+            if (blobUrl) {
                 attachmentHasPreview = true;
                 if (mimeType.match(/image\//i)) {
                     $targetElement.html(
                         $(document.createElement('img'))
-                            .attr('src', data)
+                            .attr('src', blobUrl)
                             .attr('class', 'img-thumbnail')
                     );
                 } else if (mimeType.match(/video\//i)) {
@@ -2778,7 +2780,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
 
                             .append($(document.createElement('source'))
                             .attr('type', mimeType)
-                            .attr('src', data))
+                            .attr('src', blobUrl))
                     );
                 } else if (mimeType.match(/audio\//i)) {
                     $targetElement.html(
@@ -2788,26 +2790,15 @@ jQuery.PrivateBin = (function($, RawDeflate) {
 
                             .append($(document.createElement('source'))
                             .attr('type', mimeType)
-                            .attr('src', data))
+                            .attr('src', blobUrl))
                     );
                 } 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
-                    const clientHeight = $(window).height();
+                    var clientHeight = $(window).height();
 
                     $targetElement.html(
                         $(document.createElement('embed'))
-                            .attr('src', data)
+                            .attr('src', blobUrl)
                             .attr('type', 'application/pdf')
                             .attr('class', 'pdfPreview')
                             .css('height', clientHeight)

+ 15 - 3
js/test/AttachmentViewer.js

@@ -11,13 +11,13 @@ describe('AttachmentViewer', function () {
         jsc.property(
             'displays & hides data as requested',
             common.jscMimeTypes(),
-            jsc.nearray(common.jscBase64String()),
             'string',
             'string',
             'string',
-            function (mimeType, base64, filename, prefix, postfix) {
+            'string',
+            function (mimeType, rawdata, filename, prefix, postfix) {
                 var clean = jsdom(),
-                    data = 'data:' + mimeType + ';base64,' + base64.join(''),
+                    data = 'data:' + mimeType + ';base64,' + btoa(rawdata),
                     previewSupported = (
                         mimeType.substring(0, 6) === 'image/' ||
                         mimeType.substring(0, 6) === 'audio/' ||
@@ -34,6 +34,16 @@ describe('AttachmentViewer', function () {
                     'Download attachment</a></div><div id="attachmentPrevie' +
                     '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();
                 results.push(
                     !$.PrivateBin.AttachmentViewer.hasAttachment() &&
@@ -45,6 +55,8 @@ describe('AttachmentViewer', function () {
                 } else {
                     $.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();
                 results.push(
                     $.PrivateBin.AttachmentViewer.hasAttachment() &&

+ 1 - 1
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:; 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,
         ),
         'expire' => array(

+ 1 - 1
tpl/bootstrap.php

@@ -72,7 +72,7 @@ if ($MARKDOWN):
 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/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]>
 		<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
 		<![endif]-->

+ 1 - 1
tpl/page.php

@@ -50,7 +50,7 @@ if ($MARKDOWN):
 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/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]>
 		<style type="text/css">body {padding-left:60px;padding-right:60px;} #ienotice {display:block;} #oldienotice {display:block;}</style>
 		<![endif]-->