Просмотр исходного кода

Merge branch 'master' into dompurify-3.2.6

# Conflicts:
#	lib/Configuration.php
Ribas160 1 год назад
Родитель
Сommit
c7b9ce0bc2

+ 1 - 1
.github/workflows/test-results.yml

@@ -24,7 +24,7 @@ jobs:
 
     steps:
        - name: Download and Extract Artifacts
-         uses: dawidd6/action-download-artifact@4c1e823582f43b179e2cbb49c3eade4e41f992e2
+         uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5
          with:
           run_id: ${{ github.event.workflow_run.id }}
           path: artifacts

+ 1 - 0
CHANGELOG.md

@@ -6,6 +6,7 @@
 * CHANGED: Removed use of ctype functions and polyfill library for ctype
 * CHANGED: Upgrading libraries to: DOMpurify 3.2.6, ip-lib 1.20.0
 * CHANGED: Support for multiple file uploads (#1060)
+* CHANGED: Documented CSP change necessary to allow PDF attachment preview (#1552)
 * FIXED: Hide Reply button in the discussions once clicked to avoid losing the text input (#1508)
 
 ## 1.7.6 (2025-02-01)

+ 9 - 1
cfg/conf.sample.php

@@ -118,7 +118,15 @@ languageselection = false
 ;   for details.
 ; - The 'wasm-unsafe-eval' is used to enable webassembly support (used for zlib
 ;   compression). You can remove it if compression doesn't need to be supported.
-; cspheader = "default-src 'none'; base-uri 'self'; form-action 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'wasm-unsafe-eval'; style-src 'self'; font-src 'self'; frame-ancestors 'none'; img-src 'self' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-downloads"
+; - The 'unsafe-inline' style-src is used by Chrome when displaying PDF previews
+;   and can be omitted if attachment upload is disabled (which is the default).
+;   See https://issues.chromium.org/issues/343754409
+; - To allow displaying PDF previews in Firefox or Chrome, sandboxing must also
+;   get turned off. The following CSP allows PDF previews:
+; cspheader = "default-src 'none'; base-uri 'self'; form-action 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; font-src 'self'; frame-ancestors 'none'; frame-src blob:; img-src 'self' data: blob:; media-src blob:; object-src blob:"
+;
+; The recommended and default used CSP is:
+; cspheader = "default-src 'none'; base-uri 'self'; form-action 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'wasm-unsafe-eval'; style-src 'self'; font-src 'self'; frame-ancestors 'none'; frame-src blob:; img-src 'self' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-downloads"
 
 ; 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

+ 9 - 9
i18n/ar.json

@@ -168,13 +168,13 @@
     "Plain Text": "نص عادي",
     "Source Code": "كود مصدر",
     "Markdown": "ماركداون",
-    "Download attachment": "تنزيل المرفقات",
+    "Download attachment": "نزّل المرفق",
     "Cloned: '%s'": "مستنسخ: '%s'",
-    "The cloned file '%s' was attached to this paste.": "تم إرفاق المِلَفّ المستنسخ '%s' بهذا اللصق.",
-    "Attach a file": "إرفاق مِلَفّ",
+    "The cloned file '%s' was attached to this paste.": "تم إرفاق الملف المستنسخ '%s' بهذا اللصق.",
+    "Attach a file": "أرفق ملف",
     "alternatively drag & drop a file or paste an image from the clipboard": "بدلاً من ذلك، اسحب ملفًا وأسقطه أو الصق صورة من الحافظة",
-    "File too large, to display a preview. Please download the attachment.": "المِلَفّ كبير جدًا، بحيث لا يمكن عرض معاينة. الرجاء تنزيل المرفق.",
-    "Remove attachment": "إزالة المرفق",
+    "File too large, to display a preview. Please download the attachment.": "الملف كبير جدًا، بحيث لا يمكن عرض معاينة. الرجاء تنزيل المرفق.",
+    "Remove attachment": "أزِل المرفق",
     "Your browser does not support uploading encrypted files. Please use a newer browser.": "متصفحك لا يدعم رفع الملفات المشفرة. الرجاء استخدام متصفح أحدث.",
     "Invalid attachment.": "مرفق غير صحيح.",
     "Options": "الخيارات",
@@ -215,16 +215,16 @@
     "Trying to shorten a URL that isn't pointing at our instance.": "محاولة تقصير عنوان URL لا يشير إلى خادمنا.",
     "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "خطأ في الاتصال بـ YOURLS. ربما تكون هناك مشكلة في التضبيط، مثل \"apiurl\" أو \"التوقيع\" الخاطئ أو المفقود.",
     "Error parsing YOURLS response.": "خطأ في تحليل استجابة YOURLS.",
-    "This secret message can only be displayed once. Would you like to see it now?": "لا يمكن عرض اللصق احرقه بعد قراءته إلا مرة واحدة عند تحميله. هل تريد فتحه الآن؟",
-    "Yes, see it": "نعم، حمله",
+    "This secret message can only be displayed once. Would you like to see it now?": "يمكن عرض هذه الرسالة السرية مرة واحدة فقط. هل ترغب في رؤيتها الآن؟",
+    "Yes, see it": "نعم، دعني اراها",
     "Dark Mode": "الوضع الداكن",
     "Error compressing paste, due to missing WebAssembly support.": "خطأ في ضغط اللصق، بسبب فقدان دعم WebAssembly.",
     "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "خطأ في فك ضغط اللصق، متصفحك لا يدعم WebAssembly. الرجاء استخدام متصفح آخر لعرض هذه اللصقة.",
     "Start over": "ابدأ من جديد",
-    "Paste copied to clipboard": "تم نسخ اللصق إلى الحافظة",
+    "Paste copied to clipboard": "نُسخ اللصق إلى الحافظة",
     "To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>": "لنسخ اللصق انقر على زر النسخ أو استخدم اختصار الحافظة <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>",
     "Copy link": "نسخ الرابط",
-    "Link copied to clipboard": "تم نسخ الرابط إلى الحافظة",
+    "Link copied to clipboard": "نُسخ الرابط إلى الحافظة",
     "Paste text": "لصق النص",
     "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "مفتاح التبويب يعمل كشخصية (انقر <kbd>Ctrl</kbd>+<kbd>m</kbd> أو <kbd>Esc</kbd> للتبديل)",
     "Theme": "السمة"

+ 1 - 1
lib/Configuration.php

@@ -65,7 +65,7 @@ class Configuration
             'qrcode'                   => true,
             'email'                    => true,
             'icon'                     => 'identicon',
-            'cspheader'                => 'default-src \'none\'; base-uri \'self\'; form-action \'none\'; manifest-src \'self\'; connect-src * blob:; script-src \'self\' \'wasm-unsafe-eval\'; style-src \'self\'; font-src \'self\'; frame-ancestors \'none\'; img-src \'self\' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-downloads',
+            'cspheader'                => 'default-src \'none\'; base-uri \'self\'; form-action \'none\'; manifest-src \'self\'; connect-src * blob:; script-src \'self\' \'wasm-unsafe-eval\'; style-src \'self\'; font-src \'self\'; frame-ancestors \'none\'; frame-src blob:; img-src \'self\' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-downloads',
             'zerobincompatibility'     => false,
             'httpwarning'              => true,
             'compression'              => 'zlib',

+ 14 - 2
lib/TemplateSwitcher.php

@@ -25,7 +25,7 @@ class TemplateSwitcher
      * @static
      * @var    string
      */
-    protected static $_templateFallback;
+    protected static $_templateFallback = 'bootstrap';
 
     /**
      * available templates
@@ -59,6 +59,11 @@ class TemplateSwitcher
     {
         if (self::isTemplateAvailable($template)) {
             self::$_templateFallback = $template;
+
+            if (!in_array($template, self::getAvailableTemplates())) {
+                // Add custom template to the available templates list
+                self::$_availableTemplates[] = $template;
+            }
         }
     }
 
@@ -96,7 +101,14 @@ class TemplateSwitcher
      */
     public static function isTemplateAvailable(string $template): bool
     {
-        return in_array($template, self::getAvailableTemplates());
+        $available = in_array($template, self::getAvailableTemplates());
+
+        if (!$available && !View::isBootstrapTemplate($template)) {
+            $path      = View::getTemplateFilePath($template);
+            $available = file_exists($path);
+        }
+
+        return $available;
     }
 
     /**

+ 26 - 2
lib/View.php

@@ -49,8 +49,7 @@ class View
      */
     public function draw($template)
     {
-        $file = substr($template, 0, 10) === 'bootstrap-' ? 'bootstrap' : $template;
-        $path = PATH . 'tpl' . DIRECTORY_SEPARATOR . $file . '.php';
+        $path = self::getTemplateFilePath($template);
         if (!file_exists($path)) {
             throw new Exception('Template ' . $template . ' not found!', 80);
         }
@@ -58,6 +57,31 @@ class View
         include $path;
     }
 
+    /**
+     * Get template file path
+     *
+     * @access public
+     * @param  string $template
+     * @return string
+     */
+    public static function getTemplateFilePath(string $template): string
+    {
+        $file = self::isBootstrapTemplate($template) ? 'bootstrap' : $template;
+        return PATH . 'tpl' . DIRECTORY_SEPARATOR . $file . '.php';
+    }
+
+    /**
+     * Is the template a variation of the bootstrap template
+     *
+     * @access public
+     * @param  string $template
+     * @return bool
+     */
+    public static function isBootstrapTemplate(string $template): bool
+    {
+        return substr($template, 0, 10) === 'bootstrap-';
+    }
+
     /**
      * echo script tag incl. SRI hash for given script file
      *

+ 11 - 5
tst/TemplateSwitcherTest.php

@@ -10,15 +10,21 @@ class TemplateSwitcherTest extends TestCase
     {
         $conf = new Configuration;
 
-        $existingTemplateFallback = 'bootstrap-dark';
-        $wrongTemplateFallback    = 'bootstrap-wrong';
+        $defaultTemplateFallback        = 'bootstrap';
+        $existingTemplateFallback       = 'bootstrap-dark';
+        $wrongBootstrapTemplateFallback = 'bootstrap-wrong';
+        $wrongTemplateFallback          = 'wrong-template';
 
         TemplateSwitcher::setAvailableTemplates($conf->getKey('availabletemplates'));
-        TemplateSwitcher::setTemplateFallback($existingTemplateFallback);
-        $this->assertEquals($existingTemplateFallback, TemplateSwitcher::getTemplate(), 'Correct template fallback');
+
+        TemplateSwitcher::setTemplateFallback($wrongBootstrapTemplateFallback);
+        $this->assertEquals($defaultTemplateFallback, TemplateSwitcher::getTemplate(), 'Wrong bootstrap template fallback');
 
         TemplateSwitcher::setTemplateFallback($wrongTemplateFallback);
-        $this->assertEquals($existingTemplateFallback, TemplateSwitcher::getTemplate(), 'Wrong template fallback');
+        $this->assertEquals($defaultTemplateFallback, TemplateSwitcher::getTemplate(), 'Wrong template fallback');
+
+        TemplateSwitcher::setTemplateFallback($existingTemplateFallback);
+        $this->assertEquals($existingTemplateFallback, TemplateSwitcher::getTemplate(), 'Correct template fallback');
     }
 
     public function testSetAvailableTemplates()

+ 16 - 0
tst/ViewTest.php

@@ -142,4 +142,20 @@ class ViewTest extends TestCase
         $this->expectExceptionCode(80);
         $test->draw('123456789 does not exist!');
     }
+
+    public function testTemplateFilePath()
+    {
+        $template     = 'bootstrap';
+        $templatePath = PATH . 'tpl' . DIRECTORY_SEPARATOR . $template . '.php';
+        $path         = View::getTemplateFilePath($template);
+        $this->assertEquals($templatePath, $path, 'Template file path');
+    }
+
+    public function testIsBootstrapTemplate()
+    {
+        $bootstrapTemplate    = 'bootstrap-dark';
+        $nonBootstrapTemplate = 'page';
+        $this->assertTrue(View::isBootstrapTemplate($bootstrapTemplate), 'Is bootstrap template');
+        $this->assertFalse(View::isBootstrapTemplate($nonBootstrapTemplate), 'Is not bootstrap template');
+    }
 }