diff --git a/.github/workflows/test-results.yml b/.github/workflows/test-results.yml
index b9d605f1..2a315b7a 100644
--- a/.github/workflows/test-results.yml
+++ b/.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
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 37fa672a..f2b405b1 100644
--- a/CHANGELOG.md
+++ b/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)
diff --git a/cfg/conf.sample.php b/cfg/conf.sample.php
index a372eb5f..66727cb2 100644
--- a/cfg/conf.sample.php
+++ b/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
diff --git a/i18n/ar.json b/i18n/ar.json
index 71fcf042..cd116da0 100644
--- a/i18n/ar.json
+++ b/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 Ctrl+c/Cmd+c": "لنسخ اللصق انقر على زر النسخ أو استخدم اختصار الحافظة Ctrl+c/Cmd+c",
"Copy link": "نسخ الرابط",
- "Link copied to clipboard": "تم نسخ الرابط إلى الحافظة",
+ "Link copied to clipboard": "نُسخ الرابط إلى الحافظة",
"Paste text": "لصق النص",
"Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "مفتاح التبويب يعمل كشخصية (انقر Ctrl+m أو Esc للتبديل)",
"Theme": "السمة"
diff --git a/lib/Configuration.php b/lib/Configuration.php
index 2f278e18..c39f71f5 100644
--- a/lib/Configuration.php
+++ b/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',
diff --git a/lib/TemplateSwitcher.php b/lib/TemplateSwitcher.php
index 8ecdad17..99dd317b 100644
--- a/lib/TemplateSwitcher.php
+++ b/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;
}
/**
diff --git a/lib/View.php b/lib/View.php
index 666a03f7..dd15e321 100644
--- a/lib/View.php
+++ b/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
*
diff --git a/tst/TemplateSwitcherTest.php b/tst/TemplateSwitcherTest.php
index d66e320b..482f23a1 100644
--- a/tst/TemplateSwitcherTest.php
+++ b/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()
diff --git a/tst/ViewTest.php b/tst/ViewTest.php
index 26994579..cafd63ed 100644
--- a/tst/ViewTest.php
+++ b/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');
+ }
}