Compare commits

..

No commits in common. "master" and "1.7.6" have entirely different histories.

125 changed files with 2223 additions and 2080 deletions

View File

@ -43,7 +43,7 @@ jobs:
actions: read actions: read
id-token: write id-token: write
contents: write contents: write
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0 uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
with: with:
base64-subjects: "${{ needs.release.outputs.hashes }}" base64-subjects: "${{ needs.release.outputs.hashes }}"
draft-release: true draft-release: true

View File

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

View File

@ -121,7 +121,7 @@ jobs:
- name: Setup Node - name: Setup Node
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: '18' node-version: '20'
cache: 'npm' cache: 'npm'
cache-dependency-path: 'js/package-lock.json' cache-dependency-path: 'js/package-lock.json'

View File

@ -2,7 +2,6 @@ RewriteEngine on
RewriteCond !%{HTTP_USER_AGENT} "Let's Encrypt validation server" [NC] RewriteCond !%{HTTP_USER_AGENT} "Let's Encrypt validation server" [NC]
RewriteCond %{HTTP_USER_AGENT} ^.*(bot|spider|crawl|https?://|WhatsApp|SkypeUriPreview|facebookexternalhit) [NC] RewriteCond %{HTTP_USER_AGENT} ^.*(bot|spider|crawl|https?://|WhatsApp|SkypeUriPreview|facebookexternalhit) [NC]
RewriteRule .* - [R=403,L] RewriteRule .* - [R=403,L]
AddType application/wasm .wasm
<IfModule mod_php7.c> <IfModule mod_php7.c>
php_value max_execution_time 30 php_value max_execution_time 30

View File

@ -1,11 +1,5 @@
# PrivateBin version history # PrivateBin version history
## 1.7.7 (not yet released)
* ADDED: Switching templates using the web ui (#1501)
* CHANGED: Passing large data structures by reference to reduce memory consumption (#858)
* CHANGED: Removed use of ctype functions and polyfill library for ctype
* CHANGED: Upgrading libraries to: DOMpurify 3.2.5, ip-lib 1.20.0
## 1.7.6 (2025-02-01) ## 1.7.6 (2025-02-01)
* ADDED: Ability to copy the paste by clicking the copy icon button or using the keyboard shortcut ctrl+c/cmd+c (#1390 & #12) * ADDED: Ability to copy the paste by clicking the copy icon button or using the keyboard shortcut ctrl+c/cmd+c (#1390 & #12)
* CHANGED: Allow toggling tab-key-support using `[Ctrl]+[m]` or `[Esc]` in textarea for keyboard navigation (#1386) * CHANGED: Allow toggling tab-key-support using `[Ctrl]+[m]` or `[Esc]` in textarea for keyboard navigation (#1386)

View File

@ -33,7 +33,7 @@
* Mounir Idrassi & J. Mozdzen - secure YOURLS integration * Mounir Idrassi & J. Mozdzen - secure YOURLS integration
* Felipe Nakandakari - enabled AWS SDK to use default credential provider chain in the S3 Storage backend * Felipe Nakandakari - enabled AWS SDK to use default credential provider chain in the S3 Storage backend
* Aaron Sherber - cache control headers for API calls & use of `shortenviayourls` in query parameters * Aaron Sherber - cache control headers for API calls & use of `shortenviayourls` in query parameters
* Mikhail Romanov - copying to clipboard, UI/UX improvements, templates switching * Mikhail Romanov - copying to clipboard, UI/UX improvements
## Translations ## Translations
* Hexalyse - French * Hexalyse - French

View File

@ -14,8 +14,5 @@ a response within a week (usually during the next weekend). The respondee will
reply from their personal address and can offer you their GPG public key to reply from their personal address and can offer you their GPG public key to
support end-to-end encrypted communication on sensitive topics or attachments. support end-to-end encrypted communication on sensitive topics or attachments.
You can also [use the corresponding GitHub form](https://github.com/PrivateBin/PrivateBin/security/advisories/new)
to report a new vulnerability directly on GitHub.
You can also contact us via the regular issue tracker if the risk of early You can also contact us via the regular issue tracker if the risk of early
publication is low or you would request input from other PrivateBin users. publication is low or you would request input from other PrivateBin users.

View File

@ -72,35 +72,6 @@ class Administration
exit("paste $pasteId successfully deleted" . PHP_EOL); exit("paste $pasteId successfully deleted" . PHP_EOL);
} }
/**
* lists all stored paste IDs
*
* @access private
*/
private function _list_ids()
{
$ids = $this->_store->getAllPastes();
foreach ($ids as $pasteid) {
echo $pasteid, PHP_EOL;
}
exit;
}
/**
* deletes all stored pastes (regardless of expiration)
*
* @access private
*/
private function _delete_all()
{
$ids = $this->_store->getAllPastes();
foreach ($ids as $pasteid) {
echo "Deleting paste ID: $pasteid" . PHP_EOL;
$this->_store->delete($pasteid);
}
exit("All pastes successfully deleted" . PHP_EOL);
}
/** /**
* removes empty directories, if current storage model uses Filesystem * removes empty directories, if current storage model uses Filesystem
* *
@ -153,15 +124,13 @@ class Administration
{ {
echo <<<'EOT' echo <<<'EOT'
Usage: Usage:
administration [--delete <paste id> | --delete-all | --empty-dirs | --help | --list-ids | --purge | --statistics] administration [--delete <paste id> | --empty-dirs | --help | --purge | --statistics]
Options: Options:
-d, --delete deletes the requested paste ID -d, --delete deletes the requested paste ID
--delete-all deletes all paste IDs
-e, --empty-dirs removes empty directories (only if Filesystem storage is -e, --empty-dirs removes empty directories (only if Filesystem storage is
configured) configured)
-h, --help displays this help message -h, --help displays this help message
-l, --list-ids lists all paste IDs
-p, --purge purge all expired pastes -p, --purge purge all expired pastes
-s, --statistics reads all stored pastes and comments and reports statistics -s, --statistics reads all stored pastes and comments and reports statistics
EOT, PHP_EOL; EOT, PHP_EOL;
@ -208,8 +177,7 @@ EOT, PHP_EOL;
self::_help(2); self::_help(2);
} }
$this->_opts = getopt('hd:epsl', array('help', 'delete:', 'empty-dirs', 'purge', 'statistics', 'list-ids', 'delete-all')); $this->_opts = getopt('hd:eps', array('help', 'delete:', 'empty-dirs', 'purge', 'statistics'));
if (!$this->_opts) { if (!$this->_opts) {
self::_error_echo('unsupported arguments given'); self::_error_echo('unsupported arguments given');
echo PHP_EOL; echo PHP_EOL;
@ -340,12 +308,6 @@ EOT, PHP_EOL;
$class = 'PrivateBin\\Data\\' . $this->_conf->getKey('class', 'model'); $class = 'PrivateBin\\Data\\' . $this->_conf->getKey('class', 'model');
$this->_store = new $class($this->_conf->getSection('model_options')); $this->_store = new $class($this->_conf->getSection('model_options'));
if ($this->_option('l', 'list-ids') !== null) {
$this->_list_ids();
}
if ($this->_option(null, 'delete-all') !== null) {
$this->_delete_all();
}
if (($pasteId = $this->_option('d', 'delete')) !== null) { if (($pasteId = $this->_option('d', 'delete')) !== null) {
$this->_delete($pasteId); $this->_delete($pasteId);
} }

View File

@ -42,28 +42,13 @@ defaultformatter = "plaintext"
; size limit per paste or comment in bytes, defaults to 10 Mebibytes ; size limit per paste or comment in bytes, defaults to 10 Mebibytes
sizelimit = 10485760 sizelimit = 10485760
; by default PrivateBin use "bootstrap" template (tpl/bootstrap.php). ; template to include, default is "bootstrap" (tpl/bootstrap.php), also
; Optionally you can enable the template selection menu, which uses
; a session cookie to store the choice until the browser is closed.
templateselection = false
; List of available for selection templates when "templateselection" option is enabled
availabletemplates[] = "bootstrap"
availabletemplates[] = "bootstrap-page"
availabletemplates[] = "bootstrap-dark"
availabletemplates[] = "bootstrap-dark-page"
availabletemplates[] = "bootstrap-compact"
availabletemplates[] = "bootstrap-compact-page"
availabletemplates[] = "bootstrap5"
availabletemplates[] = "page"
; set the template your installs defaults to, defaults to "bootstrap" (tpl/bootstrap.php), also
; available are "page" (tpl/page.php), the classic ZeroBin style and several ; available are "page" (tpl/page.php), the classic ZeroBin style and several
; bootstrap variants: "bootstrap-dark", "bootstrap-compact", "bootstrap-page", ; bootstrap variants: "bootstrap-dark", "bootstrap-compact", "bootstrap-page",
; which can be combined with "-dark" and "-compact" for "bootstrap-dark-page", ; which can be combined with "-dark" and "-compact" for "bootstrap-dark-page"
; "bootstrap-compact-page" and finally "bootstrap5" (tpl/bootstrap5.php) - previews at: ; and finally "bootstrap-compact-page" - previews at:
; https://privatebin.info/screenshots.html ; https://privatebin.info/screenshots.html
; template = "bootstrap" template = "bootstrap"
; (optional) info text to display ; (optional) info text to display
; use single, instead of double quotes for HTML attributes ; use single, instead of double quotes for HTML attributes

View File

@ -26,8 +26,9 @@
"require" : { "require" : {
"php": "^7.3 || ^8.0", "php": "^7.3 || ^8.0",
"jdenticon/jdenticon": "1.0.2", "jdenticon/jdenticon": "1.0.2",
"mlocati/ip-lib": "1.20.0", "mlocati/ip-lib": "1.18.1",
"symfony/polyfill-php80": "1.31.0", "symfony/polyfill-ctype": "^1.31",
"symfony/polyfill-php80": "^1.31",
"yzalis/identicon": "2.0.0" "yzalis/identicon": "2.0.0"
}, },
"suggest" : { "suggest" : {

105
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "6c7e6dea19e8bfd5641b220cb68c4b65", "content-hash": "0fdf0f08646fa2a4cf9c076131f529f5",
"packages": [ "packages": [
{ {
"name": "jdenticon/jdenticon", "name": "jdenticon/jdenticon",
@ -57,16 +57,16 @@
}, },
{ {
"name": "mlocati/ip-lib", "name": "mlocati/ip-lib",
"version": "1.20.0", "version": "1.18.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/mlocati/ip-lib.git", "url": "https://github.com/mlocati/ip-lib.git",
"reference": "fd45fc3bf08ed6c7e665e2e70562082ac954afd4" "reference": "08bb43b4949069c543ebdf099a6b2c322d0172ab"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/mlocati/ip-lib/zipball/fd45fc3bf08ed6c7e665e2e70562082ac954afd4", "url": "https://api.github.com/repos/mlocati/ip-lib/zipball/08bb43b4949069c543ebdf099a6b2c322d0172ab",
"reference": "fd45fc3bf08ed6c7e665e2e70562082ac954afd4", "reference": "08bb43b4949069c543ebdf099a6b2c322d0172ab",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -112,7 +112,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/mlocati/ip-lib/issues", "issues": "https://github.com/mlocati/ip-lib/issues",
"source": "https://github.com/mlocati/ip-lib/tree/1.20.0" "source": "https://github.com/mlocati/ip-lib/tree/1.18.1"
}, },
"funding": [ "funding": [
{ {
@ -124,7 +124,86 @@
"type": "other" "type": "other"
} }
], ],
"time": "2025-02-04T17:30:58+00:00" "time": "2024-10-29T15:44:19+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"provide": {
"ext-ctype": "*"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
}, },
{ {
"name": "symfony/polyfill-php80", "name": "symfony/polyfill-php80",
@ -337,16 +416,16 @@
}, },
{ {
"name": "myclabs/deep-copy", "name": "myclabs/deep-copy",
"version": "1.13.0", "version": "1.12.1",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/myclabs/DeepCopy.git", "url": "https://github.com/myclabs/DeepCopy.git",
"reference": "024473a478be9df5fdaca2c793f2232fe788e414" "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414", "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845",
"reference": "024473a478be9df5fdaca2c793f2232fe788e414", "reference": "123267b2c49fbf30d78a7b2d333f6be754b94845",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -385,7 +464,7 @@
], ],
"support": { "support": {
"issues": "https://github.com/myclabs/DeepCopy/issues", "issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.0" "source": "https://github.com/myclabs/DeepCopy/tree/1.12.1"
}, },
"funding": [ "funding": [
{ {
@ -393,7 +472,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2025-02-12T12:17:51+00:00" "time": "2024-11-08T17:47:46+00:00"
}, },
{ {
"name": "nikic/php-parser", "name": "nikic/php-parser",

View File

@ -22,6 +22,7 @@ for more information.
### Minimal Requirements ### Minimal Requirements
- PHP version 7.3 or above - PHP version 7.3 or above
- ctype extension
- GD extension (when using identicon or vizhash icons, jdenticon works without it) - GD extension (when using identicon or vizhash icons, jdenticon works without it)
- zlib extension - zlib extension
- some disk space or a database supported by [PDO](https://php.net/manual/book.pdo.php) - some disk space or a database supported by [PDO](https://php.net/manual/book.pdo.php)

View File

@ -218,14 +218,13 @@
"This secret message can only be displayed once. Would you like to see it now?": "لا يمكن عرض اللصق احرقه بعد قراءته إلا مرة واحدة عند تحميله. هل تريد فتحه الآن؟", "This secret message can only be displayed once. Would you like to see it now?": "لا يمكن عرض اللصق احرقه بعد قراءته إلا مرة واحدة عند تحميله. هل تريد فتحه الآن؟",
"Yes, see it": "نعم، حمله", "Yes, see it": "نعم، حمله",
"Dark Mode": "الوضع الداكن", "Dark Mode": "الوضع الداكن",
"Error compressing paste, due to missing WebAssembly support.": "خطأ في ضغط اللصق، بسبب فقدان دعم WebAssembly.", "Error compressing paste, due to missing WebAssembly support.": "Error compressing paste, due to missing WebAssembly support.",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "خطأ في فك ضغط اللصق، متصفحك لا يدعم WebAssembly. الرجاء استخدام متصفح آخر لعرض هذه اللصقة.", "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.",
"Start over": "ابدأ من جديد", "Start over": "Start over",
"Paste copied to clipboard": "تم نسخ اللصق إلى الحافظة", "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>", "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>": "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>",
"Copy link": "نسخ الرابط", "Copy link": "Copy link",
"Link copied to clipboard": "تم نسخ الرابط إلى الحافظة", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "لصق النص", "Paste text": "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> للتبديل)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "السمة"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Cupià u liame", "Copy link": "Cupià u liame",
"Link copied to clipboard": "U liame hè statu cupiatu in u premepapei", "Link copied to clipboard": "U liame hè statu cupiatu in u premepapei",
"Paste text": "Testu di lappiccicu", "Paste text": "Testu di lappiccicu",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "U tastu di tabulazione ghjova cumè un caratteru (Appughjate nantà <kbd>Ctrl</kbd>+<kbd>m</kbd> o <kbd>Scapp</kbd> per scambià)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "U tastu di tabulazione ghjova cumè un caratteru (Appughjate nantà <kbd>Ctrl</kbd>+<kbd>m</kbd> o <kbd>Scapp</kbd> per scambià)"
"Theme": "Tema"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Verknüpfung kopieren", "Copy link": "Verknüpfung kopieren",
"Link copied to clipboard": "Verknüpfung wurde in die Zwischenablage kopiert.", "Link copied to clipboard": "Verknüpfung wurde in die Zwischenablage kopiert.",
"Paste text": "Text", "Paste text": "Text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulatortaste als Zeichen interpretieren (Umschalten durch <kbd>Strg</kbd>+<kbd>m</kbd> oder <kbd>Esc</kbd>)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulatortaste als Zeichen interpretieren (Umschalten durch <kbd>Strg</kbd>+<kbd>m</kbd> oder <kbd>Esc</kbd>)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -215,17 +215,16 @@
"Trying to shorten a URL that isn't pointing at our instance.": "Püüame lühendada URL-i, mis ei viita meie instantsile.", "Trying to shorten a URL that isn't pointing at our instance.": "Püüame lühendada URL-i, mis ei viita meie instantsile.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Viga YOURLS-i kutsumisel. Tõenäoliselt konfiguratsiooniprobleem, näiteks vale või puuduv \"apiurl\" või \"signature\".", "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Viga YOURLS-i kutsumisel. Tõenäoliselt konfiguratsiooniprobleem, näiteks vale või puuduv \"apiurl\" või \"signature\".",
"Error parsing YOURLS response.": "Viga YOURLS vastuse parsimisel.", "Error parsing YOURLS response.": "Viga YOURLS vastuse parsimisel.",
"This secret message can only be displayed once. Would you like to see it now?": "Seda turvalist sõnumit saab kuvada vaid ühe korra. \nKas soovid seda näha nüüd?", "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?",
"Yes, see it": "Jah, vaata seda", "Yes, see it": "Yes, see it",
"Dark Mode": "Tume režiim", "Dark Mode": "Tume režiim",
"Error compressing paste, due to missing WebAssembly support.": "Error compressing paste, due to missing WebAssembly support.", "Error compressing paste, due to missing WebAssembly support.": "Error compressing paste, due to missing WebAssembly support.",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.", "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.",
"Start over": "Alusta uuesti", "Start over": "Start over",
"Paste copied to clipboard": "Kleebe kopeeriti lõikelauale", "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>": "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>", "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>": "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>",
"Copy link": "Kopeeri link", "Copy link": "Copy link",
"Link copied to clipboard": "Link kopeeriti lõikelauale", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Kleebi tekst", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Teema"
} }

View File

@ -218,14 +218,13 @@
"This secret message can only be displayed once. Would you like to see it now?": "Tämä salainen viesti voidaan näyttää vain kerran. Haluatko nähdä sen nyt?", "This secret message can only be displayed once. Would you like to see it now?": "Tämä salainen viesti voidaan näyttää vain kerran. Haluatko nähdä sen nyt?",
"Yes, see it": "Kyllä, näet sen", "Yes, see it": "Kyllä, näet sen",
"Dark Mode": "Tumma tila", "Dark Mode": "Tumma tila",
"Error compressing paste, due to missing WebAssembly support.": "Virhe pakattaessa pastea, koska WebAssembly-tuki puuttuu.", "Error compressing paste, due to missing WebAssembly support.": "Error compressing paste, due to missing WebAssembly support.",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Virhe pasten purkamisessa, selaimesi ei tue WebAssemblyä. Ole hyvä ja käytä toista selainta nähdäksesi tämä paste.", "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.",
"Start over": "Aloita alusta", "Start over": "Start over",
"Paste copied to clipboard": "Paste kopioitu leikepöydälle", "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>": "Voit kopioida pasten painamalla kopioi-painiketta tai käyttämällä leikepöydän oikotietä <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>", "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>": "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>",
"Copy link": "Kopioi linkki", "Copy link": "Copy link",
"Link copied to clipboard": "Linkki kopioitu leikepöydälle", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Liitä teksti", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulaattori toimii merkkinä (Paina <kbd>Ctrl</kbd>+<kbd>m</kbd> tai <kbd>Esc</kbd> vaihtaaksesi)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Teema"
} }

View File

@ -151,7 +151,7 @@
"server error or not responding": "Le serveur ne répond pas ou a rencontré une erreur", "server error or not responding": "Le serveur ne répond pas ou a rencontré une erreur",
"Could not post comment: %s": "Impossible de poster le commentaire : %s", "Could not post comment: %s": "Impossible de poster le commentaire : %s",
"Sending paste…": "Envoi du paste…", "Sending paste…": "Envoi du paste…",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit <kbd>Ctrl</kbd>+<kbd>c</kbd> to copy)</span>": "Votre paste est disponible à l'adresse <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Appuyez sur <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd> pour copier)</span>", "Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit <kbd>Ctrl</kbd>+<kbd>c</kbd> to copy)</span>": "Votre paste est disponible à l'adresse <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Appuyez sur <kbd>Ctrl</kbd>+<kbd>c</kbd> pour copier)</span>",
"Delete data": "Supprimer les données du paste", "Delete data": "Supprimer les données du paste",
"Could not create paste: %s": "Impossible de créer le paste : %s", "Could not create paste: %s": "Impossible de créer le paste : %s",
"Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Impossible de déchiffrer le paste : Clé de déchiffrement manquante dans l'URL (Avez-vous utilisé un redirecteur ou un site de réduction d'URL qui supprime une partie de l'URL ?)", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Impossible de déchiffrer le paste : Clé de déchiffrement manquante dans l'URL (Avez-vous utilisé un redirecteur ou un site de réduction d'URL qui supprime une partie de l'URL ?)",
@ -221,11 +221,10 @@
"Error compressing paste, due to missing WebAssembly support.": "Erreur lors de la compression du paste, en raison du support de WebAssembly manquant.", "Error compressing paste, due to missing WebAssembly support.": "Erreur lors de la compression du paste, en raison du support de WebAssembly manquant.",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Erreur lors de la décompression du paste, votre navigateur ne supporte pas WebAssembly. Veuillez utiliser un autre navigateur pour voir ce paste.", "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Erreur lors de la décompression du paste, votre navigateur ne supporte pas WebAssembly. Veuillez utiliser un autre navigateur pour voir ce paste.",
"Start over": "Recommencer", "Start over": "Recommencer",
"Paste copied to clipboard": "Paste copié dans le presse-papier", "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>": "Pour copier-coller appuyer sur le bouton 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>", "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>": "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>",
"Copy link": "Copier le lien", "Copy link": "Copier le lien",
"Link copied to clipboard": "Lien copié dans le presse-papier", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Texte du paste", "Paste text": "Texte du paste",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "La touche de tabulation sert de caractère (Presser <kbd>Ctrl</kbd>+<kbd>m</kbd> ou <kbd>Esc</kbd> pour basculer)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -1,7 +1,7 @@
{ {
"PrivateBin": "PrivateBin", "PrivateBin": "PrivateBin",
"%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s הוא שירות pastebin מקוון, מינימליסטי וקוד פתוח, שבו לשרת אין כל ידע על המידע שהודבק. הנתונים מוצפנים ומפוענחים %sבדפדפן%s באמצעות הצפנת AES ב-256 סיביות.", "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.",
"More information on the <a href=\"https://privatebin.info/\">project page</a>.": "מידע נוסף בדף <a href=\"https://privatebin.info/\">הפרויקט</a>.", "More information on the <a href=\"https://privatebin.info/\">project page</a>.": "More information on the <a href=\"https://privatebin.info/\">project page</a>.",
"Because ignorance is bliss": "כיוון שבורות היא ברכה", "Because ignorance is bliss": "כיוון שבורות היא ברכה",
"Paste does not exist, has expired or has been deleted.": "ההדבקה לא קיימת, פגה או נמחקה.", "Paste does not exist, has expired or has been deleted.": "ההדבקה לא קיימת, פגה או נמחקה.",
"%s requires php %s or above to work. Sorry.": "%s דורש PHP %s כדי לפעול.", "%s requires php %s or above to work. Sorry.": "%s דורש PHP %s כדי לפעול.",
@ -29,7 +29,7 @@
"Create": "צור", "Create": "צור",
"Clone": "שכפול", "Clone": "שכפול",
"Raw text": "טקסט גולמי", "Raw text": "טקסט גולמי",
"Expires": "יפוג ב", "Expires": "Expires",
"Burn after reading": "קוראים-שורפים", "Burn after reading": "קוראים-שורפים",
"Open discussion": "פתיחת דיון", "Open discussion": "פתיחת דיון",
"Password (recommended)": "ססמה (מומלץ)", "Password (recommended)": "ססמה (מומלץ)",
@ -53,11 +53,11 @@
], ],
"%d hours": [ "%d hours": [
"שעה אחת", "שעה אחת",
"%d שעות", "%d hours (1st plural)",
"%d שעות", "%d hours (2nd plural)",
"%d שעות", "%d hours (3rd plural)",
"%d שעות", "%d hours (4th plural)",
"%d שעות" "%d hours (5th plural)"
], ],
"%d days": [ "%d days": [
"יום אחד", "יום אחד",
@ -94,44 +94,44 @@
"Never": "לעולם לא", "Never": "לעולם לא",
"Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "הערה: זהו שירות בדקה: המידע לא ישמר.", "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "הערה: זהו שירות בדקה: המידע לא ישמר.",
"This document will expire in %d seconds.": [ "This document will expire in %d seconds.": [
"מסמך זה יפוג בעוד שנייה אחת.", "This document will expire in %d second. (singular)",
"מסמך זה יפוג בעוד %d שניות.", "This document will expire in %d seconds. (1st plural)",
"מסמך זה יפוג בעוד %d שניות.", "This document will expire in %d seconds. (2nd plural)",
"מסמך זה יפוג בעוד %d שניות.", "This document will expire in %d seconds. (3rd plural)",
"מסמך זה יפוג בעוד %d שניות.", "This document will expire in %d seconds. (4th plural)",
"מסמך זה יפוג בעוד %d שניות." "This document will expire in %d seconds. (5th plural)"
], ],
"This document will expire in %d minutes.": [ "This document will expire in %d minutes.": [
"מסמך זה יפוג בעוד דקה אחת.", "This document will expire in %d minute. (singular)",
"מסמך זה יפוג בעוד %d דקות.", "This document will expire in %d minutes. (1st plural)",
"מסמך זה יפוג בעוד %d דקות.", "This document will expire in %d minutes. (2nd plural)",
"מסמך זה יפוג בעוד %d דקות.", "This document will expire in %d minutes. (3rd plural)",
"מסמך זה יפוג בעוד %d דקות.", "This document will expire in %d minutes. (4th plural)",
"מסמך זה יפוג בעוד %d דקות." "This document will expire in %d minutes. (5th plural)"
], ],
"This document will expire in %d hours.": [ "This document will expire in %d hours.": [
"מסמך זה יפוג בעוד שעה אחת.", "This document will expire in %d hour. (singular)",
"מסמך זה יפוג בעוד %d שעות.", "This document will expire in %d hours. (1st plural)",
"מסמך זה יפוג בעוד %d שעות.", "This document will expire in %d hours. (2nd plural)",
"מסמך זה יפוג בעוד %d שעות.", "This document will expire in %d hours. (3rd plural)",
"מסמך זה יפוג בעוד %d שעות.", "This document will expire in %d hours. (4th plural)",
"מסמך זה יפוג בעוד %d שעות." "This document will expire in %d hours. (5th plural)"
], ],
"This document will expire in %d days.": [ "This document will expire in %d days.": [
"מסמך זה יפוג בעוד יום אחד.", "This document will expire in %d day. (singular)",
"מסמך זה יפוג בעוד %d ימים.", "This document will expire in %d days. (1st plural)",
"מסמך זה יפוג בעוד %d ימים.", "This document will expire in %d days. (2nd plural)",
"מסמך זה יפוג בעוד %d ימים.", "This document will expire in %d days. (3rd plural)",
"מסמך זה יפוג בעוד %d ימים.", "This document will expire in %d days. (4th plural)",
"מסמך זה יפוג בעוד %d ימים." "This document will expire in %d days. (5th plural)"
], ],
"This document will expire in %d months.": [ "This document will expire in %d months.": [
"מסמך זה יפוג בעוד חודש אחד.", "This document will expire in %d month. (singular)",
"מסמך זה יפוג בעוד %d חודשים.", "This document will expire in %d months. (1st plural)",
"מסמך זה יפוג בעוד %d חודשים.", "This document will expire in %d months. (2nd plural)",
"מסמך זה יפוג בעוד %d חודשים.", "This document will expire in %d months. (3rd plural)",
"מסמך זה יפוג בעוד %d חודשים.", "This document will expire in %d months. (4th plural)",
"מסמך זה יפוג בעוד %d חודשים." "This document will expire in %d months. (5th plural)"
], ],
"Please enter the password for this paste:": "נא למלא את הססמה להדבקה הזו:", "Please enter the password for this paste:": "נא למלא את הססמה להדבקה הזו:",
"Could not decrypt data (Wrong key?)": "לא ניתן לפענח את הנתונים (מפתח שגוי?)", "Could not decrypt data (Wrong key?)": "לא ניתן לפענח את הנתונים (מפתח שגוי?)",
@ -170,29 +170,29 @@
"Markdown": "Markdown", "Markdown": "Markdown",
"Download attachment": "הורדת קובץ מצורף", "Download attachment": "הורדת קובץ מצורף",
"Cloned: '%s'": "שוכפל: '%s'", "Cloned: '%s'": "שוכפל: '%s'",
"The cloned file '%s' was attached to this paste.": "הקובץ '%s' שהועתק צורף להדבקה זו.", "The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.",
"Attach a file": "צירוף קובץ", "Attach a file": "צירוף קובץ",
"alternatively drag & drop a file or paste an image from the clipboard": "לחלופין, ניתן לגרור ולשחרר קובץ או להדביק תמונה מהלוח.", "alternatively drag & drop a file or paste an image from the clipboard": "alternatively drag & drop a file or paste an image from the clipboard",
"File too large, to display a preview. Please download the attachment.": "הקובץ גדול מדי כדי להציג תצוגה מקדימה. אנא הורד את הקובץ המצורף.", "File too large, to display a preview. Please download the attachment.": "File too large, to display a preview. Please download the attachment.",
"Remove attachment": "הסר קובץ מצורף", "Remove attachment": "Remove attachment",
"Your browser does not support uploading encrypted files. Please use a newer browser.": "הדפדפן שלך אינו תומך בהעלאת קבצים מוצפנים. אנא השתמש בדפדפן עדכני יותר.", "Your browser does not support uploading encrypted files. Please use a newer browser.": "Your browser does not support uploading encrypted files. Please use a newer browser.",
"Invalid attachment.": "קובץ מצורף שגוי.", "Invalid attachment.": "קובץ מצורף שגוי.",
"Options": "אפשרויות", "Options": "אפשרויות",
"Shorten URL": "קיצור כתובת", "Shorten URL": "קיצור כתובת",
"Editor": "עורך", "Editor": "עורך",
"Preview": "תצוגה מקדימה", "Preview": "תצוגה מקדימה",
"%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s דורש שה-PATH יסתיים ב-\"%s\". אנא עדכן את ה-PATH בקובץ index.php שלך.", "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.",
"Decrypt": "פענוח", "Decrypt": "פענוח",
"Enter password": "נא למלא ססמה", "Enter password": "נא למלא ססמה",
"Loading…": "בטעינה…", "Loading…": "בטעינה…",
"Decrypting paste…": "ההדבקה מפוענחת…", "Decrypting paste…": "ההדבקה מפוענחת…",
"Preparing new paste…": "ההדבקה החדשה בהכנות…", "Preparing new paste…": "ההדבקה החדשה בהכנות…",
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.": "אם הודעה זו לא נעלמת, אנא עיין ב- <a href=\"%s\">שאלות נפוצות אלה למידע לפתרון בעיות</a>.", "In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.": "In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.",
"+++ no paste text +++": "+++ אין טקסט להדבקה +++", "+++ no paste text +++": "+++ אין טקסט להדבקה +++",
"Could not get paste data: %s": "לא ניתן לקבל את נתוני ההדבקה: %s", "Could not get paste data: %s": "לא ניתן לקבל את נתוני ההדבקה: %s",
"QR code": "קוד QR", "QR code": "קוד QR",
"This website is using an insecure HTTP connection! Please use it only for testing.": "האתר הזה משתמש בחיבור HTTP בלתי מאובטח! נא להשתמש בזה לבדיקות בלבד.", "This website is using an insecure HTTP connection! Please use it only for testing.": "האתר הזה משתמש בחיבור HTTP בלתי מאובטח! נא להשתמש בזה לבדיקות בלבד.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "לפרטים נוספים <a href=\"%s\">עיין ברשומת שאלות נפוצות זו</a>.", "For more information <a href=\"%s\">see this FAQ entry</a>.": "יש מידע נוסף <a href=\"%s\">ברשומה הזאת בשו״ת</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "יכול להיות שהדפדפן שלך ידרוש חיבור HTTPS כדי לתמוך ב־API של WebCrypto. כדי לנסות <a href=\"%s\">לעבור ל־HTTPS</a>.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "יכול להיות שהדפדפן שלך ידרוש חיבור HTTPS כדי לתמוך ב־API של WebCrypto. כדי לנסות <a href=\"%s\">לעבור ל־HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "הדפדפן שלך לא תומך ב־WebAssembly שמשמש לדחיסת zlib. אפשר ליצור מסמכים בלתי מוצפנים אך אין אפשרות לקרוא מסמכים מוצפנים.", "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "הדפדפן שלך לא תומך ב־WebAssembly שמשמש לדחיסת zlib. אפשר ליצור מסמכים בלתי מוצפנים אך אין אפשרות לקרוא מסמכים מוצפנים.",
"waiting on user to provide a password": "בהמתנה למילוי הססמה מצד המשתמש", "waiting on user to provide a password": "בהמתנה למילוי הססמה מצד המשתמש",
@ -209,23 +209,22 @@
"Close": "סגירה", "Close": "סגירה",
"Encrypted note on %s": "%sהערה מוצפנת ב־", "Encrypted note on %s": "%sהערה מוצפנת ב־",
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "נא לבקר בקישור כדי לצפות בהערה. מסירת הקישור לאנשים כלשהם תאפשר גם להם לגשת להערה.", "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "נא לבקר בקישור כדי לצפות בהערה. מסירת הקישור לאנשים כלשהם תאפשר גם להם לגשת להערה.",
"URL shortener may expose your decrypt key in URL.": "שירות קיצור כתובת URL עשוי לחשוף את מפתח הפענוח שלך בכתובת ה-URL.", "URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
"Save paste": "שמור הדבקה", "Save paste": "Save paste",
"Your IP is not authorized to create pastes.": "ה-IP שלך אינו מורשה ליצור הדבקות.", "Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
"Trying to shorten a URL that isn't pointing at our instance.": "מנסים לקצר כתובת URL שאינה מצביעה על המערכת שלנו.", "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "שגיאה בעת קריאה ל-YOURLS. כנראה מדובר בבעיה בהגדרות, כמו \"apiurl\" או \"signature\" שגויים או חסרים.", "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "שגיאה בניתוח התגובה מ-YOURLS.", "Error parsing YOURLS response.": "Error parsing YOURLS response.",
"This secret message can only be displayed once. Would you like to see it now?": "ההודעה הסודית הזו יכולה להוצג רק פעם אחת. האם תרצה לראות אותה עכשיו?", "This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?",
"Yes, see it": "כן, ראה אותה", "Yes, see it": "Yes, see it",
"Dark Mode": "מצב כהה", "Dark Mode": "Dark Mode",
"Error compressing paste, due to missing WebAssembly support.": "שגיאה בדחיסת ההדבקה, עקב חוסר תמיכה ב-WebAssembly.", "Error compressing paste, due to missing WebAssembly support.": "Error compressing paste, due to missing WebAssembly support.",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "שגיאה בהפקת ההדבקה, הדפדפן שלך לא תומך ב-WebAssembly. אנא השתמש בדפדפן אחר כדי לצפות בהדבקה זו.", "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.",
"Start over": "להתחיל מחדש", "Start over": "Start over",
"Paste copied to clipboard": "ההדבקה הועתקה ללוח", "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>", "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>": "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>",
"Copy link": "העתק קישור", "Copy link": "Copy link",
"Link copied to clipboard": "הקישור הועתק ללוח", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "הדבק טקסט", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "משטח ה-tab פועל כמקש תו (לחץ על <kbd>Ctrl</kbd>+<kbd>m</kbd> או <kbd>Esc</kbd> להחלפה)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "נושא"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copia il link", "Copy link": "Copia il link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Testo del messaggio", "Paste text": "Testo del messaggio",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -143,7 +143,7 @@
"Avatar generated from IP address": "Anonieme avatar (van het IP-adres)", "Avatar generated from IP address": "Anonieme avatar (van het IP-adres)",
"Add comment": "Commentaar toevoegen", "Add comment": "Commentaar toevoegen",
"Optional nickname…": "Optionele bijnaam…", "Optional nickname…": "Optionele bijnaam…",
"Post comment": "Plaats commentaar", "Post comment": "Plaats een commentaar",
"Sending comment…": "Commentaar verzenden…", "Sending comment…": "Commentaar verzenden…",
"Comment posted.": "Commentaar geplaatst.", "Comment posted.": "Commentaar geplaatst.",
"Could not refresh display: %s": "Kon de weergave niet vernieuwen: %s", "Could not refresh display: %s": "Kon de weergave niet vernieuwen: %s",
@ -220,12 +220,11 @@
"Dark Mode": "Donkere modus", "Dark Mode": "Donkere modus",
"Error compressing paste, due to missing WebAssembly support.": "Fout bij het comprimeren van notitie door ontbrekende ondersteuning voor WebAssembly.", "Error compressing paste, due to missing WebAssembly support.": "Fout bij het comprimeren van notitie door ontbrekende ondersteuning voor WebAssembly.",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Fout bij het decomprimeren van de notitie, uw browser ondersteunt WebAssembly niet. Gebruik een andere browser om deze notitie te bekijken.", "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Fout bij het decomprimeren van de notitie, uw browser ondersteunt WebAssembly niet. Gebruik een andere browser om deze notitie te bekijken.",
"Start over": "Opnieuw beginnen", "Start over": "Start over",
"Paste copied to clipboard": "Notitie gekopieerd naar klembord", "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>": "Om te kopiëren en plakken druk je op de knop Kopiëren of gebruik je de sneltoets op het klembord <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>", "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>": "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>",
"Copy link": "Kopieer link", "Copy link": "Copy link",
"Link copied to clipboard": "Link gekopieerd naar klembord", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Tekst plakken", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulatortoets dient als teken (gebruik <kbd>Ctrl</kbd>+<kbd>m</kbd> of <kbd>Esc</kbd> om te schakelen)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -220,12 +220,11 @@
"Dark Mode": "Ciemny motyw", "Dark Mode": "Ciemny motyw",
"Error compressing paste, due to missing WebAssembly support.": "Błąd kompresowania wklejenia przez brak obsługi WebAssembly.", "Error compressing paste, due to missing WebAssembly support.": "Błąd kompresowania wklejenia przez brak obsługi WebAssembly.",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Błąd dekompresowania wklejenia przez brak obsługi WebAssembly przez przeglądarkę. Użyj innej przeglądarki, aby zobaczyć to wklejenie.", "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Błąd dekompresowania wklejenia przez brak obsługi WebAssembly przez przeglądarkę. Użyj innej przeglądarki, aby zobaczyć to wklejenie.",
"Start over": "Zacznij od nowa", "Start over": "Start over",
"Paste copied to clipboard": "Wklejka skopiowana do schowka", "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>": "Aby skopiować wklejkę, naciśnij przycisk kopiowania lub użyj skrótu schowka <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>", "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>": "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>",
"Copy link": "Kopiuj link", "Copy link": "Copy link",
"Link copied to clipboard": "Link został skopiowany do schowka", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Wklej tekst", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Klawisz Tabulatora służy jako znak (przytrzymaj <kbd>Ctrl</kbd>+<kbd>m</kbd> lub <kbd>Esc</kbd> aby przełączać)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Motyw"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Скопировать ссылку", "Copy link": "Скопировать ссылку",
"Link copied to clipboard": "Ссылка скопирована в буфер обмена", "Link copied to clipboard": "Ссылка скопирована в буфер обмена",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Тема"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -226,6 +226,5 @@
"Copy link": "Copy link", "Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "Theme"
} }

View File

@ -221,11 +221,10 @@
"Error compressing paste, due to missing WebAssembly support.": "由于缺少 WebAssembly 支持,在压缩粘贴时出错。", "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。请使用其他浏览器查看此粘贴。", "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "解压粘贴时出错,您的浏览器不支持 WebAssembly。请使用其他浏览器查看此粘贴。",
"Start over": "重新开始", "Start over": "重新开始",
"Paste copied to clipboard": "粘贴内容已复制到剪贴板", "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>。", "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>": "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>",
"Copy link": "复制链接", "Copy link": "Copy link",
"Link copied to clipboard": "链接已复制到剪贴板", "Link copied to clipboard": "Link copied to clipboard",
"Paste text": "粘贴文本", "Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tab 键可作为字符(按 <kbd>Ctrl</kbd>+<kbd>m</kbd> 或 <kbd>Esc</kbd> 切换开关)", "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Theme": "主题"
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 741 B

After

Width:  |  Height:  |  Size: 749 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 180 B

After

Width:  |  Height:  |  Size: 266 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 B

After

Width:  |  Height:  |  Size: 253 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 B

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 200 B

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 B

After

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 B

After

Width:  |  Height:  |  Size: 209 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 B

After

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -5,6 +5,7 @@ global.assert = require('assert');
global.jsc = require('jsverify'); global.jsc = require('jsverify');
global.jsdom = require('jsdom-global'); global.jsdom = require('jsdom-global');
global.cleanup = global.jsdom(); global.cleanup = global.jsdom();
global.URL = require('jsdom-url').URL;
global.fs = require('fs'); global.fs = require('fs');
global.WebCrypto = require('@peculiar/webcrypto').Crypto; global.WebCrypto = require('@peculiar/webcrypto').Crypto;
@ -16,7 +17,7 @@ require('./prettify');
global.prettyPrint = window.PR.prettyPrint; global.prettyPrint = window.PR.prettyPrint;
global.prettyPrintOne = window.PR.prettyPrintOne; global.prettyPrintOne = window.PR.prettyPrintOne;
global.showdown = require('./showdown-2.1.0'); global.showdown = require('./showdown-2.1.0');
global.DOMPurify = require('./purify-3.2.5'); global.DOMPurify = require('./purify-3.2.4');
global.baseX = require('./base-x-4.0.0').baseX; global.baseX = require('./base-x-4.0.0').baseX;
global.Legacy = require('./legacy').Legacy; global.Legacy = require('./legacy').Legacy;
require('./bootstrap-3.4.1'); require('./bootstrap-3.4.1');
@ -78,16 +79,8 @@ function parseMime(line) {
} }
// common testing helper functions // common testing helper functions
// as of jsDOM 22 the base64 functions provided in the DOM are more restrictive exports.atob = atob;
// than browser implementation and throw when being passed invalid unicode exports.btoa = btoa;
// codepoints - as we use these in the encryption with binary data, we need
// these to be character encoding agnostic
exports.atob = function(encoded) {
return Buffer.from(encoded, 'base64').toString('binary');
}
exports.btoa = function(text) {
return Buffer.from(text, 'binary').toString('base64');
}
// provides random lowercase characters from a to z // provides random lowercase characters from a to z
exports.jscA2zString = function() { exports.jscA2zString = function() {

1988
js/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,11 +6,13 @@
"directories": { "directories": {
"test": "test" "test": "test"
}, },
"dependencies": {},
"devDependencies": { "devDependencies": {
"@peculiar/webcrypto": "^1.5.0", "jsdom": "^9.12.0",
"jsdom": "^26.0.0", "jsdom-global": "^2.1.1",
"jsdom-global": "^3.0.2", "jsdom-url": "^2.2.1",
"jsverify": "^0.8.3" "jsverify": "^0.8.3",
"@peculiar/webcrypto": "^1.1.1"
}, },
"scripts": { "scripts": {
"test": "mocha", "test": "mocha",

View File

@ -58,6 +58,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
*/ */
const purifyHtmlConfig = { const purifyHtmlConfig = {
ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|magnet):)/i, ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|magnet):)/i,
SAFE_FOR_JQUERY: true,
USE_PROFILES: { USE_PROFILES: {
html: true html: true
} }
@ -3932,26 +3933,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
*/ */
function setLanguage(event) function setLanguage(event)
{ {
let lang = $(event.target).data('lang') || event.target.value; document.cookie = 'lang=' + $(event.target).data('lang') + '; SameSite=Lax; Secure';
document.cookie = 'lang=' + lang + '; SameSite=Lax; Secure';
window.location.reload();
event.preventDefault();
}
/**
* save the template in a cookie and reloads the page
*
* @name TopNav.setTemplate
* @private
* @function
* @param {Event} event
*/
function setTemplate(event)
{
let template = $(event.target).data('template') || event.target.value;
document.cookie = 'template=' + template + '; SameSite=Lax; Secure';
window.location.reload(); window.location.reload();
event.preventDefault(); event.preventDefault();
} }
@ -4643,12 +4625,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
// bootstrap template drop down // bootstrap template drop down
$('#language ul.dropdown-menu li a').click(setLanguage); $('#language ul.dropdown-menu li a').click(setLanguage);
// page template drop down // page template drop down
$('#language select').change(setLanguage); $('#language select option').click(setLanguage);
// bootstrap template drop down
$('#template ul.dropdown-menu li a').click(setTemplate);
// page template drop down
$('#template select').change(setTemplate);
// bind events // bind events
$burnAfterReading.change(changeBurnAfterReading); $burnAfterReading.change(changeBurnAfterReading);

2
js/purify-3.2.4.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
'use strict'; 'use strict';
const common = require('../common'); var common = require('../common');
describe('AttachmentViewer', function () { describe('AttachmentViewer', function () {
describe('setAttachment, showAttachment, removeAttachment, hideAttachment, hideAttachmentPreview, hasAttachment, getAttachment & moveAttachmentTo', function () { describe('setAttachment, showAttachment, removeAttachment, hideAttachment, hideAttachmentPreview, hasAttachment, getAttachment & moveAttachmentTo', function () {
@ -14,12 +14,11 @@ describe('AttachmentViewer', function () {
'string', 'string',
function (mimeType, rawdata, filename, prefix, postfix) { function (mimeType, rawdata, filename, prefix, postfix) {
let clean = jsdom(), let clean = jsdom(),
data = 'data:' + mimeType + ';base64,' + common.btoa(rawdata), data = 'data:' + mimeType + ';base64,' + btoa(rawdata),
mimePrefix = mimeType.substring(0, 6),
previewSupported = ( previewSupported = (
mimePrefix === 'image/' || mimeType.substring(0, 6) === 'image/' ||
mimePrefix === 'audio/' || mimeType.substring(0, 6) === 'audio/' ||
mimePrefix === 'video/' || mimeType.substring(0, 6) === 'video/' ||
mimeType.match(/\/pdf/i) mimeType.match(/\/pdf/i)
), ),
results = [], results = [],
@ -49,7 +48,6 @@ describe('AttachmentViewer', function () {
$('#attachment').hasClass('hidden') && $('#attachment').hasClass('hidden') &&
$('#attachmentPreview').hasClass('hidden') $('#attachmentPreview').hasClass('hidden')
); );
global.atob = common.atob;
if (filename.length) { if (filename.length) {
$.PrivateBin.AttachmentViewer.setAttachment(data, filename); $.PrivateBin.AttachmentViewer.setAttachment(data, filename);
} else { } else {

View File

@ -19,9 +19,10 @@ describe('Check', function () {
} }
); );
Legacy.Check.init(); Legacy.Check.init();
const result = Legacy.Check.getInit() && !Legacy.Check.getStatus(); const result1 = Legacy.Check.getInit() && !Legacy.Check.getStatus(),
result2 = (document.getElementById('errormessage').className !== 'hidden');
clean(); clean();
return result; return result1 && result2;
} }
), ),
{tests: 10}); {tests: 10});
@ -66,10 +67,7 @@ describe('Check', function () {
'url': (secureProtocol ? 'https' : 'http' ) + '://' + domain.join('') + '/' 'url': (secureProtocol ? 'https' : 'http' ) + '://' + domain.join('') + '/'
} }
); );
Object.defineProperty(window, 'crypto', { window.crypto = new WebCrypto();
value: new WebCrypto(),
writeable: false,
});
Legacy.Check.init(); Legacy.Check.init();
const result1 = Legacy.Check.getInit() && Legacy.Check.getStatus(), const result1 = Legacy.Check.getInit() && Legacy.Check.getStatus(),
result2 = secureProtocol === (document.getElementById('httpnotice').className === 'hidden'); result2 = secureProtocol === (document.getElementById('httpnotice').className === 'hidden');

View File

@ -4,136 +4,120 @@ const common = require('../common');
describe('CopyToClipboard', function() { describe('CopyToClipboard', function() {
this.timeout(30000); this.timeout(30000);
describe ('Copy paste to clipboard', function () { describe ('Copy paste co clipboard', function () {
jsc.property('Copy with button click', jsc.property('Copy with button click', common.jscFormats(), 'nestring', async function (format, text) {
common.jscFormats(), var clean = jsdom();
'nestring', common.enableClipboard();
async function (format, text) {
var clean = jsdom(); $('body').html(
common.enableClipboard(); '<div id="placeholder" class="hidden">+++ no paste text ' +
'+++</div><div id="prettymessage" class="hidden">' +
'<button type="button" id="prettyMessageCopyBtn"><svg id="copyIcon"></svg>' +
'<svg id="copySuccessIcon"></svg></button><pre ' +
'id="prettyprint" class="prettyprint linenums:1"></pre>' +
'</div><div id="plaintext" class="hidden"></div>'
);
$.PrivateBin.PasteViewer.init();
$.PrivateBin.PasteViewer.setFormat(format);
$.PrivateBin.PasteViewer.setText(text);
$.PrivateBin.PasteViewer.run();
$.PrivateBin.CopyToClipboard.init();
$('#prettyMessageCopyBtn').trigger('click');
$('body').html( const savedToClipboardText = await navigator.clipboard.readText();
'<div id="placeholder" class="hidden">+++ no paste text ' +
'+++</div><div id="prettymessage" class="hidden">' + clean();
'<button type="button" id="prettyMessageCopyBtn"><svg id="copyIcon"></svg>' +
'<svg id="copySuccessIcon"></svg></button><pre ' + return text === savedToClipboardText;
'id="prettyprint" class="prettyprint linenums:1"></pre>' + });
'</div><div id="plaintext" class="hidden"></div>'
);
$.PrivateBin.PasteViewer.init();
$.PrivateBin.PasteViewer.setFormat(format);
$.PrivateBin.PasteViewer.setText(text);
$.PrivateBin.PasteViewer.run();
$.PrivateBin.CopyToClipboard.init();
$('#prettyMessageCopyBtn').trigger('click');
const savedToClipboardText = await navigator.clipboard.readText();
clean();
return text === savedToClipboardText;
}
);
/** /**
* Unfortunately in JSVerify impossible to check if copy with shortcut when user selected some text on the page * Unfortunately in JSVerify impossible to check if copy with shortcut when user selected some text on the page
* (the copy paste to clipboard should not work in this case) due to lacking window.getSelection() in jsdom. * (the copy paste to clipboard should not work in this case) due to lucking window.getSelection() in jsdom.
*/ */
jsc.property('Copy with keyboard shortcut', jsc.property('Copy with keyboard shortcut', common.jscFormats(), 'nestring', async function (format, text) {
common.jscFormats(),
'nestring',
async function (format, text) {
var clean = jsdom();
common.enableClipboard();
$('body').html(
'<div id="placeholder">+++ no paste text ' +
'+++</div><div id="prettymessage" class="hidden">' +
'<button type="button" id="prettyMessageCopyBtn"><svg id="copyIcon"></svg>' +
'<svg id="copySuccessIcon"></svg></button><pre ' +
'id="prettyprint" class="prettyprint linenums:1"></pre>' +
'</div><div id="plaintext" class="hidden"></div>'
);
$.PrivateBin.PasteViewer.init();
$.PrivateBin.PasteViewer.setFormat(format);
$.PrivateBin.PasteViewer.setText(text);
$.PrivateBin.PasteViewer.run();
$.PrivateBin.CopyToClipboard.init();
$('body').trigger('copy');
const copiedTextWithoutSelectedText = await navigator.clipboard.readText();
clean();
return copiedTextWithoutSelectedText === text;
}
);
});
jsc.property('Copy link to clipboard',
'nestring',
async function (text) {
var clean = jsdom(); var clean = jsdom();
common.enableClipboard(); common.enableClipboard();
$('body').html('<button id="copyLink"></button>'); $('body').html(
'<div id="placeholder">+++ no paste text ' +
'+++</div><div id="prettymessage" class="hidden">' +
'<button type="button" id="prettyMessageCopyBtn"><svg id="copyIcon"></svg>' +
'<svg id="copySuccessIcon"></svg></button><pre ' +
'id="prettyprint" class="prettyprint linenums:1"></pre>' +
'</div><div id="plaintext" class="hidden"></div>'
);
$.PrivateBin.PasteViewer.init();
$.PrivateBin.PasteViewer.setFormat(format);
$.PrivateBin.PasteViewer.setText(text);
$.PrivateBin.PasteViewer.run();
$.PrivateBin.CopyToClipboard.init(); $.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.setUrl(text);
$('#copyLink').trigger('click'); $('body').trigger('copy');
const copiedText = await navigator.clipboard.readText(); const copiedTextWithoutSelectedText = await navigator.clipboard.readText();
clean(); clean();
return text === copiedText; return copiedTextWithoutSelectedText === text;
} });
); });
jsc.property('Copy link to clipboard', 'nestring', async function (text) {
var clean = jsdom();
common.enableClipboard();
$('body').html('<button id="copyLink"></button>');
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.setUrl(text);
$('#copyLink').trigger('click');
const copiedText = await navigator.clipboard.readText();
clean();
return text === copiedText;
});
describe('Keyboard shortcut hint', function () { describe('Keyboard shortcut hint', function () {
jsc.property('Show hint', jsc.property('Show hint', 'nestring', function (text) {
'nestring', var clean = jsdom();
function (text) {
var clean = jsdom(); $('body').html('<small id="copyShortcutHintText"></small>');
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.showKeyboardShortcutHint();
const keyboardShortcutHint = $('#copyShortcutHintText').text();
clean();
return keyboardShortcutHint.length > 0;
});
$('body').html('<small id="copyShortcutHintText"></small>'); jsc.property('Hide hint', 'nestring', function (text) {
var clean = jsdom();
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.showKeyboardShortcutHint(); $('body').html('<small id="copyShortcutHintText">' + text + '</small>');
const keyboardShortcutHint = $('#copyShortcutHintText').text(); $.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.hideKeyboardShortcutHint();
clean();
const keyboardShortcutHint = $('#copyShortcutHintText').text();
return keyboardShortcutHint.length > 0;
} clean();
);
return keyboardShortcutHint.length === 0;
jsc.property('Hide hint', });
'nestring',
function (text) {
var clean = jsdom();
$('body').html('<small id="copyShortcutHintText">' + text + '</small>');
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.hideKeyboardShortcutHint();
const keyboardShortcutHint = $('#copyShortcutHintText').text();
clean();
return keyboardShortcutHint.length === 0;
}
);
}); });
}); });

View File

@ -1,5 +1,5 @@
'use strict'; 'use strict';
const common = require('../common'); require('../common');
describe('CryptTool', function () { describe('CryptTool', function () {
describe('cipher & decipher', function () { describe('cipher & decipher', function () {
@ -15,26 +15,21 @@ describe('CryptTool', function () {
'string', 'string',
'string', 'string',
async function (key, password, message) { async function (key, password, message) {
const clean = jsdom(); // pause to let async functions conclude
await new Promise(resolve => setTimeout(resolve, 300));
let clean = jsdom();
// ensure zlib is getting loaded // ensure zlib is getting loaded
$.PrivateBin.Controller.initZ(); $.PrivateBin.Controller.initZ();
Object.defineProperty(window, 'crypto', { window.crypto = new WebCrypto();
value: new WebCrypto(),
writeable: false,
});
global.atob = common.atob;
global.btoa = common.btoa;
message = message.trim(); message = message.trim();
const cipherMessage = await $.PrivateBin.CryptTool.cipher( let cipherMessage = await $.PrivateBin.CryptTool.cipher(
key, password, message, [] key, password, message, []
), ),
plaintext = await $.PrivateBin.CryptTool.decipher( plaintext = await $.PrivateBin.CryptTool.decipher(
key, password, cipherMessage key, password, cipherMessage
); );
clean(); clean();
const result = (message === plaintext); return message === plaintext;
if (!result) console.log(plaintext, cipherMessage);
return result;
} }
), ),
{tests: 3}); {tests: 3});
@ -43,19 +38,15 @@ describe('CryptTool', function () {
// The below static unit tests are included to ensure deciphering of "classic" // The below static unit tests are included to ensure deciphering of "classic"
// SJCL based pastes still works // SJCL based pastes still works
it( it(
'supports PrivateBin v1 ciphertext with password (SJCL & browser atob)', 'supports PrivateBin v1 ciphertext (SJCL & browser atob)',
async function () { function () {
delete global.Base64; delete global.Base64;
const clean = jsdom(); let clean = jsdom();
Object.defineProperty(window, 'crypto', { window.crypto = new WebCrypto();
value: new WebCrypto(),
writeable: false,
});
global.atob = common.atob;
// Of course you can easily decipher the following texts, if you like. // Of course you can easily decipher the following texts, if you like.
// Bonus points for finding their sources and hidden meanings. // Bonus points for finding their sources and hidden meanings.
const paste = await $.PrivateBin.CryptTool.decipher( return $.PrivateBin.CryptTool.decipher(
'6t2qsmLyfXIokNCL+3/yl15rfTUBQvm5SOnFPvNE7Q8=', '6t2qsmLyfXIokNCL+3/yl15rfTUBQvm5SOnFPvNE7Q8=',
// -- "That's amazing. I've got the same combination on my luggage." // -- "That's amazing. I've got the same combination on my luggage."
Array.apply(0, Array(6)).map((_,b) => b + 1).join(''), Array.apply(0, Array(6)).map((_,b) => b + 1).join(''),
@ -86,76 +77,53 @@ describe('CryptTool', function () {
'QUxMXI5htsn2rf0HxCFu7Po8DNYLxTS+67hYjDIYWYaEIc8LXWMLyDm9' + 'QUxMXI5htsn2rf0HxCFu7Po8DNYLxTS+67hYjDIYWYaEIc8LXWMLyDm9' +
'C5fARPJ4F2BIWgzgzkNj+dVjusft2XnziamWdbS5u3kuRlVuz5LQj+R5' + 'C5fARPJ4F2BIWgzgzkNj+dVjusft2XnziamWdbS5u3kuRlVuz5LQj+R5' +
'imnqQAincdZTkTT1nYx+DatlOLllCYIHffpI="}' 'imnqQAincdZTkTT1nYx+DatlOLllCYIHffpI="}'
); ).then(function (paste1) {
clean(); $.PrivateBin.CryptTool.decipher(
const result = typeof paste === 'string' && paste.includes('securely packed in iron'); 's9pmKZKOBN7EVvHpTA8jjLFH3Xlz/0l8lB4+ONPACrM=',
if (!result) console.log(paste); '', // no password
assert.ok(result); '{"iv":"WA42mdxIVXUwBqZu7JYNiw==","v":1,"iter":10000,"ks"' +
} ':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' +
); 'lt":"jN6CjbQMJCM=","ct":"kYYMo5DFG1+w0UHiYXT5pdV0IUuXxzO' +
'lslkW/c3DRCbGFROCVkAskHce7HoRczee1N9c5MhHjVMJUIZE02qIS8U' +
it( 'yHdJ/GqcPVidTUcj9rnDNWsTXkjVv8jCwHS/cwmAjDTWpwp5ThECN+ov' +
'supports PrivateBin v1 ciphertext no password (SJCL & browser atob)', '/wNp/NdtTj8Qj7f/T3rfZIOCWfwLH9s4Des35UNcUidfPTNQ1l0Gm0X+' +
async function () { 'r98CCUSYZjQxkZc6hRZBLPQ8EaNVooUwd5eP4GiYlmSDNA0wOSA+5isP' +
delete global.Base64; 'YxomVCt+kFf58VBlNhpfNi7BLYAUTPpXT4SfH5drR9+C7NTeZ+tTCYjb' +
const clean = jsdom(); 'U94PzYItOpu8vgnB1/a6BAM5h3m9w+giUb0df4hgTWeZnZxLjo5BN8WV' +
// ensure zlib is getting loaded '+kdTXMj3/Vv0gw0DQrDcCuX/cBAjpy3lQGwlAN1vXoOIyZJUjMpQRrOL' +
$.PrivateBin.Controller.initZ(); 'dKvLB+zcmVNtGDbgnfP2IYBzk9NtodpUa27ne0T0ZpwOPlVwevsIVZO2' +
Object.defineProperty(window, 'crypto', { '24WLa+iQmmHOWDFFpVDlS0t0fLfOk7Hcb2xFsTxiCIiyKMho/IME1Du3' +
value: new WebCrypto(), 'X4e6BVa3hobSSZv0rRtNgY1KcyYPrUPW2fxZ+oik3y9SgGvb7XpjVIta' +
writeable: false, '8DWlDWRfZ9kzoweWEYqz9IA8Xd373RefpyuWI25zlHoX3nwljzsZU6dC' +
'//h/Dt2DNr+IAvKO3+u23cWoB9kgcZJ2FJuqjLvVfCF+OWcig7zs2pTY' +
'JW6Rg6lqbBCxiUUlae6xJrjfv0pzD2VYCLY7v1bVTagppwKzNI3WaluC' +
'OrdDYUCxUSe56yd1oAoLPRVbYvomRboUO6cjQhEknERyvt45og2kORJO' +
'EJayHW+jZgR0Y0jM3Nk17ubpij2gHxNx9kiLDOiCGSV5mn9mV7qd3HHc' +
'OMSykiBgbyzjobi96LT2dIGLeDXTIdPOog8wyobO4jWq0GGs0vBB8oSY' +
'XhHvixZLcSjX2KQuHmEoWzmJcr3DavdoXZmAurGWLKjzEdJc5dSD/eNr' +
'99gjHX7wphJ6umKMM+fn6PcbYJkhDh2GlJL5COXjXfm/5aj/vuyaRRWZ' +
'MZtmnYpGAtAPg7AUG"}'
).then(function (paste2) {
clean();
assert.ok(
paste1.includes('securely packed in iron') &&
paste2.includes('Sol is right')
);
});
}); });
global.atob = common.atob;
// Of course you can easily decipher the following texts, if you like.
// Bonus points for finding their sources and hidden meanings.
const paste = await $.PrivateBin.CryptTool.decipher(
's9pmKZKOBN7EVvHpTA8jjLFH3Xlz/0l8lB4+ONPACrM=',
'', // no password
'{"iv":"WA42mdxIVXUwBqZu7JYNiw==","v":1,"iter":10000,"ks"' +
':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' +
'lt":"jN6CjbQMJCM=","ct":"kYYMo5DFG1+w0UHiYXT5pdV0IUuXxzO' +
'lslkW/c3DRCbGFROCVkAskHce7HoRczee1N9c5MhHjVMJUIZE02qIS8U' +
'yHdJ/GqcPVidTUcj9rnDNWsTXkjVv8jCwHS/cwmAjDTWpwp5ThECN+ov' +
'/wNp/NdtTj8Qj7f/T3rfZIOCWfwLH9s4Des35UNcUidfPTNQ1l0Gm0X+' +
'r98CCUSYZjQxkZc6hRZBLPQ8EaNVooUwd5eP4GiYlmSDNA0wOSA+5isP' +
'YxomVCt+kFf58VBlNhpfNi7BLYAUTPpXT4SfH5drR9+C7NTeZ+tTCYjb' +
'U94PzYItOpu8vgnB1/a6BAM5h3m9w+giUb0df4hgTWeZnZxLjo5BN8WV' +
'+kdTXMj3/Vv0gw0DQrDcCuX/cBAjpy3lQGwlAN1vXoOIyZJUjMpQRrOL' +
'dKvLB+zcmVNtGDbgnfP2IYBzk9NtodpUa27ne0T0ZpwOPlVwevsIVZO2' +
'24WLa+iQmmHOWDFFpVDlS0t0fLfOk7Hcb2xFsTxiCIiyKMho/IME1Du3' +
'X4e6BVa3hobSSZv0rRtNgY1KcyYPrUPW2fxZ+oik3y9SgGvb7XpjVIta' +
'8DWlDWRfZ9kzoweWEYqz9IA8Xd373RefpyuWI25zlHoX3nwljzsZU6dC' +
'//h/Dt2DNr+IAvKO3+u23cWoB9kgcZJ2FJuqjLvVfCF+OWcig7zs2pTY' +
'JW6Rg6lqbBCxiUUlae6xJrjfv0pzD2VYCLY7v1bVTagppwKzNI3WaluC' +
'OrdDYUCxUSe56yd1oAoLPRVbYvomRboUO6cjQhEknERyvt45og2kORJO' +
'EJayHW+jZgR0Y0jM3Nk17ubpij2gHxNx9kiLDOiCGSV5mn9mV7qd3HHc' +
'OMSykiBgbyzjobi96LT2dIGLeDXTIdPOog8wyobO4jWq0GGs0vBB8oSY' +
'XhHvixZLcSjX2KQuHmEoWzmJcr3DavdoXZmAurGWLKjzEdJc5dSD/eNr' +
'99gjHX7wphJ6umKMM+fn6PcbYJkhDh2GlJL5COXjXfm/5aj/vuyaRRWZ' +
'MZtmnYpGAtAPg7AUG"}'
);
clean();
const result = typeof paste === 'string' && paste.includes('Sol is right');
if (!result) console.log(paste);
assert.ok(result);
} }
); );
it( it(
'supports ZeroBin ciphertext with password (SJCL & Base64 1.7)', 'supports ZeroBin ciphertext (SJCL & Base64 1.7)',
async function () { function () {
global.Base64 = require('../base64-1.7').Base64; global.Base64 = require('../base64-1.7').Base64;
const clean = jsdom(); var clean = jsdom();
Object.defineProperty(window, 'crypto', { window.crypto = new WebCrypto();
value: new WebCrypto(),
writeable: false,
});
global.atob = common.atob;
// Of course you can easily decipher the following texts, if you like. // Of course you can easily decipher the following texts, if you like.
// Bonus points for finding their sources and hidden meanings. // Bonus points for finding their sources and hidden meanings.
const paste = await $.PrivateBin.CryptTool.decipher( return $.PrivateBin.CryptTool.decipher(
'6t2qsmLyfXIokNCL+3/yl15rfTUBQvm5SOnFPvNE7Q8=', '6t2qsmLyfXIokNCL+3/yl15rfTUBQvm5SOnFPvNE7Q8=',
// -- "That's amazing. I've got the same combination on my luggage." // -- "That's amazing. I've got the same combination on my luggage."
Array.apply(0, Array(6)).map((_,b) => b + 1).join(''), Array.apply(0, Array(6)).map((_,b) => b + 1).join(''),
@ -178,74 +146,54 @@ describe('CryptTool', function () {
'7mNNo7xba/YT9KoPDaniqnYqb+q2pX1WNWE7dLS2wfroMAS3kh8P22DA' + '7mNNo7xba/YT9KoPDaniqnYqb+q2pX1WNWE7dLS2wfroMAS3kh8P22DA' +
'V37AeiNoD2PcI6ZcHbRdPa+XRrRcJhSPPW7UQ0z4OvBfjdu/w390QxAx' + 'V37AeiNoD2PcI6ZcHbRdPa+XRrRcJhSPPW7UQ0z4OvBfjdu/w390QxAx' +
'SxvZewoh49fKKB6hTsRnZb4tpHkjlww=="}' 'SxvZewoh49fKKB6hTsRnZb4tpHkjlww=="}'
); ).then(function (paste1) {
clean(); $.PrivateBin.CryptTool.decipher(
delete global.Base64; 's9pmKZKOBN7EVvHpTA8jjLFH3Xlz/0l8lB4+ONPACrM=',
const result = typeof paste === 'string' && paste.includes('securely packed in iron'); '', // no password
if (!result) console.log(paste); '{"iv":"Z7lAZQbkrqGMvruxoSm6Pw==","v":1,"iter":10000,"ks"' +
assert.ok(result); ':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' +
} 'lt":"jN6CjbQMJCM=","ct":"PuOPWB3i2FPcreSrLYeQf84LdE8RHjs' +
); 'c+MGtiOr4b7doNyWKYtkNorbRadxaPnEee2/Utrp1MIIfY5juJSy8RGw' +
'EPX5ciWcYe6EzsXWznsnvhmpKNj9B7eIIrfSbxfy8E2e/g7xav1nive+' +
it( 'ljToka3WT1DZ8ILQd/NbnJeHWaoSEOfvz8+d8QJPb1tNZvs7zEY95Dum' +
'supports ZeroBin ciphertext no password (SJCL & Base64 1.7)', 'QwbyOsIMKAvcZHJ9OJNpujXzdMyt6DpcFcqlldWBZ/8q5rAUTw0HNx/r' +
async function () { 'CgbhAxRYfNoTLIcMM4L0cXbPSgCjwf5FuO3EdE13mgEDhcClW79m0Qvc' +
global.Base64 = require('../base64-1.7').Base64; 'nIh8xgzYoxLbp0+AwvC/MbZM8savN/0ieWr2EKkZ04ggiOIEyvfCUuNp' +
const clean = jsdom(); 'rQBYO+y8kKduNEN6by0Yf4LRCPfmwN+GezDLuzTnZIMhPbGqUAdgV6Ex' +
Object.defineProperty(window, 'crypto', { 'qK2ULEEIrQEMoOuQIxfoMhqLlzG79vXGt2O+BY+4IiYfvmuRLks4UXfy' +
value: new WebCrypto(), 'HqxPXTJg48IYbGs0j4TtJPUgp3523EyYLwEGyVTAuWhYAmVIwd/hoV7d' +
writeable: false, '7tmfcF73w9dufDFI3LNca2KxzBnWNPYvIZKBwWbq8ncxkb191dP6mjEi' +
'7NnhqVk5A6vIBbu4AC5PZf76l6yep4xsoy/QtdDxCMocCXeAML9MQ9uP' +
'QbuspOKrBvMfN5igA1kBqasnxI472KBNXsdZnaDddSVUuvhTcETM="}'
).then(function (paste2) {
clean();
delete global.Base64;
assert.ok(
paste1.includes('securely packed in iron') &&
paste2.includes('Sol is right')
);
});
}); });
global.atob = common.atob;
const paste = await $.PrivateBin.CryptTool.decipher(
's9pmKZKOBN7EVvHpTA8jjLFH3Xlz/0l8lB4+ONPACrM=',
'', // no password
'{"iv":"Z7lAZQbkrqGMvruxoSm6Pw==","v":1,"iter":10000,"ks"' +
':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' +
'lt":"jN6CjbQMJCM=","ct":"PuOPWB3i2FPcreSrLYeQf84LdE8RHjs' +
'c+MGtiOr4b7doNyWKYtkNorbRadxaPnEee2/Utrp1MIIfY5juJSy8RGw' +
'EPX5ciWcYe6EzsXWznsnvhmpKNj9B7eIIrfSbxfy8E2e/g7xav1nive+' +
'ljToka3WT1DZ8ILQd/NbnJeHWaoSEOfvz8+d8QJPb1tNZvs7zEY95Dum' +
'QwbyOsIMKAvcZHJ9OJNpujXzdMyt6DpcFcqlldWBZ/8q5rAUTw0HNx/r' +
'CgbhAxRYfNoTLIcMM4L0cXbPSgCjwf5FuO3EdE13mgEDhcClW79m0Qvc' +
'nIh8xgzYoxLbp0+AwvC/MbZM8savN/0ieWr2EKkZ04ggiOIEyvfCUuNp' +
'rQBYO+y8kKduNEN6by0Yf4LRCPfmwN+GezDLuzTnZIMhPbGqUAdgV6Ex' +
'qK2ULEEIrQEMoOuQIxfoMhqLlzG79vXGt2O+BY+4IiYfvmuRLks4UXfy' +
'HqxPXTJg48IYbGs0j4TtJPUgp3523EyYLwEGyVTAuWhYAmVIwd/hoV7d' +
'7tmfcF73w9dufDFI3LNca2KxzBnWNPYvIZKBwWbq8ncxkb191dP6mjEi' +
'7NnhqVk5A6vIBbu4AC5PZf76l6yep4xsoy/QtdDxCMocCXeAML9MQ9uP' +
'QbuspOKrBvMfN5igA1kBqasnxI472KBNXsdZnaDddSVUuvhTcETM="}'
);
clean();
delete global.Base64;
const result = typeof paste === 'string' && paste.includes('Sol is right');
if (!result) console.log(paste);
assert.ok(result);
} }
); );
it('does not truncate messages', async function () { it('does not truncate messages', async function () {
const message = fs.readFileSync('test/compression-sample.txt', 'ascii').trim(), let message = fs.readFileSync('test/compression-sample.txt', 'utf8'),
clean = jsdom(); clean = jsdom();
Object.defineProperty(window, 'crypto', { window.crypto = new WebCrypto();
value: new WebCrypto(),
writeable: false,
});
// ensure zlib is getting loaded // ensure zlib is getting loaded
$.PrivateBin.Controller.initZ(); $.PrivateBin.Controller.initZ();
global.atob = common.atob; let cipherMessage = await $.PrivateBin.CryptTool.cipher(
global.btoa = common.btoa;
const cipherMessage = await $.PrivateBin.CryptTool.cipher(
'foo', 'bar', message, [] 'foo', 'bar', message, []
), ),
plaintext = await $.PrivateBin.CryptTool.decipher( plaintext = await $.PrivateBin.CryptTool.decipher(
'foo', 'bar', cipherMessage 'foo', 'bar', cipherMessage
); );
clean(); clean();
const result = (message === plaintext); assert.strictEqual(
if (!result) console.log(plaintext, cipherMessage); message,
assert.ok(result); plaintext
);
}); });
it('can en- and decrypt a particular message (#260)', function () { it('can en- and decrypt a particular message (#260)', function () {
@ -253,6 +201,8 @@ describe('CryptTool', function () {
'string', 'string',
'string', 'string',
async function (key, password) { async function (key, password) {
// pause to let async functions conclude
await new Promise(resolve => setTimeout(resolve, 300));
const message = ` const message = `
1 subgoal 1 subgoal
@ -275,23 +225,18 @@ isWhile : interp (while expr sBody) (MemElem mem) =
======================== ( 1 / 1 ) ======================== ( 1 / 1 )
conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem)) conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem))
`; `;
const clean = jsdom(); let clean = jsdom();
// ensure zlib is getting loaded // ensure zlib is getting loaded
$.PrivateBin.Controller.initZ(); $.PrivateBin.Controller.initZ();
Object.defineProperty(window, 'crypto', { window.crypto = new WebCrypto();
value: new WebCrypto(), let cipherMessage = await $.PrivateBin.CryptTool.cipher(
writeable: false,
});
const cipherMessage = await $.PrivateBin.CryptTool.cipher(
key, password, message, [] key, password, message, []
), ),
plaintext = await $.PrivateBin.CryptTool.decipher( plaintext = await $.PrivateBin.CryptTool.decipher(
key, password, cipherMessage key, password, cipherMessage
); );
clean(); clean();
const result = (message === plaintext); return message === plaintext;
if (!result) console.log(plaintext, cipherMessage);
return result;
} }
), ),
{tests: 3}); {tests: 3});
@ -299,27 +244,23 @@ conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem))
}); });
describe('getSymmetricKey', function () { describe('getSymmetricKey', function () {
this.timeout(10000); this.timeout(30000);
let keys = []; var keys = [];
// the parameter is used to ensure the test is run more then one time // the parameter is used to ensure the test is run more then one time
it('returns random, non-empty keys', function () { jsc.property(
jsc.assert(jsc.forall( 'returns random, non-empty keys',
'integer', 'integer',
function(counter) { function(counter) {
const clean = jsdom(); var clean = jsdom();
Object.defineProperty(window, 'crypto', { window.crypto = new WebCrypto();
value: new WebCrypto(), var key = $.PrivateBin.CryptTool.getSymmetricKey(),
writeable: false, result = (key !== '' && keys.indexOf(key) === -1);
}); keys.push(key);
const key = $.PrivateBin.CryptTool.getSymmetricKey(), clean();
result = (key !== '' && keys.indexOf(key) === -1); return result;
keys.push(key); }
clean(); );
return result;
}
),
{tests: 10});
});
}); });
}); });

View File

@ -229,30 +229,30 @@ describe('Helper', function () {
cleanup(); cleanup();
}); });
/* TODO test fails since jsDOM version 17 - document.cookie remains empty
jsc.property( jsc.property(
'returns the requested cookie', 'returns the requested cookie',
jsc.nearray(jsc.nearray(common.jscAlnumString())), jsc.nearray(jsc.nearray(common.jscAlnumString())),
jsc.nearray(jsc.nearray(common.jscAlnumString())), jsc.nearray(jsc.nearray(common.jscAlnumString())),
function (labels, values) { function (labels, values) {
let selectedKey = '', selectedValue = ''; var selectedKey = '', selectedValue = '',
const clean = jsdom(); cookieArray = [];
labels.forEach(function(item, i) { labels.forEach(function(item, i) {
const key = item.join(''), var key = item.join(''),
value = (values[i] || values[0]).join(''); value = (values[i] || values[0]).join('');
document.cookie = key + '=' + value; cookieArray.push(key + '=' + value);
if (Math.random() < 1 / i || selectedKey === key) if (Math.random() < 1 / i || selectedKey === key)
{ {
selectedKey = key; selectedKey = key;
selectedValue = value; selectedValue = value;
} }
}); });
const result = $.PrivateBin.Helper.getCookie(selectedKey); var clean = jsdom('', {cookie: cookieArray}),
result = $.PrivateBin.Helper.getCookie(selectedKey);
$.PrivateBin.Helper.reset(); $.PrivateBin.Helper.reset();
clean(); clean();
return result === selectedValue; return result === selectedValue;
} }
); */ );
}); });
describe('baseUri', function () { describe('baseUri', function () {

View File

@ -94,6 +94,7 @@ describe('Model', function () {
url.query = queryStart.concat(pasteId, queryEnd); url.query = queryStart.concat(pasteId, queryEnd);
const pasteIdString = pasteId.join(''), const pasteIdString = pasteId.join(''),
clean = jsdom('', {url: common.urlToString(url)}); clean = jsdom('', {url: common.urlToString(url)});
global.URL = require('jsdom-url').URL;
const result = $.PrivateBin.Model.getPasteId(); const result = $.PrivateBin.Model.getPasteId();
$.PrivateBin.Model.reset(); $.PrivateBin.Model.reset();
clean(); clean();
@ -106,6 +107,7 @@ describe('Model', function () {
function (url) { function (url) {
let clean = jsdom('', {url: common.urlToString(url)}), let clean = jsdom('', {url: common.urlToString(url)}),
result = false; result = false;
global.URL = require('jsdom-url').URL;
try { try {
$.PrivateBin.Model.getPasteId(); $.PrivateBin.Model.getPasteId();
} }
@ -129,7 +131,7 @@ describe('Model', function () {
'returns the fragment of a v1 URL', 'returns the fragment of a v1 URL',
common.jscUrl(), common.jscUrl(),
function (url) { function (url) {
url.fragment = '0OIl'; // any non-base58 string url.fragment = common.btoa(url.fragment.padStart(32, '\u0000'));
const clean = jsdom('', {url: common.urlToString(url)}), const clean = jsdom('', {url: common.urlToString(url)}),
result = $.PrivateBin.Model.getPasteKey(); result = $.PrivateBin.Model.getPasteKey();
$.PrivateBin.Model.reset(); $.PrivateBin.Model.reset();
@ -138,17 +140,17 @@ describe('Model', function () {
} }
); );
jsc.property( jsc.property(
'returns the fragment stripped of trailing query parts', 'returns the v1 fragment stripped of trailing query parts',
common.jscUrl(), common.jscUrl(),
jsc.array(common.jscHashString()), jsc.array(common.jscHashString()),
function (url, trail) { function (url, trail) {
const fragment = url.fragment.padStart(32, '\u0000'); const fragmentString = common.btoa(url.fragment.padStart(32, '\u0000'));
url.fragment = $.PrivateBin.CryptTool.base58encode(fragment) + '&' + trail.join(''); url.fragment = fragmentString + '&' + trail.join('');
const clean = jsdom('', {url: common.urlToString(url)}), const clean = jsdom('', {url: common.urlToString(url)}),
result = $.PrivateBin.Model.getPasteKey(); result = $.PrivateBin.Model.getPasteKey();
$.PrivateBin.Model.reset(); $.PrivateBin.Model.reset();
clean(); clean();
return fragment === result; return fragmentString === result;
} }
); );
jsc.property( jsc.property(

View File

@ -11,7 +11,7 @@ describe('Prompt', function () {
'returns the password fed into the dialog', 'returns the password fed into the dialog',
'string', 'string',
function (password) { function (password) {
password = password.replace(/\r+|\n+/g, ''); password = password.replace(/\r+/g, '');
var clean = jsdom('', {url: 'ftp://example.com/?0000000000000000'}); var clean = jsdom('', {url: 'ftp://example.com/?0000000000000000'});
$('body').html( $('body').html(
'<div id="passwordmodal" class="modal fade" role="dialog">' + '<div id="passwordmodal" class="modal fade" role="dialog">' +
@ -32,8 +32,7 @@ describe('Prompt', function () {
//var result = $.PrivateBin.Prompt.getPassword(); //var result = $.PrivateBin.Prompt.getPassword();
var result = $('#passworddecrypt').val(); var result = $('#passworddecrypt').val();
$.PrivateBin.Model.reset(); $.PrivateBin.Model.reset();
// TODO triggers error messages in jsDOM since version 11 clean();
//clean();
return result === password; return result === password;
} }
); );

View File

@ -621,7 +621,7 @@ describe('TopNav', function () {
'returns the contents of the password input', 'returns the contents of the password input',
'string', 'string',
function (password) { function (password) {
password = password.replace(/\r+|\n+/g, ''); password = password.replace(/\r+/g, '');
var results = []; var results = [];
$('body').html( $('body').html(
'<nav><div id="navbar"><ul><li><div id="password" ' + '<nav><div id="navbar"><ul><li><div id="password" ' +
@ -727,11 +727,11 @@ describe('TopNav', function () {
cleanup(); cleanup();
}); });
// TODO triggers error messages in jsDOM since version 12, but passes
it( it(
'displays raw text view correctly', 'displays raw text view correctly',
function () { function () {
const clean = jsdom('', {url: 'https://privatebin.net/?0123456789abcdef#0'}); const clean = jsdom('', {url: 'https://privatebin.net/?0123456789abcdef#0'});
global.URL = require('jsdom-url').URL;
$('body').html('<button id="rawtextbutton"></button>'); $('body').html('<button id="rawtextbutton"></button>');
const sample = 'example'; const sample = 'example';
$.PrivateBin.PasteViewer.setText(sample); $.PrivateBin.PasteViewer.setText(sample);

View File

@ -18,6 +18,11 @@ describe('UiHelper', function () {
const expected = common.urlToString(url), const expected = common.urlToString(url),
clean = jsdom('', {url: expected}); clean = jsdom('', {url: expected});
// make window.location.href writable
Object.defineProperty(window.location, 'href', {
writable: true,
value: window.location.href
});
$.PrivateBin.UiHelper.mockHistoryChange(); $.PrivateBin.UiHelper.mockHistoryChange();
$.PrivateBin.Helper.reset(); $.PrivateBin.Helper.reset();
var result = window.location.href; var result = window.location.href;
@ -35,6 +40,11 @@ describe('UiHelper', function () {
const expected = common.urlToString(url), const expected = common.urlToString(url),
clean = jsdom('', {url: expected}); clean = jsdom('', {url: expected});
// make window.location.href writable
Object.defineProperty(window.location, 'href', {
writable: true,
value: window.location.href
});
$.PrivateBin.UiHelper.mockHistoryChange([ $.PrivateBin.UiHelper.mockHistoryChange([
{type: 'newpaste'}, '', expected {type: 'newpaste'}, '', expected
]); ]);
@ -47,8 +57,6 @@ describe('UiHelper', function () {
}); });
describe('reloadHome', function () { describe('reloadHome', function () {
// TODO triggers error messages in jsDOM since version 11
/*
this.timeout(30000); this.timeout(30000);
before(function () { before(function () {
$.PrivateBin.Helper.reset(); $.PrivateBin.Helper.reset();
@ -63,6 +71,11 @@ describe('UiHelper', function () {
delete(url.fragment); delete(url.fragment);
const expected = common.urlToString(url); const expected = common.urlToString(url);
// make window.location.href writable
Object.defineProperty(window.location, 'href', {
writable: true,
value: window.location.href
});
$.PrivateBin.UiHelper.reloadHome(); $.PrivateBin.UiHelper.reloadHome();
$.PrivateBin.Helper.reset(); $.PrivateBin.Helper.reset();
var result = window.location.href; var result = window.location.href;
@ -70,7 +83,6 @@ describe('UiHelper', function () {
return expected === result; return expected === result;
} }
); );
*/
}); });
describe('isVisible', function () { describe('isVisible', function () {

View File

@ -45,18 +45,7 @@ class Configuration
'defaultformatter' => 'plaintext', 'defaultformatter' => 'plaintext',
'syntaxhighlightingtheme' => '', 'syntaxhighlightingtheme' => '',
'sizelimit' => 10485760, 'sizelimit' => 10485760,
'templateselection' => false,
'template' => 'bootstrap', 'template' => 'bootstrap',
'availabletemplates' => array(
'bootstrap5',
'bootstrap',
'bootstrap-page',
'bootstrap-dark',
'bootstrap-dark-page',
'bootstrap-compact',
'bootstrap-compact-page',
'page',
),
'info' => 'More information on the <a href=\'https://privatebin.info/\'>project page</a>.', 'info' => 'More information on the <a href=\'https://privatebin.info/\'>project page</a>.',
'notice' => '', 'notice' => '',
'languageselection' => false, 'languageselection' => false,
@ -119,8 +108,8 @@ class Configuration
'js/kjua-0.9.0.js' => 'sha512-CVn7af+vTMBd9RjoS4QM5fpLFEOtBCoB0zPtaqIDC7sF4F8qgUSRFQQpIyEDGsr6yrjbuOLzdf20tkHHmpaqwQ==', 'js/kjua-0.9.0.js' => 'sha512-CVn7af+vTMBd9RjoS4QM5fpLFEOtBCoB0zPtaqIDC7sF4F8qgUSRFQQpIyEDGsr6yrjbuOLzdf20tkHHmpaqwQ==',
'js/legacy.js' => 'sha512-UxW/TOZKon83n6dk/09GsYKIyeO5LeBHokxyIq+r7KFS5KMBeIB/EM7NrkVYIezwZBaovnyNtY2d9tKFicRlXg==', 'js/legacy.js' => 'sha512-UxW/TOZKon83n6dk/09GsYKIyeO5LeBHokxyIq+r7KFS5KMBeIB/EM7NrkVYIezwZBaovnyNtY2d9tKFicRlXg==',
'js/prettify.js' => 'sha512-puO0Ogy++IoA2Pb9IjSxV1n4+kQkKXYAEUtVzfZpQepyDPyXk8hokiYDS7ybMogYlyyEIwMLpZqVhCkARQWLMg==', 'js/prettify.js' => 'sha512-puO0Ogy++IoA2Pb9IjSxV1n4+kQkKXYAEUtVzfZpQepyDPyXk8hokiYDS7ybMogYlyyEIwMLpZqVhCkARQWLMg==',
'js/privatebin.js' => 'sha512-yN0ZaVFrXpiYaeFRcofdCrlHVcw4ZJAXU3K1l6H9rsoY//iLKegX0GdWxRCFWzhd1xO4eDJKCT7qyaA1Vt65bg==', 'js/privatebin.js' => 'sha512-POa+8KNXFFwJFsqp7r9APmR5Rc1w2l363y+OScSzLCySrHN7UhOOgt1VH/o8mVddFvvUozj3FZVmdkTxRlrS5g==',
'js/purify-3.2.5.js' => 'sha512-eLlLLL/zYuf5JuG0x4WQm687MToqOGP9cDQHIdmOy1ZpjiY4J48BBcOM7DtZheKk1UogW920+9RslWYB4KGuuA==', 'js/purify-3.2.4.js' => 'sha512-Mu9BqoHURMeycg6AgqTpokUv9guq88pajfaFqz53fx1OxohyROkydXPLEIbdKCQ7EdDs9hgcrYeZ9zTiPQQ4CA==',
'js/rawinflate-0.3.js' => 'sha512-g8uelGgJW9A/Z1tB6Izxab++oj5kdD7B4qC7DHwZkB6DGMXKyzx7v5mvap2HXueI2IIn08YlRYM56jwWdm2ucQ==', 'js/rawinflate-0.3.js' => 'sha512-g8uelGgJW9A/Z1tB6Izxab++oj5kdD7B4qC7DHwZkB6DGMXKyzx7v5mvap2HXueI2IIn08YlRYM56jwWdm2ucQ==',
'js/showdown-2.1.0.js' => 'sha512-WYXZgkTR0u/Y9SVIA4nTTOih0kXMEd8RRV6MLFdL6YU8ymhR528NLlYQt1nlJQbYz4EW+ZsS0fx1awhiQJme1Q==', 'js/showdown-2.1.0.js' => 'sha512-WYXZgkTR0u/Y9SVIA4nTTOih0kXMEd8RRV6MLFdL6YU8ymhR528NLlYQt1nlJQbYz4EW+ZsS0fx1awhiQJme1Q==',
'js/zlib-1.3.1.js' => 'sha512-5bU9IIP4PgBrOKLZvGWJD4kgfQrkTz8Z3Iqeu058mbQzW3mCumOU6M3UVbVZU9rrVoVwaW4cZK8U8h5xjF88eQ==', 'js/zlib-1.3.1.js' => 'sha512-5bU9IIP4PgBrOKLZvGWJD4kgfQrkTz8Z3Iqeu058mbQzW3mCumOU6M3UVbVZU9rrVoVwaW4cZK8U8h5xjF88eQ==',

View File

@ -112,12 +112,10 @@ class Controller
* *
* initializes and runs PrivateBin * initializes and runs PrivateBin
* *
* @param ?Configuration $config
*
* @access public * @access public
* @throws Exception * @throws Exception
*/ */
public function __construct(?Configuration $config = null) public function __construct()
{ {
if (version_compare(PHP_VERSION, self::MIN_PHP_VERSION) < 0) { if (version_compare(PHP_VERSION, self::MIN_PHP_VERSION) < 0) {
error_log(I18n::_('%s requires php %s or above to work. Sorry.', I18n::_('PrivateBin'), self::MIN_PHP_VERSION)); error_log(I18n::_('%s requires php %s or above to work. Sorry.', I18n::_('PrivateBin'), self::MIN_PHP_VERSION));
@ -128,8 +126,7 @@ class Controller
return; return;
} }
// load config (using ini file by default) & initialize required classes // load config from ini file, initialize required classes
$this->_conf = $config ?? new Configuration();
$this->_init(); $this->_init();
switch ($this->_request->getOperation()) { switch ($this->_request->getOperation()) {
@ -177,21 +174,12 @@ class Controller
*/ */
private function _init() private function _init()
{ {
$this->_conf = new Configuration;
$this->_model = new Model($this->_conf); $this->_model = new Model($this->_conf);
$this->_request = new Request; $this->_request = new Request;
$this->_urlBase = $this->_request->getRequestUri(); $this->_urlBase = $this->_request->getRequestUri();
$this->_setDefaultLanguage(); // set default language
$this->_setDefaultTemplate();
}
/**
* Set default language
*
* @access private
*/
private function _setDefaultLanguage()
{
$lang = $this->_conf->getKey('languagedefault'); $lang = $this->_conf->getKey('languagedefault');
I18n::setLanguageFallback($lang); I18n::setLanguageFallback($lang);
// force default language, if language selection is disabled and a default is set // force default language, if language selection is disabled and a default is set
@ -201,25 +189,6 @@ class Controller
} }
} }
/**
* Set default template
*
* @access private
*/
private function _setDefaultTemplate()
{
$templates = $this->_conf->getKey('availabletemplates');
$template = $this->_conf->getKey('template');
TemplateSwitcher::setAvailableTemplates($templates);
TemplateSwitcher::setTemplateFallback($template);
// force default template, if template selection is disabled and a default is set
if (!$this->_conf->getKey('templateselection') && !empty($template)) {
$_COOKIE['template'] = $template;
setcookie('template', $template, array('SameSite' => 'Lax', 'Secure' => true));
}
}
/** /**
* Turn off browser caching * Turn off browser caching
* *
@ -431,13 +400,6 @@ class Controller
setcookie('lang', $languageselection, array('SameSite' => 'Lax', 'Secure' => true)); setcookie('lang', $languageselection, array('SameSite' => 'Lax', 'Secure' => true));
} }
// set template cookie if that functionality was enabled
$templateselection = '';
if ($this->_conf->getKey('templateselection')) {
$templateselection = TemplateSwitcher::getTemplate();
setcookie('template', $templateselection, array('SameSite' => 'Lax', 'Secure' => true));
}
// strip policies that are unsupported in meta tag // strip policies that are unsupported in meta tag
$metacspheader = str_replace( $metacspheader = str_replace(
array( array(
@ -476,8 +438,6 @@ class Controller
$page->assign('ZEROBINCOMPATIBILITY', $this->_conf->getKey('zerobincompatibility')); $page->assign('ZEROBINCOMPATIBILITY', $this->_conf->getKey('zerobincompatibility'));
$page->assign('LANGUAGESELECTION', $languageselection); $page->assign('LANGUAGESELECTION', $languageselection);
$page->assign('LANGUAGES', I18n::getLanguageLabels(I18n::getAvailableLanguages())); $page->assign('LANGUAGES', I18n::getLanguageLabels(I18n::getAvailableLanguages()));
$page->assign('TEMPLATESELECTION', $templateselection);
$page->assign('TEMPLATES', TemplateSwitcher::getAvailableTemplates());
$page->assign('EXPIRE', $expire); $page->assign('EXPIRE', $expire);
$page->assign('EXPIREDEFAULT', $this->_conf->getKey('default', 'expire')); $page->assign('EXPIREDEFAULT', $this->_conf->getKey('default', 'expire'));
$page->assign('URLSHORTENER', $this->_conf->getKey('urlshortener')); $page->assign('URLSHORTENER', $this->_conf->getKey('urlshortener'));
@ -487,7 +447,7 @@ class Controller
$page->assign('HTTPSLINK', 'https://' . $this->_request->getHost() . $this->_request->getRequestUri()); $page->assign('HTTPSLINK', 'https://' . $this->_request->getHost() . $this->_request->getRequestUri());
$page->assign('COMPRESSION', $this->_conf->getKey('compression')); $page->assign('COMPRESSION', $this->_conf->getKey('compression'));
$page->assign('SRI', $this->_conf->getSection('sri')); $page->assign('SRI', $this->_conf->getSection('sri'));
$page->draw(TemplateSwitcher::getTemplate()); $page->draw($this->_conf->getKey('template'));
} }
/** /**

View File

@ -34,7 +34,7 @@ abstract class AbstractData
* @param array $paste * @param array $paste
* @return bool * @return bool
*/ */
abstract public function create($pasteid, array &$paste); abstract public function create($pasteid, array $paste);
/** /**
* Read a paste. * Read a paste.
@ -72,7 +72,7 @@ abstract class AbstractData
* @param array $comment * @param array $comment
* @return bool * @return bool
*/ */
abstract public function createComment($pasteid, $parentid, $commentid, array &$comment); abstract public function createComment($pasteid, $parentid, $commentid, array $comment);
/** /**
* Read all comments of paste. * Read all comments of paste.
@ -199,7 +199,7 @@ abstract class AbstractData
* @param array $paste * @param array $paste
* @return array * @return array
*/ */
protected static function upgradePreV1Format(array &$paste) protected static function upgradePreV1Format(array $paste)
{ {
if (array_key_exists('attachment', $paste['meta'])) { if (array_key_exists('attachment', $paste['meta'])) {
$paste['attachment'] = $paste['meta']['attachment']; $paste['attachment'] = $paste['meta']['attachment'];

View File

@ -140,7 +140,7 @@ class Database extends AbstractData
* @param array $paste * @param array $paste
* @return bool * @return bool
*/ */
public function create($pasteid, array &$paste) public function create($pasteid, array $paste)
{ {
$expire_date = 0; $expire_date = 0;
$opendiscussion = $burnafterreading = false; $opendiscussion = $burnafterreading = false;
@ -297,18 +297,14 @@ class Database extends AbstractData
* @param array $comment * @param array $comment
* @return bool * @return bool
*/ */
public function createComment($pasteid, $parentid, $commentid, array &$comment) public function createComment($pasteid, $parentid, $commentid, array $comment)
{ {
if (array_key_exists('data', $comment)) { if (array_key_exists('data', $comment)) {
$version = 1; $version = 1;
$data = $comment['data']; $data = $comment['data'];
} else { } else {
try { $version = 2;
$version = 2; $data = Json::encode($comment);
$data = Json::encode($comment);
} catch (Exception $e) {
return false;
}
} }
list($createdKey, $iconKey) = $this->_getVersionedKeys($version); list($createdKey, $iconKey) = $this->_getVersionedKeys($version);
$meta = $comment['meta']; $meta = $comment['meta'];

View File

@ -85,7 +85,7 @@ class Filesystem extends AbstractData
* @param array $paste * @param array $paste
* @return bool * @return bool
*/ */
public function create($pasteid, array &$paste) public function create($pasteid, array $paste)
{ {
$storagedir = $this->_dataid2path($pasteid); $storagedir = $this->_dataid2path($pasteid);
$file = $storagedir . $pasteid . '.php'; $file = $storagedir . $pasteid . '.php';
@ -188,7 +188,7 @@ class Filesystem extends AbstractData
* @param array $comment * @param array $comment
* @return bool * @return bool
*/ */
public function createComment($pasteid, $parentid, $commentid, array &$comment) public function createComment($pasteid, $parentid, $commentid, array $comment)
{ {
$storagedir = $this->_dataid2discussionpath($pasteid); $storagedir = $this->_dataid2discussionpath($pasteid);
$file = $storagedir . $pasteid . '.' . $commentid . '.' . $parentid . '.php'; $file = $storagedir . $pasteid . '.' . $commentid . '.' . $parentid . '.php';
@ -343,11 +343,12 @@ class Filesystem extends AbstractData
*/ */
private function _get($filename) private function _get($filename)
{ {
$data = substr( return Json::decode(
file_get_contents($filename), substr(
strlen(self::PROTECTION_LINE . PHP_EOL) file_get_contents($filename),
strlen(self::PROTECTION_LINE . PHP_EOL)
)
); );
return Json::decode($data);
} }
/** /**

View File

@ -105,7 +105,7 @@ class GoogleCloudStorage extends AbstractData
* @param $payload array to store * @param $payload array to store
* @return bool true if successful, otherwise false. * @return bool true if successful, otherwise false.
*/ */
private function _upload($key, &$payload) private function _upload($key, $payload)
{ {
$metadata = array_key_exists('meta', $payload) ? $payload['meta'] : array(); $metadata = array_key_exists('meta', $payload) ? $payload['meta'] : array();
unset($metadata['attachment'], $metadata['attachmentname'], $metadata['salt']); unset($metadata['attachment'], $metadata['attachmentname'], $metadata['salt']);
@ -136,7 +136,7 @@ class GoogleCloudStorage extends AbstractData
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function create($pasteid, array &$paste) public function create($pasteid, array $paste)
{ {
if ($this->exists($pasteid)) { if ($this->exists($pasteid)) {
return false; return false;
@ -201,7 +201,7 @@ class GoogleCloudStorage extends AbstractData
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function createComment($pasteid, $parentid, $commentid, array &$comment) public function createComment($pasteid, $parentid, $commentid, array $comment)
{ {
if ($this->existsComment($pasteid, $parentid, $commentid)) { if ($this->existsComment($pasteid, $parentid, $commentid)) {
return false; return false;
@ -219,8 +219,7 @@ class GoogleCloudStorage extends AbstractData
$prefix = $this->_getKey($pasteid) . '/discussion/'; $prefix = $this->_getKey($pasteid) . '/discussion/';
try { try {
foreach ($this->_bucket->objects(array('prefix' => $prefix)) as $key) { foreach ($this->_bucket->objects(array('prefix' => $prefix)) as $key) {
$data = $this->_bucket->object($key->name())->downloadAsString(); $comment = JSON::decode($this->_bucket->object($key->name())->downloadAsString());
$comment = Json::decode($data);
$comment['id'] = basename($key->name()); $comment['id'] = basename($key->name());
$slot = $this->getOpenSlot($comments, (int) $comment['meta']['created']); $slot = $this->getOpenSlot($comments, (int) $comment['meta']['created']);
$comments[$slot] = $comment; $comments[$slot] = $comment;

View File

@ -165,7 +165,7 @@ class S3Storage extends AbstractData
* @param $payload array to store * @param $payload array to store
* @return bool true if successful, otherwise false. * @return bool true if successful, otherwise false.
*/ */
private function _upload($key, &$payload) private function _upload($key, $payload)
{ {
$metadata = array_key_exists('meta', $payload) ? $payload['meta'] : array(); $metadata = array_key_exists('meta', $payload) ? $payload['meta'] : array();
unset($metadata['attachment'], $metadata['attachmentname'], $metadata['salt']); unset($metadata['attachment'], $metadata['attachmentname'], $metadata['salt']);
@ -191,7 +191,7 @@ class S3Storage extends AbstractData
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function create($pasteid, array &$paste) public function create($pasteid, array $paste)
{ {
if ($this->exists($pasteid)) { if ($this->exists($pasteid)) {
return false; return false;
@ -263,7 +263,7 @@ class S3Storage extends AbstractData
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function createComment($pasteid, $parentid, $commentid, array &$comment) public function createComment($pasteid, $parentid, $commentid, array $comment)
{ {
if ($this->existsComment($pasteid, $parentid, $commentid)) { if ($this->existsComment($pasteid, $parentid, $commentid)) {
return false; return false;

View File

@ -29,7 +29,7 @@ class FormatV2
* @param bool $isComment * @param bool $isComment
* @return bool * @return bool
*/ */
public static function isValid(&$message, $isComment = false) public static function isValid($message, $isComment = false)
{ {
$required_keys = array('adata', 'v', 'ct'); $required_keys = array('adata', 'v', 'ct');
if ($isComment) { if ($isComment) {

View File

@ -183,12 +183,9 @@ class I18n
// load translations // load translations
self::$_language = $match; self::$_language = $match;
if ($match == 'en') { self::$_translations = ($match == 'en') ? array() : Json::decode(
self::$_translations = array(); file_get_contents(self::_getPath($match . '.json'))
} else { );
$data = file_get_contents(self::_getPath($match . '.json'));
self::$_translations = Json::decode($data);
}
} }
/** /**
@ -276,8 +273,7 @@ class I18n
{ {
$file = self::_getPath('languages.json'); $file = self::_getPath('languages.json');
if (count(self::$_languageLabels) == 0 && is_readable($file)) { if (count(self::$_languageLabels) == 0 && is_readable($file)) {
$data = file_get_contents($file); self::$_languageLabels = Json::decode(file_get_contents($file));
self::$_languageLabels = Json::decode($data);
} }
if (count($languages) == 0) { if (count($languages) == 0) {
return self::$_languageLabels; return self::$_languageLabels;

View File

@ -29,7 +29,7 @@ class Json
* @throws Exception * @throws Exception
* @return string * @return string
*/ */
public static function encode(&$input) public static function encode($input)
{ {
$jsonString = json_encode($input); $jsonString = json_encode($input);
self::_detectError(); self::_detectError();
@ -45,7 +45,7 @@ class Json
* @throws Exception * @throws Exception
* @return mixed * @return mixed
*/ */
public static function decode(&$input) public static function decode($input)
{ {
$output = json_decode($input, true); $output = json_decode($input, true);
self::_detectError(); self::_detectError();

View File

@ -100,9 +100,9 @@ abstract class AbstractModel
* @param array $data * @param array $data
* @throws Exception * @throws Exception
*/ */
public function setData(array &$data) public function setData(array $data)
{ {
$this->_sanitize($data); $data = $this->_sanitize($data);
$this->_validate($data); $this->_validate($data);
$this->_data = $data; $this->_data = $data;
@ -155,7 +155,7 @@ abstract class AbstractModel
*/ */
public static function isValidId($id) public static function isValidId($id)
{ {
return (bool) preg_match('#\A[a-f0-9]{16}\z#', (string) $id); return (bool) preg_match('#\A[a-f\d]{16}\z#', (string) $id);
} }
/** /**
@ -163,8 +163,9 @@ abstract class AbstractModel
* *
* @access protected * @access protected
* @param array $data * @param array $data
* @return array
*/ */
abstract protected function _sanitize(array &$data); abstract protected function _sanitize(array $data);
/** /**
* Validate data. * Validate data.
@ -173,7 +174,7 @@ abstract class AbstractModel
* @param array $data * @param array $data
* @throws Exception * @throws Exception
*/ */
protected function _validate(array &$data) protected function _validate(array $data)
{ {
} }
} }

View File

@ -104,7 +104,7 @@ class Comment extends AbstractModel
* @param Paste $paste * @param Paste $paste
* @throws Exception * @throws Exception
*/ */
public function setPaste(Paste &$paste) public function setPaste(Paste $paste)
{ {
$this->_paste = $paste; $this->_paste = $paste;
$this->_data['pasteid'] = $paste->getId(); $this->_data['pasteid'] = $paste->getId();
@ -155,8 +155,9 @@ class Comment extends AbstractModel
* *
* @access protected * @access protected
* @param array $data * @param array $data
* @return array
*/ */
protected function _sanitize(array &$data) protected function _sanitize(array $data)
{ {
// we generate an icon based on a SHA512 HMAC of the users IP, if configured // we generate an icon based on a SHA512 HMAC of the users IP, if configured
$icon = $this->_conf->getKey('icon'); $icon = $this->_conf->getKey('icon');
@ -189,5 +190,6 @@ class Comment extends AbstractModel
$data['meta']['icon'] = $pngdata; $data['meta']['icon'] = $pngdata;
} }
} }
return $data;
} }
} }

View File

@ -219,10 +219,11 @@ class Paste extends AbstractModel
* *
* @access protected * @access protected
* @param array $data * @param array $data
* @return array
*/ */
protected function _sanitize(array &$data) protected function _sanitize(array $data)
{ {
$expiration = $data['meta']['expire'] ?? 0; $expiration = $data['meta']['expire'];
unset($data['meta']['expire']); unset($data['meta']['expire']);
$expire_options = $this->_conf->getSection('expire_options'); $expire_options = $this->_conf->getSection('expire_options');
if (array_key_exists($expiration, $expire_options)) { if (array_key_exists($expiration, $expire_options)) {
@ -234,6 +235,7 @@ class Paste extends AbstractModel
if ($expire > 0) { if ($expire > 0) {
$data['meta']['expire_date'] = time() + $expire; $data['meta']['expire_date'] = time() + $expire;
} }
return $data;
} }
/** /**
@ -243,7 +245,7 @@ class Paste extends AbstractModel
* @param array $data * @param array $data
* @throws Exception * @throws Exception
*/ */
protected function _validate(array &$data) protected function _validate(array $data)
{ {
// reject invalid or disabled formatters // reject invalid or disabled formatters
if (!array_key_exists($data['adata'][1], $this->_conf->getSection('formatter_options'))) { if (!array_key_exists($data['adata'][1], $this->_conf->getSection('formatter_options'))) {

View File

@ -12,7 +12,6 @@
namespace PrivateBin; namespace PrivateBin;
use Exception; use Exception;
use PrivateBin\Model\Paste;
/** /**
* Request * Request
@ -85,7 +84,7 @@ class Request
foreach ($_GET as $key => $value) { foreach ($_GET as $key => $value) {
// only return if value is empty and key is 16 hex chars // only return if value is empty and key is 16 hex chars
$key = (string) $key; $key = (string) $key;
if (empty($value) && Paste::isValidId($key)) { if (($value === '') && strlen($key) === 16 && ctype_xdigit($key)) {
return $key; return $key;
} }
} }
@ -111,8 +110,9 @@ class Request
// it might be a creation or a deletion, the latter is detected below // it might be a creation or a deletion, the latter is detected below
$this->_operation = 'create'; $this->_operation = 'create';
try { try {
$data = file_get_contents(self::$_inputStream); $this->_params = Json::decode(
$this->_params = Json::decode($data); file_get_contents(self::$_inputStream)
);
} catch (Exception $e) { } catch (Exception $e) {
// ignore error, $this->_params will remain empty // ignore error, $this->_params will remain empty
} }

View File

@ -1,120 +0,0 @@
<?php declare(strict_types=1);
/**
* PrivateBin
*
* a zero-knowledge paste bin
*
* @link https://github.com/PrivateBin/PrivateBin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
*/
namespace PrivateBin;
/**
* TemplateSwitcher
*
* Provides tool to change application template
*/
class TemplateSwitcher
{
/**
* template fallback
*
* @access protected
* @static
* @var string
*/
protected static $_templateFallback;
/**
* available templates
*
* @access protected
* @static
* @var array
*/
protected static $_availableTemplates = array();
/**
* set available templates
*
* @access public
* @static
* @param array $templates
*/
public static function setAvailableTemplates(array $templates)
{
self::$_availableTemplates = $templates;
}
/**
* set the default template
*
* @access public
* @static
* @param string $template
*/
public static function setTemplateFallback(string $template)
{
if (self::isTemplateAvailable($template)) {
self::$_templateFallback = $template;
}
}
/**
* get currently loaded template
*
* @access public
* @static
* @return string
*/
public static function getTemplate(): string
{
$selectedTemplate = self::getSelectedByUserTemplate();
return $selectedTemplate ?? self::$_templateFallback;
}
/**
* get list of available templates
*
* @access public
* @static
* @return array
*/
public static function getAvailableTemplates(): array
{
return self::$_availableTemplates;
}
/**
* check if the provided template is available
*
* @access public
* @static
* @return bool
*/
public static function isTemplateAvailable(string $template): bool
{
return in_array($template, self::getAvailableTemplates());
}
/**
* get the template selected by user
*
* @access private
* @static
* @return string|null
*/
private static function getSelectedByUserTemplate(): ?string
{
$selectedTemplate = null;
$templateCookieValue = $_COOKIE['template'] ?? '';
if (self::isTemplateAvailable($templateCookieValue)) {
$selectedTemplate = $templateCookieValue;
}
return $selectedTemplate;
}
}

View File

@ -70,7 +70,7 @@ class View
$sri = array_key_exists($file, $this->_variables['SRI']) ? $sri = array_key_exists($file, $this->_variables['SRI']) ?
' integrity="' . $this->_variables['SRI'][$file] . '"' : ''; ' integrity="' . $this->_variables['SRI'][$file] . '"' : '';
// if the file isn't versioned (ends in a digit), add our own version // if the file isn't versioned (ends in a digit), add our own version
$cacheBuster = (bool) preg_match('#[0-9]\.js$#', (string) $file) ? $cacheBuster = ctype_digit(substr($file, -4, 1)) ?
'' : '?' . rawurlencode($this->_variables['VERSION']); '' : '?' . rawurlencode($this->_variables['VERSION']);
echo '<script ', $attributes, echo '<script ', $attributes,
' type="text/javascript" data-cfasync="false" src="', $file, ' type="text/javascript" data-cfasync="false" src="', $file,

View File

@ -71,7 +71,7 @@ if ($MARKDOWN) :
<?php <?php
endif; endif;
?> ?>
<?php $this->_scriptTag('js/purify-3.2.5.js', 'async'); ?> <?php $this->_scriptTag('js/purify-3.2.4.js', 'async'); ?>
<?php $this->_scriptTag('js/legacy.js', 'async'); ?> <?php $this->_scriptTag('js/legacy.js', 'async'); ?>
<?php $this->_scriptTag('js/privatebin.js', 'defer'); ?> <?php $this->_scriptTag('js/privatebin.js', 'defer'); ?>
<!-- icon --> <!-- icon -->
@ -457,28 +457,6 @@ if (!empty($LANGUAGESELECTION)) :
</li> </li>
<?php <?php
endif; endif;
?>
<?php
if (!empty($TEMPLATESELECTION)) :
?>
<li id="template" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><?php echo I18n::_('Theme'); ?>: <?php echo $TEMPLATESELECTION; ?> <span class="caret"></span></a>
<ul class="dropdown-menu dropdown-menu-right">
<?php
foreach ($TEMPLATES as $value) :
?>
<li>
<a href="#" data-template="<?php echo $value; ?>">
<?php echo $value; ?>
</a>
</li>
<?php
endforeach;
?>
</ul>
</li>
<?php
endif;
?> ?>
</ul> </ul>
</div> </div>
@ -575,8 +553,8 @@ if (!empty($URLSHORTENER)) :
?> ?>
<p> <p>
<button id="shortenbutton" data-shortener="<?php echo I18n::encode($URLSHORTENER); ?>" type="button" class="btn btn-<?php echo $isDark ? 'warning' : 'primary'; ?> btn-block"> <button id="shortenbutton" data-shortener="<?php echo I18n::encode($URLSHORTENER); ?>" type="button" class="btn btn-<?php echo $isDark ? 'warning' : 'primary'; ?> btn-block">
<span class="glyphicon glyphicon-send" aria-hidden="true"></span> <?php echo I18n::_('Shorten URL'), PHP_EOL; ?> <span class="glyphicon glyphicon-send" aria-hidden="true"></span> <?php echo I18n::_('Shorten URL'), PHP_EOL; ?>
</button> </button>
</p> </p>
<div role="alert" class="alert alert-danger"> <div role="alert" class="alert alert-danger">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span> <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>

View File

@ -55,7 +55,7 @@ if ($MARKDOWN) :
<?php <?php
endif; endif;
?> ?>
<?php $this->_scriptTag('js/purify-3.2.5.js', 'defer'); ?> <?php $this->_scriptTag('js/purify-3.2.4.js', 'defer'); ?>
<?php $this->_scriptTag('js/legacy.js', 'async'); ?> <?php $this->_scriptTag('js/legacy.js', 'async'); ?>
<?php $this->_scriptTag('js/privatebin.js', 'defer'); ?> <?php $this->_scriptTag('js/privatebin.js', 'defer'); ?>
<!-- icon --> <!-- icon -->
@ -323,30 +323,6 @@ if (!empty($LANGUAGESELECTION)) :
</li> </li>
<?php <?php
endif; endif;
?>
<?php
if (!empty($TEMPLATESELECTION)) :
?>
<li id="template" class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle d-flex align-items-center gap-1" data-bs-toggle="dropdown" role="button" aria-expanded="false">
<?php echo I18n::_('Theme'); ?>: <?php echo $TEMPLATESELECTION, PHP_EOL; ?>
</a>
<ul class="dropdown-menu dropdown-menu-end" role="menu">
<?php
foreach ($TEMPLATES as $value) :
?>
<li>
<a href="#" class="dropdown-item" data-template="<?php echo $value; ?>">
<?php echo $value; ?>
</a>
</li>
<?php
endforeach;
?>
</ul>
</li>
<?php
endif;
?> ?>
</ul> </ul>
</div> </div>
@ -442,8 +418,8 @@ if (!empty($URLSHORTENER)) :
?> ?>
<p> <p>
<button id="shortenbutton" data-shortener="<?php echo I18n::encode($URLSHORTENER); ?>" type="button" class="btn btn-primary btn-block d-flex justify-content-center align-items-center gap-1"> <button id="shortenbutton" data-shortener="<?php echo I18n::encode($URLSHORTENER); ?>" type="button" class="btn btn-primary btn-block d-flex justify-content-center align-items-center gap-1">
<svg width="16" height="16" fill="currentColor" aria-hidden="true"><use href="img/bootstrap-icons.svg#send" /></svg> <?php echo I18n::_('Shorten URL'), PHP_EOL; ?> <svg width="16" height="16" fill="currentColor" aria-hidden="true"><use href="img/bootstrap-icons.svg#send" /></svg> <?php echo I18n::_('Shorten URL'), PHP_EOL; ?>
</button> </button>
</p> </p>
<div role="alert" class="alert alert-danger"> <div role="alert" class="alert alert-danger">
<svg width="16" height="16" fill="currentColor" aria-hidden="true"><use href="img/bootstrap-icons.svg#exclamation-circle" /></svg> <svg width="16" height="16" fill="currentColor" aria-hidden="true"><use href="img/bootstrap-icons.svg#exclamation-circle" /></svg>

View File

@ -49,7 +49,7 @@ if ($MARKDOWN):
<?php <?php
endif; endif;
?> ?>
<?php $this->_scriptTag('js/purify-3.2.5.js', 'async'); ?> <?php $this->_scriptTag('js/purify-3.2.4.js', 'async'); ?>
<?php $this->_scriptTag('js/legacy.js', 'async'); ?> <?php $this->_scriptTag('js/legacy.js', 'async'); ?>
<?php $this->_scriptTag('js/privatebin.js', 'defer'); ?> <?php $this->_scriptTag('js/privatebin.js', 'defer'); ?>
<!-- icon --> <!-- icon -->
@ -222,27 +222,6 @@ if (!empty($LANGUAGESELECTION)):
</div> </div>
<?php <?php
endif; endif;
?>
<?php
if (!empty($TEMPLATESELECTION)):
?>
<div id="template" class="button"><?php echo I18n::_('Theme'); ?>:
<select name="template">
<?php
foreach ($TEMPLATES as $value):
?>
<option data-template="<?php echo $value; ?>" value="<?php echo $value; ?>"<?php
if ($value == $TEMPLATESELECTION):
?> selected="selected"<?php
endif;
?>><?php echo $value; ?></option>
<?php
endforeach;
?>
</select>
</div>
<?php
endif;
?> ?>
</div> </div>
<?php <?php

View File

@ -823,11 +823,6 @@ class ConnectionInterfaceStub implements ConnectionInterface
throw new BadMethodCallException('not supported by this stub'); throw new BadMethodCallException('not supported by this stub');
} }
public function moveObject(array $args = array())
{
throw new BadMethodCallException('not supported by this stub');
}
public function composeObject(array $args = array()) public function composeObject(array $args = array())
{ {
throw new BadMethodCallException('not supported by this stub'); throw new BadMethodCallException('not supported by this stub');

Some files were not shown because too many files have changed in this diff Show More