From f49c042cc9958acd1792fcebfb817d4e395c1add Mon Sep 17 00:00:00 2001 From: El RIDO Date: Sat, 7 Jun 2025 11:44:02 +0200 Subject: [PATCH 1/5] document change necessary to allow PDF preview to work in Firefox & Chrome Since attachement upload is not enabled by default, I suggest to retain the safer CSP as the default but document what is necassary. Disabling the sandboxing is problematic. --- CHANGELOG.md | 1 + cfg/conf.sample.php | 10 +++++++++- lib/Configuration.php | 4 ++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5dff30e4..c66c3d79 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.5, 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/lib/Configuration.php b/lib/Configuration.php index b562a047..297f30ad 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', @@ -119,7 +119,7 @@ class Configuration 'js/kjua-0.9.0.js' => 'sha512-CVn7af+vTMBd9RjoS4QM5fpLFEOtBCoB0zPtaqIDC7sF4F8qgUSRFQQpIyEDGsr6yrjbuOLzdf20tkHHmpaqwQ==', 'js/legacy.js' => 'sha512-UxW/TOZKon83n6dk/09GsYKIyeO5LeBHokxyIq+r7KFS5KMBeIB/EM7NrkVYIezwZBaovnyNtY2d9tKFicRlXg==', 'js/prettify.js' => 'sha512-puO0Ogy++IoA2Pb9IjSxV1n4+kQkKXYAEUtVzfZpQepyDPyXk8hokiYDS7ybMogYlyyEIwMLpZqVhCkARQWLMg==', - 'js/privatebin.js' => 'm6RrsOsz4RgIWXDzgRghQDx6aegFCpkpqURwhfXwE/rNWhe/1rPJaLR+FXII82iTWo0n9JCzSbqrDqkYVPI50w==', + 'js/privatebin.js' => 'sha512-m6RrsOsz4RgIWXDzgRghQDx6aegFCpkpqURwhfXwE/rNWhe/1rPJaLR+FXII82iTWo0n9JCzSbqrDqkYVPI50w==', 'js/purify-3.2.5.js' => 'sha512-eLlLLL/zYuf5JuG0x4WQm687MToqOGP9cDQHIdmOy1ZpjiY4J48BBcOM7DtZheKk1UogW920+9RslWYB4KGuuA==', 'js/rawinflate-0.3.js' => 'sha512-g8uelGgJW9A/Z1tB6Izxab++oj5kdD7B4qC7DHwZkB6DGMXKyzx7v5mvap2HXueI2IIn08YlRYM56jwWdm2ucQ==', 'js/showdown-2.1.0.js' => 'sha512-WYXZgkTR0u/Y9SVIA4nTTOih0kXMEd8RRV6MLFdL6YU8ymhR528NLlYQt1nlJQbYz4EW+ZsS0fx1awhiQJme1Q==', From d544d1281d2daf58c81f45970b26be335b5bf04e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 16 Jun 2025 12:22:51 +0000 Subject: [PATCH 2/5] Bump dawidd6/action-download-artifact from 10 to 11 Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 10 to 11. - [Release notes](https://github.com/dawidd6/action-download-artifact/releases) - [Commits](https://github.com/dawidd6/action-download-artifact/compare/4c1e823582f43b179e2cbb49c3eade4e41f992e2...ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5) --- updated-dependencies: - dependency-name: dawidd6/action-download-artifact dependency-version: '11' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/test-results.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From 44f8cfbfb8df4b4bec1cbf79aa8ce51abdb18be3 Mon Sep 17 00:00:00 2001 From: Ribas160 Date: Wed, 18 Jun 2025 14:51:11 +0300 Subject: [PATCH 3/5] Fix error when a custom template is not in the default available templates list --- lib/TemplateSwitcher.php | 16 ++++++++++++++-- lib/View.php | 28 ++++++++++++++++++++++++++-- tst/TemplateSwitcherTest.php | 16 +++++++++++----- tst/ViewTest.php | 16 ++++++++++++++++ 4 files changed, 67 insertions(+), 9 deletions(-) diff --git a/lib/TemplateSwitcher.php b/lib/TemplateSwitcher.php index 8ecdad17..8b69c211 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'); + } } From c7f465fe8b7f66bfc084c50090f989de53458726 Mon Sep 17 00:00:00 2001 From: El RIDO Date: Wed, 18 Jun 2025 15:08:05 +0200 Subject: [PATCH 4/5] apply StyleCI recommendation --- lib/TemplateSwitcher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/TemplateSwitcher.php b/lib/TemplateSwitcher.php index 8b69c211..99dd317b 100644 --- a/lib/TemplateSwitcher.php +++ b/lib/TemplateSwitcher.php @@ -25,7 +25,7 @@ class TemplateSwitcher * @static * @var string */ - protected static $_templateFallback = "bootstrap"; + protected static $_templateFallback = 'bootstrap'; /** * available templates From d7b32f0219ad41dc3504d9e2ab37a6bffb23d6af Mon Sep 17 00:00:00 2001 From: PrivateBin Translator Bot <72346835+privatebin-translator@users.noreply.github.com> Date: Thu, 19 Jun 2025 11:14:42 +0200 Subject: [PATCH 5/5] New translations en.json (Arabic) --- i18n/ar.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) 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": "السمة"