diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3d858651..f3795964 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -43,7 +43,7 @@ jobs: actions: read id-token: write contents: write - uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0 + uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0 with: base64-subjects: "${{ needs.release.outputs.hashes }}" draft-release: true diff --git a/.github/workflows/test-results.yml b/.github/workflows/test-results.yml index 4e20737d..2a315b7a 100644 --- a/.github/workflows/test-results.yml +++ b/.github/workflows/test-results.yml @@ -24,7 +24,7 @@ jobs: steps: - name: Download and Extract Artifacts - uses: dawidd6/action-download-artifact@bf251b5aa9c2f7eeb574a96ee720e24f801b7c11 + uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5 with: run_id: ${{ github.event.workflow_run.id }} path: artifacts diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d668d74e..b8c75ccb 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -22,11 +22,12 @@ jobs: continue-on-error: "${{ matrix.experimental }}" strategy: matrix: - php-versions: ['7.3', '7.4', '8.0', '8.1', '8.2', '8.3'] + php-versions: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4'] experimental: [false] - include: - - php-versions: '8.4' # development release, things can break - experimental: true +# uncomment this to start testing on development release +# include: +# - php-versions: '8.5' # development release, things can break +# experimental: true env: extensions: gd, sqlite3 extensions-cache-key-name: phpextensions @@ -120,7 +121,7 @@ jobs: - name: Setup Node uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '18' cache: 'npm' cache-dependency-path: 'js/package-lock.json' diff --git a/.htaccess.disabled b/.htaccess.disabled index 5a3abe46..b635612b 100644 --- a/.htaccess.disabled +++ b/.htaccess.disabled @@ -2,6 +2,7 @@ RewriteEngine on RewriteCond !%{HTTP_USER_AGENT} "Let's Encrypt validation server" [NC] RewriteCond %{HTTP_USER_AGENT} ^.*(bot|spider|crawl|https?://|WhatsApp|SkypeUriPreview|facebookexternalhit) [NC] RewriteRule .* - [R=403,L] +AddType application/wasm .wasm php_value max_execution_time 30 diff --git a/CHANGELOG.md b/CHANGELOG.md index 13bdfaa0..955f987f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,42 @@ # PrivateBin version history +## 2.0.0 (not yet released) +* ADDED: Error logging in database and filesystem backend (#1554) +* CHANGED: Remove page template (#265) +* CHANGED: Jdenticons are now used as the default icons +* CHANGED: Upgrading libraries to: jdenticon 2.0.0 +* CHANGED: Minimum required PHP version is 7.4, due to a change in the jdenticon library +* FIXED: Name mismatches in attached files (#1584) +* FIXED: Unable to paste attachments from clipboard (#1589) + +## 1.7.8 (2025-06-30) +* FIXED: Duplicate attachment for every comment (#1577) +* FIXED: Attachments with empty file names (#1577) +* FIXED: Page template scripts loading order (#1579) + +## 1.7.7 (2025-06-28) +* ADDED: Switching templates using the web ui (#1501) +* ADDED: Show file name and size on download page (#603) +* 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.6, ip-lib 1.20.0 +* CHANGED: Support for multiple file uploads (#1060) +* CHANGED: Documented CSP change necessary to allow PDF attachment preview (#1552) +* FIXED: Hide Reply button in the discussions once clicked to avoid losing the text input (#1508) +* FIXED: Bump zlib library suffix, ensuring cache refresh for WASM streaming change +* FIXED: Handle undefined globals in file based persisted values (#1544) + +## 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) +* CHANGED: Allow toggling tab-key-support using `[Ctrl]+[m]` or `[Esc]` in textarea for keyboard navigation (#1386) +* CHANGED: Switched to WASM streaming and replace unsafe-eval with wasm-unsafe-eval CSP declaration (#1464), requires webserver to have `application/wasm` MIME type configured. +* CHANGED: Replaced usage of strpos with str_starts_with & str_contains (#1373) +* CHANGED: Added polyfill libraries for ctype, str_starts_with & str_contains functions (#1476) +* CHANGED: Turned paste delete link into a button (#266) +* CHANGED: Upgrading libraries to: DOMpurify 3.2.4, cloud-storage 1.45.0, aws-sdk-php 3.336.2 +* CHANGED: `bootstrap5` template UI improvements +* FIXED: Redirect to the home page after changing the language (#92) + ## 1.7.5 (2024-11-16) * ADDED: Allow non persistent SQL connections, if configured (#1394) * ADDED: Show a button (that redirects to the `basepath` URL) inside the alert after a paste is deleted diff --git a/CREDITS.md b/CREDITS.md index 2ca6fe0b..37026898 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -5,6 +5,7 @@ * Simon Rupf - current developer and maintainer * rugk - security review, doc improvment, JS refactoring & various other stuff * R4SAS - python client, compression, blob URI to support larger attachments +* Mikhail Romanov - UI improvements, theme switching, clipboard support, multi-file upload, bugfixes, code refactoring ## Past contributions diff --git a/Makefile b/Makefile index 36ba9047..792e09d1 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ .PHONY: all coverage coverage-js coverage-php doc doc-js doc-php increment sign test test-js test-php help -CURRENT_VERSION = 1.7.5 -VERSION ?= 1.7.6 +CURRENT_VERSION = 1.7.8 +VERSION ?= 2.0.0 VERSION_FILES = README.md SECURITY.md doc/Installation.md js/package*.json lib/Controller.php Makefile REGEX_CURRENT_VERSION := $(shell echo $(CURRENT_VERSION) | sed "s/\./\\\./g") REGEX_VERSION := $(shell echo $(VERSION) | sed "s/\./\\\./g") diff --git a/README.md b/README.md index 0ba28eaf..2ef2fcfb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # [![PrivateBin](https://cdn.rawgit.com/PrivateBin/assets/master/images/preview/logoSmall.png)](https://privatebin.info/) -*Current version: 1.7.5* +*Current version: 1.7.8* **PrivateBin** is a minimalist, open source online [pastebin](https://en.wikipedia.org/wiki/Pastebin) diff --git a/SECURITY.md b/SECURITY.md index 19c84f0a..276fce2a 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,8 +4,8 @@ | Version | Supported | | ------- | ------------------ | -| 1.7.5 | :heavy_check_mark: | -| < 1.7.5 | :x: | +| 1.7.8 | :heavy_check_mark: | +| < 1.7.8 | :x: | ## Reporting a Vulnerability @@ -14,5 +14,8 @@ 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 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 publication is low or you would request input from other PrivateBin users. diff --git a/bin/administration b/bin/administration index 17b2e0f5..7c4057be 100755 --- a/bin/administration +++ b/bin/administration @@ -72,6 +72,35 @@ class Administration 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 * @@ -124,13 +153,15 @@ class Administration { echo <<<'EOT' Usage: - administration [--delete | --empty-dirs | --help | --purge | --statistics] + administration [--delete | --delete-all | --empty-dirs | --help | --list-ids | --purge | --statistics] Options: -d, --delete deletes the requested paste ID + --delete-all deletes all paste IDs -e, --empty-dirs removes empty directories (only if Filesystem storage is configured) -h, --help displays this help message + -l, --list-ids lists all paste IDs -p, --purge purge all expired pastes -s, --statistics reads all stored pastes and comments and reports statistics EOT, PHP_EOL; @@ -177,7 +208,8 @@ EOT, PHP_EOL; self::_help(2); } - $this->_opts = getopt('hd:eps', array('help', 'delete:', 'empty-dirs', 'purge', 'statistics')); + $this->_opts = getopt('hd:epsl', array('help', 'delete:', 'empty-dirs', 'purge', 'statistics', 'list-ids', 'delete-all')); + if (!$this->_opts) { self::_error_echo('unsupported arguments given'); echo PHP_EOL; @@ -308,6 +340,12 @@ EOT, PHP_EOL; $class = 'PrivateBin\\Data\\' . $this->_conf->getKey('class', 'model'); $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) { $this->_delete($pasteId); } diff --git a/bin/configuration-test-generator b/bin/configuration-test-generator index d81c3302..9b3de8f9 100755 --- a/bin/configuration-test-generator +++ b/bin/configuration-test-generator @@ -164,14 +164,14 @@ new ConfigurationTestGenerator(array( ), 'main/template' => array( array( - 'setting' => 'page', + 'setting' => 'bootstrap5', 'tests' => array( array( 'type' => 'MatchesRegularExpression', 'args' => array( - '#]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/privatebin\.css\\?\d[\d\.]+\d+"[^>]*/>#', + '#]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/bootstrap5/privatebin\.css\\?\d[\d\.]+\d+"[^>]*/>#', '$content', - 'outputs "page" stylesheet correctly', + 'outputs "bootstrap5" stylesheet correctly', ), ), array( 'type' => 'DoesNotMatchRegularExpression', @@ -189,9 +189,9 @@ new ConfigurationTestGenerator(array( array( 'type' => 'DoesNotMatchRegularExpression', 'args' => array( - '#]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/privatebin\.css\\?\d[\d\.]+\d+"[^>]*/>#', + '#]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/bootstrap5/privatebin\.css\\?\d[\d\.]+\d+"[^>]*/>#', '$content', - 'removes "page" stylesheet correctly', + 'removes "bootstrap5" stylesheet correctly', ), ), array( 'type' => 'MatchesRegularExpression', diff --git a/cfg/conf.sample.php b/cfg/conf.sample.php index e9880471..449feebd 100644 --- a/cfg/conf.sample.php +++ b/cfg/conf.sample.php @@ -42,13 +42,26 @@ defaultformatter = "plaintext" ; size limit per paste or comment in bytes, defaults to 10 Mebibytes sizelimit = 10485760 -; template to include, default is "bootstrap" (tpl/bootstrap.php), also -; available are "page" (tpl/page.php), the classic ZeroBin style and several +; by default PrivateBin use "bootstrap" template (tpl/bootstrap.php). +; 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[] = "bootstrap5" +availabletemplates[] = "bootstrap" +availabletemplates[] = "bootstrap-page" +availabletemplates[] = "bootstrap-dark" +availabletemplates[] = "bootstrap-dark-page" +availabletemplates[] = "bootstrap-compact" +availabletemplates[] = "bootstrap-compact-page" + +; set the template your installs defaults to, defaults to "bootstrap" (tpl/bootstrap.php), also ; bootstrap variants: "bootstrap-dark", "bootstrap-compact", "bootstrap-page", -; which can be combined with "-dark" and "-compact" for "bootstrap-dark-page" -; and finally "bootstrap-compact-page" - previews at: +; which can be combined with "-dark" and "-compact" for "bootstrap-dark-page", +; "bootstrap-compact-page" and finally "bootstrap5" (tpl/bootstrap5.php) - previews at: ; https://privatebin.info/screenshots.html -template = "bootstrap" +; template = "bootstrap" ; (optional) info text to display ; use single, instead of double quotes for HTML attributes @@ -84,7 +97,7 @@ languageselection = false ; used to get the IP of a comment poster if the server salt is leaked and a ; SHA512 HMAC rainbow table is generated for all (relevant) IPs. ; Can be set to one these values: -; "none" / "identicon" (default) / "jdenticon" / "vizhash". +; "none" / "identicon" / "jdenticon" (default) / "vizhash". ; icon = "none" ; Content Security Policy headers allow a website to restrict what sources are @@ -93,19 +106,23 @@ languageselection = false ; scripts or run your site behind certain DDoS-protection services. ; Check the documentation at https://content-security-policy.com/ ; Notes: -; - If you use any bootstrap theme, you can remove the allow-popups from the -; sandbox restrictions. ; - If you use the bootstrap5 theme, you must change default-src to 'self' to ; enable display of the svg icons ; - By default this disallows to load images from third-party servers, e.g. when ; they are embedded in pastes. If you wish to allow that, you can adjust the ; policy here. See https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-it-load-embedded-images ; for details. -; - The 'unsafe-eval' is used in two cases; to check if the browser supports -; async functions and display an error if not and for Chrome to enable -; webassembly support (used for zlib compression). You can remove it if Chrome -; doesn't need to be supported and old browsers don't need to be warned. -; cspheader = "default-src 'none'; base-uri 'self'; form-action 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'unsafe-eval'; style-src 'self'; font-src 'self'; frame-ancestors 'none'; img-src 'self' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-downloads" +; - The 'wasm-unsafe-eval' is used to enable webassembly support (used for zlib +; compression). You can remove it if compression doesn't need to be supported. +; - The 'unsafe-inline' style-src is used by Chrome when displaying PDF previews +; and can be omitted if attachment upload is disabled (which is the default). +; See https://issues.chromium.org/issues/343754409 +; - To allow displaying PDF previews in Firefox or Chrome, sandboxing must also +; get turned off. The following CSP allows PDF previews: +; cspheader = "default-src 'none'; base-uri 'self'; form-action 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; font-src 'self'; frame-ancestors 'none'; frame-src blob:; img-src 'self' data: blob:; media-src blob:; object-src blob:" +; +; The recommended and default used CSP is: +; cspheader = "default-src 'none'; base-uri 'self'; form-action 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'wasm-unsafe-eval'; style-src 'self'; font-src 'self'; frame-ancestors 'none'; frame-src blob:; img-src 'self' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-modals allow-downloads" ; stay compatible with PrivateBin Alpha 0.19, less secure ; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of diff --git a/codacy-analysis.yml b/codacy-analysis.yml index 9850708b..31d065cd 100644 --- a/codacy-analysis.yml +++ b/codacy-analysis.yml @@ -24,7 +24,7 @@ jobs: steps: # Checkout the repository to the GitHub Actions runner - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v4 # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis - name: Run Codacy Analysis CLI diff --git a/composer.json b/composer.json index d16a562b..ee1ad842 100644 --- a/composer.json +++ b/composer.json @@ -24,14 +24,15 @@ "docs" : "https://privatebin.info/codedoc/" }, "require" : { - "php": "^7.3 || ^8.0", - "jdenticon/jdenticon": "1.0.2", - "mlocati/ip-lib": "1.18.1", + "php": "^7.4 || ^8.0", + "jdenticon/jdenticon": "2.0.0", + "mlocati/ip-lib": "1.20.0", + "symfony/polyfill-php80": "1.31.0", "yzalis/identicon": "2.0.0" }, "suggest" : { - "google/cloud-storage" : "1.43.0", - "aws/aws-sdk-php" : "3.325.0" + "google/cloud-storage" : "1.45.0", + "aws/aws-sdk-php" : "3.336.2" }, "require-dev" : { "phpunit/phpunit" : "^9" @@ -47,7 +48,7 @@ "preferred-install": "dist", "sort-packages": true, "platform": { - "php": "7.3" + "php": "7.4" } } } diff --git a/composer.lock b/composer.lock index 3b298cb5..b032e9c4 100644 --- a/composer.lock +++ b/composer.lock @@ -4,27 +4,27 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "bb78267a7d61d23706111a91bc90d515", + "content-hash": "cc778a671eac2ba1ec70bf9398b2e1bf", "packages": [ { "name": "jdenticon/jdenticon", - "version": "1.0.2", + "version": "2.0.0", "source": { "type": "git", "url": "https://github.com/dmester/jdenticon-php.git", - "reference": "cabb7a44c413c318392a341c5d3ca30fcdd57a6f" + "reference": "fb39a98a0a54982a130b7e7b06305d4fd8c9717e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/dmester/jdenticon-php/zipball/cabb7a44c413c318392a341c5d3ca30fcdd57a6f", - "reference": "cabb7a44c413c318392a341c5d3ca30fcdd57a6f", + "url": "https://api.github.com/repos/dmester/jdenticon-php/zipball/fb39a98a0a54982a130b7e7b06305d4fd8c9717e", + "reference": "fb39a98a0a54982a130b7e7b06305d4fd8c9717e", "shasum": "" }, "require": { - "php": ">=5.3.0" + "php": ">=7.4.0" }, "require-dev": { - "phpunit/phpunit": "^5.7" + "phpunit/phpunit": "^9" }, "type": "library", "autoload": { @@ -53,20 +53,20 @@ "issues": "https://github.com/dmester/jdenticon-php/issues", "source": "https://github.com/dmester/jdenticon-php" }, - "time": "2022-10-30T17:15:02+00:00" + "time": "2025-07-14T18:30:29+00:00" }, { "name": "mlocati/ip-lib", - "version": "1.18.1", + "version": "1.20.0", "source": { "type": "git", "url": "https://github.com/mlocati/ip-lib.git", - "reference": "08bb43b4949069c543ebdf099a6b2c322d0172ab" + "reference": "fd45fc3bf08ed6c7e665e2e70562082ac954afd4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/mlocati/ip-lib/zipball/08bb43b4949069c543ebdf099a6b2c322d0172ab", - "reference": "08bb43b4949069c543ebdf099a6b2c322d0172ab", + "url": "https://api.github.com/repos/mlocati/ip-lib/zipball/fd45fc3bf08ed6c7e665e2e70562082ac954afd4", + "reference": "fd45fc3bf08ed6c7e665e2e70562082ac954afd4", "shasum": "" }, "require": { @@ -112,7 +112,7 @@ ], "support": { "issues": "https://github.com/mlocati/ip-lib/issues", - "source": "https://github.com/mlocati/ip-lib/tree/1.18.1" + "source": "https://github.com/mlocati/ip-lib/tree/1.20.0" }, "funding": [ { @@ -124,7 +124,87 @@ "type": "other" } ], - "time": "2024-10-29T15:44:19+00:00" + "time": "2025-02-04T17:30:58+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.31.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "reference": "60328e362d4c2c802a54fcbf04f9d3fb892b4cf8", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/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": "yzalis/identicon", @@ -257,16 +337,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.12.0", + "version": "1.13.3", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c" + "reference": "faed855a7b5f4d4637717c2b3863e277116beb36" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", - "reference": "3a6b9a42cd8f8771bd4295d13e1423fa7f3d942c", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/faed855a7b5f4d4637717c2b3863e277116beb36", + "reference": "faed855a7b5f4d4637717c2b3863e277116beb36", "shasum": "" }, "require": { @@ -305,7 +385,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.12.0" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.3" }, "funding": [ { @@ -313,29 +393,31 @@ "type": "tidelift" } ], - "time": "2024-06-12T14:39:25+00:00" + "time": "2025-07-05T12:25:42+00:00" }, { "name": "nikic/php-parser", - "version": "v4.19.4", + "version": "v5.5.0", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2" + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/715f4d25e225bc47b293a8b997fe6ce99bf987d2", - "reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", "shasum": "" }, "require": { + "ext-ctype": "*", + "ext-json": "*", "ext-tokenizer": "*", - "php": ">=7.1" + "php": ">=7.4" }, "require-dev": { "ircmaxell/php-yacc": "^0.0.7", - "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" + "phpunit/phpunit": "^9.0" }, "bin": [ "bin/php-parse" @@ -343,7 +425,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "4.9-dev" + "dev-master": "5.0-dev" } }, "autoload": { @@ -367,9 +449,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v4.19.4" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0" }, - "time": "2024-09-29T15:01:53+00:00" + "time": "2025-05-31T08:24:38+00:00" }, { "name": "phar-io/manifest", @@ -810,16 +892,16 @@ }, { "name": "phpunit/phpunit", - "version": "9.6.21", + "version": "9.6.23", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa" + "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", - "reference": "de6abf3b6f8dd955fac3caad3af7a9504e8c2ffa", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", + "reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95", "shasum": "" }, "require": { @@ -830,7 +912,7 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.12.0", + "myclabs/deep-copy": "^1.13.1", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=7.3", @@ -893,7 +975,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.21" + "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.23" }, "funding": [ { @@ -904,12 +986,20 @@ "url": "https://github.com/sebastianbergmann", "type": "github" }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, { "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", "type": "tidelift" } ], - "time": "2024-09-19T10:50:18+00:00" + "time": "2025-05-02T06:40:34+00:00" }, { "name": "sebastian/cli-parser", @@ -1931,11 +2021,11 @@ "prefer-stable": false, "prefer-lowest": false, "platform": { - "php": "^7.3 || ^8.0" + "php": "^7.4 || ^8.0" }, "platform-dev": [], "platform-overrides": { - "php": "7.3" + "php": "7.4" }, "plugin-api-version": "2.3.0" } diff --git a/css/bootstrap/privatebin.css b/css/bootstrap/privatebin.css index 74ea788a..ab2fdebc 100644 --- a/css/bootstrap/privatebin.css +++ b/css/bootstrap/privatebin.css @@ -69,47 +69,8 @@ body.loading { margin-right: 8px; } -#qrcodemodalClose { - float: right; -} - -#qrcode-display { - width: 200px; - height: 200px; - margin: auto; -} - -#pastelink { - display: inline; -} - -#pastelink > a { - word-wrap: break-word; -} - -#message { - height: 70dvh; -} - -@media ((max-width: 450px) and (max-height: 950px)) { - #message { - height: 55dvh; - } -} - -#message, .replymessage { - font-family: monospace; - resize: vertical; -} - -#nickname { - margin: 5px 0; -} - .comment { - border-left: 1px solid #ccc; padding: 5px 0 5px 10px; - transition: background-color 0.75s ease-out; } footer h4 { @@ -177,3 +138,31 @@ html[dir="rtl"] #language { html[dir="rtl"] #deletelink, html[dir="rtl"] #qrcodemodalClose { float: left; } + +#prettyprint { + padding-right: 30px; +} + +#prettyMessageCopyBtn { + position: absolute; + top: 8px; + right: 25px; + left: auto; + padding: 0; + background: none; + border: none; + z-index: 1; +} + +html[dir="rtl"] #prettyMessageCopyBtn { + left: 25px; + right: auto; +} + +#copySuccessIcon { + display: none; +} + +#copyShortcutHint { + margin-bottom: 5px; +} \ No newline at end of file diff --git a/css/bootstrap5/privatebin.css b/css/bootstrap5/privatebin.css index f486869d..29481963 100644 --- a/css/bootstrap5/privatebin.css +++ b/css/bootstrap5/privatebin.css @@ -14,48 +14,23 @@ display: none !important; } -#qrcodemodalClose { - float: right; +.opacity-05-1-hover { + opacity: 0.5; + transition: all 0.15s ease; } -#qrcode-display { - width: 200px; - height: 200px; - margin: auto; -} - -#pastelink { - display: inline; -} - -#pastelink > a { - word-wrap: break-word; -} - -#message { - height: 70dvh; -} - -@media ((max-width: 450px) and (max-height: 950px)) { - #message { - height: 55dvh; - } -} - -#message, .replymessage { - font-family: monospace; - resize: vertical; -} - -.comment { - border-left: 1px solid #ccc; - transition: background-color 0.75s ease-out; +.opacity-05-1-hover:hover { + opacity: 1; } .dropdown-menu { --bs-dropdown-min-width: 23rem; } +pre { + margin-bottom: 0; +} + [data-bs-theme=light] pre, [data-bs-theme=light] .card { background-color: RGBA(var(--bs-light-rgb), var(--bs-bg-opacity, 1)); } @@ -77,3 +52,39 @@ li.L0, li.L1, li.L2, li.L3, li.L4, li.L5, li.L6, li.L7, li.L8, li.L9 { html[dir="rtl"] #deletelink, html[dir="rtl"] #qrcodemodalClose { float: left; } + +#prettyprint { + padding-right: 30px; +} + +#prettyMessageCopyBtn { + position: absolute; + top: 8px; + right: 8px; + left: auto; + width: 20px; + height: 20px; + padding: 0; + background: none; + border: none; + z-index: 1; +} + +html[dir="rtl"] #prettyMessageCopyBtn { + left: 8px; + right: auto; +} + +#prettyMessageCopyBtn svg { + width: 100%; + height: 100%; + vertical-align: baseline; +} + +#copySuccessIcon { + display: none; +} + +#sendbutton svg { + transform: translateY(1.5px); +} diff --git a/css/common.css b/css/common.css index d44530e0..b5019c47 100644 --- a/css/common.css +++ b/css/common.css @@ -8,6 +8,12 @@ * @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License */ +#attachmentPreview { + display: flex; + flex-direction: column; + align-items: center; +} + #attachmentPreview img { max-width: 100%; height: auto; @@ -38,27 +44,64 @@ outline-offset: -50px; } -.dragAndDropFile { - color: #777; - font-size: 1em; - display: inline; - white-space: normal; -} - #filewrap { transition: background-color 0.75s ease-out; } -.highlight { - background-color: #fd8; - transition: background-color 0.2s ease-in; -} - #deletelink { float: right; margin-left: 5px; } +#qrcodemodalClose { + float: right; +} + +#qrcode-display { + width: 200px; + margin: auto; +} + +#pastelink { + display: inline; +} + +#pastelink > a, #plaintext > a { + word-wrap: break-word; +} + +#message { + height: 70dvh; +} + +@media ((max-width: 450px) and (max-height: 950px)) { + #message { + height: 55dvh; + } +} + +#message, .replymessage { + font-family: monospace; + resize: vertical; +} + +.comment { + border-left: 1px solid #ccc; + transition: background-color 0.75s ease-out; +} + .commentdata { white-space: pre-wrap; } + +.dragAndDropFile { + color: #777; + font-size: 1em; + display: inline; + white-space: normal; +} + +.highlight { + background-color: #fd8; + transition: background-color 0.2s ease-in; +} diff --git a/css/privatebin.css b/css/privatebin.css deleted file mode 100644 index 77824fb6..00000000 --- a/css/privatebin.css +++ /dev/null @@ -1,459 +0,0 @@ -/** - * PrivateBin - * - * Cascading style sheets for page template. - * - * @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 - */ - -@import url("common.css"); - -/* CSS Reset from YUI 3.4.1 (build 4118) - Copyright 2011 Yahoo! Inc. All rights reserved. -Licensed under the BSD License. - http://yuilibrary.com/license/ */ -html{color:#000;background:#fff}body,div,dl,dt,dd,ul,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0}table{border-collapse:collapse;border-spacing:0}fieldset,img{border:0}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal}ol,ul{list-style:none}caption,th{text-align:left}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}q:before,q:after{content:''}abbr,acronym{border:0;font-variant:normal}sup{vertical-align:text-top}sub{vertical-align:text-bottom}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit}input,textarea,select{font-size:100%;}legend{color:#000} - -html { - background-color: #455463; - color: #fff; - min-height: 100%; - background-image: linear-gradient(bottom, #0f1823 0, #455463 100%); - background-image: -o-linear-gradient(bottom, #0f1823 0, #455463 100%); - background-image: -moz-linear-gradient(bottom, #0f1823 0, #455463 100%); - background-image: -webkit-linear-gradient(bottom, #0f1823 0, #455463 100%); - background-image: -ms-linear-gradient(bottom, #0f1823 0, #455463 100%); - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #0f1823), color-stop(1, #455463)); -} - -body { - font-family: Helvetica, Arial, sans-serif; - font-size: 0.9em; - margin-bottom: 15px; - padding-left: 60px; - padding-right: 60px; -} - -a { color: #0f388f; cursor:pointer; } - -h1.title { - font-size: 3.5em; - font-weight: bold; - color: #000; - position: relative; - display: inline; - cursor: pointer; -} - -h1.title:before { - content: attr(title); - position: absolute; - color: rgba(255,255,255,0.15); - top: 1px; - left: 1px; - cursor: pointer; -} - -h2.title { - color: #000; - font-size: 1em; - display: inline; - font-style: italic; - font-weight: bold; - position: relative; - bottom: 8px; -} - -h3.title { - color: #94a3b4; - font-size: 0.7em; - display: inline; - margin-top: 10px; - position: relative; - bottom: 8px; -} - -#aboutbox { - color: #94a3b4; - padding: 4px 8px 4px 16px; - position: relative; - top: 10px; - border-left: 2px solid #94a3b4; - float: right; - width: 60%; -} - -#aboutbox a { color: #94a3b4; } - -#message, #cleartext, #prettymessage, #attachment, .replymessage { - clear: both; - color: #000; - background-color: #fff; - font-size: 9pt; - border: 1px solid #28343F; - box-sizing: border-box; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - -ms-box-sizing: border-box; - -o-box-sizing: border-box; - width: 100%; -} - -#message, .replymessage { - padding: 5px; - white-space: pre-wrap; - font-family: Consolas, "Lucida Console", "DejaVu Sans Mono", Monaco, monospace; - resize: vertical; -} - -#status { - clear: both; - padding: 5px 10px; -} - -#pasteresult { - background-color: #1F2833; - color: #fff; - padding: 4px 12px; - clear: both; - -moz-box-shadow: inset 0 2px 2px #000; - -webkit-box-shadow: inset 0 2px 2px #000; - box-shadow: inset 0 2px 2px #000; -} - -#pasteresult a { color: #fff; } - -#pasteresult button { margin-left: 11px; } - -#toolbar, #status { margin-bottom: 5px; } - -#copyhint { color: #666; font-size: 0.85em } - -button, .button { - color: #fff; - background-color: #323b47; - background-repeat: no-repeat; - background-position: center left; - padding: 4px 8px; - font-size: 1em; - margin-right: 5px; - display: inline-block; - background-image: linear-gradient(bottom, #323b47 0, #51606e 100%); - background-image: -o-linear-gradient(bottom, #323b47 0, #51606e 100%); - background-image: -moz-linear-gradient(bottom, #323b47 0, #51606e 100%); - background-image: -webkit-linear-gradient(bottom, #323b47 0, #51606e 100%); - background-image: -ms-linear-gradient(bottom, #323b47 0, #51606e 100%); - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #323b47), color-stop(1, #51606e)); - border: 1px solid #28343F; - -moz-box-shadow: inset 0 1px 2px #647384; - -webkit-box-shadow: inset 0 1px 2px #647384; - box-shadow: inset 0 1px 2px #647384; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - -moz-background-clip: padding; - -webkit-background-clip: padding-box; - background-clip: padding-box; -} - -button:hover { - background-image: linear-gradient(bottom, #424b57 0%, #61707e 100%); - background-image: -o-linear-gradient(bottom, #424b57 0%, #61707e 100%); - background-image: -moz-linear-gradient(bottom, #424b57 0%, #61707e 100%); - background-image: -webkit-linear-gradient(bottom, #424b57 0%, #61707e 100%); - background-image: -ms-linear-gradient(bottom, #424b57 0%, #61707e 100%); - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #424b57), color-stop(1, #61707e)); -} - -button:active { - background-image: linear-gradient(bottom, #51606e 0, #323b47 100%); - background-image: -o-linear-gradient(bottom, #51606e 0, #323b47 100%); - background-image: -moz-linear-gradient(bottom, #51606e 0, #323b47 100%); - background-image: -webkit-linear-gradient(bottom, #51606e 0, #323b47 100%); - background-image: -ms-linear-gradient(bottom, #51606e 0, #323b47 100%); - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #51606e), color-stop(1, #323b47)); - position:relative; - top:1px; -} - -button:disabled, .buttondisabled { - background: #ccc; - color: #888; - top: 0; -} - -button img { - margin-right: 8px; - position: relative; - top: 2px; -} - -.button { - background-color: #414d5a; - padding: 6px 8px; - margin: 0 5px 0 0; - position: relative; - bottom: 1px; /* WTF ? Why is this shifted by 1 pixel ? */ -} - -.button select { - color: #eee; - background: transparent; - border: none; -} - - -.button select option { - color:#eee; - background: #414d5a; -} - -#rawtextbutton img { - padding: 1px 0 1px 0; -} - -#downloadtextbutton img { - padding: 1px 0 1px 0; -} - -#remainingtime, #password { - color: #94a3b4; - display: inline; - font-size: 0.85em; -} - -#newbutton { - float: right; - margin-left: 0; - margin-right: 0; - margin-bottom: 5px; - display: inline; -} - -input { - color: #777; - font-size: 1em; - padding: 6px; - border: 1px solid #28343f; -} - -.blink { - text-decoration: blink; - font-size: 0.8em; - color: #a4b3c4; -} - -.foryoureyesonly { - color: #ff0 !important; - font-size: 1em !important; - font-weight: bold !important; -} - -#attachmentPreview, .nonworking { - background-color: #fff; - color: #000; - width: 100%; - text-align: center; - font-weight: bold; - font-size: 10pt; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - padding: 5px 0; -} - -.hidden { display: none !important; } - -#ienotice { - background-color: #7e98af; - color: #000; - font-size: 0.85em; - padding: 3px 5px; - text-align: center; - -webkit-border-radius: 4px; - -moz-border-radius: 4px; - border-radius: 4px; - display: none; -} - -#ienotice a { color: #000; } - -#oldnotice, #httpnotice { display: none; } - -#errormessage, .errorMessage { - background-color: #f77 !important; - color:#ff0; -} - -.small { - font-size: 80%; -} - -/* --- discussion related CSS ------- */ - -#discussion { /* Discussion container */ - margin-top: 20px; - width: 100%; - margin-left: -30px; - min-width: 200px; -} - -h4.title { - font-size: 1.2em; - color: #94a3b4; - font-style: italic; - font-weight: bold; - position: relative; - margin-left: 30px; -} - -.comment /* One single reply */ -{ - background-color: #ceced6; - color: #000; - white-space: pre-wrap; - font-family: Consolas,"Lucida Console","DejaVu Sans Mono",Monaco,monospace; - font-size: 9pt; - border-left: 1px solid #859AAE; - border-top: 1px solid #859AAE; - padding: 5px 0px 5px 5px; - margin-left: 30px; - -moz-box-shadow: -3px -3px 5px rgba(0,0,0,0.15); - -webkit-box-shadow: -3px -3px 5px rgba(0,0,0,0.15); - box-shadow: -3px -3px 5px rgba(0,0,0,0.15); - min-width: 200px; - overflow: auto; -} - -.reply { margin: 5px 0 0 30px; } - -#replystatus { - display: inline; - padding: 1px 7px; - font-family: Arial, Helvetica, sans-serif; -} - -.comment button { - color: #446; - background-color: #aab; - background-repeat: no-repeat; - background-position: center left; - padding: 0 2px; - font-size: 0.73em; - margin: 3px 5px 3px 0; - display: inline; - background-image: linear-gradient(bottom, #aab 0, #ccc 100%); - background-image: -o-linear-gradient(bottom, #aab 0, #ccc 100%); - background-image: -moz-linear-gradient(bottom, #aab 0, #ccc 100%); - background-image: -webkit-linear-gradient(bottom, #aab 0, #ccc 100%); - background-image: -ms-linear-gradient(bottom, #aab 0, #ccc 100%); - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #aab), color-stop(1, #ccc)); - border: 1px solid #ccd; - -moz-box-shadow: inset 0 1px 2px #ddd; - -webkit-box-shadow: inset 0 1px 2px #fff; - box-shadow: inset 0 1px 2px #eee; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - -moz-background-clip: padding; - -webkit-background-clip: padding-box; - background-clip: padding-box; -} - -.comment button:hover { - background-image: linear-gradient(bottom, #ccd 0, #fff 100%); - background-image: -o-linear-gradient(bottom, #ccd 0, #fff 100%); - background-image: -moz-linear-gradient(bottom, #ccd 0, #fff 100%); - background-image: -webkit-linear-gradient(bottom, #ccd 0, #fff 100%); - background-image: -ms-linear-gradient(bottom, #ccd 0, #fff 100%); - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccd), color-stop(1, #fff)); -} - -.comment button:active { - background-image: linear-gradient(bottom, #fff 0, #889 100%); - background-image: -o-linear-gradient(bottom, #fff 0, #889 100%); - background-image: -moz-linear-gradient(bottom, #fff 0, #889 100%); - background-image: -webkit-linear-gradient(bottom, #fff 0, #889 100%); - background-image: -ms-linear-gradient(bottom, #fff 0, #889 100%); - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(1, #889)); - position:relative; - top:1px; -} - -.comment input { padding: 2px; } - -#replymessage { margin-top: 5px; } - -.commentmeta { - color: #fff; - background-color: #8ea0b2; - margin-bottom: 3px; - padding: 0 0 0 3px; -} - -.commentdate { color: #bfcede; } - -img.vizhash { - width: 16px; - height: 16px; - position: relative; - top: 2px; - left: -3px; -} - -#prettyprint { - color: #000000; - font-size: 1.2em; -} - -#prettyprint.prettyprinted { - overflow: auto; -} - -#cleartext { - padding: 10px; -} - -#cleartext * { - margin-bottom: 10px; -} - -#cleartext ol { - list-style: auto; - margin-left: 15px; -} - -#cleartext ul { - list-style: disc; - margin-left: 15px; -} - -#cleartext h1, #cleartext h2, #cleartext h3, #cleartext h4, #cleartext h5, #cleartext h6 { - font-weight: bold; -} - -#cleartext h1 { - font-size: 2em; -} - -#cleartext h2 { - font-size: 1.5em; -} - -#cleartext h3 { - font-size: 1.2em; -} - -/* right-to-left overrides */ -html[dir="rtl"] #aboutbox, html[dir="rtl"] #deletelink, html[dir="rtl"] #newbutton { - float: left; -} - -html[dir="rtl"] button, html[dir="rtl"] .button, html[dir="rtl"] button img { - margin-left: 5px; - margin-right: inherit; -} - -html[dir="rtl"] button img { - margin-left: 8px; -} diff --git a/doc/Installation.md b/doc/Installation.md index 11aae68b..c0d141c2 100644 --- a/doc/Installation.md +++ b/doc/Installation.md @@ -21,8 +21,7 @@ for more information. ### Minimal Requirements -- PHP version 7.3 or above -- ctype extension +- PHP version 7.4 or above - GD extension (when using identicon or vizhash icons, jdenticon works without it) - zlib extension - some disk space or a database supported by [PDO](https://php.net/manual/book.pdo.php) @@ -201,7 +200,7 @@ CREATE INDEX parent ON prefix_comment(pasteid); CREATE TABLE prefix_config ( id CHAR(16) NOT NULL, value TEXT, PRIMARY KEY (id) ); -INSERT INTO prefix_config VALUES('VERSION', '1.7.5'); +INSERT INTO prefix_config VALUES('VERSION', '1.7.8'); ``` In **PostgreSQL**, the `data`, `attachment`, `nickname` and `vizhash` columns diff --git a/doc/Running Unit Tests.md b/doc/Running Unit Tests.md index 1a5770bc..bf020789 100644 --- a/doc/Running Unit Tests.md +++ b/doc/Running Unit Tests.md @@ -18,7 +18,7 @@ The parameters in detail: an accidentally destructive test case in it. - `--read-only` - This image supports running in read-only mode. Only /tmp may be written into. -- `-rm` - Remove the container after the run. This saves you doing a cleanup +- `--rm` - Remove the container after the run. This saves you doing a cleanup on your docker environment, if you run the image frequently. You can also run just the php and javascript test suites instead of both: diff --git a/i18n/ar.json b/i18n/ar.json index 66138b38..f56d44bb 100644 --- a/i18n/ar.json +++ b/i18n/ar.json @@ -151,7 +151,7 @@ "server error or not responding": "خطأ في الخادم أو لا يستجيب", "Could not post comment: %s": "لا يمكن نشر تعليق: %s", "Sending paste…": "يُرسل لصق…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "لصقك هو %s (اضغط على [Ctrl] + [c] للنسخ)", + "Your paste is %s (Hit Ctrl+c to copy)": "لصقك هو %s (اضغط على Ctrl + c للنسخ)", "Delete data": "حذف البيانات", "Could not create paste: %s": "تعذر إنشاء اللصق: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "لا يمكن فك تشفير اللصق: مفتاح فك التشفير مفقود في URL (هل استخدمت معيد توجيه أو أداة تقصير لعناوين URL تزيل جزءًا من عنوان URL؟)", @@ -164,17 +164,25 @@ "EiB": "إكسابايت", "ZiB": "زيتابايت", "YiB": "يوتابايت", + "kB": "كيلوبايت", + "MB": "ميجابايت", + "GB": "جيجابايت", + "TB": "تيرابايت", + "PB": "بيتابايت", + "EB": "إكسابايت", + "ZB": "زيتابايت", + "YB": "يوتابايت", "Format": "التنسيق", "Plain Text": "نص عادي", "Source Code": "كود مصدر", "Markdown": "ماركداون", - "Download attachment": "تنزيل المرفقات", + "Download attachment": "نزّل المرفق", "Cloned: '%s'": "مستنسخ: '%s'", - "The cloned file '%s' was attached to this paste.": "تم إرفاق المِلَفّ المستنسخ '%s' بهذا اللصق.", - "Attach a file": "إرفاق مِلَفّ", + "The cloned file '%s' was attached to this paste.": "تم إرفاق الملف المستنسخ '%s' بهذا اللصق.", + "Attach a file": "أرفق ملف", "alternatively drag & drop a file or paste an image from the clipboard": "بدلاً من ذلك، اسحب ملفًا وأسقطه أو الصق صورة من الحافظة", - "File too large, to display a preview. Please download the attachment.": "المِلَفّ كبير جدًا، بحيث لا يمكن عرض معاينة. الرجاء تنزيل المرفق.", - "Remove attachment": "إزالة المرفق", + "File too large, to display a preview. Please download the attachment.": "الملف كبير جدًا، بحيث لا يمكن عرض معاينة. الرجاء تنزيل المرفق.", + "Remove attachment": "أزِل المرفق", "Your browser does not support uploading encrypted files. Please use a newer browser.": "متصفحك لا يدعم رفع الملفات المشفرة. الرجاء استخدام متصفح أحدث.", "Invalid attachment.": "مرفق غير صحيح.", "Options": "الخيارات", @@ -215,10 +223,17 @@ "Trying to shorten a URL that isn't pointing at our instance.": "محاولة تقصير عنوان URL لا يشير إلى خادمنا.", "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "خطأ في الاتصال بـ YOURLS. ربما تكون هناك مشكلة في التضبيط، مثل \"apiurl\" أو \"التوقيع\" الخاطئ أو المفقود.", "Error parsing YOURLS response.": "خطأ في تحليل استجابة YOURLS.", - "This secret message can only be displayed once. Would you like to see it now?": "لا يمكن عرض اللصق احرقه بعد قراءته إلا مرة واحدة عند تحميله. هل تريد فتحه الآن؟", - "Yes, see it": "نعم، حمله", + "This secret message can only be displayed once. Would you like to see it now?": "يمكن عرض هذه الرسالة السرية مرة واحدة فقط. هل ترغب في رؤيتها الآن؟", + "Yes, see it": "نعم، دعني اراها", "Dark Mode": "الوضع الداكن", - "Error compressing paste, due to missing WebAssembly support.": "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.", - "Start over": "Start over" + "Error compressing paste, due to missing WebAssembly support.": "خطأ في ضغط اللصق، بسبب فقدان دعم WebAssembly.", + "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "خطأ في فك ضغط اللصق، متصفحك لا يدعم WebAssembly. الرجاء استخدام متصفح آخر لعرض هذه اللصقة.", + "Start over": "ابدأ من جديد", + "Paste copied to clipboard": "نُسخ اللصق إلى الحافظة", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "لنسخ اللصق انقر على زر النسخ أو استخدم اختصار الحافظة Ctrl+c/Cmd+c", + "Copy link": "نسخ الرابط", + "Link copied to clipboard": "نُسخ الرابط إلى الحافظة", + "Paste text": "لصق النص", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "مفتاح التبويب يعمل كشخصية (انقر Ctrl+m أو Esc للتبديل)", + "Theme": "السمة" } diff --git a/i18n/bg.json b/i18n/bg.json index 14194e0c..33737086 100644 --- a/i18n/bg.json +++ b/i18n/bg.json @@ -151,7 +151,7 @@ "server error or not responding": "Грешка в сървъра или не отговаря", "Could not post comment: %s": "Публикуването на коментара Ви беше неуспешно: %s", "Sending paste…": "Изпращане на информацията Ви…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Вашата връзка е %s (Натиснете [Ctrl]+[c] за да копирате)", + "Your paste is %s (Hit Ctrl+c to copy)": "Вашата връзка е %s (Натиснете Ctrl+c за да копирате)", "Delete data": "Изтриване на информацията", "Could not create paste: %s": "Създаването на връзката ви беше неуспешно: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Дешифроването на информацията беше неуспешно: Ключа за декриптиране липсва във връзката (Да не сте използвали услуга за пренасочване или скъсяване на връзката, което би изрязало части от нея?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Формат", "Plain Text": "Чист текст", "Source Code": "Изходен код", @@ -220,5 +228,12 @@ "Dark Mode": "Dark Mode", "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.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/ca.json b/i18n/ca.json index fbfb6bb6..7f1b098e 100644 --- a/i18n/ca.json +++ b/i18n/ca.json @@ -151,7 +151,7 @@ "server error or not responding": "server error or not responding", "Could not post comment: %s": "No s'ha pogut publicar el comentari: %s", "Sending paste…": "Enviant paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Your paste is %s (Hit [Ctrl]+[c] to copy)", + "Your paste is %s (Hit Ctrl+c to copy)": "Your paste is %s (Hit Ctrl+c to copy)", "Delete data": "Esborrar les dades", "Could not create paste: %s": "Could not create 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?)": "No es pot desxifrar la nota: falta la clau de desxifrat a l'URL (vau utilitzar un adreçament o un escurçador d'URL que elimina part de l'URL?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Text sense format", "Source Code": "Codi font", @@ -220,5 +228,12 @@ "Dark Mode": "Dark Mode", "Error compressing paste, due to missing WebAssembly support.": "Error de compressió de la nota, no hi ha suport de 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": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/co.json b/i18n/co.json index b79964a3..943cc631 100644 --- a/i18n/co.json +++ b/i18n/co.json @@ -151,32 +151,40 @@ "server error or not responding": "sbagliu di u servitore o u servitore ùn risponde micca", "Could not post comment: %s": "Ùn si pò micca impustà u cummentu : %s", "Sending paste…": "Inviu di l’appiccicu…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "U vostru appiccicu si trova à l’indirizzu%s (Appughjate [Ctrl]+[c] per cupià u liame)", + "Your paste is %s (Hit Ctrl+c to copy)": "U vostru appiccicu si trova à l’indirizzu %s (Appughjate nant’à Ctrl+c per cupià u liame)", "Delete data": "Squassà i dati", "Could not create paste: %s": "Ùn si pò micca creà l’appiccicu : %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Ùn si pò micca dicifrà l’appiccicu : A chjave di dicifratura hè assente in l’indirizzu. Averiate impiegatu un orientadore d’indirizzu o un riduttore chì ammuzzeghja una parte di l’indirizzu ?", "B": "o", - "KiB": "Ko", - "MiB": "Mo", - "GiB": "Go", - "TiB": "To", - "PiB": "Po", - "EiB": "Eo", - "ZiB": "Zo", - "YiB": "Yo", + "KiB": "Kio", + "MiB": "Mio", + "GiB": "Gio", + "TiB": "Tio", + "PiB": "Pio", + "EiB": "Eio", + "ZiB": "Zio", + "YiB": "Yio", + "kB": "Ko", + "MB": "Mo", + "GB": "Go", + "TB": "To", + "PB": "Po", + "EB": "Eo", + "ZB": "Zo", + "YB": "Yo", "Format": "Furmatu", "Plain Text": "Testu in chjaru", "Source Code": "Codice di fonte", "Markdown": "Markdown", - "Download attachment": "Scaricà a pezza aghjunta", + "Download attachment": "Scaricà a pezza ghjunta", "Cloned: '%s'": "Duppiatu : « %s »", "The cloned file '%s' was attached to this paste.": "U schedariu duppiatu « %s » hè statu aghjuntu à st’appiccicu.", "Attach a file": "Aghjunghje un schedariu", "alternatively drag & drop a file or paste an image from the clipboard": "in alternanza, sguillà è depone un schedariu o incullà una fiura da u preme’papei", - "File too large, to display a preview. Please download the attachment.": "Schedariu troppu maiò per affissà una fighjulata. Scaricate a pezza aghjunta.", - "Remove attachment": "Caccià a pezza aghjunta", + "File too large, to display a preview. Please download the attachment.": "Schedariu troppu maiò per affissà una fighjulata. Scaricate a pezza ghjunta.", + "Remove attachment": "Caccià a pezza ghjunta", "Your browser does not support uploading encrypted files. Please use a newer browser.": "U vostru navigatore ùn accetta micca l’inviu di i schedarii cifrati. Impiegate un navigatore più recente.", - "Invalid attachment.": "A pezza aghjunta hè inaccettevule.", + "Invalid attachment.": "A pezza ghjunta hè inaccettevule.", "Options": "Ozzioni", "Shorten URL": "Ammuzzà l’indirizzu", "Editor": "Editore", @@ -220,5 +228,12 @@ "Dark Mode": "Modu scuru", "Error compressing paste, due to missing WebAssembly support.": "Sbagliu durante a cumpressione di l’appiccicu, perchè WebAssembly ùn hè micca accettatu.", "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Sbagliu durante a scumpressione di l’appiccicu, perchè u vostru navigatore ùn accetteghja micca WebAssembly. Ci vole à impiegà un altru navigatore per affissà st’appiccicu.", - "Start over": "Principià torna" + "Start over": "Principià torna", + "Paste copied to clipboard": "L’appiccicu hè statu cupiatu in u preme’papei", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "Per cupià l’appiccicu, appughjate nant’à u buttone di copia o impiegate l’accurtatoghju di u preme’papei Ctrl+c/Cmd+c", + "Copy link": "Cupià u liame", + "Link copied to clipboard": "U liame hè statu cupiatu in u preme’papei", + "Paste text": "Testu di l’appiccicu", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "U tastu di tabulazione ghjova cum’è un caratteru (Appughjate nant’à Ctrl+m o Scapp per scambià)", + "Theme": "Tema" } diff --git a/i18n/cs.json b/i18n/cs.json index b81f0f7c..143e58be 100644 --- a/i18n/cs.json +++ b/i18n/cs.json @@ -151,7 +151,7 @@ "server error or not responding": "Chyba na serveru nebo server neodpovídá", "Could not post comment: %s": "Nelze odeslat komentář: %s", "Sending paste…": "Odesílání příspěvku…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Váš příspěvek je %s (Stiskněte [Ctrl]+[c] pro zkopírování)", + "Your paste is %s (Hit Ctrl+c to copy)": "Váš příspěvek je %s (Stiskněte Ctrl+c pro zkopírování)", "Delete data": "Odstranit data", "Could not create paste: %s": "Nepodařilo se vytvořit příspěvek: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nepodařilo se dešifrovat příspěvek: V adrese chybí dešifrovací klíč (Nepoužili jste přesměrovač nebo zkracovač URL, který maže části URL?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formát", "Plain Text": "Prostý text", "Source Code": "Zdrojový kód", @@ -220,5 +228,12 @@ "Dark Mode": "Tmavý režim", "Error compressing paste, due to missing WebAssembly support.": "Chyba při komprimování příspěvku kvůli chybějící podpoře WebAssembly.", "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Chyba při dekomprimování příspěvku, váš prohlížeč nepodporuje WebAssembly. Pro zobrazení tohoto příspěvku prosím použijte jiný prohlížeč.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/de.json b/i18n/de.json index ded2841c..e484e35c 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -151,7 +151,7 @@ "server error or not responding": "Fehler auf dem Server oder keine Antwort vom Server", "Could not post comment: %s": "Konnte Kommentar nicht senden: %s", "Sending paste…": "Sende Paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Dein Text ist unter %s zu finden (Drücke [Strg]+[c] um den Link zu kopieren)", + "Your paste is %s (Hit Ctrl+c to copy)": "Dein Text ist unter %s zu finden (Drücke Strg+c um den Link zu kopieren)", "Delete data": "Lösche Daten", "Could not create paste: %s": "Text konnte nicht erstellt werden: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Konnte Paste nicht entschlüsseln: Der Schlüssel fehlt in der Adresse (Hast du eine Umleitung oder einen URL-Verkürzer benutzt, der Teile der Adresse entfernt?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Nur Text", "Source Code": "Quellcode", @@ -220,5 +228,12 @@ "Dark Mode": "Nachtmodus", "Error compressing paste, due to missing WebAssembly support.": "Fehler beim Komprimieren des Textes, da WebAssembly-Unterstützung fehlt.", "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Fehler beim Dekomprimieren des Textes. Dein Browser unterstützt WebAssembly nicht. Bitte verwende einen anderen Browser, um diesen Text anzuzeigen.", - "Start over": "Neuen Text erstellen" + "Start over": "Neuen Text erstellen", + "Paste copied to clipboard": "Text wurde in Zwischenablage kopiert.", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "Zum Kopieren des Textes drücken Sie die Kopieren-Schaltfläche oder verwenden Sie die Tastenkombination Strg+c/Cmd+c", + "Copy link": "Verknüpfung kopieren", + "Link copied to clipboard": "Verknüpfung wurde in die Zwischenablage kopiert.", + "Paste text": "Text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulatortaste als Zeichen interpretieren (Umschalten durch Strg+m oder Esc)", + "Theme": "Theme" } diff --git a/i18n/el.json b/i18n/el.json index 07f81d7a..cf17b4da 100644 --- a/i18n/el.json +++ b/i18n/el.json @@ -151,7 +151,7 @@ "server error or not responding": "Πρόβλημα του διακομιστή ή δεν υπάρχει απάντηση", "Could not post comment: %s": "Δεν ήταν δυνατή η δημοσίευση του σχολίου: %s", "Sending paste…": "Η επικόλληση αποστέλλεται…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Η επικόλλησή σας είναι %s (Πληκτρολογήστε [Ctrl]+[c] για αντιγραφή)", + "Your paste is %s (Hit Ctrl+c to copy)": "Η επικόλλησή σας είναι %s (Πληκτρολογήστε Ctrl+c για αντιγραφή)", "Delete data": "Διαγραφή δεδομένων", "Could not create paste: %s": "Δεν ήταν δυνατή η δημιουργία επικόλλησης: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Δεν ήταν δυνατή η αποκρυπτογράφηση της επικόλλησης: Το κλειδί αποκρυπτογράφησης λείπει από τον σύνδεσμο (Μήπως χρησιμοποιήσατε ανακατεύθυνση συνδέσμου ή υπηρεσία συντόμευσης συνδέσμου;)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Μορφοποίηση", "Plain Text": "Απλό κείμενο", "Source Code": "Πηγαίος Κώδικας", @@ -220,5 +228,12 @@ "Dark Mode": "Σκοτεινό Θέμα", "Error compressing paste, due to missing WebAssembly support.": "Σφάλμα συμπίεσης επικόλλησης, λόγω έλλειψης υποστήριξης WebAssembly.", "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Σφάλμα αποσυμπίεσης της επικόλλησης, ο περιηγητής σας δεν υποστηρίζει WebAssembly. Παρακαλούμε χρησιμοποιήστε έναν άλλο περιηγητή για να δείτε αυτή την επικόλληση.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/en.json b/i18n/en.json index abc2e80a..6cd88118 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -151,7 +151,7 @@ "server error or not responding": "server error or not responding", "Could not post comment: %s": "Could not post comment: %s", "Sending paste…": "Sending paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Your paste is %s (Hit [Ctrl]+[c] to copy)", + "Your paste is %s (Hit Ctrl+c to copy)": "Your paste is %s (Hit Ctrl+c to copy)", "Delete data": "Delete data", "Could not create paste: %s": "Could not create 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?)": "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Plain Text", "Source Code": "Source Code", @@ -220,5 +228,12 @@ "Dark Mode": "Dark Mode", "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.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/es.json b/i18n/es.json index 40b63dfb..72877fe0 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -151,7 +151,7 @@ "server error or not responding": "Error del servidor o el servidor no responde", "Could not post comment: %s": "No fue posible publicar comentario: %s", "Sending paste…": "Enviando \"paste\"…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Su texto está en %s (Presione [Ctrl]+[c] para copiar)", + "Your paste is %s (Hit Ctrl+c to copy)": "Su texto está en %s (Presione Ctrl+c para copiar)", "Delete data": "Eliminar datos", "Could not create paste: %s": "No fue posible crear el archivo: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "No es posible descifrar el documento: Falta la clave de descifrado en la URL (¿Utilizó un redirector o un acortador de URL que quite parte de la URL?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formato", "Plain Text": "Texto sin formato", "Source Code": "Código fuente", @@ -220,5 +228,12 @@ "Dark Mode": "Modo nocturno", "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.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/et.json b/i18n/et.json index 3d21e4fe..db4236c8 100644 --- a/i18n/et.json +++ b/i18n/et.json @@ -151,7 +151,7 @@ "server error or not responding": "serveri viga või ei vasta", "Could not post comment: %s": "Ei suutnud kommentaari postitada: %s", "Sending paste…": "Kleepe saatmine…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Sinu kleebe on %s (Kopeerimiseks vajuta [Ctrl]+[c])", + "Your paste is %s (Hit Ctrl+c to copy)": "Sinu kleebe on %s (Kopeerimiseks vajuta Ctrl+c)", "Delete data": "Kustuta andmed", "Could not create paste: %s": "Ei suutnud kleebet luua: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Ei suutnud kleebet dekrüpteerida: Dekrüpteerimisvõti on URL-ist puudu (Kas kasutasid ümbersuunajat või URL-i lühendajat, mis eemaldab osa URL-ist?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formaat", "Plain Text": "Lihttekst", "Source Code": "Lähtekood", @@ -215,10 +223,17 @@ "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 parsing YOURLS response.": "Viga YOURLS vastuse parsimisel.", - "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", + "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?", + "Yes, see it": "Jah, vaata seda", "Dark Mode": "Tume režiim", "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.", - "Start over": "Start over" + "Start over": "Alusta uuesti", + "Paste copied to clipboard": "Kleebe kopeeriti lõikelauale", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Kopeeri link", + "Link copied to clipboard": "Link kopeeriti lõikelauale", + "Paste text": "Kleebi tekst", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Teema" } diff --git a/i18n/fi.json b/i18n/fi.json index de5742a4..e9b1f87b 100644 --- a/i18n/fi.json +++ b/i18n/fi.json @@ -151,7 +151,7 @@ "server error or not responding": "palvelinvirhe tai palvelin ei vastaa", "Could not post comment: %s": "Kommenttia ei voitu lähettää: %s", "Sending paste…": "Lähetetään pastea…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Pastesi on %s (Paina [Ctrl]+[c] kopioidaksesi)", + "Your paste is %s (Hit Ctrl+c to copy)": "Pastesi on %s (Paina Ctrl+c kopioidaksesi)", "Delete data": "Poista data", "Could not create paste: %s": "Pastea ei voitu luoda: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Pastea ei voitu purkaa: Purkausavain puuttuu URL:stä (Käytitkö uudelleenohjaajaa tai URL-lyhentäjää joka poistaa osan URL:stä?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formaatti", "Plain Text": "Perusteksti", "Source Code": "Lähdekoodi", @@ -218,7 +226,14 @@ "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", "Dark Mode": "Tumma tila", - "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.", - "Start over": "Start over" + "Error compressing paste, due to missing WebAssembly support.": "Virhe pakattaessa pastea, koska WebAssembly-tuki puuttuu.", + "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.", + "Start over": "Aloita alusta", + "Paste copied to clipboard": "Paste kopioitu leikepöydälle", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "Voit kopioida pasten painamalla kopioi-painiketta tai käyttämällä leikepöydän oikotietä Ctrl+c/Cmd+c", + "Copy link": "Kopioi linkki", + "Link copied to clipboard": "Linkki kopioitu leikepöydälle", + "Paste text": "Liitä teksti", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulaattori toimii merkkinä (Paina Ctrl+m tai Esc vaihtaaksesi)", + "Theme": "Teema" } diff --git a/i18n/fr.json b/i18n/fr.json index d8b00b96..23dfae8d 100644 --- a/i18n/fr.json +++ b/i18n/fr.json @@ -151,7 +151,7 @@ "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", "Sending paste…": "Envoi du paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Votre paste est disponible à l'adresse %s (Appuyez sur [Ctrl]+[c] pour copier)", + "Your paste is %s (Hit Ctrl+c to copy)": "Votre paste est disponible à l'adresse %s (Appuyez sur Ctrl+c/Cmd+c pour copier)", "Delete data": "Supprimer les données du paste", "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 ?)", @@ -164,6 +164,14 @@ "EiB": "Eio", "ZiB": "Zio", "YiB": "Yio", + "kB": "ko", + "MB": "Mo", + "GB": "Go", + "TB": "To", + "PB": "Po", + "EB": "Eo", + "ZB": "Zo", + "YB": "Yo", "Format": "Format", "Plain Text": "Texte brut", "Source Code": "Code source", @@ -220,5 +228,12 @@ "Dark Mode": "Mode Sombre", "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.", - "Start over": "Recommencer" + "Start over": "Recommencer", + "Paste copied to clipboard": "Paste copié dans le presse-papier", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "Pour copier-coller appuyer sur le bouton To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copier le lien", + "Link copied to clipboard": "Lien copié dans le presse-papier", + "Paste text": "Texte du paste", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "La touche de tabulation sert de caractère (Presser Ctrl+m ou Esc pour basculer)", + "Theme": "Thème" } diff --git a/i18n/he.json b/i18n/he.json index b32f3b8e..4c41e1e4 100644 --- a/i18n/he.json +++ b/i18n/he.json @@ -1,7 +1,7 @@ { "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 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 project page.": "More information on the project page.", + "%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 סיביות.", + "More information on the project page.": "מידע נוסף בדף הפרויקט.", "Because ignorance is bliss": "כיוון שבורות היא ברכה", "Paste does not exist, has expired or has been deleted.": "ההדבקה לא קיימת, פגה או נמחקה.", "%s requires php %s or above to work. Sorry.": "%s דורש PHP %s כדי לפעול.", @@ -29,7 +29,7 @@ "Create": "צור", "Clone": "שכפול", "Raw text": "טקסט גולמי", - "Expires": "Expires", + "Expires": "יפוג ב", "Burn after reading": "קוראים-שורפים", "Open discussion": "פתיחת דיון", "Password (recommended)": "ססמה (מומלץ)", @@ -53,11 +53,11 @@ ], "%d hours": [ "שעה אחת", - "%d hours (1st plural)", - "%d hours (2nd plural)", - "%d hours (3rd plural)", - "%d hours (4th plural)", - "%d hours (5th plural)" + "%d שעות", + "%d שעות", + "%d שעות", + "%d שעות", + "%d שעות" ], "%d days": [ "יום אחד", @@ -94,44 +94,44 @@ "Never": "לעולם לא", "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 second. (singular)", - "This document will expire in %d seconds. (1st plural)", - "This document will expire in %d seconds. (2nd plural)", - "This document will expire in %d seconds. (3rd plural)", - "This document will expire in %d seconds. (4th plural)", - "This document will expire in %d seconds. (5th plural)" + "מסמך זה יפוג בעוד שנייה אחת.", + "מסמך זה יפוג בעוד %d שניות.", + "מסמך זה יפוג בעוד %d שניות.", + "מסמך זה יפוג בעוד %d שניות.", + "מסמך זה יפוג בעוד %d שניות.", + "מסמך זה יפוג בעוד %d שניות." ], "This document will expire in %d minutes.": [ - "This document will expire in %d minute. (singular)", - "This document will expire in %d minutes. (1st plural)", - "This document will expire in %d minutes. (2nd plural)", - "This document will expire in %d minutes. (3rd plural)", - "This document will expire in %d minutes. (4th plural)", - "This document will expire in %d minutes. (5th plural)" + "מסמך זה יפוג בעוד דקה אחת.", + "מסמך זה יפוג בעוד %d דקות.", + "מסמך זה יפוג בעוד %d דקות.", + "מסמך זה יפוג בעוד %d דקות.", + "מסמך זה יפוג בעוד %d דקות.", + "מסמך זה יפוג בעוד %d דקות." ], "This document will expire in %d hours.": [ - "This document will expire in %d hour. (singular)", - "This document will expire in %d hours. (1st plural)", - "This document will expire in %d hours. (2nd plural)", - "This document will expire in %d hours. (3rd plural)", - "This document will expire in %d hours. (4th plural)", - "This document will expire in %d hours. (5th plural)" + "מסמך זה יפוג בעוד שעה אחת.", + "מסמך זה יפוג בעוד %d שעות.", + "מסמך זה יפוג בעוד %d שעות.", + "מסמך זה יפוג בעוד %d שעות.", + "מסמך זה יפוג בעוד %d שעות.", + "מסמך זה יפוג בעוד %d שעות." ], "This document will expire in %d days.": [ - "This document will expire in %d day. (singular)", - "This document will expire in %d days. (1st plural)", - "This document will expire in %d days. (2nd plural)", - "This document will expire in %d days. (3rd plural)", - "This document will expire in %d days. (4th plural)", - "This document will expire in %d days. (5th plural)" + "מסמך זה יפוג בעוד יום אחד.", + "מסמך זה יפוג בעוד %d ימים.", + "מסמך זה יפוג בעוד %d ימים.", + "מסמך זה יפוג בעוד %d ימים.", + "מסמך זה יפוג בעוד %d ימים.", + "מסמך זה יפוג בעוד %d ימים." ], "This document will expire in %d months.": [ - "This document will expire in %d month. (singular)", - "This document will expire in %d months. (1st plural)", - "This document will expire in %d months. (2nd plural)", - "This document will expire in %d months. (3rd plural)", - "This document will expire in %d months. (4th plural)", - "This document will expire in %d months. (5th plural)" + "מסמך זה יפוג בעוד חודש אחד.", + "מסמך זה יפוג בעוד %d חודשים.", + "מסמך זה יפוג בעוד %d חודשים.", + "מסמך זה יפוג בעוד %d חודשים.", + "מסמך זה יפוג בעוד %d חודשים.", + "מסמך זה יפוג בעוד %d חודשים." ], "Please enter the password for this paste:": "נא למלא את הססמה להדבקה הזו:", "Could not decrypt data (Wrong key?)": "לא ניתן לפענח את הנתונים (מפתח שגוי?)", @@ -151,7 +151,7 @@ "server error or not responding": "שגיאת שרת או שהשרת לא מגיב", "Could not post comment: %s": "לא ניתן לפרסם תגובה: %s", "Sending paste…": "ההדבקה נשלחת…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "ההדבקה שלך היא %s (יש ללחוץ [Ctrl]+[c] כדי להעתיק)", + "Your paste is %s (Hit Ctrl+c to copy)": "ההדבקה שלך היא %s (יש ללחוץ Ctrl+c כדי להעתיק)", "Delete data": "מחיקת נתונים", "Could not create paste: %s": "לא ניתן ליצור הדבקה: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "לא ניתן לפענח הדבקה: מפתח הפענוח חסר בכתובת (השתמשת במערכת הפנייה או מקצר כתובות שחותכים חלק מהכתובת?)", @@ -164,35 +164,43 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "פורמט", "Plain Text": "טקסט פשוט", "Source Code": "קוד מקור", "Markdown": "Markdown", "Download attachment": "הורדת קובץ מצורף", "Cloned: '%s'": "שוכפל: '%s'", - "The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.", + "The cloned file '%s' was attached to this paste.": "הקובץ '%s' שהועתק צורף להדבקה זו.", "Attach a file": "צירוף קובץ", - "alternatively drag & drop a file or paste an image from the clipboard": "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.", - "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.", + "alternatively drag & drop a file or paste an image from the clipboard": "לחלופין, ניתן לגרור ולשחרר קובץ או להדביק תמונה מהלוח.", + "File too large, to display a preview. Please download the attachment.": "הקובץ גדול מדי כדי להציג תצוגה מקדימה. אנא הורד את הקובץ המצורף.", + "Remove attachment": "הסר קובץ מצורף", + "Your browser does not support uploading encrypted files. Please use a newer browser.": "הדפדפן שלך אינו תומך בהעלאת קבצים מוצפנים. אנא השתמש בדפדפן עדכני יותר.", "Invalid attachment.": "קובץ מצורף שגוי.", "Options": "אפשרויות", "Shorten URL": "קיצור כתובת", "Editor": "עורך", "Preview": "תצוגה מקדימה", - "%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.", + "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s דורש שה-PATH יסתיים ב-\"%s\". אנא עדכן את ה-PATH בקובץ index.php שלך.", "Decrypt": "פענוח", "Enter password": "נא למלא ססמה", "Loading…": "בטעינה…", "Decrypting paste…": "ההדבקה מפוענחת…", "Preparing new paste…": "ההדבקה החדשה בהכנות…", - "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "In case this message never disappears please have a look at this FAQ for information to troubleshoot.", + "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "אם הודעה זו לא נעלמת, אנא עיין ב- שאלות נפוצות אלה למידע לפתרון בעיות.", "+++ no paste text +++": "+++ אין טקסט להדבקה +++", "Could not get paste data: %s": "לא ניתן לקבל את נתוני ההדבקה: %s", "QR code": "קוד QR", "This website is using an insecure HTTP connection! Please use it only for testing.": "האתר הזה משתמש בחיבור HTTP בלתי מאובטח! נא להשתמש בזה לבדיקות בלבד.", - "For more information see this FAQ entry.": "יש מידע נוסף ברשומה הזאת בשו״ת.", + "For more information see this FAQ entry.": "לפרטים נוספים עיין ברשומת שאלות נפוצות זו.", "Your browser may require an HTTPS connection to support the WebCrypto API. Try switching to HTTPS.": "יכול להיות שהדפדפן שלך ידרוש חיבור HTTPS כדי לתמוך ב־API של WebCrypto. כדי לנסות לעבור ל־HTTPS.", "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": "בהמתנה למילוי הססמה מצד המשתמש", @@ -209,16 +217,23 @@ "Close": "סגירה", "Encrypted note on %s": "%sהערה מוצפנת ב־", "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 shortener may expose your decrypt key in URL.", - "Save paste": "Save paste", - "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.": "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\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".", - "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?", - "Yes, see it": "Yes, see it", - "Dark Mode": "Dark Mode", - "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.", - "Start over": "Start over" + "URL shortener may expose your decrypt key in URL.": "שירות קיצור כתובת URL עשוי לחשוף את מפתח הפענוח שלך בכתובת ה-URL.", + "Save paste": "שמור הדבקה", + "Your IP is not authorized to create pastes.": "ה-IP שלך אינו מורשה ליצור הדבקות.", + "Trying to shorten a URL that isn't pointing at our instance.": "מנסים לקצר כתובת URL שאינה מצביעה על המערכת שלנו.", + "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "שגיאה בעת קריאה ל-YOURLS. כנראה מדובר בבעיה בהגדרות, כמו \"apiurl\" או \"signature\" שגויים או חסרים.", + "Error parsing YOURLS response.": "שגיאה בניתוח התגובה מ-YOURLS.", + "This secret message can only be displayed once. Would you like to see it now?": "ההודעה הסודית הזו יכולה להוצג רק פעם אחת. האם תרצה לראות אותה עכשיו?", + "Yes, see it": "כן, ראה אותה", + "Dark Mode": "מצב כהה", + "Error compressing paste, due to missing WebAssembly support.": "שגיאה בדחיסת ההדבקה, עקב חוסר תמיכה ב-WebAssembly.", + "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "שגיאה בהפקת ההדבקה, הדפדפן שלך לא תומך ב-WebAssembly. אנא השתמש בדפדפן אחר כדי לצפות בהדבקה זו.", + "Start over": "להתחיל מחדש", + "Paste copied to clipboard": "ההדבקה הועתקה ללוח", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "על מנת להעתיק את ההדבקה, לחץ על כפתור ההעתקה או השתמש בקיצור הדרך ללוח Ctrl+c/Cmd+c", + "Copy link": "העתק קישור", + "Link copied to clipboard": "הקישור הועתק ללוח", + "Paste text": "הדבק טקסט", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "משטח ה-tab פועל כמקש תו (לחץ על Ctrl+m או Esc להחלפה)", + "Theme": "נושא" } diff --git a/i18n/hi.json b/i18n/hi.json index abc2e80a..6cd88118 100644 --- a/i18n/hi.json +++ b/i18n/hi.json @@ -151,7 +151,7 @@ "server error or not responding": "server error or not responding", "Could not post comment: %s": "Could not post comment: %s", "Sending paste…": "Sending paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Your paste is %s (Hit [Ctrl]+[c] to copy)", + "Your paste is %s (Hit Ctrl+c to copy)": "Your paste is %s (Hit Ctrl+c to copy)", "Delete data": "Delete data", "Could not create paste: %s": "Could not create 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?)": "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Plain Text", "Source Code": "Source Code", @@ -220,5 +228,12 @@ "Dark Mode": "Dark Mode", "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.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/hu.json b/i18n/hu.json index ed652a53..6fdeb5d4 100644 --- a/i18n/hu.json +++ b/i18n/hu.json @@ -151,7 +151,7 @@ "server error or not responding": "A szerveren hiba lépett fel vagy nem válaszol.", "Could not post comment: %s": "Nem tudtuk beküldeni a hozzászólást: %s", "Sending paste…": "Bejegyzés elküldése...", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "A bejegyzésed a %s címen elérhető. [Ctrl]+[c]-vel tudod vágólapra másolni.", + "Your paste is %s (Hit Ctrl+c to copy)": "A bejegyzésed a %s címen elérhető. Ctrl+c-vel tudod vágólapra másolni.", "Delete data": "Adat törlése", "Could not create paste: %s": "Nem tudtuk létrehozni a bejegyzést: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nem tudjuk visszafejteni a bejegyzést: a dekódoláshoz szükséges kulcs hiányzik a címből. Talán URL rövidítőt használtál ami kivágta azt belőle?", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formátum", "Plain Text": "Egyszerű szöveg", "Source Code": "Forráskód", @@ -220,5 +228,12 @@ "Dark Mode": "Sötét mód", "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.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/id.json b/i18n/id.json index 62f94a98..e1a5d6a2 100644 --- a/i18n/id.json +++ b/i18n/id.json @@ -151,7 +151,7 @@ "server error or not responding": "kesalahan server atau server tidak merespon", "Could not post comment: %s": "Tidak dapat memposting komentar: %s", "Sending paste…": "Mengirim paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Paste Anda adalah %s(Tekan [Ctrl]+[c] untuk menyalin)", + "Your paste is %s (Hit Ctrl+c to copy)": "Paste Anda adalah %s(Tekan Ctrl+c untuk menyalin)", "Delete data": "Hapus data", "Could not create paste: %s": "Tidak dapat membuat 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?)": "Tidak dapat mendekripsi paste: Kunci dekripsi tidak ada di URL (Apakah Anda menggunakan redirector atau penyingkat URL yang menghapus bagian dari URL?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Teks Biasa", "Source Code": "Kode Sumber", @@ -220,5 +228,12 @@ "Dark Mode": "Mode Gelap", "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.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/it.json b/i18n/it.json index 217a779c..fcb978aa 100644 --- a/i18n/it.json +++ b/i18n/it.json @@ -151,7 +151,7 @@ "server error or not responding": "errore o mancata risposta dal server", "Could not post comment: %s": "Impossibile inviare il commento: %s", "Sending paste…": "Messaggio in fase di invio…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Il tuo messaggio è qui: %s (Premi [Ctrl]+[c] (Windows) o [Cmd]+[c] (Mac) per copiare il link)", + "Your paste is %s (Hit Ctrl+c to copy)": "Il tuo messaggio è qui: %s (Premi Ctrl+c (Windows) o [Cmd]+[c] (Mac) per copiare il link)", "Delete data": "Cancella i dati", "Could not create paste: %s": "Non riesco a creare il messaggio: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Non riesco a decifrare il messaggio: manca la chiave di decifrazione nell'URL (La chiave è parte integrante dell'URL. Per caso hai usato un Redirector o un altro servizio che ha rimosso una parte dell'URL?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formato", "Plain Text": "Solo Testo", "Source Code": "Codice Sorgente", @@ -220,5 +228,12 @@ "Dark Mode": "Tema Scuro", "Error compressing paste, due to missing WebAssembly support.": "Errore nella compressione dell messaggio, a causa del supporto WebAssembly mancante.", "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Errore nella decompressione dell messaggio, il tuo browser non supporta WebAssembly. Utilizza un altro browser per visualizzare questo messaggio.", - "Start over": "Ricominciare" + "Start over": "Ricominciare", + "Paste copied to clipboard": "Messaggio copiato", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copia il link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Testo del messaggio", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/ja.json b/i18n/ja.json index 528097d5..be652d1f 100644 --- a/i18n/ja.json +++ b/i18n/ja.json @@ -151,7 +151,7 @@ "server error or not responding": "サーバーエラーまたは応答しません", "Could not post comment: %s": "コメントを投稿できませんでした:%s", "Sending paste…": "ペーストを送信しています…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "ペーストは%sです(コピーするには[Ctrl]+[c]を押してください)", + "Your paste is %s (Hit Ctrl+c to copy)": "ペーストは%sです(コピーするにはCtrl+cを押してください)", "Delete data": "データを削除", "Could not create paste: %s": "ペーストを作成できませんでした:%s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "ペーストを復号化できません:復号化キーがURLにありません(URLの一部を削除するリダイレクト機能またはURLの短縮アプリケーションを使いましたか?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "形式", "Plain Text": "プレーンテキスト", "Source Code": "ソースコード", @@ -220,5 +228,12 @@ "Dark Mode": "ダークモード", "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.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/jbo.json b/i18n/jbo.json index 86f1d983..385e024a 100644 --- a/i18n/jbo.json +++ b/i18n/jbo.json @@ -151,7 +151,7 @@ "server error or not responding": "server error or not responding", "Could not post comment: %s": "Could not post comment: %s", "Sending paste…": "Sending paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Your paste is %s (Hit [Ctrl]+[c] to copy)", + "Your paste is %s (Hit Ctrl+c to copy)": "Your paste is %s (Hit Ctrl+c to copy)", "Delete data": "Delete data", "Could not create paste: %s": "Could not create 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?)": "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Plain Text", "Source Code": "Source Code", @@ -220,5 +228,12 @@ "Dark Mode": "Dark Mode", "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.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/ko.json b/i18n/ko.json index abc2e80a..6cd88118 100644 --- a/i18n/ko.json +++ b/i18n/ko.json @@ -151,7 +151,7 @@ "server error or not responding": "server error or not responding", "Could not post comment: %s": "Could not post comment: %s", "Sending paste…": "Sending paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Your paste is %s (Hit [Ctrl]+[c] to copy)", + "Your paste is %s (Hit Ctrl+c to copy)": "Your paste is %s (Hit Ctrl+c to copy)", "Delete data": "Delete data", "Could not create paste: %s": "Could not create 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?)": "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Plain Text", "Source Code": "Source Code", @@ -220,5 +228,12 @@ "Dark Mode": "Dark Mode", "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.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/ku.json b/i18n/ku.json index 11b87e66..5bc421dd 100644 --- a/i18n/ku.json +++ b/i18n/ku.json @@ -151,7 +151,7 @@ "server error or not responding": "server error or not responding", "Could not post comment: %s": "Could not post comment: %s", "Sending paste…": "Sending paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Your paste is %s (Hit [Ctrl]+[c] to copy)", + "Your paste is %s (Hit Ctrl+c to copy)": "Your paste is %s (Hit Ctrl+c to copy)", "Delete data": "Delete data", "Could not create paste: %s": "Could not create 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?)": "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Plain Text", "Source Code": "Source Code", @@ -220,5 +228,12 @@ "Dark Mode": "جۆری ڕەش", "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.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/la.json b/i18n/la.json index 5ee106fd..85bdddfb 100644 --- a/i18n/la.json +++ b/i18n/la.json @@ -151,7 +151,7 @@ "server error or not responding": "server error or not responding", "Could not post comment: %s": "Could not post comment: %s", "Sending paste…": "Sending paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Your paste is %s (Hit [Ctrl]+[c] to copy)", + "Your paste is %s (Hit Ctrl+c to copy)": "Your paste is %s (Hit Ctrl+c to copy)", "Delete data": "Delete data", "Could not create paste: %s": "Could not create 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?)": "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Plain Text", "Source Code": "Source Code", @@ -220,5 +228,12 @@ "Dark Mode": "Dark Mode", "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.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/lt.json b/i18n/lt.json index 3bbf0745..bfe66044 100644 --- a/i18n/lt.json +++ b/i18n/lt.json @@ -151,7 +151,7 @@ "server error or not responding": "serverio klaida arba jis neatsako", "Could not post comment: %s": "Nepavyko paskelbti komentaro: %s", "Sending paste…": "Siunčiamas įdėjimas…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Jūsų įdėjimas yra %s (Paspauskite [Vald]+[c] norėdami nukopijuoti)", + "Your paste is %s (Hit Ctrl+c to copy)": "Jūsų įdėjimas yra %s (Paspauskite Vald+c norėdami nukopijuoti)", "Delete data": "Ištrinti duomenis", "Could not create paste: %s": "Nepavyko sukurti įdėjimo: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nepavyksta iššifruoti įdėjimo: URL adrese trūksta iššifravimo rakto (Ar naudojote peradresavimo ar URL trumpinimo įrankį, kuris pašalina URL dalį?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formatas", "Plain Text": "Grynasis tekstas", "Source Code": "Pirminis kodas", @@ -220,5 +228,12 @@ "Dark Mode": "Tamsi veiksena", "Error compressing paste, due to missing WebAssembly support.": "Klaida glaudinant įdėjimą, nes trūksta WebAssembly palaikymo.", "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Klaida išglaudinant įdėjimą, jūsų naršyklė nepalaiko WebAssembly. Norėdami peržiūrėti šį įdėjimą, naudokite kitą naršyklę.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/nl.json b/i18n/nl.json index 39762f6e..90aa54f6 100644 --- a/i18n/nl.json +++ b/i18n/nl.json @@ -143,7 +143,7 @@ "Avatar generated from IP address": "Anonieme avatar (van het IP-adres)", "Add comment": "Commentaar toevoegen", "Optional nickname…": "Optionele bijnaam…", - "Post comment": "Plaats een commentaar", + "Post comment": "Plaats commentaar", "Sending comment…": "Commentaar verzenden…", "Comment posted.": "Commentaar geplaatst.", "Could not refresh display: %s": "Kon de weergave niet vernieuwen: %s", @@ -151,7 +151,7 @@ "server error or not responding": "Serverfout of server reageert niet", "Could not post comment: %s": "Kon het commentaar niet plaatsen: %s", "Sending paste…": "Paste verzenden…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Je paste is %s (Druk [Ctrl]+[c] om te kopiëren)", + "Your paste is %s (Hit Ctrl+c to copy)": "Je paste is %s (Druk Ctrl+c om te kopiëren)", "Delete data": "Gegevens wissen", "Could not create paste: %s": "Kon de paste niet aanmaken: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Kon de paste niet decoderen: Decoderingssleutel ontbreekt in URL (Heb je een doorverwijzer of een URL-verkorter gebruikt die een deel van de URL verwijdert?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formaat", "Plain Text": "Platte tekst", "Source Code": "Broncode", @@ -220,5 +228,12 @@ "Dark Mode": "Donkere modus", "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.", - "Start over": "Start over" + "Start over": "Opnieuw beginnen", + "Paste copied to clipboard": "Notitie gekopieerd naar klembord", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "Om te kopiëren en plakken druk je op de knop Kopiëren of gebruik je de sneltoets op het klembord Ctrl+c/Cmd+c", + "Copy link": "Kopieer link", + "Link copied to clipboard": "Link gekopieerd naar klembord", + "Paste text": "Tekst plakken", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulatortoets dient als teken (gebruik Ctrl+m of Esc om te schakelen)", + "Theme": "Thema" } diff --git a/i18n/no.json b/i18n/no.json index 0917cbee..b22354dd 100644 --- a/i18n/no.json +++ b/i18n/no.json @@ -151,7 +151,7 @@ "server error or not responding": "tjener feilet eller svarer ikke", "Could not post comment: %s": "Kunne ikke sende kommentar: %s", "Sending paste…": "Sender innlegg…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Ditt innlegg er %s (Trykk [Ctrl]+[c] for å kopiere)", + "Your paste is %s (Hit Ctrl+c to copy)": "Ditt innlegg er %s (Trykk Ctrl+c for å kopiere)", "Delete data": "Slett data", "Could not create paste: %s": "Kunne ikke opprette innlegg: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Kan ikke dekryptere innlegg: Dekrypteringsnøkkelen mangler i adressen (Har du bruket en redirector eller en URL forkorter som fjerner en del av addressen?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Ren Tekst", "Source Code": "Kildekode", @@ -211,14 +219,21 @@ "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Besøk denne lenken for å se notatet. Hvis lenken deles med andre, vil de også kunne se notatet.", "URL shortener may expose your decrypt key in URL.": "URL forkorter kan avsløre dekrypteringsnøkkelen.", "Save paste": "Lagre utklipp", - "Your IP is not authorized to create pastes.": "Din IP er ikke autorisert til å opprette advarsler.", + "Your IP is not authorized to create pastes.": "Din IP er ikke autorisert til å opprette dokumenter.", "Trying to shorten a URL that isn't pointing at our instance.": "Prøver å forkorte en URL som ikke peker i vår instans.", - "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Feil ved å ringe YOURLS. Sannsynligvis et konfigurasjonsproblem, som feil eller mangler, \"apiurl\" eller \"signatur\".", + "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Feil ved å besøke YOURLS. Sannsynligvis et konfigurasjonsproblem, eksempelvis feil eller mangler, med \"apiurl\" eller \"signatur\".", "Error parsing YOURLS response.": "Feil ved analyse av YOURLS svar.", "This secret message can only be displayed once. Would you like to see it now?": "Denne hemmelige meldingen kan bare vises én gang. Vil du se den nå?", "Yes, see it": "Ja, se det", "Dark Mode": "Mørk modus", "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.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/oc.json b/i18n/oc.json index d863f283..f39eeb06 100644 --- a/i18n/oc.json +++ b/i18n/oc.json @@ -151,7 +151,7 @@ "server error or not responding": "lo servidor respond pas o a rescontrat una error", "Could not post comment: %s": "Impossible de mandar lo comentari : %s", "Sending paste…": "Mandadís del tèxte…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Vòstre tèxte es disponible a l’adreça %s (Picatz sus [Ctrl]+[c] per copiar)", + "Your paste is %s (Hit Ctrl+c to copy)": "Vòstre tèxte es disponible a l’adreça %s (Picatz sus Ctrl+c per copiar)", "Delete data": "Supprimir las donadas del tèxte", "Could not create paste: %s": "Impossible de crear lo tèxte : %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 deschifrar lo tèxte : clau de deschiframent absenta de l’URL (Avètz utilizat un redirector o un site de reduccion d’URL que suprimís una partida de l’URL ?)", @@ -164,6 +164,14 @@ "EiB": "Eio", "ZiB": "Zio", "YiB": "Yio", + "kB": "ko", + "MB": "Mo", + "GB": "Go", + "TB": "To", + "PB": "Po", + "EB": "Eo", + "ZB": "Zo", + "YB": "Yo", "Format": "Format", "Plain Text": "Tèxte brut", "Source Code": "Còdi font", @@ -220,5 +228,12 @@ "Dark Mode": "Mòde escur", "Error compressing paste, due to missing WebAssembly support.": "Error al moment de la compression de l'empegatge, a causa de la manca de presa en carga de WebAssembly.", "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Error al moment de descompresar l'empegatge, vòstre navegador pren pas en carga WebAssembly. Mercés d'utilizar un autre navigador per visualizar aquesta pega.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/pl.json b/i18n/pl.json index 616ec987..1b1185d5 100644 --- a/i18n/pl.json +++ b/i18n/pl.json @@ -151,7 +151,7 @@ "server error or not responding": "błąd serwera lub brak odpowiedzi", "Could not post comment: %s": "Nie udało się wysłać komentarza: %s", "Sending paste…": "Wysyłanie wklejki…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Twoja wklejka to %s (wciśnij [Ctrl]+[c] aby skopiować)", + "Your paste is %s (Hit Ctrl+c to copy)": "Twoja wklejka to %s (wciśnij Ctrl+c aby skopiować)", "Delete data": "Skasuj dane", "Could not create paste: %s": "Nie udało się utworzyć wklejki: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nie udało się odszyfrować wklejki - brak klucza deszyfrującego w adresie (użyłeś skracacza linków, który ucina część adresu?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Czysty tekst", "Source Code": "Kod źródłowy", @@ -220,5 +228,12 @@ "Dark Mode": "Ciemny motyw", "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.", - "Start over": "Start over" + "Start over": "Zacznij od nowa", + "Paste copied to clipboard": "Wklejka skopiowana do schowka", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "Aby skopiować wklejkę, naciśnij przycisk kopiowania lub użyj skrótu schowka Ctrl+c/Cmd+c", + "Copy link": "Kopiuj link", + "Link copied to clipboard": "Link został skopiowany do schowka", + "Paste text": "Wklej tekst", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Klawisz Tabulatora służy jako znak (przytrzymaj Ctrl+m lub Esc aby przełączać)", + "Theme": "Motyw" } diff --git a/i18n/pt.json b/i18n/pt.json index 2cb3b7a0..4ca64bbe 100644 --- a/i18n/pt.json +++ b/i18n/pt.json @@ -151,7 +151,7 @@ "server error or not responding": "Servidor em erro ou não responsivo", "Could not post comment: %s": "Não foi possível publicar o comentário: %s", "Sending paste…": "Enviando cópia…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Sua cópia é %s (Pressione [Ctrl]+[c] para copiar)", + "Your paste is %s (Hit Ctrl+c to copy)": "Sua cópia é %s (Pressione Ctrl+c para copiar)", "Delete data": "Excluir dados", "Could not create paste: %s": "Não foi possível criar cópia: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Não foi possível decifrar a cópia: chave de decriptografia ausente na URL (Você utilizou um redirecionador ou encurtador de URL que removeu parte dela?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formato", "Plain Text": "Texto sem formato", "Source Code": "Código fonte", @@ -220,5 +228,12 @@ "Dark Mode": "Modo Noturno", "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.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/ro.json b/i18n/ro.json index 5e264979..26b5425d 100644 --- a/i18n/ro.json +++ b/i18n/ro.json @@ -151,7 +151,7 @@ "server error or not responding": "eroare de server sau nu răspunde", "Could not post comment: %s": "Nu s-a putut posta comentariul: %s", "Sending paste…": "Se trimite paste-ul…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Paste-ul dvs. este %s (Apăsați [Ctrl]+[c] pentru a copia)", + "Your paste is %s (Hit Ctrl+c to copy)": "Paste-ul dvs. este %s (Apăsați Ctrl+c pentru a copia)", "Delete data": "Ștergeți datele", "Could not create paste: %s": "Nu s-a putut crea paste-ul: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nu s-a putut decripta paste-ul: Cheia de decriptare lipsește din URL (Ați folosit un redirector sau un scurtător de URL care a tăiat o parte din URL?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formatare", "Plain Text": "Text neformatat", "Source Code": "Cod sursă", @@ -220,5 +228,12 @@ "Dark Mode": "Mod întunecat", "Error compressing paste, due to missing WebAssembly support.": "Eroare la compresia paste-ului din cauza incompatibilității cu WebAssembly.", "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Eroare la deschiderea paste-ului, browserul dvs. nu acceptă WebAssembly. Vă rugăm să utilizați un alt browser pentru a vedea acest paste.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/ru.json b/i18n/ru.json index 387ec8f4..0759e507 100644 --- a/i18n/ru.json +++ b/i18n/ru.json @@ -151,7 +151,7 @@ "server error or not responding": "ошибка сервера или нет ответа", "Could not post comment: %s": "Не удалось опубликовать комментарий: %s", "Sending paste…": "Отправка записи…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Ссылка на запись %s (Нажмите [Ctrl]+[c], чтобы скопировать ссылку)", + "Your paste is %s (Hit Ctrl+c to copy)": "Ссылка на запись %s (Нажмите Ctrl+c, чтобы скопировать ссылку)", "Delete data": "Удалить запись", "Could not create paste: %s": "Не удалось опубликовать запись: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Невозможно расшифровать запись: Ключ расшифровки отсутствует в ссылке (Может быть, вы используете сокращатель ссылок, который удаляет часть ссылки?)", @@ -164,6 +164,14 @@ "EiB": "Эбайт", "ZiB": "Збайт", "YiB": "Йбайт", + "kB": "кбайт", + "MB": "Мбайт", + "GB": "Гбайт", + "TB": "Тбайт", + "PB": "Пбайт", + "EB": "Эбайт", + "ZB": "Збайт", + "YB": "Йбайт", "Format": "Формат", "Plain Text": "Обычный текст", "Source Code": "Исходный код", @@ -220,5 +228,12 @@ "Dark Mode": "Тёмная", "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.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Запись скопирована в буфер обмена", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "Чтобы скопировать запись нажмите на кнопку копирования или используйте комбинацию клавиш Ctrl+c/Cmd+c", + "Copy link": "Скопировать ссылку", + "Link copied to clipboard": "Ссылка скопирована в буфер обмена", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Тема" } diff --git a/i18n/sk.json b/i18n/sk.json index 6ed38c68..2e351739 100644 --- a/i18n/sk.json +++ b/i18n/sk.json @@ -151,7 +151,7 @@ "server error or not responding": "chyba servera alebo server neodpovedá", "Could not post comment: %s": "Nepodarilo sa pridať komentár: %s", "Sending paste…": "Odosiela sa príspevok…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Váš príspevok je %s (skopírujte stlačením [Ctrl]+[c])", + "Your paste is %s (Hit Ctrl+c to copy)": "Váš príspevok je %s (skopírujte stlačením Ctrl+c)", "Delete data": "Odstrániť dáta", "Could not create paste: %s": "Nepodarilo sa vytvoriť príspevok: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nie je možné dešifrovať príspevok: V URL adrese chýba dešifrovací kľúč (Použili ste presmerovač alebo skracovač adresy, ktorý odstráni časť adresy URL?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Formát", "Plain Text": "Čistý text", "Source Code": "Zdrojový kód", @@ -220,5 +228,12 @@ "Dark Mode": "Tmavý Režim", "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.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/sl.json b/i18n/sl.json index 987724ec..6870870d 100644 --- a/i18n/sl.json +++ b/i18n/sl.json @@ -151,7 +151,7 @@ "server error or not responding": "napaka na strežniku, ali pa se strežnik ne odziva", "Could not post comment: %s": "Komentarja ni bilo mogoče objaviti : %s", "Sending paste…": "Pošiljam prilepek…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Tvoj prilepek je dostopen na naslovu: %s (Pritisni [Ctrl]+[c] ali [Cmd] + [c] in skopiraj)", + "Your paste is %s (Hit Ctrl+c to copy)": "Tvoj prilepek je dostopen na naslovu: %s (Pritisni Ctrl+c ali [Cmd] + [c] in skopiraj)", "Delete data": "Izbriši podatke", "Could not create paste: %s": "Ne morem ustvariti prilepka: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Ne morem odkodirati prilepka: V URL-ju manjka ključ (A si uporabil krajšalnik URL-jev, ki odstrani del URL-ja?)", @@ -164,6 +164,14 @@ "EiB": "EB", "ZiB": "ZB", "YiB": "YB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Surov tekst", "Source Code": "Odprta koda", @@ -220,5 +228,12 @@ "Dark Mode": "Temni način", "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.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/sv.json b/i18n/sv.json index 9bd57df9..7d116f33 100644 --- a/i18n/sv.json +++ b/i18n/sv.json @@ -151,7 +151,7 @@ "server error or not responding": "server error or not responding", "Could not post comment: %s": "Could not post comment: %s", "Sending paste…": "Sending paste…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Your paste is %s (Hit [Ctrl]+[c] to copy)", + "Your paste is %s (Hit Ctrl+c to copy)": "Your paste is %s (Hit Ctrl+c to copy)", "Delete data": "Delete data", "Could not create paste: %s": "Could not create 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?)": "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Plain Text", "Source Code": "Source Code", @@ -220,5 +228,12 @@ "Dark Mode": "Mörkt Läge", "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.", - "Start over": "Start over" + "Start over": "Start over", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/th.json b/i18n/th.json index ddebf39f..da12d56b 100644 --- a/i18n/th.json +++ b/i18n/th.json @@ -151,7 +151,7 @@ "server error or not responding": "เซิร์ฟเวอร์มีข้อผิดพลาดหรือไม่ตอบสนอง", "Could not post comment: %s": "ไม่สามารถส่งความคิดเห็นได้: %s", "Sending paste…": "กำลังส่งข้อมูล…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "การฝากโค้ดของคุณอยู่ที่ %s (กดปุ่ม [Ctrl]+[c] เพื่อคัดลอก)", + "Your paste is %s (Hit Ctrl+c to copy)": "การฝากโค้ดของคุณอยู่ที่ %s (กดปุ่ม Ctrl+c เพื่อคัดลอก)", "Delete data": "ลบข้อมูล", "Could not create paste: %s": "ไม่สามารถสร้างข้อมูลการฝากโค้ดได้: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "ไม่สามารถถอดรหัสข้อมูลการฝากโค้ดได้: คีย์ถอดรหัสที่อยู่ใน URL หายไป (คุณได้ใช้ตัวเปลี่ยนเส้นทางหรือตัวย่อ URL ที่มีการตัดส่วนของ URL ออกหรือไม่)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "รูปแบบ", "Plain Text": "ข้อความล้วน", "Source Code": "ซอร์สโค้ด", @@ -215,10 +223,17 @@ "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 parsing YOURLS response.": "เกิดข้อผิดพลาดในการแยกวิเคราะห์การตอบสนองของ YOURLS", - "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": "โหมดมืด", - "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.", - "Start over": "Start over" + "This secret message can only be displayed once. Would you like to see it now?": "ข้อความลับนี้จะแสดงได้เพียงครั้งเดียวเท่านั้น คุณต้องการดูข้อความนี้ตอนนี้เลยใช่หรือไม่", + "Yes, see it": "ใช่ ดูเลย", + "Dark Mode": "โหมดสีเข้ม", + "Error compressing paste, due to missing WebAssembly support.": "ไม่สามารถบีบอัดข้อมูลที่คุณต้องการฝากโค้ดได้ เนื่องจากอุปกรณ์ของคุณขาดการรองรับ WebAssembly", + "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "ไม่สามารถอ่านข้อมูลที่คุณได้ฝากโค้ดไว้ เบราว์เซอร์ของคุณไม่รองรับ WebAssembly กรุณาลองเปลี่ยนใช้เบราว์เซอร์ตัวอื่นเพื่อดูการฝากโค้ดนี้อีกครั้ง", + "Start over": "เริ่มใหม่", + "Paste copied to clipboard": "คัดลอกการฝากโค้ดไปที่คลิปบอร์ดแล้ว", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "หากต้องการคัดลอกและวาง กรุณากดปุ่มคัดลอก หรือใช้ปุ่มลัด Ctrl+c/Cmd+c สำหรับคลิปบอร์ด", + "Copy link": "คัดลอกลิงก์", + "Link copied to clipboard": "คัดลอกลิงก์ไปที่คลิปบอร์ดแล้ว", + "Paste text": "ฝากข้อความ", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "ปุ่ม Tabulator ใช้เป็นอักขระ (กด Ctrl+m หรือ Esc เพื่อสลับ)", + "Theme": "ธีม" } diff --git a/i18n/tr.json b/i18n/tr.json index eb813269..9214bf5c 100644 --- a/i18n/tr.json +++ b/i18n/tr.json @@ -151,7 +151,7 @@ "server error or not responding": "sunucu hatası veya yanıt vermiyor", "Could not post comment: %s": "Yorum paylaşılamadı: %s", "Sending paste…": "Yazı gönderiliyor…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Yazınız: %s ([Ctrl]+[c] tuşlarına basarak kopyalayın.)", + "Your paste is %s (Hit Ctrl+c to copy)": "Yazınız: %s (Ctrl+c tuşlarına basarak kopyalayın.)", "Delete data": "Veriyi sil", "Could not create paste: %s": "Yazı oluşturulamadı: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Yazı şifresi çözülemedi, çözme anahtarı URL'de bulunamadı. (Buraya bir yönlendirici veya URL kısaltıcı kullanarak gelmiş olabilirsiniz.)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "Format", "Plain Text": "Düz Yazı", "Source Code": "Kaynak Kodu", @@ -220,5 +228,12 @@ "Dark Mode": "Koyu Mod", "Error compressing paste, due to missing WebAssembly support.": "WebAssembly desteği eksik olduğundan yazı sıkıştırılamadı.", "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Yazı açılırken hata oluştu, tarayıcınız WebAssembly'i desteklemiyor. Lütfen bu yazıyı görüntülemek için başka bir tarayıcı kullanın.", - "Start over": "Baştan başla" + "Start over": "Baştan başla", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/uk.json b/i18n/uk.json index 9b1f2970..4ca9572d 100644 --- a/i18n/uk.json +++ b/i18n/uk.json @@ -151,7 +151,7 @@ "server error or not responding": "помилка на сервері чи немає відповіді", "Could not post comment: %s": "Не вдалося опублікувати коментар: %s", "Sending paste…": "Відправка допису…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "Посилання на допис %s (Тисніть [Ctrl]+[c], щоб скопіювати посилання)", + "Your paste is %s (Hit Ctrl+c to copy)": "Посилання на допис %s (Тисніть Ctrl+c, щоб скопіювати посилання)", "Delete data": "Видалити допис", "Could not create paste: %s": "Не вдалося опублікувати допис: %s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Неможливо розшифрувати запис: Ключ дешифрування відсутній в посиланні (Можливо, ви використовуєте скорочувач посилань, що видаляє частину посилання?)", @@ -164,6 +164,14 @@ "EiB": "Ебайт", "ZiB": "Збайт", "YiB": "Йбайт", + "kB": "кбайт", + "MB": "Мбайт", + "GB": "Гбайт", + "TB": "Тбайт", + "PB": "Пбайт", + "EB": "Ебайт", + "ZB": "Збайт", + "YB": "Йбайт", "Format": "Формат", "Plain Text": "Звичайний текст", "Source Code": "Вихідний код", @@ -220,5 +228,12 @@ "Dark Mode": "Темний режим", "Error compressing paste, due to missing WebAssembly support.": "Помилка при стисканні допису, через відсутність підтримки WebAssembly сервера.", "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Помилка при розпакуванні допису, бо ваш браузер не підтримує WebAssembly. Будь ласка, відкрийте в іншому браузері для перегляду цього допису.", - "Start over": "Start over" + "Start over": "Почати знову", + "Paste copied to clipboard": "Paste copied to clipboard", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c", + "Copy link": "Copy link", + "Link copied to clipboard": "Link copied to clipboard", + "Paste text": "Paste text", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)", + "Theme": "Theme" } diff --git a/i18n/zh.json b/i18n/zh.json index da1d4e9a..8046939c 100644 --- a/i18n/zh.json +++ b/i18n/zh.json @@ -7,12 +7,12 @@ "%s requires php %s or above to work. Sorry.": "抱歉,%s 需要 PHP %s 及以上版本才能运行。", "%s requires configuration section [%s] to be present in configuration file.": "%s 需要设置配置文件中的 [%s] 部分。", "Please wait %d seconds between each post.": [ - "每 %d 秒只能粘贴一次。", - "每 %d 秒只能粘贴一次。", - "每 %d 秒只能粘贴一次。", - "每 %d 秒只能粘贴一次。", - "每 %d 秒只能粘贴一次。", - "每 %d 秒只能粘贴一次。" + "每 %d 秒只能创建一次粘贴。", + "每 %d 秒只能创建一次粘贴。", + "每 %d 秒只能创建一次粘贴。", + "每 %d 秒只能创建一次粘贴。", + "每 %d 秒只能创建一次粘贴。", + "每 %d 秒只能创建一次粘贴。" ], "Paste is limited to %s of encrypted data.": "对于加密数据,上限为 %s。", "Invalid data.": "无效的数据。", @@ -46,10 +46,10 @@ "%d minutes": [ "%d 分钟", "%d 分钟", - "%d 秒", - "%d 秒", - "%d 秒", - "%d 秒" + "%d 分钟", + "%d 分钟", + "%d 分钟", + "%d 分钟" ], "%d hours": [ "%d 小时", @@ -94,7 +94,7 @@ "Never": "永不过期", "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.": [ - "这份文档将在一秒后过期。", + "这份文档将在 %d 秒后过期。", "这份文档将在 %d 秒后过期。", "这份文档将在 %d 秒后过期。", "这份文档将在 %d 秒后过期。", @@ -102,7 +102,7 @@ "这份文档将在 %d 秒后过期。" ], "This document will expire in %d minutes.": [ - "这份文档将在一分钟后过期。", + "这份文档将在 %d 分钟后过期。", "这份文档将在 %d 分钟后过期。", "这份文档将在 %d 分钟后过期。", "这份文档将在 %d 分钟后过期。", @@ -110,7 +110,7 @@ "这份文档将在 %d 分钟后过期。" ], "This document will expire in %d hours.": [ - "这份文档将在一小时后过期。", + "这份文档将在 %d 小时后过期。", "这份文档将在 %d 小时后过期。", "这份文档将在 %d 小时后过期。", "这份文档将在 %d 小时后过期。", @@ -118,7 +118,7 @@ "这份文档将在 %d 小时后过期。" ], "This document will expire in %d days.": [ - "这份文档将在一天后过期。", + "这份文档将在 %d 天后过期。", "这份文档将在 %d 天后过期。", "这份文档将在 %d 天后过期。", "这份文档将在 %d 天后过期。", @@ -126,7 +126,7 @@ "这份文档将在 %d 天后过期。" ], "This document will expire in %d months.": [ - "这份文档将在一个月后过期。", + "这份文档将在 %d 个月后过期。", "这份文档将在 %d 个月后过期。", "这份文档将在 %d 个月后过期。", "这份文档将在 %d 个月后过期。", @@ -136,7 +136,7 @@ "Please enter the password for this paste:": "请输入这份粘贴内容的密码:", "Could not decrypt data (Wrong key?)": "无法解密数据(密钥错误?)", "Could not delete the paste, it was not stored in burn after reading mode.": "无法删除此粘贴内容,它没有以阅后即焚模式保存。", - "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "看!仔!细!了!不要关闭窗口,否则你再也见不到这条消息了。", + "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "睁大眼睛看清楚!不要关闭窗口,否则你再也见不到这条消息了。", "Could not decrypt comment; Wrong key?": "无法解密评论;密钥错误?", "Reply": "回复", "Anonymous": "匿名", @@ -150,8 +150,8 @@ "unknown status": "未知状态", "server error or not responding": "服务器错误或无回应", "Could not post comment: %s": "无法发送评论: %s", - "Sending paste…": "粘贴内容提交中…", - "Your paste is %s (Hit [Ctrl]+[c] to copy)": "您粘贴内容的链接是 %s (按下 [Ctrl]+[C] 以复制)", + "Sending paste…": "正在发送粘贴内容…", + "Your paste is %s (Hit Ctrl+c to copy)": "您粘贴内容的链接是 %s (按下 Ctrl+c 以复制)", "Delete data": "删除数据", "Could not create paste: %s": "无法创建粘贴:%s", "Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "无法解密粘贴:URL中缺失解密密钥(是否使用了重定向或者短链接导致密钥丢失?)", @@ -164,6 +164,14 @@ "EiB": "EiB", "ZiB": "ZiB", "YiB": "YiB", + "kB": "kB", + "MB": "MB", + "GB": "GB", + "TB": "TB", + "PB": "PB", + "EB": "EB", + "ZB": "ZB", + "YB": "YB", "Format": "格式", "Plain Text": "纯文本", "Source Code": "源代码", @@ -185,8 +193,8 @@ "Decrypt": "解密", "Enter password": "输入密码", "Loading…": "载入中…", - "Decrypting paste…": "正在解密", - "Preparing new paste…": "正在准备新的粘贴内容", + "Decrypting paste…": "正在解密…", + "Preparing new paste…": "正在准备新的粘贴内容…", "In case this message never disappears please have a look at this FAQ for information to troubleshoot.": "如果此消息一直存在,请参考 这里的 FAQ(英文版)排除故障。", "+++ no paste text +++": "+++ 无粘贴内容 +++", "Could not get paste data: %s": "无法获取粘贴数据:%s", @@ -200,7 +208,7 @@ "Retry": "重试", "Showing raw text…": "显示原始文字…", "Notice:": "注意:", - "This link will expire after %s.": "这个链接将会在 %s 过期。", + "This link will expire after %s.": "此链接将会在 %s 过期。", "This link can only be accessed once, do not use back or refresh button in your browser.": "此链接只能被访问一次,请勿使用浏览器中的返回和刷新按钮。", "Link:": "链接:", "Recipient may become aware of your timezone, convert time to UTC?": "收件人可能会知道您的时区,将时间转换为 UTC?", @@ -217,8 +225,15 @@ "Error parsing YOURLS response.": "解析 YOURLS 响应时出错。", "This secret message can only be displayed once. Would you like to see it now?": "读取粘贴后只能在加载时显示一次。您想现在打开吗?", "Yes, see it": "是的,加载它", - "Dark Mode": "暗黑模式", - "Error compressing paste, due to missing WebAssembly support.": "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.", - "Start over": "Start over" + "Dark Mode": "夜间模式", + "Error compressing paste, due to missing WebAssembly support.": "由于缺少 WebAssembly 支持,在压缩粘贴时出错。", + "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "解压粘贴时出错,您的浏览器不支持 WebAssembly。请使用其他浏览器查看此粘贴。", + "Start over": "重新开始", + "Paste copied to clipboard": "粘贴内容已复制到剪贴板", + "To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c": "要复制粘贴内容,请点击复制按钮或使用快捷键 Ctrl+c/Cmd+c。", + "Copy link": "复制链接", + "Link copied to clipboard": "链接已复制到剪贴板", + "Paste text": "粘贴文本", + "Tabulator key serves as character (Hit Ctrl+m or Esc to toggle)": "Tab 键可作为字符(按 Ctrl+mEsc 切换开关)", + "Theme": "主题" } diff --git a/img/android-chrome-192x192.png b/img/android-chrome-192x192.png index 42baf753..6f417b9b 100644 Binary files a/img/android-chrome-192x192.png and b/img/android-chrome-192x192.png differ diff --git a/img/android-chrome-512x512.png b/img/android-chrome-512x512.png index 48e6608b..6294b81c 100644 Binary files a/img/android-chrome-512x512.png and b/img/android-chrome-512x512.png differ diff --git a/img/apple-touch-icon.png b/img/apple-touch-icon.png index aa6e2b04..00d9f373 100644 Binary files a/img/apple-touch-icon.png and b/img/apple-touch-icon.png differ diff --git a/img/bootstrap-icons.svg b/img/bootstrap-icons.svg index 11afeae1..18390345 100644 --- a/img/bootstrap-icons.svg +++ b/img/bootstrap-icons.svg @@ -1 +1 @@ - + diff --git a/img/favicon-32x32.png b/img/favicon-32x32.png index be42cb39..3e20546d 100644 Binary files a/img/favicon-32x32.png and b/img/favicon-32x32.png differ diff --git a/img/icon_clone.png b/img/icon_clone.png index 455b82f9..a0afc1d8 100644 Binary files a/img/icon_clone.png and b/img/icon_clone.png differ diff --git a/img/icon_email.png b/img/icon_email.png index cd3fdf42..3a404dfb 100644 Binary files a/img/icon_email.png and b/img/icon_email.png differ diff --git a/img/icon_new.png b/img/icon_new.png index dd96fa2b..f311d869 100644 Binary files a/img/icon_new.png and b/img/icon_new.png differ diff --git a/img/icon_qr.png b/img/icon_qr.png index 28d10ca7..53e7373f 100644 Binary files a/img/icon_qr.png and b/img/icon_qr.png differ diff --git a/img/icon_raw.png b/img/icon_raw.png index 41b586f0..d4677775 100644 Binary files a/img/icon_raw.png and b/img/icon_raw.png differ diff --git a/img/icon_send.png b/img/icon_send.png index a6e62ebd..78c617a5 100644 Binary files a/img/icon_send.png and b/img/icon_send.png differ diff --git a/img/icon_shorten.png b/img/icon_shorten.png index 009c2e10..ad393037 100644 Binary files a/img/icon_shorten.png and b/img/icon_shorten.png differ diff --git a/img/mstile-144x144.png b/img/mstile-144x144.png index 81953077..872741fa 100644 Binary files a/img/mstile-144x144.png and b/img/mstile-144x144.png differ diff --git a/img/mstile-150x150.png b/img/mstile-150x150.png index 9b9d36d1..ac4704c9 100644 Binary files a/img/mstile-150x150.png and b/img/mstile-150x150.png differ diff --git a/img/mstile-310x150.png b/img/mstile-310x150.png index 14dbf533..2c77221e 100644 Binary files a/img/mstile-310x150.png and b/img/mstile-310x150.png differ diff --git a/img/mstile-310x310.png b/img/mstile-310x310.png index 47264533..ff1ebec5 100644 Binary files a/img/mstile-310x310.png and b/img/mstile-310x310.png differ diff --git a/img/mstile-70x70.png b/img/mstile-70x70.png index 02b11be0..f2c07187 100644 Binary files a/img/mstile-70x70.png and b/img/mstile-70x70.png differ diff --git a/js/common.js b/js/common.js index a81dbc82..a7efe670 100644 --- a/js/common.js +++ b/js/common.js @@ -5,19 +5,18 @@ global.assert = require('assert'); global.jsc = require('jsverify'); global.jsdom = require('jsdom-global'); global.cleanup = global.jsdom(); -global.URL = require('jsdom-url').URL; global.fs = require('fs'); global.WebCrypto = require('@peculiar/webcrypto').Crypto; // application libraries to test global.$ = global.jQuery = require('./jquery-3.7.1'); global.RawDeflate = require('./rawinflate-0.3').RawDeflate; -global.zlib = require('./zlib-1.3.1').zlib; +global.zlib = require('./zlib-1.3.1-1').zlib; require('./prettify'); global.prettyPrint = window.PR.prettyPrint; global.prettyPrintOne = window.PR.prettyPrintOne; global.showdown = require('./showdown-2.1.0'); -global.DOMPurify = require('./purify-3.1.7'); +global.DOMPurify = require('./purify-3.2.6'); global.baseX = require('./base-x-4.0.0').baseX; global.Legacy = require('./legacy').Legacy; require('./bootstrap-3.4.1'); @@ -79,8 +78,16 @@ function parseMime(line) { } // common testing helper functions -exports.atob = atob; -exports.btoa = btoa; +// as of jsDOM 22 the base64 functions provided in the DOM are more restrictive +// than browser implementation and throw when being passed invalid unicode +// 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 exports.jscA2zString = function() { @@ -152,3 +159,22 @@ exports.urlToString = function (url) { encodeURI(url.query.join('').replace(/^&+|&+$/gm,'')) : '') + (url.fragment ? '#' + encodeURI(url.fragment) : ''); }; + +exports.enableClipboard = function () { + navigator.clipboard = (function () { + let savedText = ""; + + async function writeText(text) { + savedText = text; + }; + + async function readText() { + return savedText; + }; + + return { + writeText, + readText, + }; + })(); +}; diff --git a/js/dark-mode-switch.js b/js/dark-mode-switch.js index 07288ee6..e60bedb5 100644 --- a/js/dark-mode-switch.js +++ b/js/dark-mode-switch.js @@ -68,7 +68,7 @@ } else { delStoredPrettifyTheme() } - const toggle = document.querySelector('#bd-theme') + const toggle = document.getElementById('bd-theme') const theme = getStoredPreferredTheme() setTheme(theme) toggle.checked = (theme === 'dark') diff --git a/js/legacy.js b/js/legacy.js index 0e65ff78..922e9a0e 100644 --- a/js/legacy.js +++ b/js/legacy.js @@ -6,7 +6,6 @@ * @see {@link https://github.com/PrivateBin/PrivateBin} * @copyright 2012 Sébastien SAUVAGE ({@link http://sebsauvage.net}) * @license {@link https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License} - * @version 1.3.1 * @name Legacy * @namespace */ @@ -175,18 +174,6 @@ )) { return true; } - - // async & ES6 support - try { - eval('async () => {}'); - } catch (e) { - if (e instanceof SyntaxError) { - return true; - } else { - throw e; // throws CSP error - } - } - return false; } @@ -238,7 +225,7 @@ { return init; }; - + /** * returns the current status of the check * @@ -250,7 +237,7 @@ { return status; }; - + /** * init on application start, returns an all-clear signal * @@ -308,4 +295,4 @@ this.Legacy = { Check: Check }; -}).call(this); \ No newline at end of file +}).call(this); diff --git a/js/package-lock.json b/js/package-lock.json index 8e627e0a..976ceedf 100644 --- a/js/package-lock.json +++ b/js/package-lock.json @@ -1,30 +1,152 @@ { "name": "privatebin", - "version": "1.7.5", + "version": "1.7.8", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "privatebin", - "version": "1.7.5", + "version": "1.7.8", "license": "zlib-acknowledgement", "devDependencies": { - "@peculiar/webcrypto": "^1.1.1", - "jsdom": "^9.12.0", - "jsdom-global": "^2.1.1", - "jsdom-url": "^2.2.1", + "@peculiar/webcrypto": "^1.5.0", + "jsdom": "^26.0.0", + "jsdom-global": "^3.0.2", "jsverify": "^0.8.3" } }, + "node_modules/@asamuzakjp/css-color": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-2.8.3.tgz", + "integrity": "sha512-GIc76d9UI1hCvOATjZPyHFmE5qhRccp3/zGfMPapK3jBi+yocEzp6BBB0UnfRYP9NP4FANqUZYb0hnfs3TM3hw==", + "dev": true, + "dependencies": { + "@csstools/css-calc": "^2.1.1", + "@csstools/css-color-parser": "^3.0.7", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.1.tgz", + "integrity": "sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.1.tgz", + "integrity": "sha512-rL7kaUnTkL9K+Cvo2pnCieqNpTKgQzy5f+N+5Iuko9HAoasP+xgprVh7KN/MaJVvVL1l0EzQq2MoqBHKSrDrag==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.7.tgz", + "integrity": "sha512-nkMp2mTICw32uE5NN+EsJ4f5N+IGFeCFu4bGpiKgb2Pq/7J/MpyLBeQ5ry4KKtRFZaYs6sTmcMYrSRIyj5DFKA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "dependencies": { + "@csstools/color-helpers": "^5.0.1", + "@csstools/css-calc": "^2.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", + "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", + "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@peculiar/asn1-schema": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.2.0.tgz", - "integrity": "sha512-1ENEJNY7Lwlua/1wvzpYP194WtjQBfFxvde2FlzfBFh/ln6wvChrtxlORhbKEnYswzn6fOC4c7HdC5izLPMTJg==", + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.15.tgz", + "integrity": "sha512-QPeD8UA8axQREpgR5UTAfu2mqQmm97oUqahDtNdBcfj3qAnoXzFdQW+aNf/tD2WVXF8Fhmftxoj0eMIT++gX2w==", "dev": true, "dependencies": { "asn1js": "^3.0.5", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0" + "pvtsutils": "^1.3.6", + "tslib": "^2.8.1" } }, "node_modules/@peculiar/json-schema": { @@ -40,77 +162,28 @@ } }, "node_modules/@peculiar/webcrypto": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.0.tgz", - "integrity": "sha512-U58N44b2m3OuTgpmKgf0LPDOmP3bhwNz01vAnj1mBwxBASRhptWYK+M3zG+HBkDqGQM+bFsoIihTW8MdmPXEqg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.5.0.tgz", + "integrity": "sha512-BRs5XUAwiyCDQMsVA9IDvDa7UBR9gAvPHgugOeGng3YN6vJ9JYonyDc0lNczErgtCWtucjR5N7VtaonboD/ezg==", "dev": true, "dependencies": { - "@peculiar/asn1-schema": "^2.1.6", + "@peculiar/asn1-schema": "^2.3.8", "@peculiar/json-schema": "^1.1.12", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0", - "webcrypto-core": "^1.7.5" + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2", + "webcrypto-core": "^1.8.0" }, "engines": { "node": ">=10.12.0" } }, - "node_modules/abab": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz", - "integrity": "sha512-I+Wi+qiE2kUXyrRhNsWv6XsjUTBJjSoVSctKNBfLG5zG/Xe7Rjbxf13+vqYHNTwHaFU+FtSlVxOCTiMEVtPv0A==", - "dev": true - }, - "node_modules/acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha512-fu2ygVGuMmlzG8ZeRJ0bvR41nsAkxxhbyk8bZ1SS521Z7vmgJFTQQlfz/Mp/nJexGBz+v8sC9bM6+lNgskt4Ug==", + "node_modules/agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", "dev": true, - "bin": { - "acorn": "bin/acorn" - }, "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-globals": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", - "integrity": "sha512-uWttZCk96+7itPxK8xCzY86PnxKTMrReKDqrHzv42VQY0K30PUO8WY13WMOuI+cOdX4EIdzdvQ8k6jkuGRFMYw==", - "dev": true, - "dependencies": { - "acorn": "^4.0.4" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha512-H3LU5RLiSsGXPhN+Nipar0iR0IofH+8r89G2y1tBKxQ/agagKyAjhkAFDRBfodP2caPrNKHpAWNIM/c9yeL7uA==", - "dev": true - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "dependencies": { - "safer-buffer": "~2.1.0" + "node": ">= 14" } }, "node_modules/asn1js": { @@ -127,57 +200,12 @@ "node": ">=12.0.0" } }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, - "node_modules/class-proxy": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/class-proxy/-/class-proxy-1.1.2.tgz", - "integrity": "sha512-kowpC1EGn0b5ZxOMbF8f7IO03gg6dtI1rwBIHMfG5dEAeOVpZpukN9cT4K9cxv+IG8JihVdsqPr0V5bitB+pqQ==", - "dev": true - }, "node_modules/combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -190,49 +218,87 @@ "node": ">= 0.8" } }, - "node_modules/content-type-parser": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.2.tgz", - "integrity": "sha512-lM4l4CnMEwOLHAHr/P6MEZwZFPJFtAAKgL6pogbXmVZggIqXhdB6RbBtPOTsw2FcXwYhehRGERJmRrjOiIB8pQ==", - "dev": true - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true - }, - "node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, "node_modules/cssstyle": { - "version": "0.2.37", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz", - "integrity": "sha512-FUpKc+1FNBsHUr9IsfSGCovr8VuGOiiuzlgCyppKBjJi2jYTOFLN3oiiNRMIvYqbFzF38mqKj4BgcevzU5/kIA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.2.1.tgz", + "integrity": "sha512-9+vem03dMXG7gDmZ62uqmRiMRNtinIZ9ZyuF6BdxzfOD+FdN5hretzynkn0ReS2DO2GSw76RWHs0UmJPI2zUjw==", "dev": true, "dependencies": { - "cssom": "0.3.x" - } - }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" + "@asamuzakjp/css-color": "^2.8.2", + "rrweb-cssom": "^0.8.0" }, "engines": { - "node": ">=0.10" + "node": ">=18" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls/node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dev": true, + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/data-urls/node_modules/whatwg-url": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", + "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", + "dev": true, + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", + "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", "dev": true }, "node_modules/delayed-stream": { @@ -244,305 +310,169 @@ "node": ">=0.4.0" } }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "node_modules/escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1" + "engines": { + "node": ">=0.12" }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=4.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true, - "engines": [ - "node >=0.6.0" - ] - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true, - "engines": { - "node": "*" + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "dev": true, "dependencies": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", + "combined-stream": "^1.0.8", "mime-types": "^2.1.12" }, "engines": { - "node": ">= 0.12" - } - }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0" - } - }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" + "node": ">= 6" } }, "node_modules/html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", "dev": true, "dependencies": { - "whatwg-encoding": "^1.0.1" - } - }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "dev": true, - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "whatwg-encoding": "^3.1.1" }, "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" } }, "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, "node_modules/jsdom": { - "version": "9.12.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz", - "integrity": "sha512-Qw4oqNxo4LyzkSqVIyCnEltTc4xV3g1GBaI88AvYTesWzmWHUSoMNmhBjUBa+6ldXIBJS9xoeLNJPfUAykTyxw==", + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.0.0.tgz", + "integrity": "sha512-BZYDGVAIriBWTpIxYzrXjv3E/4u8+/pSG5bQdIYCbNCGOvsPkDQfTVLAIXAf9ETdCpduCVTkDe2NNZ8NIwUVzw==", "dev": true, "dependencies": { - "abab": "^1.0.3", - "acorn": "^4.0.4", - "acorn-globals": "^3.1.0", - "array-equal": "^1.0.0", - "content-type-parser": "^1.0.1", - "cssom": ">= 0.3.2 < 0.4.0", - "cssstyle": ">= 0.2.37 < 0.3.0", - "escodegen": "^1.6.1", - "html-encoding-sniffer": "^1.0.1", - "nwmatcher": ">= 1.3.9 < 2.0.0", - "parse5": "^1.5.1", - "request": "^2.79.0", - "sax": "^1.2.1", - "symbol-tree": "^3.2.1", - "tough-cookie": "^2.3.2", - "webidl-conversions": "^4.0.0", - "whatwg-encoding": "^1.0.1", - "whatwg-url": "^4.3.0", - "xml-name-validator": "^2.0.1" + "cssstyle": "^4.2.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.1", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.16", + "parse5": "^7.2.1", + "rrweb-cssom": "^0.8.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.1.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } } }, "node_modules/jsdom-global": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/jsdom-global/-/jsdom-global-2.1.1.tgz", - "integrity": "sha512-nVZiKQhXZzmkFSF+AfpvErIYuzPEuBV684gYpWagtwWTLiy0p5EgQbP7gmNNA6/qxFb8l1E5w1NjES5nSBCw5A==", - "dev": true - }, - "node_modules/jsdom-url": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/jsdom-url/-/jsdom-url-2.2.1.tgz", - "integrity": "sha512-+wha7QGq/vPR97R/wz5+213pyWP1362/xmAMmesyVgxyTFOfAeKtwPah+f2znabdNdcqOPbyM7j/xWHbXAqhmg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsdom-global/-/jsdom-global-3.0.2.tgz", + "integrity": "sha512-t1KMcBkz/pT5JrvcJbpUR2u/w1kO9jXctaaGJ0vZDzwFnIvGWw9IDSRciT83kIs8Bnw4qpOl8bQK08V01YgMPg==", "dev": true, - "dependencies": { - "class-proxy": "^1.1.1", - "whatwg-url": "^7.0.0" + "peerDependencies": { + "jsdom": ">=10.0.0" } }, - "node_modules/jsdom-url/node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "node_modules/jsdom/node_modules/tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", "dev": true, "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/jsdom-url/node_modules/whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" + "punycode": "^2.3.1" }, "engines": { - "node": ">=0.6.0" + "node": ">=18" + } + }, + "node_modules/jsdom/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", + "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", + "dev": true, + "dependencies": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" } }, "node_modules/jsverify": { @@ -569,23 +499,10 @@ "node": ">= 0.10.0" } }, - "node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true }, "node_modules/mime-db": { @@ -609,81 +526,46 @@ "node": ">= 0.6" } }, - "node_modules/nwmatcher": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.4.tgz", - "integrity": "sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ==", + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } + "node_modules/nwsapi": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", + "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==", + "dev": true }, "node_modules/parse5": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz", - "integrity": "sha512-w2jx/0tJzvgKwZa58sj2vAYq/S/K1QJfIB3cWYea/Iu1scFPDQQ3IQiVZTHWtRBwAjv2Yd7S/xeZf3XqLDb3bA==", - "dev": true - }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true - }, - "node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", "dev": true, - "engines": { - "node": ">= 0.8.0" + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" } }, "node_modules/pvtsutils": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.2.tgz", - "integrity": "sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", "dev": true, "dependencies": { - "tslib": "^2.4.0" + "tslib": "^2.8.1" } }, "node_modules/pvutils": { @@ -695,15 +577,6 @@ "node": ">=6.0.0" } }, - "node_modules/qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, "node_modules/rc4": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/rc4/-/rc4-0.1.5.tgz", @@ -713,57 +586,11 @@ "node": ">=0.10.0" } }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] + "node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -771,45 +598,16 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" + "xmlchars": "^2.2.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=v12.22.7" } }, "node_modules/symbol-tree": { @@ -818,25 +616,36 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "node_modules/tldts": { + "version": "6.1.77", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.77.tgz", + "integrity": "sha512-lBpoWgy+kYmuXWQ83+R7LlJCnsd9YW8DGpZSHhrMl4b8Ly/1vzOie3OdtmUJDkKxcgRGOehDu5btKkty+JEe+g==", "dev": true, "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "tldts-core": "^6.1.77" }, - "engines": { - "node": ">=0.8" + "bin": { + "tldts": "bin/cli.js" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "node_modules/tldts-core": { + "version": "6.1.77", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.77.tgz", + "integrity": "sha512-bCaqm24FPk8OgBkM0u/SrEWJgHnhBWYqeBo6yUmcZJDCHt/IfyWBb+14CXdGi4RInMv4v7eUAin15W0DoA+Ytg==", "dev": true }, + "node_modules/tough-cookie": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.1.tgz", + "integrity": "sha512-Ek7HndSVkp10hmHP9V4qZO1u+pn1RU5sI0Fw+jCU3lyvuMZcgqsNgc6CmJJZyByK4Vm/qotGRJlfgAX8q+4JiA==", + "dev": true, + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/trampa": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trampa/-/trampa-1.0.1.tgz", @@ -844,41 +653,11 @@ "dev": true }, "node_modules/tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" - } - }, "node_modules/typify-parser": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/typify-parser/-/typify-parser-1.1.0.tgz", @@ -888,109 +667,148 @@ "node": ">= 0.10.0" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", "dev": true, "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, - "bin": { - "uuid": "bin/uuid" - } - }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" } }, "node_modules/webcrypto-core": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.5.tgz", - "integrity": "sha512-gaExY2/3EHQlRNNNVSrbG2Cg94Rutl7fAaKILS1w8ZDhGxdFOaw6EbCfHIxPy9vt/xwp5o0VQAx9aySPF6hU1A==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.8.1.tgz", + "integrity": "sha512-P+x1MvlNCXlKbLSOY4cYrdreqPG5hbzkmawbcXLKN/mf6DZW0SdNNkZ+sjwsqVkI4A4Ko2sPZmkZtCKY58w83A==", "dev": true, "dependencies": { - "@peculiar/asn1-schema": "^2.1.6", + "@peculiar/asn1-schema": "^2.3.13", "@peculiar/json-schema": "^1.1.12", - "asn1js": "^3.0.1", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0" + "asn1js": "^3.0.5", + "pvtsutils": "^1.3.5", + "tslib": "^2.7.0" } }, - "node_modules/webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", "dev": true, "dependencies": { - "iconv-lite": "0.4.24" + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" } }, - "node_modules/whatwg-url": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-4.8.0.tgz", - "integrity": "sha512-nUvUPuenPFtPfy/X+dAYh/TfRbTBlnXTM5iIfLseJFkkQewmpG9pGR6i87E9qL+lZaJzv+99kkQWoGOtLfkZQQ==", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/whatwg-url/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, - "node_modules/word-wrap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", - "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=18" + } + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } } }, "node_modules/xml-name-validator": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz", - "integrity": "sha512-jRKe/iQYMyVJpzPH+3HL97Lgu5HrCfii+qSo+TfjKHtOnvbnvdVfMYrn9Q34YV81M2e5sviJlI6Ko9y+nByzvA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true } }, "dependencies": { + "@asamuzakjp/css-color": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-2.8.3.tgz", + "integrity": "sha512-GIc76d9UI1hCvOATjZPyHFmE5qhRccp3/zGfMPapK3jBi+yocEzp6BBB0UnfRYP9NP4FANqUZYb0hnfs3TM3hw==", + "dev": true, + "requires": { + "@csstools/css-calc": "^2.1.1", + "@csstools/css-color-parser": "^3.0.7", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "@csstools/color-helpers": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.1.tgz", + "integrity": "sha512-MKtmkA0BX87PKaO1NFRTFH+UnkgnmySQOvNxJubsadusqPEC2aJ9MOQiMceZJJ6oitUl/i0L6u0M1IrmAOmgBA==", + "dev": true + }, + "@csstools/css-calc": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.1.tgz", + "integrity": "sha512-rL7kaUnTkL9K+Cvo2pnCieqNpTKgQzy5f+N+5Iuko9HAoasP+xgprVh7KN/MaJVvVL1l0EzQq2MoqBHKSrDrag==", + "dev": true, + "requires": {} + }, + "@csstools/css-color-parser": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.7.tgz", + "integrity": "sha512-nkMp2mTICw32uE5NN+EsJ4f5N+IGFeCFu4bGpiKgb2Pq/7J/MpyLBeQ5ry4KKtRFZaYs6sTmcMYrSRIyj5DFKA==", + "dev": true, + "requires": { + "@csstools/color-helpers": "^5.0.1", + "@csstools/css-calc": "^2.1.1" + } + }, + "@csstools/css-parser-algorithms": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", + "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", + "dev": true, + "requires": {} + }, + "@csstools/css-tokenizer": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", + "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", + "dev": true + }, "@peculiar/asn1-schema": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.2.0.tgz", - "integrity": "sha512-1ENEJNY7Lwlua/1wvzpYP194WtjQBfFxvde2FlzfBFh/ln6wvChrtxlORhbKEnYswzn6fOC4c7HdC5izLPMTJg==", + "version": "2.3.15", + "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.3.15.tgz", + "integrity": "sha512-QPeD8UA8axQREpgR5UTAfu2mqQmm97oUqahDtNdBcfj3qAnoXzFdQW+aNf/tD2WVXF8Fhmftxoj0eMIT++gX2w==", "dev": true, "requires": { "asn1js": "^3.0.5", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0" + "pvtsutils": "^1.3.6", + "tslib": "^2.8.1" } }, "@peculiar/json-schema": { @@ -1003,66 +821,24 @@ } }, "@peculiar/webcrypto": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.4.0.tgz", - "integrity": "sha512-U58N44b2m3OuTgpmKgf0LPDOmP3bhwNz01vAnj1mBwxBASRhptWYK+M3zG+HBkDqGQM+bFsoIihTW8MdmPXEqg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@peculiar/webcrypto/-/webcrypto-1.5.0.tgz", + "integrity": "sha512-BRs5XUAwiyCDQMsVA9IDvDa7UBR9gAvPHgugOeGng3YN6vJ9JYonyDc0lNczErgtCWtucjR5N7VtaonboD/ezg==", "dev": true, "requires": { - "@peculiar/asn1-schema": "^2.1.6", + "@peculiar/asn1-schema": "^2.3.8", "@peculiar/json-schema": "^1.1.12", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0", - "webcrypto-core": "^1.7.5" + "pvtsutils": "^1.3.5", + "tslib": "^2.6.2", + "webcrypto-core": "^1.8.0" } }, - "abab": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz", - "integrity": "sha512-I+Wi+qiE2kUXyrRhNsWv6XsjUTBJjSoVSctKNBfLG5zG/Xe7Rjbxf13+vqYHNTwHaFU+FtSlVxOCTiMEVtPv0A==", + "agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", "dev": true }, - "acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha512-fu2ygVGuMmlzG8ZeRJ0bvR41nsAkxxhbyk8bZ1SS521Z7vmgJFTQQlfz/Mp/nJexGBz+v8sC9bM6+lNgskt4Ug==", - "dev": true - }, - "acorn-globals": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-3.1.0.tgz", - "integrity": "sha512-uWttZCk96+7itPxK8xCzY86PnxKTMrReKDqrHzv42VQY0K30PUO8WY13WMOuI+cOdX4EIdzdvQ8k6jkuGRFMYw==", - "dev": true, - "requires": { - "acorn": "^4.0.4" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha512-H3LU5RLiSsGXPhN+Nipar0iR0IofH+8r89G2y1tBKxQ/agagKyAjhkAFDRBfodP2caPrNKHpAWNIM/c9yeL7uA==", - "dev": true - }, - "asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, "asn1js": { "version": "3.0.5", "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz", @@ -1074,51 +850,12 @@ "tslib": "^2.4.0" } }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true - }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true - }, - "aws4": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", - "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true - }, - "class-proxy": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/class-proxy/-/class-proxy-1.1.2.tgz", - "integrity": "sha512-kowpC1EGn0b5ZxOMbF8f7IO03gg6dtI1rwBIHMfG5dEAeOVpZpukN9cT4K9cxv+IG8JihVdsqPr0V5bitB+pqQ==", - "dev": true - }, "combined-stream": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", @@ -1128,46 +865,66 @@ "delayed-stream": "~1.0.0" } }, - "content-type-parser": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/content-type-parser/-/content-type-parser-1.0.2.tgz", - "integrity": "sha512-lM4l4CnMEwOLHAHr/P6MEZwZFPJFtAAKgL6pogbXmVZggIqXhdB6RbBtPOTsw2FcXwYhehRGERJmRrjOiIB8pQ==", - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true - }, - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, "cssstyle": { - "version": "0.2.37", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz", - "integrity": "sha512-FUpKc+1FNBsHUr9IsfSGCovr8VuGOiiuzlgCyppKBjJi2jYTOFLN3oiiNRMIvYqbFzF38mqKj4BgcevzU5/kIA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.2.1.tgz", + "integrity": "sha512-9+vem03dMXG7gDmZ62uqmRiMRNtinIZ9ZyuF6BdxzfOD+FdN5hretzynkn0ReS2DO2GSw76RWHs0UmJPI2zUjw==", "dev": true, "requires": { - "cssom": "0.3.x" + "@asamuzakjp/css-color": "^2.8.2", + "rrweb-cssom": "^0.8.0" } }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", "dev": true, "requires": { - "assert-plus": "^1.0.0" + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "dependencies": { + "tr46": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", + "dev": true, + "requires": { + "punycode": "^2.3.1" + } + }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true + }, + "whatwg-url": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", + "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", + "dev": true, + "requires": { + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" + } + } } }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "requires": { + "ms": "^2.1.3" + } + }, + "decimal.js": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", + "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", "dev": true }, "delayed-stream": { @@ -1176,260 +933,129 @@ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "escodegen": { - "version": "1.14.3", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz", - "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", - "dev": true, - "requires": { - "esprima": "^4.0.1", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true }, "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "dev": true, "requires": { "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", + "combined-stream": "^1.0.8", "mime-types": "^2.1.12" } }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "dev": true - }, - "har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "dev": true, - "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - } - }, "html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", "dev": true, "requires": { - "whatwg-encoding": "^1.0.1" + "whatwg-encoding": "^3.1.1" } }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", "dev": true, "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "requires": { + "agent-base": "^7.1.2", + "debug": "4" } }, "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, "requires": { - "safer-buffer": ">= 2.1.2 < 3" + "safer-buffer": ">= 2.1.2 < 3.0.0" } }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", "dev": true }, "jsdom": { - "version": "9.12.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-9.12.0.tgz", - "integrity": "sha512-Qw4oqNxo4LyzkSqVIyCnEltTc4xV3g1GBaI88AvYTesWzmWHUSoMNmhBjUBa+6ldXIBJS9xoeLNJPfUAykTyxw==", + "version": "26.0.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.0.0.tgz", + "integrity": "sha512-BZYDGVAIriBWTpIxYzrXjv3E/4u8+/pSG5bQdIYCbNCGOvsPkDQfTVLAIXAf9ETdCpduCVTkDe2NNZ8NIwUVzw==", "dev": true, "requires": { - "abab": "^1.0.3", - "acorn": "^4.0.4", - "acorn-globals": "^3.1.0", - "array-equal": "^1.0.0", - "content-type-parser": "^1.0.1", - "cssom": ">= 0.3.2 < 0.4.0", - "cssstyle": ">= 0.2.37 < 0.3.0", - "escodegen": "^1.6.1", - "html-encoding-sniffer": "^1.0.1", - "nwmatcher": ">= 1.3.9 < 2.0.0", - "parse5": "^1.5.1", - "request": "^2.79.0", - "sax": "^1.2.1", - "symbol-tree": "^3.2.1", - "tough-cookie": "^2.3.2", - "webidl-conversions": "^4.0.0", - "whatwg-encoding": "^1.0.1", - "whatwg-url": "^4.3.0", - "xml-name-validator": "^2.0.1" - } - }, - "jsdom-global": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/jsdom-global/-/jsdom-global-2.1.1.tgz", - "integrity": "sha512-nVZiKQhXZzmkFSF+AfpvErIYuzPEuBV684gYpWagtwWTLiy0p5EgQbP7gmNNA6/qxFb8l1E5w1NjES5nSBCw5A==", - "dev": true - }, - "jsdom-url": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/jsdom-url/-/jsdom-url-2.2.1.tgz", - "integrity": "sha512-+wha7QGq/vPR97R/wz5+213pyWP1362/xmAMmesyVgxyTFOfAeKtwPah+f2znabdNdcqOPbyM7j/xWHbXAqhmg==", - "dev": true, - "requires": { - "class-proxy": "^1.1.1", - "whatwg-url": "^7.0.0" + "cssstyle": "^4.2.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.4.3", + "form-data": "^4.0.1", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.16", + "parse5": "^7.2.1", + "rrweb-cssom": "^0.8.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.1.0", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" }, "dependencies": { "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz", + "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==", "dev": true, "requires": { - "punycode": "^2.1.0" + "punycode": "^2.3.1" } }, + "webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true + }, "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", + "integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", "dev": true, "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" + "tr46": "^5.0.0", + "webidl-conversions": "^7.0.0" } } } }, - "json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true - }, - "jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "jsdom-global": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsdom-global/-/jsdom-global-3.0.2.tgz", + "integrity": "sha512-t1KMcBkz/pT5JrvcJbpUR2u/w1kO9jXctaaGJ0vZDzwFnIvGWw9IDSRciT83kIs8Bnw4qpOl8bQK08V01YgMPg==", "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - } + "requires": {} }, "jsverify": { "version": "0.8.4", @@ -1449,20 +1075,10 @@ "integrity": "sha512-AQ4vRcnULa7FX6R6YTAjKQAE1MuEThidVQm0TEtTpedaBpnOwid5k6go16E5NDkafel1xAsZL73WkwdG03IzhA==", "dev": true }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true }, "mime-db": { @@ -1480,69 +1096,40 @@ "mime-db": "1.52.0" } }, - "nwmatcher": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.4.tgz", - "integrity": "sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ==", + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "nwsapi": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.16.tgz", + "integrity": "sha512-F1I/bimDpj3ncaNDhfyMWuFqmQDBwDB0Fogc2qpL3BWvkQteFD/8BzWuIRl83rq0DXfm8SGt/HFhLXZyljTXcQ==", "dev": true }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, "parse5": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz", - "integrity": "sha512-w2jx/0tJzvgKwZa58sj2vAYq/S/K1QJfIB3cWYea/Iu1scFPDQQ3IQiVZTHWtRBwAjv2Yd7S/xeZf3XqLDb3bA==", - "dev": true - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==", - "dev": true - }, - "psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "dev": true, + "requires": { + "entities": "^4.5.0" + } }, "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true }, "pvtsutils": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.2.tgz", - "integrity": "sha512-+Ipe2iNUyrZz+8K/2IOo+kKikdtfhRKzNpQbruF2URmqPtoqAs8g3xS7TJvFF2GcPXjh7DkqMnpVveRFq4PgEQ==", + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", "dev": true, "requires": { - "tslib": "^2.4.0" + "tslib": "^2.8.1" } }, "pvutils": { @@ -1551,50 +1138,16 @@ "integrity": "sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ==", "dev": true }, - "qs": { - "version": "6.5.3", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", - "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", - "dev": true - }, "rc4": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/rc4/-/rc4-0.1.5.tgz", "integrity": "sha512-xdDTNV90z5x5u25Oc871Xnvu7yAr4tV7Eluh0VSvrhUkry39q1k+zkz7xroqHbRq+8PiazySHJPArqifUvz9VA==", "dev": true }, - "request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - } - }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", "dev": true }, "safer-buffer": { @@ -1603,34 +1156,13 @@ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "optional": true - }, - "sshpk": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", - "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" + "xmlchars": "^2.2.0" } }, "symbol-tree": { @@ -1639,22 +1171,30 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "tldts": { + "version": "6.1.77", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.77.tgz", + "integrity": "sha512-lBpoWgy+kYmuXWQ83+R7LlJCnsd9YW8DGpZSHhrMl4b8Ly/1vzOie3OdtmUJDkKxcgRGOehDu5btKkty+JEe+g==", "dev": true, "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "tldts-core": "^6.1.77" } }, - "tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "tldts-core": { + "version": "6.1.77", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.77.tgz", + "integrity": "sha512-bCaqm24FPk8OgBkM0u/SrEWJgHnhBWYqeBo6yUmcZJDCHt/IfyWBb+14CXdGi4RInMv4v7eUAin15W0DoA+Ytg==", "dev": true }, + "tough-cookie": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.1.tgz", + "integrity": "sha512-Ek7HndSVkp10hmHP9V4qZO1u+pn1RU5sI0Fw+jCU3lyvuMZcgqsNgc6CmJJZyByK4Vm/qotGRJlfgAX8q+4JiA==", + "dev": true, + "requires": { + "tldts": "^6.1.32" + } + }, "trampa": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/trampa/-/trampa-1.0.1.tgz", @@ -1662,123 +1202,71 @@ "dev": true }, "tslib": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", - "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "dev": true }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, "typify-parser": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/typify-parser/-/typify-parser-1.1.0.tgz", "integrity": "sha512-p5+L1sc6Al3bcStMwiZNxDh4ii4JxL+famEbSIUuOUMVoNn9Nz27AT1jL3x7poMHxqKK0UQIUAp5lGkKbyKkFA==", "dev": true }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", "dev": true, "requires": { - "punycode": "^2.1.0" - } - }, - "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "xml-name-validator": "^5.0.0" } }, "webcrypto-core": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.7.5.tgz", - "integrity": "sha512-gaExY2/3EHQlRNNNVSrbG2Cg94Rutl7fAaKILS1w8ZDhGxdFOaw6EbCfHIxPy9vt/xwp5o0VQAx9aySPF6hU1A==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/webcrypto-core/-/webcrypto-core-1.8.1.tgz", + "integrity": "sha512-P+x1MvlNCXlKbLSOY4cYrdreqPG5hbzkmawbcXLKN/mf6DZW0SdNNkZ+sjwsqVkI4A4Ko2sPZmkZtCKY58w83A==", "dev": true, "requires": { - "@peculiar/asn1-schema": "^2.1.6", + "@peculiar/asn1-schema": "^2.3.13", "@peculiar/json-schema": "^1.1.12", - "asn1js": "^3.0.1", - "pvtsutils": "^1.3.2", - "tslib": "^2.4.0" + "asn1js": "^3.0.5", + "pvtsutils": "^1.3.5", + "tslib": "^2.7.0" } }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", "dev": true, "requires": { - "iconv-lite": "0.4.24" + "iconv-lite": "0.6.3" } }, - "whatwg-url": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-4.8.0.tgz", - "integrity": "sha512-nUvUPuenPFtPfy/X+dAYh/TfRbTBlnXTM5iIfLseJFkkQewmpG9pGR6i87E9qL+lZaJzv+99kkQWoGOtLfkZQQ==", - "dev": true, - "requires": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - }, - "dependencies": { - "webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - } - } - }, - "word-wrap": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz", - "integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==", + "whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", "dev": true }, + "ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "requires": {} + }, "xml-name-validator": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz", - "integrity": "sha512-jRKe/iQYMyVJpzPH+3HL97Lgu5HrCfii+qSo+TfjKHtOnvbnvdVfMYrn9Q34YV81M2e5sviJlI6Ko9y+nByzvA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true + }, + "xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true } } diff --git a/js/package.json b/js/package.json index 000498e2..c851e9ee 100644 --- a/js/package.json +++ b/js/package.json @@ -1,18 +1,16 @@ { "name": "privatebin", - "version": "1.7.5", + "version": "1.7.8", "description": "PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted in the browser using 256 bit AES in Galois Counter mode (GCM).", "main": "privatebin.js", "directories": { "test": "test" }, - "dependencies": {}, "devDependencies": { - "jsdom": "^9.12.0", - "jsdom-global": "^2.1.1", - "jsdom-url": "^2.2.1", - "jsverify": "^0.8.3", - "@peculiar/webcrypto": "^1.1.1" + "@peculiar/webcrypto": "^1.5.0", + "jsdom": "^26.0.0", + "jsdom-global": "^3.0.2", + "jsverify": "^0.8.3" }, "scripts": { "test": "mocha", diff --git a/js/privatebin.js b/js/privatebin.js index 8167d805..042c9ddb 100644 --- a/js/privatebin.js +++ b/js/privatebin.js @@ -58,7 +58,6 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ const purifyHtmlConfig = { ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|magnet):)/i, - SAFE_FOR_JQUERY: true, USE_PROFILES: { html: true } @@ -592,6 +591,32 @@ jQuery.PrivateBin = (function($, RawDeflate) { return expirationDate; }; + /** + * Convert Bytes to KiB/MiB/GiB + * + * @name Helper.formatBytes + * @function + * + * @param {number} bytes + * @return {string} + */ + me.formatBytes = function (bytes) + { + let result = ''; + const kilobyte = 1024; + const decimalPoint = 2; + const sizes = [I18n._('B'), I18n._('KiB'), I18n._('MiB'), I18n._('GiB')]; + const index = Math.floor(Math.log(bytes) / Math.log(kilobyte)); + + if (bytes > 0) { + result = parseFloat((bytes / Math.pow(kilobyte, index)).toFixed(decimalPoint)) + ' ' + sizes[index]; + } else { + result = `0 ${I18n._('B')}`; + } + + return result; + } + /** * resets state, used for unit testing * @@ -603,6 +628,17 @@ jQuery.PrivateBin = (function($, RawDeflate) { baseUri = null; }; + /** + * check if bootstrap5 object detected + * + * @name Helper.isBootstrap5 + * @returns {Boolean} + */ + me.isBootstrap5 = function () + { + return typeof bootstrap !== 'undefined'; + }; + return me; })(); @@ -757,14 +793,14 @@ jQuery.PrivateBin = (function($, RawDeflate) { args[0] = translations[messageId]; } - // messageID may contain links, but should be from a trusted source (code or translation JSON files) - let containsLinks = args[0].indexOf(' 0) may never contain HTML as they may come from untrusted parties - if ((containsLinks ? i > 1 : i > 0) || !containsLinks) { + if ((containsHtml ? i > 1 : i > 0) || !containsHtml) { args[i] = Helper.htmlEntities(args[i]); } } @@ -772,11 +808,11 @@ jQuery.PrivateBin = (function($, RawDeflate) { // format string let output = Helper.sprintf.apply(this, args); - if (containsLinks) { + if (containsHtml) { // only allow tags/attributes we actually use in translations output = DOMPurify.sanitize( output, { - ALLOWED_TAGS: ['a', 'i', 'span'], + ALLOWED_TAGS: ['a', 'i', 'span', 'kbd'], ALLOWED_ATTR: ['href', 'id'] } ); @@ -784,7 +820,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { // if $element is given, insert translation if ($element !== null) { - if (containsLinks) { + if (containsHtml) { $element.html(output); } else { // text node takes care of entity encoding @@ -914,6 +950,25 @@ jQuery.PrivateBin = (function($, RawDeflate) { translations = mockTranslations || {}; }; + /** + * Check if string contains valid HTML code + * + * @name I18n.isStringContainsHtml + * @function + * @private + * @param {string} messageId + * @returns {boolean} + */ + function isStringContainsHtml(messageId) { + // An integer which specifies the type of the node. An Element node like

or

. + const elementNodeType = 1; + + const div = document.createElement('div'); + div.innerHTML = messageId; + + return Array.from(div.childNodes).some(node => node.nodeType === elementNodeType); + } + return me; })(); @@ -2092,7 +2147,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { { I18n._( $('#pastelink'), - 'Your paste is %s (Hit [Ctrl]+[c] to copy)', + 'Your paste is %s (Hit Ctrl+c to copy)', url, url ); // save newly created element @@ -2101,8 +2156,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { $pasteUrl.click(pasteLinkClick); // delete link - $('#deletelink').html(''); - I18n._($('#deletelink a').first(), 'Delete data'); + $('#deletelink').attr('href', deleteUrl); + I18n._($('#deletelink span').not('.glyphicon').first(), 'Delete data'); // enable shortener button $shortenButton.removeClass('buttondisabled'); @@ -2237,8 +2292,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { const me = {}; let $passwordDecrypt, - $passwordForm, $passwordModal, + bootstrap5PasswordModal = null, password = ''; /** @@ -2257,7 +2312,11 @@ jQuery.PrivateBin = (function($, RawDeflate) { password = $passwordDecrypt.val(); // hide modal - $passwordModal.modal('hide'); + if (bootstrap5PasswordModal) { + bootstrap5PasswordModal.hide(); + } else { + $passwordModal.modal('hide'); + } PasteDecrypter.run(); } @@ -2271,22 +2330,19 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.requestLoadConfirmation = function() { const $loadconfirmmodal = $('#loadconfirmmodal'); - if ($loadconfirmmodal.length > 0) { - const $loadconfirmOpenNow = $loadconfirmmodal.find('#loadconfirm-open-now'); - $loadconfirmOpenNow.off('click.loadPaste'); - $loadconfirmOpenNow.on('click.loadPaste', PasteDecrypter.run); - const $loadconfirmClose = $loadconfirmmodal.find('.close'); - $loadconfirmClose.off('click.close'); - $loadconfirmClose.on('click.close', Controller.newPaste); - $loadconfirmmodal.modal('show'); + + const $loadconfirmOpenNow = $loadconfirmmodal.find('#loadconfirm-open-now'); + $loadconfirmOpenNow.off('click.loadPaste'); + $loadconfirmOpenNow.on('click.loadPaste', PasteDecrypter.run); + + const $loadconfirmClose = $loadconfirmmodal.find('.close'); + $loadconfirmClose.off('click.close'); + $loadconfirmClose.on('click.close', Controller.newPaste); + + if (typeof bootstrap !== 'undefined' && bootstrap.Tooltip.VERSION) { + (new bootstrap.Modal($loadconfirmmodal[0])).show(); } else { - if (window.confirm( - I18n._('This secret message can only be displayed once. Would you like to see it now?') - )) { - PasteDecrypter.run(); - } else { - Controller.newPaste(); - } + $loadconfirmmodal.modal('show'); } } @@ -2300,29 +2356,14 @@ jQuery.PrivateBin = (function($, RawDeflate) { { // show new bootstrap method (if available) if ($passwordModal.length !== 0) { - $passwordModal.modal({ - backdrop: 'static', - keyboard: false - }); - $passwordModal.modal('show'); - // focus password input - $passwordDecrypt.focus(); - // then re-focus it, when modal causes it to loose focus again - setTimeout(function () { - $passwordDecrypt.focus(); - }, 500); + if (bootstrap5PasswordModal) { + bootstrap5PasswordModal.show(); + } else { + $passwordModal.modal('show'); + } return; } - // fallback to old method for page template - password = prompt(I18n._('Please enter the password for this paste:'), ''); - if (password === null) { - throw 'password prompt canceled'; - } - if (password.length === 0) { - // recurse… - return me.requestPassword(); - } PasteDecrypter.run(); }; @@ -2354,7 +2395,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { // and also reset UI $passwordDecrypt.val(''); - } + }; /** * init status manager @@ -2367,11 +2408,26 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.init = function() { $passwordDecrypt = $('#passworddecrypt'); - $passwordForm = $('#passwordform'); $passwordModal = $('#passwordmodal'); // bind events - handle Model password submission - $passwordForm.submit(submitPasswordModal); + if ($passwordModal.length !== 0) { + $('#passwordform').submit(submitPasswordModal); + + const disableClosingConfig = { + backdrop: 'static', + keyboard: false, + show: false + }; + if (typeof bootstrap !== 'undefined' && bootstrap.Tooltip.VERSION) { + bootstrap5PasswordModal = new bootstrap.Modal($passwordModal[0], disableClosingConfig); + } else { + $passwordModal.modal(disableClosingConfig); + } + $passwordModal.on('shown.bs.modal', () => { + $passwordDecrypt.focus(); + }); + } }; return me; @@ -2393,8 +2449,11 @@ jQuery.PrivateBin = (function($, RawDeflate) { $messageEditParent, $messagePreview, $messagePreviewParent, + $messageTab, + $messageTabParent, $message, - isPreview = false; + isPreview = false, + isTabSupported = true; /** * support input of tab character @@ -2406,9 +2465,13 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ function supportTabs(event) { - const keyCode = event.keyCode || event.which; - // tab was pressed - if (keyCode === 9) { + // support disabling tab support using [Esc] and [Ctrl]+[m] + if (event.key === 'Escape' || (event.ctrlKey && event.key === 'm')) { + toggleTabSupport(); + $messageTab[0].checked = isTabSupported; + event.preventDefault(); + } + else if (isTabSupported && event.key === 'Tab') { // get caret position & selection const val = this.value, start = this.selectionStart, @@ -2422,6 +2485,18 @@ jQuery.PrivateBin = (function($, RawDeflate) { } } + /** + * toggle tab support in message textarea + * + * @name Editor.toggleTabSupport + * @private + * @function + */ + function toggleTabSupport() + { + isTabSupported = !isTabSupported; + } + /** * view the Editor tab * @@ -2444,6 +2519,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { // reshow input $message.removeClass('hidden'); + $messageTabParent.removeClass('hidden'); me.focusInput(); @@ -2476,15 +2552,23 @@ jQuery.PrivateBin = (function($, RawDeflate) { // hide input as now preview is shown $message.addClass('hidden'); + $messageTabParent.addClass('hidden'); // show preview PasteViewer.setText($message.val()); if (AttachmentViewer.hasAttachmentData()) { - const attachment = AttachmentViewer.getAttachment(); - AttachmentViewer.handleBlobAttachmentPreview( - AttachmentViewer.getAttachmentPreview(), - attachment[0], attachment[1] - ); + const attachmentsData = AttachmentViewer.getAttachmentsData(); + + attachmentsData.forEach(attachmentData => { + const mimeType = AttachmentViewer.getAttachmentMimeType(attachmentData); + + AttachmentViewer.handleBlobAttachmentPreview( + AttachmentViewer.getAttachmentPreview(), + attachmentData, mimeType + ); + }); + + AttachmentViewer.showAttachment(); } PasteViewer.run(); @@ -2534,6 +2618,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.show = function() { $message.removeClass('hidden'); + $messageTabParent.removeClass('hidden'); $editorTabs.removeClass('hidden'); }; @@ -2546,6 +2631,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.hide = function() { $message.addClass('hidden'); + $messageTabParent.addClass('hidden'); $editorTabs.addClass('hidden'); }; @@ -2585,7 +2671,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { }; /** - * init status manager + * init editor * * preloads jQuery elements * @@ -2596,9 +2682,12 @@ jQuery.PrivateBin = (function($, RawDeflate) { { $editorTabs = $('#editorTabs'); $message = $('#message'); + $messageTab = $('#messagetab'); + $messageTabParent = $messageTab.parent(); // bind events $message.keydown(supportTabs); + $messageTab.change(toggleTabSupport); // bind click events to tab switchers (a), and save parents (li) $messageEdit = $('#messageedit').click(viewEditor); @@ -2619,7 +2708,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { const PasteViewer = (function () { const me = {}; - let $placeholder, + let $messageTabParent, + $placeholder, $prettyMessage, $prettyPrint, $plainText, @@ -2699,6 +2789,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { } // otherwise hide the placeholder $placeholder.addClass('hidden'); + $messageTabParent.addClass('hidden'); if (format === 'markdown') { $plainText.removeClass('hidden'); @@ -2837,6 +2928,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ me.init = function() { + $messageTabParent = $('#messagetab').parent(); $placeholder = $('#placeholder'); $plainText = $('#plaintext'); $prettyMessage = $('#prettymessage'); @@ -2861,14 +2953,12 @@ jQuery.PrivateBin = (function($, RawDeflate) { const AttachmentViewer = (function () { const me = {}; - let $attachmentLink, - $attachmentPreview, + let $attachmentPreview, $attachment, - attachmentData, - file, + attachmentsData = [], + files, $fileInput, - $dragAndDropFileName, - attachmentHasPreview = false, + $dragAndDropFileNames, $dropzone; /** @@ -2910,26 +3000,30 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.setAttachment = function(attachmentData, fileName) { // skip, if attachments got disabled - if (!$attachmentLink || !$attachmentPreview) return; + if (!$attachment || !$attachmentPreview) return; // data URI format: data:[][;base64], + const template = Model.getTemplate('attachment'); + const attachmentLink = template.find('a'); + // position in data URI string of where data begins const base64Start = attachmentData.indexOf(',') + 1; - // position in data URI string of where mimeType ends - const mimeTypeEnd = attachmentData.indexOf(';'); - // extract mimeType - const mimeType = attachmentData.substring(5, mimeTypeEnd); + const mimeType = me.getAttachmentMimeType(attachmentData); + // extract data and convert to binary const rawData = attachmentData.substring(base64Start); const decodedData = rawData.length > 0 ? atob(rawData) : ''; let blobUrl = getBlobUrl(decodedData, mimeType); - $attachmentLink.attr('href', blobUrl); + attachmentLink.attr('href', blobUrl); if (typeof fileName !== 'undefined') { - $attachmentLink.attr('download', fileName); + attachmentLink.attr('download', fileName); + + const fileSize = Helper.formatBytes(decodedData.length); + template.append(`(${fileName}, ${fileSize})`); } // sanitize SVG preview @@ -2944,6 +3038,9 @@ jQuery.PrivateBin = (function($, RawDeflate) { blobUrl = getBlobUrl(sanitizedData, mimeType); } + template.removeClass('hidden'); + $attachment.append(template); + me.handleBlobAttachmentPreview($attachmentPreview, blobUrl, mimeType); }; @@ -2960,7 +3057,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { $attachment.removeClass('hidden'); - if (attachmentHasPreview) { + if (me.hasAttachmentPreview()) { $attachmentPreview.removeClass('hidden'); } }; @@ -2981,11 +3078,9 @@ jQuery.PrivateBin = (function($, RawDeflate) { } me.hideAttachment(); me.hideAttachmentPreview(); - $attachmentLink.removeAttr('href'); - $attachmentLink.removeAttr('download'); - $attachmentLink.off('click'); + $attachment.html(''); $attachmentPreview.html(''); - $dragAndDropFileName.text(''); + $dragAndDropFileNames.html(''); AttachmentViewer.removeAttachmentData(); }; @@ -3000,8 +3095,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ me.removeAttachmentData = function() { - file = undefined; - attachmentData = undefined; + files = undefined; + attachmentsData = []; }; /** @@ -3012,9 +3107,21 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ me.clearDragAndDrop = function() { - $dragAndDropFileName.text(''); + $dragAndDropFileNames.html(''); }; + /** + * Print file names added via drag & drop + * + * @name AttachmentViewer.printDragAndDropFileNames + * @private + * @function + * @param {array} fileNames + */ + function printDragAndDropFileNames(fileNames) { + $dragAndDropFileNames.html(fileNames.join("
")); + } + /** * hides the attachment * @@ -3043,6 +3150,18 @@ jQuery.PrivateBin = (function($, RawDeflate) { } }; + /** + * checks if has any attachment preview + * + * @name AttachmentViewer.hasAttachmentPreview + * @function + * @return {JQuery} + */ + me.hasAttachmentPreview = function() + { + return $attachmentPreview.children().length > 0; + } + /** * checks if there is an attachment displayed * @@ -3054,8 +3173,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { if (!$attachment.length) { return false; } - const link = $attachmentLink.prop('href'); - return (typeof link !== 'undefined' && link !== ''); + return [...$attachment.children()].length > 0; }; /** @@ -3075,20 +3193,38 @@ jQuery.PrivateBin = (function($, RawDeflate) { }; /** - * return the attachment + * return the attachments * - * @name AttachmentViewer.getAttachment + * @name AttachmentViewer.getAttachments * @function * @returns {array} */ - me.getAttachment = function() + me.getAttachments = function() { - return [ - $attachmentLink.prop('href'), - $attachmentLink.prop('download') - ]; + return [...$attachment.find('a')].map(link => ( + [ + $(link).prop('href'), + $(link).prop('download') + ] + )); }; + /** + * Get attachment mime type + * + * @name AttachmentViewer.getAttachmentMimeType + * @function + * @param {string} attachmentData - Base64 string + */ + me.getAttachmentMimeType = function(attachmentData) + { + // position in data URI string of where mimeType ends + const mimeTypeEnd = attachmentData.indexOf(';'); + + // extract mimeType + return attachmentData.substring(5, mimeTypeEnd); + } + /** * moves the attachment link to another element * @@ -3097,27 +3233,36 @@ jQuery.PrivateBin = (function($, RawDeflate) { * @name AttachmentViewer.moveAttachmentTo * @function * @param {jQuery} $element - the wrapper/container element where this should be moved to + * @param {array} attachment - attachment data * @param {string} label - the text to show (%s will be replaced with the file name), will automatically be translated */ - me.moveAttachmentTo = function($element, label) + me.moveAttachmentTo = function($element, attachment, label) { + const attachmentLink = $(document.createElement('a')) + .addClass('alert-link') + .prop('href', attachment[0]) + .prop('download', attachment[1]); + // move elemement to new place - $attachmentLink.appendTo($element); + attachmentLink.appendTo($element); // update text - ensuring no HTML is inserted into the text node - I18n._($attachmentLink, label, $attachmentLink.attr('download')); + I18n._(attachmentLink, label, attachment[1]); }; /** - * read file data as data URL using the FileReader API + * read files data as data URL using the FileReader API * * @name AttachmentViewer.readFileData * @private * @function - * @param {object} loadedFile (optional) loaded file object + * @param {FileList[]} loadedFiles (optional) loaded files array * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/FileReader#readAsDataURL()} */ - function readFileData(loadedFile) { + function readFileData(loadedFiles) { + // Clear old cache + me.removeAttachmentData(); + if (typeof FileReader === 'undefined') { // revert loading status… me.hideAttachment(); @@ -3126,28 +3271,35 @@ jQuery.PrivateBin = (function($, RawDeflate) { return; } - const fileReader = new FileReader(); - if (loadedFile === undefined) { - loadedFile = $fileInput[0].files[0]; - $dragAndDropFileName.text(''); + if (loadedFiles === undefined) { + loadedFiles = [...$fileInput[0].files]; + me.clearDragAndDrop(); } else { - $dragAndDropFileName.text(loadedFile.name); + const fileNames = loadedFiles.map((loadedFile => loadedFile.name)); + printDragAndDropFileNames(fileNames); } - if (typeof loadedFile !== 'undefined') { - file = loadedFile; - fileReader.onload = function (event) { - const dataURL = event.target.result; - attachmentData = dataURL; + if (typeof loadedFiles !== 'undefined') { + files = loadedFiles; + loadedFiles.forEach((loadedFile, index) => { + const fileReader = new FileReader(); - if (Editor.isPreview()) { - me.handleAttachmentPreview($attachmentPreview, dataURL); - $attachmentPreview.removeClass('hidden'); - } + fileReader.onload = function (event) { + const dataURL = event.target.result; + if (dataURL) { + attachmentsData[index] = dataURL; + } - TopNav.highlightFileupload(); - }; - fileReader.readAsDataURL(loadedFile); + if (Editor.isPreview()) { + me.handleAttachmentPreview($attachmentPreview, dataURL); + $attachmentPreview.removeClass('hidden'); + } + + TopNav.highlightFileupload(); + }; + + fileReader.readAsDataURL(loadedFile); + }); } else { me.removeAttachmentData(); } @@ -3163,16 +3315,17 @@ jQuery.PrivateBin = (function($, RawDeflate) { * @argument {string} mime type */ me.handleBlobAttachmentPreview = function ($targetElement, blobUrl, mimeType) { - if (blobUrl) { - attachmentHasPreview = true; + const alreadyIncludesCurrentAttachment = $targetElement.find(`[src='${blobUrl}']`).length > 0; + + if (blobUrl && !alreadyIncludesCurrentAttachment) { if (mimeType.match(/^image\//i)) { - $targetElement.html( + $targetElement.append( $(document.createElement('img')) .attr('src', blobUrl) .attr('class', 'img-thumbnail') ); } else if (mimeType.match(/^video\//i)) { - $targetElement.html( + $targetElement.append( $(document.createElement('video')) .attr('controls', 'true') .attr('autoplay', 'true') @@ -3183,7 +3336,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { .attr('src', blobUrl)) ); } else if (mimeType.match(/^audio\//i)) { - $targetElement.html( + $targetElement.append( $(document.createElement('audio')) .attr('controls', 'true') .attr('autoplay', 'true') @@ -3196,15 +3349,13 @@ jQuery.PrivateBin = (function($, RawDeflate) { // Fallback for browsers, that don't support the vh unit const clientHeight = $(window).height(); - $targetElement.html( + $targetElement.append( $(document.createElement('embed')) .attr('src', blobUrl) .attr('type', 'application/pdf') .attr('class', 'pdfPreview') .css('height', clientHeight) ); - } else { - attachmentHasPreview = false; } } }; @@ -3237,14 +3388,14 @@ jQuery.PrivateBin = (function($, RawDeflate) { } if ($fileInput) { - const file = evt.dataTransfer.files[0]; + const files = [...evt.dataTransfer.files]; //Clear the file input: $fileInput.wrap('
').closest('form').get(0).reset(); $fileInput.unwrap(); //Only works in Chrome: //fileInput[0].files = e.dataTransfer.files; - readFileData(file); + readFileData(files); } }; @@ -3281,16 +3432,17 @@ jQuery.PrivateBin = (function($, RawDeflate) { function addClipboardEventHandler() { $(document).on('paste', function (event) { const items = (event.clipboardData || event.originalEvent.clipboardData).items; - const lastItem = items[items.length - 1]; - if (lastItem.kind === 'file') { - if (TopNav.isAttachmentReadonly()) { - event.stopPropagation(); - event.preventDefault(); - return false; - } else { - readFileData(lastItem.getAsFile()); - } + const files = [...items] + .filter(item => item.kind === 'file') + .map(item => item.getAsFile()); + + if (TopNav.isAttachmentReadonly()) { + event.stopPropagation(); + event.preventDefault(); + return false; } + + readFileData(files); }); } @@ -3298,23 +3450,12 @@ jQuery.PrivateBin = (function($, RawDeflate) { /** * getter for attachment data * - * @name AttachmentViewer.getAttachmentData + * @name AttachmentViewer.getAttachmentsData * @function - * @return {jQuery} + * @return {string[]} */ - me.getAttachmentData = function () { - return attachmentData; - }; - - /** - * getter for attachment link - * - * @name AttachmentViewer.getAttachmentLink - * @function - * @return {jQuery} - */ - me.getAttachmentLink = function () { - return $attachmentLink; + me.getAttachmentsData = function () { + return attachmentsData; }; /** @@ -3329,14 +3470,14 @@ jQuery.PrivateBin = (function($, RawDeflate) { }; /** - * getter for file data, returns the file contents + * getter for files data, returns the file list * - * @name AttachmentViewer.getFile + * @name AttachmentViewer.getFiles * @function - * @return {string} + * @return {FileList[]} */ - me.getFile = function () { - return file; + me.getFiles = function () { + return files; }; /** @@ -3350,9 +3491,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.init = function() { $attachment = $('#attachment'); - $dragAndDropFileName = $('#dragAndDropFileName'); + $dragAndDropFileNames = $('#dragAndDropFileName'); $dropzone = $('#dropzone'); - $attachmentLink = $('#attachment a') || $(''); if($attachment.length) { $attachmentPreview = $('#attachmentPreview'); @@ -3413,6 +3553,12 @@ jQuery.PrivateBin = (function($, RawDeflate) { { const $source = $(event.target); + // show all reply buttons + $commentContainer.find('button').removeClass('hidden'); + + // hide the current reply button + $source.addClass('hidden'); + // clear input $replyMessage.val(''); $replyNickname.val(''); @@ -3768,7 +3914,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { /** * Clear the password input in the top navigation - * + * * @name TopNav.clearPasswordInput * @function */ @@ -3868,8 +4014,27 @@ jQuery.PrivateBin = (function($, RawDeflate) { */ function setLanguage(event) { - document.cookie = 'lang=' + $(event.target).data('lang') + '; SameSite=Lax; Secure'; - UiHelper.reloadHome(); + let lang = $(event.target).data('lang') || event.target.value; + + 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(); event.preventDefault(); } @@ -3940,10 +4105,6 @@ jQuery.PrivateBin = (function($, RawDeflate) { text: window.location.href }); $('#qrcode-display').html(qrCanvas); - // only necessary for bootstrap 5, other templates won't have this - if (bootstrap.Tooltip.VERSION) { - $('#qrcodemodal').modal('show'); - } } /** @@ -4028,45 +4189,42 @@ jQuery.PrivateBin = (function($, RawDeflate) { expirationDateRoundedToSecond.setUTCSeconds(0); const $emailconfirmmodal = $('#emailconfirmmodal'); - if ($emailconfirmmodal.length > 0) { - if (expirationDate !== null) { - const $emailconfirmTimezoneCurrent = $emailconfirmmodal.find('#emailconfirm-timezone-current'); - const $emailconfirmTimezoneUtc = $emailconfirmmodal.find('#emailconfirm-timezone-utc'); - $emailconfirmTimezoneCurrent.off('click.sendEmailCurrentTimezone'); - $emailconfirmTimezoneCurrent.on('click.sendEmailCurrentTimezone', () => { - const emailBody = templateEmailBody(expirationDateRoundedToSecond.toLocaleString(), isBurnafterreading); + if (expirationDate !== null) { + const $emailconfirmTimezoneCurrent = $emailconfirmmodal.find('#emailconfirm-timezone-current'); + const $emailconfirmTimezoneUtc = $emailconfirmmodal.find('#emailconfirm-timezone-utc'); + let localeConfiguration = { dateStyle: 'long', timeStyle: 'long' }; + const bootstrap5EmailConfirmModal = typeof bootstrap !== 'undefined' && bootstrap.Tooltip.VERSION ? + new bootstrap.Modal($emailconfirmmodal[0]) : null; + + function sendEmailAndHideModal() { + const emailBody = templateEmailBody( + // we don't use Date.prototype.toUTCString() because we would like to avoid GMT + expirationDateRoundedToSecond.toLocaleString( + [], localeConfiguration + ), isBurnafterreading + ); + if (bootstrap5EmailConfirmModal) { + bootstrap5EmailConfirmModal.hide(); + } else { $emailconfirmmodal.modal('hide'); - triggerEmailSend(emailBody); - }); - $emailconfirmTimezoneUtc.off('click.sendEmailUtcTimezone'); - $emailconfirmTimezoneUtc.on('click.sendEmailUtcTimezone', () => { - const emailBody = templateEmailBody(expirationDateRoundedToSecond.toLocaleString( - undefined, - // we don't use Date.prototype.toUTCString() because we would like to avoid GMT - { timeZone: 'UTC', dateStyle: 'long', timeStyle: 'long' } - ), isBurnafterreading); - $emailconfirmmodal.modal('hide'); - triggerEmailSend(emailBody); - }); - $emailconfirmmodal.modal('show'); + } + triggerEmailSend(emailBody); + }; + + $emailconfirmTimezoneCurrent.off('click.sendEmailCurrentTimezone'); + $emailconfirmTimezoneCurrent.on('click.sendEmailCurrentTimezone', sendEmailAndHideModal); + $emailconfirmTimezoneUtc.off('click.sendEmailUtcTimezone'); + $emailconfirmTimezoneUtc.on('click.sendEmailUtcTimezone', () => { + localeConfiguration.timeZone = 'UTC'; + sendEmailAndHideModal(); + }); + if (bootstrap5EmailConfirmModal) { + bootstrap5EmailConfirmModal.show(); } else { - triggerEmailSend(templateEmailBody(null, isBurnafterreading)); + $emailconfirmmodal.modal('show'); } } else { - let emailBody = ''; - if (expirationDate !== null) { - const expirationDateString = window.confirm( - I18n._('Recipient may become aware of your timezone, convert time to UTC?') - ) ? expirationDateRoundedToSecond.toLocaleString( - undefined, - // we don't use Date.prototype.toUTCString() because we would like to avoid GMT - { timeZone: 'UTC', dateStyle: 'long', timeStyle: 'long' } - ) : expirationDateRoundedToSecond.toLocaleString(); - emailBody = templateEmailBody(expirationDateString, isBurnafterreading); - } else { - emailBody = templateEmailBody(null, isBurnafterreading); - } - triggerEmailSend(emailBody); + triggerEmailSend(templateEmailBody(null, isBurnafterreading)); } } @@ -4485,7 +4643,11 @@ jQuery.PrivateBin = (function($, RawDeflate) { // visually indicate file uploaded const $attachDropdownToggle = $attach.children('.dropdown-toggle'); if ($attachDropdownToggle.attr('aria-expanded') === 'false') { - $attachDropdownToggle.click(); + if (Helper.isBootstrap5()) { + new bootstrap.Dropdown($attachDropdownToggle).toggle(); + } else { + $attachDropdownToggle.click(); + } } $fileWrap.addClass('highlight'); setTimeout(function () { @@ -4549,8 +4711,9 @@ jQuery.PrivateBin = (function($, RawDeflate) { // bootstrap template drop down $('#language ul.dropdown-menu li a').click(setLanguage); - // page template drop down - $('#language select option').click(setLanguage); + + // bootstrap template drop down + $('#template ul.dropdown-menu li a').click(setTemplate); // bind events $burnAfterReading.change(changeBurnAfterReading); @@ -4629,7 +4792,10 @@ jQuery.PrivateBin = (function($, RawDeflate) { * @readonly * @enum {Object} */ - const ajaxHeaders = {'X-Requested-With': 'JSONHttpRequest'}; + const ajaxHeaders = { + 'X-Requested-With': 'JSONHttpRequest', + 'Content-Type': 'application/json' + }; /** * called after successful upload @@ -4901,6 +5067,9 @@ jQuery.PrivateBin = (function($, RawDeflate) { TopNav.showViewButtons(); + CopyToClipboard.setUrl(url); + CopyToClipboard.showKeyboardShortcutHint(); + // this cannot be grouped with showViewButtons due to remaining time calculation TopNav.showEmailButton(); @@ -5028,7 +5197,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { const plainText = Editor.getText(), format = PasteViewer.getFormat(), // the methods may return different values if no files are attached (null, undefined or false) - files = TopNav.getFileList() || AttachmentViewer.getFile() || AttachmentViewer.hasAttachment(); + files = TopNav.getFileList() || AttachmentViewer.getFiles() || AttachmentViewer.hasAttachment(); // do not send if there is no data if (plainText.length === 0 && !files) { @@ -5068,62 +5237,64 @@ jQuery.PrivateBin = (function($, RawDeflate) { PasteViewer.setFormat(format); // prepare cypher message - let file = AttachmentViewer.getAttachmentData(), + let attachmentsData = AttachmentViewer.getAttachmentsData(), cipherMessage = { 'paste': plainText }; - if (typeof file !== 'undefined' && file !== null) { - cipherMessage['attachment'] = file; - cipherMessage['attachment_name'] = AttachmentViewer.getFile().name; + if (attachmentsData.length) { + cipherMessage['attachment'] = attachmentsData; + cipherMessage['attachment_name'] = AttachmentViewer.getFiles().map((fileInfo => fileInfo.name)); } else if (AttachmentViewer.hasAttachment()) { // fall back to cloned part - let attachment = AttachmentViewer.getAttachment(); - cipherMessage['attachment'] = attachment[0]; - cipherMessage['attachment_name'] = attachment[1]; + let attachments = AttachmentViewer.getAttachments(); + cipherMessage['attachment'] = attachments.map(attachment => attachment[0]); + cipherMessage['attachment_name'] = attachments.map(attachment => attachment[1]); - // we need to retrieve data from blob if browser already parsed it in memory - if (typeof attachment[0] === 'string' && attachment[0].startsWith('blob:')) { - Alert.showStatus( - [ - 'Retrieving cloned file \'%s\' from memory...', - attachment[1] - ], - 'copy' - ); - try { - const blobData = await $.ajax({ - type: 'GET', - url: `${attachment[0]}`, - processData: false, - timeout: 10000, - xhrFields: { - withCredentials: false, - responseType: 'blob' - } - }); - if (blobData instanceof window.Blob) { - const fileReading = new Promise(function(resolve, reject) { - const fileReader = new FileReader(); - fileReader.onload = function (event) { - resolve(event.target.result); - }; - fileReader.onerror = function (error) { - reject(error); + cipherMessage['attachment'] = await Promise.all(cipherMessage['attachment'].map(async (attachment) => { + // we need to retrieve data from blob if browser already parsed it in memory + if (typeof attachment === 'string' && attachment.startsWith('blob:')) { + Alert.showStatus( + [ + 'Retrieving cloned file \'%s\' from memory...', + attachment[1] + ], + 'copy' + ); + try { + const blobData = await $.ajax({ + type: 'GET', + url: `${attachment}`, + processData: false, + timeout: 10000, + xhrFields: { + withCredentials: false, + responseType: 'blob' } - fileReader.readAsDataURL(blobData); }); - cipherMessage['attachment'] = await fileReading; - } else { - const error = 'Cannot process attachment data.'; - Alert.showError(error); - throw new TypeError(error); + if (blobData instanceof window.Blob) { + const fileReading = new Promise(function(resolve, reject) { + const fileReader = new FileReader(); + fileReader.onload = function (event) { + resolve(event.target.result); + }; + fileReader.onerror = function (error) { + reject(error); + } + fileReader.readAsDataURL(blobData); + }); + + return await fileReading; + } else { + const error = 'Cannot process attachment data.'; + Alert.showError(error); + throw new TypeError(error); + } + } catch (error) { + Alert.showError('Cannot retrieve attachment.'); + throw error; } - } catch (error) { - console.error(error); - Alert.showError('Cannot retrieve attachment.'); - throw error; } - } + })); } // encrypt message @@ -5218,7 +5389,15 @@ jQuery.PrivateBin = (function($, RawDeflate) { // version 2 paste const pasteMessage = JSON.parse(pastePlain); if (pasteMessage.hasOwnProperty('attachment') && pasteMessage.hasOwnProperty('attachment_name')) { - AttachmentViewer.setAttachment(pasteMessage.attachment, pasteMessage.attachment_name); + if (Array.isArray(pasteMessage.attachment) && Array.isArray(pasteMessage.attachment_name)) { + pasteMessage.attachment.forEach((attachment, key) => { + const attachment_name = pasteMessage.attachment_name[key]; + AttachmentViewer.setAttachment(attachment, attachment_name); + }); + } else { + // Continue to process attachment parameters as strings to ensure backward compatibility + AttachmentViewer.setAttachment(pasteMessage.attachment, pasteMessage.attachment_name); + } AttachmentViewer.showAttachment(); } pastePlain = pasteMessage.paste; @@ -5309,6 +5488,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.run = function(paste) { Alert.hideMessages(); + Alert.setCustomHandler(null); Alert.showLoading('Decrypting paste…', 'cloud-download'); if (typeof paste === 'undefined' || paste.type === 'click') { @@ -5326,6 +5506,9 @@ jQuery.PrivateBin = (function($, RawDeflate) { me.run(paste); }); + // Clear attachments to prevent duplicates + AttachmentViewer.removeAttachment(); + // decrypt paste & attachments decryptionPromises.push(decryptPaste(paste, key, password)); @@ -5337,6 +5520,8 @@ jQuery.PrivateBin = (function($, RawDeflate) { // shows the remaining time (until) deletion PasteStatus.showRemainingTime(paste); + CopyToClipboard.showKeyboardShortcutHint(); + Promise.all(decryptionPromises) .then(() => { Alert.hideLoading(); @@ -5366,6 +5551,187 @@ jQuery.PrivateBin = (function($, RawDeflate) { return me; })(); + /** + * + * @name CopyToClipboard + * @class + */ + const CopyToClipboard = (function () { + const me = {}; + + let copyButton, + copyLinkButton, + copyIcon, + successIcon, + shortcutHint, + url; + + /** + * Handle copy to clipboard button click + * + * @name CopyToClipboard.handleCopyButtonClick + * @private + * @function + */ + function handleCopyButtonClick() { + $(copyButton).click(function() { + const text = PasteViewer.getText(); + saveToClipboard(text); + + toggleSuccessIcon(); + showAlertMessage('Paste copied to clipboard'); + }); + }; + + /** + * Handle copy link to clipboard button click + * + * @name CopyToClipboard.handleCopyLinkButtonClick + * @private + * @function + */ + function handleCopyLinkButtonClick() { + $(copyLinkButton).click(function () { + saveToClipboard(url); + + showAlertMessage('Link copied to clipboard'); + }); + } + + /** + * Handle CTRL+C/CMD+C keyboard shortcut + * + * @name CopyToClipboard.handleKeyboardShortcut + * @private + * @function + */ + function handleKeyboardShortcut() { + $(document).bind('copy', function () { + if (!isUserSelectedTextToCopy()) { + const text = PasteViewer.getText(); + saveToClipboard(text); + + showAlertMessage('Paste copied to clipboard'); + } + }); + }; + + /** + * Check if user selected some text on the page to copy it + * + * @name CopyToClipboard.isUserSelectedTextToCopy + * @private + * @function + * @returns {boolean} + */ + function isUserSelectedTextToCopy() { + let text = ''; + + if (window.getSelection) { + text = window.getSelection().toString(); + } else if (document.selection && document.selection.type != 'Control') { + text = document.selection.createRange().text; + } + + return text.length > 0; + }; + + /** + * Save text to the clipboard + * + * @name CopyToClipboard.saveToClipboard + * @private + * @param {string} text + * @function + */ + function saveToClipboard(text) { + navigator.clipboard.writeText(text); + }; + + /** + * Show alert message after text copy + * + * @name CopyToClipboard.showAlertMessage + * @private + * @param {string} message + * @function + */ + function showAlertMessage(message) { + Alert.showStatus(message); + }; + + /** + * Toogle success icon after copy + * + * @name CopyToClipboard.toggleSuccessIcon + * @private + * @function + */ + function toggleSuccessIcon() { + $(copyIcon).css('display', 'none'); + $(successIcon).css('display', 'block'); + + setTimeout(function() { + $(copyIcon).css('display', 'block'); + $(successIcon).css('display', 'none'); + }, 1000); + }; + + /** + * Show keyboard shortcut hint + * + * @name CopyToClipboard.showKeyboardShortcutHint + * @function + */ + me.showKeyboardShortcutHint = function () { + I18n._( + shortcutHint, + 'To copy paste press on the copy button or use the clipboard shortcut Ctrl+c/Cmd+c' + ); + }; + + /** + * Hide keyboard shortcut hint + * + * @name CopyToClipboard.showKeyboardShortcutHint + * @function + */ + me.hideKeyboardShortcutHint = function () { + $(shortcutHint).html(''); + }; + + /** + * Set paste url + * + * @name CopyToClipboard.setUrl + * @param {string} newUrl + * @function + */ + me.setUrl = function (newUrl) { + url = newUrl; + }; + + /** + * Initialize + * + * @name CopyToClipboard.init + * @function + */ + me.init = function() { + copyButton = $('#prettyMessageCopyBtn'); + copyLinkButton = $('#copyLink'); + copyIcon = $('#copyIcon'); + successIcon = $('#copySuccessIcon'); + shortcutHint = $('#copyShortcutHintText'); + + handleCopyButtonClick(); + handleCopyLinkButtonClick(); + handleKeyboardShortcut(); + }; + + return me; + })(); + /** * (controller) main PrivateBin logic * @@ -5387,6 +5753,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { { PasteStatus.hideMessages(); Alert.hideMessages(); + CopyToClipboard.hideKeyboardShortcutHint(); }; /** @@ -5516,10 +5883,14 @@ jQuery.PrivateBin = (function($, RawDeflate) { history.pushState({type: 'clone'}, document.title, Helper.baseUri()); if (AttachmentViewer.hasAttachment()) { - AttachmentViewer.moveAttachmentTo( - TopNav.getCustomAttachment(), - 'Cloned: \'%s\'' - ); + const attachments = AttachmentViewer.getAttachments(); + attachments.forEach(attachment => { + AttachmentViewer.moveAttachmentTo( + TopNav.getCustomAttachment(), + attachment, + 'Cloned: \'%s\'' + ); + }); TopNav.hideFileSelector(); AttachmentViewer.hideAttachment(); // NOTE: it also looks nice without removing the attachment @@ -5527,12 +5898,12 @@ jQuery.PrivateBin = (function($, RawDeflate) { AttachmentViewer.hideAttachmentPreview(); TopNav.showCustomAttachment(); - // show another status message to make the user aware that the - // file was cloned too! + // show another status messages to make the user aware that the + // files were cloned too! Alert.showStatus( [ 'The cloned file \'%s\' was attached to this paste.', - AttachmentViewer.getAttachment()[1] + attachments.map(attachment => attachment[1]).join(', '), ], 'copy' ); @@ -5612,6 +5983,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { Prompt.init(); TopNav.init(); UiHelper.init(); + CopyToClipboard.init(); // check for legacy browsers before going any further if (!Legacy.Check.getInit()) { @@ -5671,6 +6043,7 @@ jQuery.PrivateBin = (function($, RawDeflate) { ServerInteraction: ServerInteraction, PasteEncrypter: PasteEncrypter, PasteDecrypter: PasteDecrypter, + CopyToClipboard: CopyToClipboard, Controller: Controller }; })(jQuery, RawDeflate); diff --git a/js/purify-3.1.7.js b/js/purify-3.1.7.js deleted file mode 100644 index ec61bc61..00000000 --- a/js/purify-3.1.7.js +++ /dev/null @@ -1,2 +0,0 @@ -/*! @license DOMPurify 3.1.7 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.1.7/LICENSE */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).DOMPurify=t()}(this,(function(){"use strict";const{entries:e,setPrototypeOf:t,isFrozen:n,getPrototypeOf:o,getOwnPropertyDescriptor:r}=Object;let{freeze:i,seal:a,create:l}=Object,{apply:c,construct:s}="undefined"!=typeof Reflect&&Reflect;i||(i=function(e){return e}),a||(a=function(e){return e}),c||(c=function(e,t,n){return e.apply(t,n)}),s||(s=function(e,t){return new e(...t)});const u=b(Array.prototype.forEach),m=b(Array.prototype.pop),p=b(Array.prototype.push),f=b(String.prototype.toLowerCase),d=b(String.prototype.toString),h=b(String.prototype.match),g=b(String.prototype.replace),T=b(String.prototype.indexOf),y=b(String.prototype.trim),E=b(Object.prototype.hasOwnProperty),_=b(RegExp.prototype.test),A=(N=TypeError,function(){for(var e=arguments.length,t=new Array(e),n=0;n1?n-1:0),r=1;r2&&void 0!==arguments[2]?arguments[2]:f;t&&t(e,null);let i=o.length;for(;i--;){let t=o[i];if("string"==typeof t){const e=r(t);e!==t&&(n(o)||(o[i]=e),t=e)}e[t]=!0}return e}function R(e){for(let t=0;t/gm),B=a(/\${[\w\W]*}/gm),W=a(/^data-[\-\w.\u00B7-\uFFFF]/),G=a(/^aria-[\-\w]+$/),Y=a(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),j=a(/^(?:\w+script|data):/i),X=a(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),q=a(/^html$/i),$=a(/^[a-z][.\w]*(-[.\w]+)+$/i);var K=Object.freeze({__proto__:null,MUSTACHE_EXPR:H,ERB_EXPR:z,TMPLIT_EXPR:B,DATA_ATTR:W,ARIA_ATTR:G,IS_ALLOWED_URI:Y,IS_SCRIPT_OR_DATA:j,ATTR_WHITESPACE:X,DOCTYPE_NAME:q,CUSTOM_ELEMENT:$});const V=1,Z=3,J=7,Q=8,ee=9,te=function(){return"undefined"==typeof window?null:window};var ne=function t(){let n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:te();const o=e=>t(e);if(o.version="3.1.7",o.removed=[],!n||!n.document||n.document.nodeType!==ee)return o.isSupported=!1,o;let{document:r}=n;const a=r,c=a.currentScript,{DocumentFragment:s,HTMLTemplateElement:N,Node:b,Element:R,NodeFilter:H,NamedNodeMap:z=n.NamedNodeMap||n.MozNamedAttrMap,HTMLFormElement:B,DOMParser:W,trustedTypes:G}=n,j=R.prototype,X=C(j,"cloneNode"),$=C(j,"remove"),ne=C(j,"nextSibling"),oe=C(j,"childNodes"),re=C(j,"parentNode");if("function"==typeof N){const e=r.createElement("template");e.content&&e.content.ownerDocument&&(r=e.content.ownerDocument)}let ie,ae="";const{implementation:le,createNodeIterator:ce,createDocumentFragment:se,getElementsByTagName:ue}=r,{importNode:me}=a;let pe={};o.isSupported="function"==typeof e&&"function"==typeof re&&le&&void 0!==le.createHTMLDocument;const{MUSTACHE_EXPR:fe,ERB_EXPR:de,TMPLIT_EXPR:he,DATA_ATTR:ge,ARIA_ATTR:Te,IS_SCRIPT_OR_DATA:ye,ATTR_WHITESPACE:Ee,CUSTOM_ELEMENT:_e}=K;let{IS_ALLOWED_URI:Ae}=K,Ne=null;const be=S({},[...L,...v,...D,...x,...M]);let Se=null;const Re=S({},[...I,...U,...P,...F]);let we=Object.seal(l(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Ce=null,Le=null,ve=!0,De=!0,Oe=!1,xe=!0,ke=!1,Me=!0,Ie=!1,Ue=!1,Pe=!1,Fe=!1,He=!1,ze=!1,Be=!0,We=!1,Ge=!0,Ye=!1,je={},Xe=null;const qe=S({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let $e=null;const Ke=S({},["audio","video","img","source","image","track"]);let Ve=null;const Ze=S({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),Je="http://www.w3.org/1998/Math/MathML",Qe="http://www.w3.org/2000/svg",et="http://www.w3.org/1999/xhtml";let tt=et,nt=!1,ot=null;const rt=S({},[Je,Qe,et],d);let it=null;const at=["application/xhtml+xml","text/html"];let lt=null,ct=null;const st=r.createElement("form"),ut=function(e){return e instanceof RegExp||e instanceof Function},mt=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!ct||ct!==e){if(e&&"object"==typeof e||(e={}),e=w(e),it=-1===at.indexOf(e.PARSER_MEDIA_TYPE)?"text/html":e.PARSER_MEDIA_TYPE,lt="application/xhtml+xml"===it?d:f,Ne=E(e,"ALLOWED_TAGS")?S({},e.ALLOWED_TAGS,lt):be,Se=E(e,"ALLOWED_ATTR")?S({},e.ALLOWED_ATTR,lt):Re,ot=E(e,"ALLOWED_NAMESPACES")?S({},e.ALLOWED_NAMESPACES,d):rt,Ve=E(e,"ADD_URI_SAFE_ATTR")?S(w(Ze),e.ADD_URI_SAFE_ATTR,lt):Ze,$e=E(e,"ADD_DATA_URI_TAGS")?S(w(Ke),e.ADD_DATA_URI_TAGS,lt):Ke,Xe=E(e,"FORBID_CONTENTS")?S({},e.FORBID_CONTENTS,lt):qe,Ce=E(e,"FORBID_TAGS")?S({},e.FORBID_TAGS,lt):{},Le=E(e,"FORBID_ATTR")?S({},e.FORBID_ATTR,lt):{},je=!!E(e,"USE_PROFILES")&&e.USE_PROFILES,ve=!1!==e.ALLOW_ARIA_ATTR,De=!1!==e.ALLOW_DATA_ATTR,Oe=e.ALLOW_UNKNOWN_PROTOCOLS||!1,xe=!1!==e.ALLOW_SELF_CLOSE_IN_ATTR,ke=e.SAFE_FOR_TEMPLATES||!1,Me=!1!==e.SAFE_FOR_XML,Ie=e.WHOLE_DOCUMENT||!1,Fe=e.RETURN_DOM||!1,He=e.RETURN_DOM_FRAGMENT||!1,ze=e.RETURN_TRUSTED_TYPE||!1,Pe=e.FORCE_BODY||!1,Be=!1!==e.SANITIZE_DOM,We=e.SANITIZE_NAMED_PROPS||!1,Ge=!1!==e.KEEP_CONTENT,Ye=e.IN_PLACE||!1,Ae=e.ALLOWED_URI_REGEXP||Y,tt=e.NAMESPACE||et,we=e.CUSTOM_ELEMENT_HANDLING||{},e.CUSTOM_ELEMENT_HANDLING&&ut(e.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(we.tagNameCheck=e.CUSTOM_ELEMENT_HANDLING.tagNameCheck),e.CUSTOM_ELEMENT_HANDLING&&ut(e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(we.attributeNameCheck=e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),e.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(we.allowCustomizedBuiltInElements=e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),ke&&(De=!1),He&&(Fe=!0),je&&(Ne=S({},M),Se=[],!0===je.html&&(S(Ne,L),S(Se,I)),!0===je.svg&&(S(Ne,v),S(Se,U),S(Se,F)),!0===je.svgFilters&&(S(Ne,D),S(Se,U),S(Se,F)),!0===je.mathMl&&(S(Ne,x),S(Se,P),S(Se,F))),e.ADD_TAGS&&(Ne===be&&(Ne=w(Ne)),S(Ne,e.ADD_TAGS,lt)),e.ADD_ATTR&&(Se===Re&&(Se=w(Se)),S(Se,e.ADD_ATTR,lt)),e.ADD_URI_SAFE_ATTR&&S(Ve,e.ADD_URI_SAFE_ATTR,lt),e.FORBID_CONTENTS&&(Xe===qe&&(Xe=w(Xe)),S(Xe,e.FORBID_CONTENTS,lt)),Ge&&(Ne["#text"]=!0),Ie&&S(Ne,["html","head","body"]),Ne.table&&(S(Ne,["tbody"]),delete Ce.tbody),e.TRUSTED_TYPES_POLICY){if("function"!=typeof e.TRUSTED_TYPES_POLICY.createHTML)throw A('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof e.TRUSTED_TYPES_POLICY.createScriptURL)throw A('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');ie=e.TRUSTED_TYPES_POLICY,ae=ie.createHTML("")}else void 0===ie&&(ie=function(e,t){if("object"!=typeof e||"function"!=typeof e.createPolicy)return null;let n=null;const o="data-tt-policy-suffix";t&&t.hasAttribute(o)&&(n=t.getAttribute(o));const r="dompurify"+(n?"#"+n:"");try{return e.createPolicy(r,{createHTML:e=>e,createScriptURL:e=>e})}catch(e){return console.warn("TrustedTypes policy "+r+" could not be created."),null}}(G,c)),null!==ie&&"string"==typeof ae&&(ae=ie.createHTML(""));i&&i(e),ct=e}},pt=S({},["mi","mo","mn","ms","mtext"]),ft=S({},["annotation-xml"]),dt=S({},["title","style","font","a","script"]),ht=S({},[...v,...D,...O]),gt=S({},[...x,...k]),Tt=function(e){p(o.removed,{element:e});try{re(e).removeChild(e)}catch(t){$(e)}},yt=function(e,t){try{p(o.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){p(o.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e&&!Se[e])if(Fe||He)try{Tt(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},Et=function(e){let t=null,n=null;if(Pe)e=""+e;else{const t=h(e,/^[\r\n\t ]+/);n=t&&t[0]}"application/xhtml+xml"===it&&tt===et&&(e=''+e+"");const o=ie?ie.createHTML(e):e;if(tt===et)try{t=(new W).parseFromString(o,it)}catch(e){}if(!t||!t.documentElement){t=le.createDocument(tt,"template",null);try{t.documentElement.innerHTML=nt?ae:o}catch(e){}}const i=t.body||t.documentElement;return e&&n&&i.insertBefore(r.createTextNode(n),i.childNodes[0]||null),tt===et?ue.call(t,Ie?"html":"body")[0]:Ie?t.documentElement:i},_t=function(e){return ce.call(e.ownerDocument||e,e,H.SHOW_ELEMENT|H.SHOW_COMMENT|H.SHOW_TEXT|H.SHOW_PROCESSING_INSTRUCTION|H.SHOW_CDATA_SECTION,null)},At=function(e){return e instanceof B&&("string"!=typeof e.nodeName||"string"!=typeof e.textContent||"function"!=typeof e.removeChild||!(e.attributes instanceof z)||"function"!=typeof e.removeAttribute||"function"!=typeof e.setAttribute||"string"!=typeof e.namespaceURI||"function"!=typeof e.insertBefore||"function"!=typeof e.hasChildNodes)},Nt=function(e){return"function"==typeof b&&e instanceof b},bt=function(e,t,n){pe[e]&&u(pe[e],(e=>{e.call(o,t,n,ct)}))},St=function(e){let t=null;if(bt("beforeSanitizeElements",e,null),At(e))return Tt(e),!0;const n=lt(e.nodeName);if(bt("uponSanitizeElement",e,{tagName:n,allowedTags:Ne}),e.hasChildNodes()&&!Nt(e.firstElementChild)&&_(/<[/\w]/g,e.innerHTML)&&_(/<[/\w]/g,e.textContent))return Tt(e),!0;if(e.nodeType===J)return Tt(e),!0;if(Me&&e.nodeType===Q&&_(/<[/\w]/g,e.data))return Tt(e),!0;if(!Ne[n]||Ce[n]){if(!Ce[n]&&wt(n)){if(we.tagNameCheck instanceof RegExp&&_(we.tagNameCheck,n))return!1;if(we.tagNameCheck instanceof Function&&we.tagNameCheck(n))return!1}if(Ge&&!Xe[n]){const t=re(e)||e.parentNode,n=oe(e)||e.childNodes;if(n&&t){for(let o=n.length-1;o>=0;--o){const r=X(n[o],!0);r.__removalCount=(e.__removalCount||0)+1,t.insertBefore(r,ne(e))}}}return Tt(e),!0}return e instanceof R&&!function(e){let t=re(e);t&&t.tagName||(t={namespaceURI:tt,tagName:"template"});const n=f(e.tagName),o=f(t.tagName);return!!ot[e.namespaceURI]&&(e.namespaceURI===Qe?t.namespaceURI===et?"svg"===n:t.namespaceURI===Je?"svg"===n&&("annotation-xml"===o||pt[o]):Boolean(ht[n]):e.namespaceURI===Je?t.namespaceURI===et?"math"===n:t.namespaceURI===Qe?"math"===n&&ft[o]:Boolean(gt[n]):e.namespaceURI===et?!(t.namespaceURI===Qe&&!ft[o])&&!(t.namespaceURI===Je&&!pt[o])&&!gt[n]&&(dt[n]||!ht[n]):!("application/xhtml+xml"!==it||!ot[e.namespaceURI]))}(e)?(Tt(e),!0):"noscript"!==n&&"noembed"!==n&&"noframes"!==n||!_(/<\/no(script|embed|frames)/i,e.innerHTML)?(ke&&e.nodeType===Z&&(t=e.textContent,u([fe,de,he],(e=>{t=g(t,e," ")})),e.textContent!==t&&(p(o.removed,{element:e.cloneNode()}),e.textContent=t)),bt("afterSanitizeElements",e,null),!1):(Tt(e),!0)},Rt=function(e,t,n){if(Be&&("id"===t||"name"===t)&&(n in r||n in st))return!1;if(De&&!Le[t]&&_(ge,t));else if(ve&&_(Te,t));else if(!Se[t]||Le[t]){if(!(wt(e)&&(we.tagNameCheck instanceof RegExp&&_(we.tagNameCheck,e)||we.tagNameCheck instanceof Function&&we.tagNameCheck(e))&&(we.attributeNameCheck instanceof RegExp&&_(we.attributeNameCheck,t)||we.attributeNameCheck instanceof Function&&we.attributeNameCheck(t))||"is"===t&&we.allowCustomizedBuiltInElements&&(we.tagNameCheck instanceof RegExp&&_(we.tagNameCheck,n)||we.tagNameCheck instanceof Function&&we.tagNameCheck(n))))return!1}else if(Ve[t]);else if(_(Ae,g(n,Ee,"")));else if("src"!==t&&"xlink:href"!==t&&"href"!==t||"script"===e||0!==T(n,"data:")||!$e[e]){if(Oe&&!_(ye,g(n,Ee,"")));else if(n)return!1}else;return!0},wt=function(e){return"annotation-xml"!==e&&h(e,_e)},Ct=function(e){bt("beforeSanitizeAttributes",e,null);const{attributes:t}=e;if(!t)return;const n={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:Se};let r=t.length;for(;r--;){const i=t[r],{name:a,namespaceURI:l,value:c}=i,s=lt(a);let p="value"===a?c:y(c);if(n.attrName=s,n.attrValue=p,n.keepAttr=!0,n.forceKeepAttr=void 0,bt("uponSanitizeAttribute",e,n),p=n.attrValue,n.forceKeepAttr)continue;if(yt(a,e),!n.keepAttr)continue;if(!xe&&_(/\/>/i,p)){yt(a,e);continue}ke&&u([fe,de,he],(e=>{p=g(p,e," ")}));const f=lt(e.nodeName);if(Rt(f,s,p))if(!We||"id"!==s&&"name"!==s||(yt(a,e),p="user-content-"+p),Me&&_(/((--!?|])>)|<\/(style|title)/i,p))yt(a,e);else{if(ie&&"object"==typeof G&&"function"==typeof G.getAttributeType)if(l);else switch(G.getAttributeType(f,s)){case"TrustedHTML":p=ie.createHTML(p);break;case"TrustedScriptURL":p=ie.createScriptURL(p)}try{l?e.setAttributeNS(l,a,p):e.setAttribute(a,p),At(e)?Tt(e):m(o.removed)}catch(e){}}}bt("afterSanitizeAttributes",e,null)},Lt=function e(t){let n=null;const o=_t(t);for(bt("beforeSanitizeShadowDOM",t,null);n=o.nextNode();)bt("uponSanitizeShadowNode",n,null),St(n)||(n.content instanceof s&&e(n.content),Ct(n));bt("afterSanitizeShadowDOM",t,null)};return o.sanitize=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=null,r=null,i=null,l=null;if(nt=!e,nt&&(e="\x3c!--\x3e"),"string"!=typeof e&&!Nt(e)){if("function"!=typeof e.toString)throw A("toString is not a function");if("string"!=typeof(e=e.toString()))throw A("dirty is not a string, aborting")}if(!o.isSupported)return e;if(Ue||mt(t),o.removed=[],"string"==typeof e&&(Ye=!1),Ye){if(e.nodeName){const t=lt(e.nodeName);if(!Ne[t]||Ce[t])throw A("root node is forbidden and cannot be sanitized in-place")}}else if(e instanceof b)n=Et("\x3c!----\x3e"),r=n.ownerDocument.importNode(e,!0),r.nodeType===V&&"BODY"===r.nodeName||"HTML"===r.nodeName?n=r:n.appendChild(r);else{if(!Fe&&!ke&&!Ie&&-1===e.indexOf("<"))return ie&&ze?ie.createHTML(e):e;if(n=Et(e),!n)return Fe?null:ze?ae:""}n&&Pe&&Tt(n.firstChild);const c=_t(Ye?e:n);for(;i=c.nextNode();)St(i)||(i.content instanceof s&&Lt(i.content),Ct(i));if(Ye)return e;if(Fe){if(He)for(l=se.call(n.ownerDocument);n.firstChild;)l.appendChild(n.firstChild);else l=n;return(Se.shadowroot||Se.shadowrootmode)&&(l=me.call(a,l,!0)),l}let m=Ie?n.outerHTML:n.innerHTML;return Ie&&Ne["!doctype"]&&n.ownerDocument&&n.ownerDocument.doctype&&n.ownerDocument.doctype.name&&_(q,n.ownerDocument.doctype.name)&&(m="\n"+m),ke&&u([fe,de,he],(e=>{m=g(m,e," ")})),ie&&ze?ie.createHTML(m):m},o.setConfig=function(){mt(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),Ue=!0},o.clearConfig=function(){ct=null,Ue=!1},o.isValidAttribute=function(e,t,n){ct||mt({});const o=lt(e),r=lt(t);return Rt(o,r,n)},o.addHook=function(e,t){"function"==typeof t&&(pe[e]=pe[e]||[],p(pe[e],t))},o.removeHook=function(e){if(pe[e])return m(pe[e])},o.removeHooks=function(e){pe[e]&&(pe[e]=[])},o.removeAllHooks=function(){pe={}},o}();return ne})); diff --git a/js/purify-3.2.6.js b/js/purify-3.2.6.js new file mode 100644 index 00000000..a4ef769b --- /dev/null +++ b/js/purify-3.2.6.js @@ -0,0 +1,2 @@ +/*! @license DOMPurify 3.2.6 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.2.6/LICENSE */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).DOMPurify=t()}(this,(function(){"use strict";const{entries:e,setPrototypeOf:t,isFrozen:n,getPrototypeOf:o,getOwnPropertyDescriptor:r}=Object;let{freeze:i,seal:a,create:l}=Object,{apply:c,construct:s}="undefined"!=typeof Reflect&&Reflect;i||(i=function(e){return e}),a||(a=function(e){return e}),c||(c=function(e,t,n){return e.apply(t,n)}),s||(s=function(e,t){return new e(...t)});const u=R(Array.prototype.forEach),m=R(Array.prototype.lastIndexOf),p=R(Array.prototype.pop),f=R(Array.prototype.push),d=R(Array.prototype.splice),h=R(String.prototype.toLowerCase),g=R(String.prototype.toString),T=R(String.prototype.match),y=R(String.prototype.replace),E=R(String.prototype.indexOf),A=R(String.prototype.trim),_=R(Object.prototype.hasOwnProperty),S=R(RegExp.prototype.test),b=(N=TypeError,function(){for(var e=arguments.length,t=new Array(e),n=0;n1?n-1:0),r=1;r2&&void 0!==arguments[2]?arguments[2]:h;t&&t(e,null);let i=o.length;for(;i--;){let t=o[i];if("string"==typeof t){const e=r(t);e!==t&&(n(o)||(o[i]=e),t=e)}e[t]=!0}return e}function O(e){for(let t=0;t/gm),G=a(/\$\{[\w\W]*/gm),Y=a(/^data-[\-\w.\u00B7-\uFFFF]+$/),j=a(/^aria-[\-\w]+$/),X=a(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|matrix):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),q=a(/^(?:\w+script|data):/i),$=a(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),K=a(/^html$/i),V=a(/^[a-z][.\w]*(-[.\w]+)+$/i);var Z=Object.freeze({__proto__:null,ARIA_ATTR:j,ATTR_WHITESPACE:$,CUSTOM_ELEMENT:V,DATA_ATTR:Y,DOCTYPE_NAME:K,ERB_EXPR:W,IS_ALLOWED_URI:X,IS_SCRIPT_OR_DATA:q,MUSTACHE_EXPR:B,TMPLIT_EXPR:G});const J=1,Q=3,ee=7,te=8,ne=9,oe=function(){return"undefined"==typeof window?null:window};var re=function t(){let n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:oe();const o=e=>t(e);if(o.version="3.2.6",o.removed=[],!n||!n.document||n.document.nodeType!==ne||!n.Element)return o.isSupported=!1,o;let{document:r}=n;const a=r,c=a.currentScript,{DocumentFragment:s,HTMLTemplateElement:N,Node:R,Element:O,NodeFilter:B,NamedNodeMap:W=n.NamedNodeMap||n.MozNamedAttrMap,HTMLFormElement:G,DOMParser:Y,trustedTypes:j}=n,q=O.prototype,$=v(q,"cloneNode"),V=v(q,"remove"),re=v(q,"nextSibling"),ie=v(q,"childNodes"),ae=v(q,"parentNode");if("function"==typeof N){const e=r.createElement("template");e.content&&e.content.ownerDocument&&(r=e.content.ownerDocument)}let le,ce="";const{implementation:se,createNodeIterator:ue,createDocumentFragment:me,getElementsByTagName:pe}=r,{importNode:fe}=a;let de={afterSanitizeAttributes:[],afterSanitizeElements:[],afterSanitizeShadowDOM:[],beforeSanitizeAttributes:[],beforeSanitizeElements:[],beforeSanitizeShadowDOM:[],uponSanitizeAttribute:[],uponSanitizeElement:[],uponSanitizeShadowNode:[]};o.isSupported="function"==typeof e&&"function"==typeof ae&&se&&void 0!==se.createHTMLDocument;const{MUSTACHE_EXPR:he,ERB_EXPR:ge,TMPLIT_EXPR:Te,DATA_ATTR:ye,ARIA_ATTR:Ee,IS_SCRIPT_OR_DATA:Ae,ATTR_WHITESPACE:_e,CUSTOM_ELEMENT:Se}=Z;let{IS_ALLOWED_URI:be}=Z,Ne=null;const Re=w({},[...L,...C,...x,...M,...U]);let we=null;const Oe=w({},[...z,...P,...H,...F]);let De=Object.seal(l(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),ve=null,Le=null,Ce=!0,xe=!0,Ie=!1,Me=!0,ke=!1,Ue=!0,ze=!1,Pe=!1,He=!1,Fe=!1,Be=!1,We=!1,Ge=!0,Ye=!1,je=!0,Xe=!1,qe={},$e=null;const Ke=w({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let Ve=null;const Ze=w({},["audio","video","img","source","image","track"]);let Je=null;const Qe=w({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),et="http://www.w3.org/1998/Math/MathML",tt="http://www.w3.org/2000/svg",nt="http://www.w3.org/1999/xhtml";let ot=nt,rt=!1,it=null;const at=w({},[et,tt,nt],g);let lt=w({},["mi","mo","mn","ms","mtext"]),ct=w({},["annotation-xml"]);const st=w({},["title","style","font","a","script"]);let ut=null;const mt=["application/xhtml+xml","text/html"];let pt=null,ft=null;const dt=r.createElement("form"),ht=function(e){return e instanceof RegExp||e instanceof Function},gt=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!ft||ft!==e){if(e&&"object"==typeof e||(e={}),e=D(e),ut=-1===mt.indexOf(e.PARSER_MEDIA_TYPE)?"text/html":e.PARSER_MEDIA_TYPE,pt="application/xhtml+xml"===ut?g:h,Ne=_(e,"ALLOWED_TAGS")?w({},e.ALLOWED_TAGS,pt):Re,we=_(e,"ALLOWED_ATTR")?w({},e.ALLOWED_ATTR,pt):Oe,it=_(e,"ALLOWED_NAMESPACES")?w({},e.ALLOWED_NAMESPACES,g):at,Je=_(e,"ADD_URI_SAFE_ATTR")?w(D(Qe),e.ADD_URI_SAFE_ATTR,pt):Qe,Ve=_(e,"ADD_DATA_URI_TAGS")?w(D(Ze),e.ADD_DATA_URI_TAGS,pt):Ze,$e=_(e,"FORBID_CONTENTS")?w({},e.FORBID_CONTENTS,pt):Ke,ve=_(e,"FORBID_TAGS")?w({},e.FORBID_TAGS,pt):D({}),Le=_(e,"FORBID_ATTR")?w({},e.FORBID_ATTR,pt):D({}),qe=!!_(e,"USE_PROFILES")&&e.USE_PROFILES,Ce=!1!==e.ALLOW_ARIA_ATTR,xe=!1!==e.ALLOW_DATA_ATTR,Ie=e.ALLOW_UNKNOWN_PROTOCOLS||!1,Me=!1!==e.ALLOW_SELF_CLOSE_IN_ATTR,ke=e.SAFE_FOR_TEMPLATES||!1,Ue=!1!==e.SAFE_FOR_XML,ze=e.WHOLE_DOCUMENT||!1,Fe=e.RETURN_DOM||!1,Be=e.RETURN_DOM_FRAGMENT||!1,We=e.RETURN_TRUSTED_TYPE||!1,He=e.FORCE_BODY||!1,Ge=!1!==e.SANITIZE_DOM,Ye=e.SANITIZE_NAMED_PROPS||!1,je=!1!==e.KEEP_CONTENT,Xe=e.IN_PLACE||!1,be=e.ALLOWED_URI_REGEXP||X,ot=e.NAMESPACE||nt,lt=e.MATHML_TEXT_INTEGRATION_POINTS||lt,ct=e.HTML_INTEGRATION_POINTS||ct,De=e.CUSTOM_ELEMENT_HANDLING||{},e.CUSTOM_ELEMENT_HANDLING&&ht(e.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(De.tagNameCheck=e.CUSTOM_ELEMENT_HANDLING.tagNameCheck),e.CUSTOM_ELEMENT_HANDLING&&ht(e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(De.attributeNameCheck=e.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),e.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(De.allowCustomizedBuiltInElements=e.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),ke&&(xe=!1),Be&&(Fe=!0),qe&&(Ne=w({},U),we=[],!0===qe.html&&(w(Ne,L),w(we,z)),!0===qe.svg&&(w(Ne,C),w(we,P),w(we,F)),!0===qe.svgFilters&&(w(Ne,x),w(we,P),w(we,F)),!0===qe.mathMl&&(w(Ne,M),w(we,H),w(we,F))),e.ADD_TAGS&&(Ne===Re&&(Ne=D(Ne)),w(Ne,e.ADD_TAGS,pt)),e.ADD_ATTR&&(we===Oe&&(we=D(we)),w(we,e.ADD_ATTR,pt)),e.ADD_URI_SAFE_ATTR&&w(Je,e.ADD_URI_SAFE_ATTR,pt),e.FORBID_CONTENTS&&($e===Ke&&($e=D($e)),w($e,e.FORBID_CONTENTS,pt)),je&&(Ne["#text"]=!0),ze&&w(Ne,["html","head","body"]),Ne.table&&(w(Ne,["tbody"]),delete ve.tbody),e.TRUSTED_TYPES_POLICY){if("function"!=typeof e.TRUSTED_TYPES_POLICY.createHTML)throw b('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof e.TRUSTED_TYPES_POLICY.createScriptURL)throw b('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');le=e.TRUSTED_TYPES_POLICY,ce=le.createHTML("")}else void 0===le&&(le=function(e,t){if("object"!=typeof e||"function"!=typeof e.createPolicy)return null;let n=null;const o="data-tt-policy-suffix";t&&t.hasAttribute(o)&&(n=t.getAttribute(o));const r="dompurify"+(n?"#"+n:"");try{return e.createPolicy(r,{createHTML:e=>e,createScriptURL:e=>e})}catch(e){return console.warn("TrustedTypes policy "+r+" could not be created."),null}}(j,c)),null!==le&&"string"==typeof ce&&(ce=le.createHTML(""));i&&i(e),ft=e}},Tt=w({},[...C,...x,...I]),yt=w({},[...M,...k]),Et=function(e){f(o.removed,{element:e});try{ae(e).removeChild(e)}catch(t){V(e)}},At=function(e,t){try{f(o.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){f(o.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e)if(Fe||Be)try{Et(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},_t=function(e){let t=null,n=null;if(He)e=""+e;else{const t=T(e,/^[\r\n\t ]+/);n=t&&t[0]}"application/xhtml+xml"===ut&&ot===nt&&(e=''+e+"");const o=le?le.createHTML(e):e;if(ot===nt)try{t=(new Y).parseFromString(o,ut)}catch(e){}if(!t||!t.documentElement){t=se.createDocument(ot,"template",null);try{t.documentElement.innerHTML=rt?ce:o}catch(e){}}const i=t.body||t.documentElement;return e&&n&&i.insertBefore(r.createTextNode(n),i.childNodes[0]||null),ot===nt?pe.call(t,ze?"html":"body")[0]:ze?t.documentElement:i},St=function(e){return ue.call(e.ownerDocument||e,e,B.SHOW_ELEMENT|B.SHOW_COMMENT|B.SHOW_TEXT|B.SHOW_PROCESSING_INSTRUCTION|B.SHOW_CDATA_SECTION,null)},bt=function(e){return e instanceof G&&("string"!=typeof e.nodeName||"string"!=typeof e.textContent||"function"!=typeof e.removeChild||!(e.attributes instanceof W)||"function"!=typeof e.removeAttribute||"function"!=typeof e.setAttribute||"string"!=typeof e.namespaceURI||"function"!=typeof e.insertBefore||"function"!=typeof e.hasChildNodes)},Nt=function(e){return"function"==typeof R&&e instanceof R};function Rt(e,t,n){u(e,(e=>{e.call(o,t,n,ft)}))}const wt=function(e){let t=null;if(Rt(de.beforeSanitizeElements,e,null),bt(e))return Et(e),!0;const n=pt(e.nodeName);if(Rt(de.uponSanitizeElement,e,{tagName:n,allowedTags:Ne}),Ue&&e.hasChildNodes()&&!Nt(e.firstElementChild)&&S(/<[/\w!]/g,e.innerHTML)&&S(/<[/\w!]/g,e.textContent))return Et(e),!0;if(e.nodeType===ee)return Et(e),!0;if(Ue&&e.nodeType===te&&S(/<[/\w]/g,e.data))return Et(e),!0;if(!Ne[n]||ve[n]){if(!ve[n]&&Dt(n)){if(De.tagNameCheck instanceof RegExp&&S(De.tagNameCheck,n))return!1;if(De.tagNameCheck instanceof Function&&De.tagNameCheck(n))return!1}if(je&&!$e[n]){const t=ae(e)||e.parentNode,n=ie(e)||e.childNodes;if(n&&t){for(let o=n.length-1;o>=0;--o){const r=$(n[o],!0);r.__removalCount=(e.__removalCount||0)+1,t.insertBefore(r,re(e))}}}return Et(e),!0}return e instanceof O&&!function(e){let t=ae(e);t&&t.tagName||(t={namespaceURI:ot,tagName:"template"});const n=h(e.tagName),o=h(t.tagName);return!!it[e.namespaceURI]&&(e.namespaceURI===tt?t.namespaceURI===nt?"svg"===n:t.namespaceURI===et?"svg"===n&&("annotation-xml"===o||lt[o]):Boolean(Tt[n]):e.namespaceURI===et?t.namespaceURI===nt?"math"===n:t.namespaceURI===tt?"math"===n&&ct[o]:Boolean(yt[n]):e.namespaceURI===nt?!(t.namespaceURI===tt&&!ct[o])&&!(t.namespaceURI===et&&!lt[o])&&!yt[n]&&(st[n]||!Tt[n]):!("application/xhtml+xml"!==ut||!it[e.namespaceURI]))}(e)?(Et(e),!0):"noscript"!==n&&"noembed"!==n&&"noframes"!==n||!S(/<\/no(script|embed|frames)/i,e.innerHTML)?(ke&&e.nodeType===Q&&(t=e.textContent,u([he,ge,Te],(e=>{t=y(t,e," ")})),e.textContent!==t&&(f(o.removed,{element:e.cloneNode()}),e.textContent=t)),Rt(de.afterSanitizeElements,e,null),!1):(Et(e),!0)},Ot=function(e,t,n){if(Ge&&("id"===t||"name"===t)&&(n in r||n in dt))return!1;if(xe&&!Le[t]&&S(ye,t));else if(Ce&&S(Ee,t));else if(!we[t]||Le[t]){if(!(Dt(e)&&(De.tagNameCheck instanceof RegExp&&S(De.tagNameCheck,e)||De.tagNameCheck instanceof Function&&De.tagNameCheck(e))&&(De.attributeNameCheck instanceof RegExp&&S(De.attributeNameCheck,t)||De.attributeNameCheck instanceof Function&&De.attributeNameCheck(t))||"is"===t&&De.allowCustomizedBuiltInElements&&(De.tagNameCheck instanceof RegExp&&S(De.tagNameCheck,n)||De.tagNameCheck instanceof Function&&De.tagNameCheck(n))))return!1}else if(Je[t]);else if(S(be,y(n,_e,"")));else if("src"!==t&&"xlink:href"!==t&&"href"!==t||"script"===e||0!==E(n,"data:")||!Ve[e]){if(Ie&&!S(Ae,y(n,_e,"")));else if(n)return!1}else;return!0},Dt=function(e){return"annotation-xml"!==e&&T(e,Se)},vt=function(e){Rt(de.beforeSanitizeAttributes,e,null);const{attributes:t}=e;if(!t||bt(e))return;const n={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:we,forceKeepAttr:void 0};let r=t.length;for(;r--;){const i=t[r],{name:a,namespaceURI:l,value:c}=i,s=pt(a),m=c;let f="value"===a?m:A(m);if(n.attrName=s,n.attrValue=f,n.keepAttr=!0,n.forceKeepAttr=void 0,Rt(de.uponSanitizeAttribute,e,n),f=n.attrValue,!Ye||"id"!==s&&"name"!==s||(At(a,e),f="user-content-"+f),Ue&&S(/((--!?|])>)|<\/(style|title)/i,f)){At(a,e);continue}if(n.forceKeepAttr)continue;if(!n.keepAttr){At(a,e);continue}if(!Me&&S(/\/>/i,f)){At(a,e);continue}ke&&u([he,ge,Te],(e=>{f=y(f,e," ")}));const d=pt(e.nodeName);if(Ot(d,s,f)){if(le&&"object"==typeof j&&"function"==typeof j.getAttributeType)if(l);else switch(j.getAttributeType(d,s)){case"TrustedHTML":f=le.createHTML(f);break;case"TrustedScriptURL":f=le.createScriptURL(f)}if(f!==m)try{l?e.setAttributeNS(l,a,f):e.setAttribute(a,f),bt(e)?Et(e):p(o.removed)}catch(t){At(a,e)}}else At(a,e)}Rt(de.afterSanitizeAttributes,e,null)},Lt=function e(t){let n=null;const o=St(t);for(Rt(de.beforeSanitizeShadowDOM,t,null);n=o.nextNode();)Rt(de.uponSanitizeShadowNode,n,null),wt(n),vt(n),n.content instanceof s&&e(n.content);Rt(de.afterSanitizeShadowDOM,t,null)};return o.sanitize=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=null,r=null,i=null,l=null;if(rt=!e,rt&&(e="\x3c!--\x3e"),"string"!=typeof e&&!Nt(e)){if("function"!=typeof e.toString)throw b("toString is not a function");if("string"!=typeof(e=e.toString()))throw b("dirty is not a string, aborting")}if(!o.isSupported)return e;if(Pe||gt(t),o.removed=[],"string"==typeof e&&(Xe=!1),Xe){if(e.nodeName){const t=pt(e.nodeName);if(!Ne[t]||ve[t])throw b("root node is forbidden and cannot be sanitized in-place")}}else if(e instanceof R)n=_t("\x3c!----\x3e"),r=n.ownerDocument.importNode(e,!0),r.nodeType===J&&"BODY"===r.nodeName||"HTML"===r.nodeName?n=r:n.appendChild(r);else{if(!Fe&&!ke&&!ze&&-1===e.indexOf("<"))return le&&We?le.createHTML(e):e;if(n=_t(e),!n)return Fe?null:We?ce:""}n&&He&&Et(n.firstChild);const c=St(Xe?e:n);for(;i=c.nextNode();)wt(i),vt(i),i.content instanceof s&&Lt(i.content);if(Xe)return e;if(Fe){if(Be)for(l=me.call(n.ownerDocument);n.firstChild;)l.appendChild(n.firstChild);else l=n;return(we.shadowroot||we.shadowrootmode)&&(l=fe.call(a,l,!0)),l}let m=ze?n.outerHTML:n.innerHTML;return ze&&Ne["!doctype"]&&n.ownerDocument&&n.ownerDocument.doctype&&n.ownerDocument.doctype.name&&S(K,n.ownerDocument.doctype.name)&&(m="\n"+m),ke&&u([he,ge,Te],(e=>{m=y(m,e," ")})),le&&We?le.createHTML(m):m},o.setConfig=function(){gt(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),Pe=!0},o.clearConfig=function(){ft=null,Pe=!1},o.isValidAttribute=function(e,t,n){ft||gt({});const o=pt(e),r=pt(t);return Ot(o,r,n)},o.addHook=function(e,t){"function"==typeof t&&f(de[e],t)},o.removeHook=function(e,t){if(void 0!==t){const n=m(de[e],t);return-1===n?void 0:d(de[e],n,1)[0]}return p(de[e])},o.removeHooks=function(e){de[e]=[]},o.removeAllHooks=function(){de={afterSanitizeAttributes:[],afterSanitizeElements:[],afterSanitizeShadowDOM:[],beforeSanitizeAttributes:[],beforeSanitizeElements:[],beforeSanitizeShadowDOM:[],uponSanitizeAttribute:[],uponSanitizeElement:[],uponSanitizeShadowNode:[]}},o}();return re})); diff --git a/js/test/AttachmentViewer.js b/js/test/AttachmentViewer.js index 54ddfc1a..029b0d84 100644 --- a/js/test/AttachmentViewer.js +++ b/js/test/AttachmentViewer.js @@ -1,5 +1,5 @@ 'use strict'; -var common = require('../common'); +const common = require('../common'); describe('AttachmentViewer', function () { describe('setAttachment, showAttachment, removeAttachment, hideAttachment, hideAttachmentPreview, hasAttachment, getAttachment & moveAttachmentTo', function () { @@ -14,11 +14,12 @@ describe('AttachmentViewer', function () { 'string', function (mimeType, rawdata, filename, prefix, postfix) { let clean = jsdom(), - data = 'data:' + mimeType + ';base64,' + btoa(rawdata), + data = 'data:' + mimeType + ';base64,' + common.btoa(rawdata), + mimePrefix = mimeType.substring(0, 6), previewSupported = ( - mimeType.substring(0, 6) === 'image/' || - mimeType.substring(0, 6) === 'audio/' || - mimeType.substring(0, 6) === 'video/' || + mimePrefix === 'image/' || + mimePrefix === 'audio/' || + mimePrefix === 'video/' || mimeType.match(/\/pdf/i) ), results = [], @@ -26,11 +27,14 @@ describe('AttachmentViewer', function () { prefix = prefix.replace(/%(s|d)/g, '%%'); postfix = postfix.replace(/%(s|d)/g, '%%'); $('body').html( - '' + '' + + '' + + '
' + + '' + + '
' ); // mock createObjectURL for jsDOM if (typeof window.URL.createObjectURL === 'undefined') { @@ -43,29 +47,35 @@ describe('AttachmentViewer', function () { ) } $.PrivateBin.AttachmentViewer.init(); + $.PrivateBin.Model.init(); results.push( !$.PrivateBin.AttachmentViewer.hasAttachment() && $('#attachment').hasClass('hidden') && + $('#attachment').children().length === 0 && + $('#attachmenttemplate').hasClass('hidden') && $('#attachmentPreview').hasClass('hidden') ); + global.atob = common.atob; if (filename.length) { $.PrivateBin.AttachmentViewer.setAttachment(data, filename); } else { $.PrivateBin.AttachmentViewer.setAttachment(data); } - // beyond this point we will get the blob URL instead of the data + // // beyond this point we will get the blob URL instead of the data data = window.URL.createObjectURL(data); - const attachment = $.PrivateBin.AttachmentViewer.getAttachment(); + const attachment = $.PrivateBin.AttachmentViewer.getAttachments(); results.push( $.PrivateBin.AttachmentViewer.hasAttachment() && $('#attachment').hasClass('hidden') && + $('#attachment').children().length > 0 && $('#attachmentPreview').hasClass('hidden') && - attachment[0] === data && - attachment[1] === filename + attachment[0][0] === data && + attachment[0][1] === filename ); $.PrivateBin.AttachmentViewer.showAttachment(); results.push( !$('#attachment').hasClass('hidden') && + $('#attachment').children().length > 0 && (previewSupported ? !$('#attachmentPreview').hasClass('hidden') : $('#attachmentPreview').hasClass('hidden')) ); $.PrivateBin.AttachmentViewer.hideAttachment(); @@ -83,7 +93,7 @@ describe('AttachmentViewer', function () { (previewSupported ? !$('#attachmentPreview').hasClass('hidden') : $('#attachmentPreview').hasClass('hidden')) ); let element = $('
'); - $.PrivateBin.AttachmentViewer.moveAttachmentTo(element, prefix + '%s' + postfix); + $.PrivateBin.AttachmentViewer.moveAttachmentTo(element, attachment[0], prefix + '%s' + postfix); // messageIDs with links get a relaxed treatment if (prefix.indexOf('').text((prefix + filename + postfix)).text(); @@ -97,16 +107,17 @@ describe('AttachmentViewer', function () { } if (filename.length) { results.push( - element.children()[0].href === data && - element.children()[0].getAttribute('download') === filename && - element.children()[0].text === result + element.find('a')[0].href === data && + element.find('a')[0].getAttribute('download') === filename && + element.find('a')[0].text === result ); } else { - results.push(element.children()[0].href === data); + results.push(element.find('a')[0].href === data); } $.PrivateBin.AttachmentViewer.removeAttachment(); results.push( $('#attachment').hasClass('hidden') && + $('#attachment').children().length === 0 && $('#attachmentPreview').hasClass('hidden') ); clean(); diff --git a/js/test/Check.js b/js/test/Check.js index 474330e3..63428c93 100644 --- a/js/test/Check.js +++ b/js/test/Check.js @@ -19,10 +19,9 @@ describe('Check', function () { } ); Legacy.Check.init(); - const result1 = Legacy.Check.getInit() && !Legacy.Check.getStatus(), - result2 = (document.getElementById('errormessage').className !== 'hidden'); + const result = Legacy.Check.getInit() && !Legacy.Check.getStatus(); clean(); - return result1 && result2; + return result; } ), {tests: 10}); @@ -67,7 +66,10 @@ describe('Check', function () { 'url': (secureProtocol ? 'https' : 'http' ) + '://' + domain.join('') + '/' } ); - window.crypto = new WebCrypto(); + Object.defineProperty(window, 'crypto', { + value: new WebCrypto(), + writeable: false, + }); Legacy.Check.init(); const result1 = Legacy.Check.getInit() && Legacy.Check.getStatus(), result2 = secureProtocol === (document.getElementById('httpnotice').className === 'hidden'); diff --git a/js/test/CopyToClipboard.js b/js/test/CopyToClipboard.js new file mode 100644 index 00000000..731cdeda --- /dev/null +++ b/js/test/CopyToClipboard.js @@ -0,0 +1,139 @@ +'use strict'; +const common = require('../common'); + +describe('CopyToClipboard', function() { + this.timeout(30000); + + describe ('Copy paste to clipboard', function () { + jsc.property('Copy with button click', + common.jscFormats(), + 'nestring', + async function (format, text) { + var clean = jsdom(); + common.enableClipboard(); + + $('body').html( + '' + ); + + $.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 + * (the copy paste to clipboard should not work in this case) due to lacking window.getSelection() in jsdom. + */ + jsc.property('Copy with keyboard shortcut', + common.jscFormats(), + 'nestring', + async function (format, text) { + var clean = jsdom(); + common.enableClipboard(); + + $('body').html( + '
+++ no paste text ' + + '+++
' + ); + + $.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(); + common.enableClipboard(); + + $('body').html(''); + + $.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 () { + jsc.property('Show hint', + 'nestring', + function (text) { + var clean = jsdom(); + + $('body').html(''); + + $.PrivateBin.CopyToClipboard.init(); + $.PrivateBin.CopyToClipboard.showKeyboardShortcutHint(); + + const keyboardShortcutHint = $('#copyShortcutHintText').text(); + + clean(); + + return keyboardShortcutHint.length > 0; + } + ); + + jsc.property('Hide hint', + 'nestring', + function (text) { + var clean = jsdom(); + + $('body').html('' + text + ''); + + $.PrivateBin.CopyToClipboard.init(); + $.PrivateBin.CopyToClipboard.hideKeyboardShortcutHint(); + + const keyboardShortcutHint = $('#copyShortcutHintText').text(); + + clean(); + + return keyboardShortcutHint.length === 0; + } + ); + }); +}); \ No newline at end of file diff --git a/js/test/CryptTool.js b/js/test/CryptTool.js index 627a242f..807e65ca 100644 --- a/js/test/CryptTool.js +++ b/js/test/CryptTool.js @@ -1,5 +1,5 @@ 'use strict'; -require('../common'); +const common = require('../common'); describe('CryptTool', function () { describe('cipher & decipher', function () { @@ -15,21 +15,26 @@ describe('CryptTool', function () { 'string', 'string', async function (key, password, message) { - // pause to let async functions conclude - await new Promise(resolve => setTimeout(resolve, 300)); - let clean = jsdom(); + const clean = jsdom(); // ensure zlib is getting loaded $.PrivateBin.Controller.initZ(); - window.crypto = new WebCrypto(); + Object.defineProperty(window, 'crypto', { + value: new WebCrypto(), + writeable: false, + }); + global.atob = common.atob; + global.btoa = common.btoa; message = message.trim(); - let cipherMessage = await $.PrivateBin.CryptTool.cipher( + const cipherMessage = await $.PrivateBin.CryptTool.cipher( key, password, message, [] ), plaintext = await $.PrivateBin.CryptTool.decipher( key, password, cipherMessage ); clean(); - return message === plaintext; + const result = (message === plaintext); + if (!result) console.log(plaintext, cipherMessage); + return result; } ), {tests: 3}); @@ -38,15 +43,19 @@ describe('CryptTool', function () { // The below static unit tests are included to ensure deciphering of "classic" // SJCL based pastes still works it( - 'supports PrivateBin v1 ciphertext (SJCL & browser atob)', - function () { + 'supports PrivateBin v1 ciphertext with password (SJCL & browser atob)', + async function () { delete global.Base64; - let clean = jsdom(); - window.crypto = new WebCrypto(); + const clean = jsdom(); + Object.defineProperty(window, 'crypto', { + value: new WebCrypto(), + writeable: false, + }); + 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. - return $.PrivateBin.CryptTool.decipher( + const paste = await $.PrivateBin.CryptTool.decipher( '6t2qsmLyfXIokNCL+3/yl15rfTUBQvm5SOnFPvNE7Q8=', // -- "That's amazing. I've got the same combination on my luggage." Array.apply(0, Array(6)).map((_,b) => b + 1).join(''), @@ -77,53 +86,76 @@ describe('CryptTool', function () { 'QUxMXI5htsn2rf0HxCFu7Po8DNYLxTS+67hYjDIYWYaEIc8LXWMLyDm9' + 'C5fARPJ4F2BIWgzgzkNj+dVjusft2XnziamWdbS5u3kuRlVuz5LQj+R5' + 'imnqQAincdZTkTT1nYx+DatlOLllCYIHffpI="}' - ).then(function (paste1) { - $.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"}' - ).then(function (paste2) { - clean(); - assert.ok( - paste1.includes('securely packed in iron') && - paste2.includes('Sol is right') - ); - }); - }); + ); + clean(); + const result = typeof paste === 'string' && paste.includes('securely packed in iron'); + if (!result) console.log(paste); + assert.ok(result); } ); it( - 'supports ZeroBin ciphertext (SJCL & Base64 1.7)', - function () { - global.Base64 = require('../base64-1.7').Base64; - var clean = jsdom(); - window.crypto = new WebCrypto(); + 'supports PrivateBin v1 ciphertext no password (SJCL & browser atob)', + async function () { + delete global.Base64; + const clean = jsdom(); + // ensure zlib is getting loaded + $.PrivateBin.Controller.initZ(); + Object.defineProperty(window, 'crypto', { + value: new WebCrypto(), + writeable: false, + }); + 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. - return $.PrivateBin.CryptTool.decipher( + 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( + 'supports ZeroBin ciphertext with password (SJCL & Base64 1.7)', + async function () { + global.Base64 = require('../base64-1.7').Base64; + const clean = jsdom(); + Object.defineProperty(window, 'crypto', { + value: new WebCrypto(), + writeable: false, + }); + 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( '6t2qsmLyfXIokNCL+3/yl15rfTUBQvm5SOnFPvNE7Q8=', // -- "That's amazing. I've got the same combination on my luggage." Array.apply(0, Array(6)).map((_,b) => b + 1).join(''), @@ -146,54 +178,74 @@ describe('CryptTool', function () { '7mNNo7xba/YT9KoPDaniqnYqb+q2pX1WNWE7dLS2wfroMAS3kh8P22DA' + 'V37AeiNoD2PcI6ZcHbRdPa+XRrRcJhSPPW7UQ0z4OvBfjdu/w390QxAx' + 'SxvZewoh49fKKB6hTsRnZb4tpHkjlww=="}' - ).then(function (paste1) { - $.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="}' - ).then(function (paste2) { - clean(); - delete global.Base64; - assert.ok( - paste1.includes('securely packed in iron') && - paste2.includes('Sol is right') - ); - }); + ); + clean(); + delete global.Base64; + const result = typeof paste === 'string' && paste.includes('securely packed in iron'); + if (!result) console.log(paste); + assert.ok(result); + } + ); + + it( + 'supports ZeroBin ciphertext no password (SJCL & Base64 1.7)', + async function () { + global.Base64 = require('../base64-1.7').Base64; + const clean = jsdom(); + Object.defineProperty(window, 'crypto', { + value: new WebCrypto(), + writeable: false, }); + 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 () { - let message = fs.readFileSync('test/compression-sample.txt', 'utf8'), + const message = fs.readFileSync('test/compression-sample.txt', 'ascii').trim(), clean = jsdom(); - window.crypto = new WebCrypto(); + Object.defineProperty(window, 'crypto', { + value: new WebCrypto(), + writeable: false, + }); // ensure zlib is getting loaded $.PrivateBin.Controller.initZ(); - let cipherMessage = await $.PrivateBin.CryptTool.cipher( + global.atob = common.atob; + global.btoa = common.btoa; + const cipherMessage = await $.PrivateBin.CryptTool.cipher( 'foo', 'bar', message, [] ), plaintext = await $.PrivateBin.CryptTool.decipher( - 'foo', 'bar', cipherMessage + 'foo', 'bar', cipherMessage ); clean(); - assert.strictEqual( - message, - plaintext - ); + const result = (message === plaintext); + if (!result) console.log(plaintext, cipherMessage); + assert.ok(result); }); it('can en- and decrypt a particular message (#260)', function () { @@ -201,8 +253,6 @@ describe('CryptTool', function () { 'string', 'string', async function (key, password) { - // pause to let async functions conclude - await new Promise(resolve => setTimeout(resolve, 300)); const message = ` 1 subgoal @@ -225,18 +275,23 @@ isWhile : interp (while expr sBody) (MemElem mem) = ======================== ( 1 / 1 ) conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem)) `; - let clean = jsdom(); + const clean = jsdom(); // ensure zlib is getting loaded $.PrivateBin.Controller.initZ(); - window.crypto = new WebCrypto(); - let cipherMessage = await $.PrivateBin.CryptTool.cipher( + Object.defineProperty(window, 'crypto', { + value: new WebCrypto(), + writeable: false, + }); + const cipherMessage = await $.PrivateBin.CryptTool.cipher( key, password, message, [] ), plaintext = await $.PrivateBin.CryptTool.decipher( key, password, cipherMessage ); clean(); - return message === plaintext; + const result = (message === plaintext); + if (!result) console.log(plaintext, cipherMessage); + return result; } ), {tests: 3}); @@ -244,23 +299,27 @@ conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem)) }); describe('getSymmetricKey', function () { - this.timeout(30000); - var keys = []; + this.timeout(10000); + let keys = []; // the parameter is used to ensure the test is run more then one time - jsc.property( - 'returns random, non-empty keys', - 'integer', - function(counter) { - var clean = jsdom(); - window.crypto = new WebCrypto(); - var key = $.PrivateBin.CryptTool.getSymmetricKey(), - result = (key !== '' && keys.indexOf(key) === -1); - keys.push(key); - clean(); - return result; - } - ); + it('returns random, non-empty keys', function () { + jsc.assert(jsc.forall( + 'integer', + function(counter) { + const clean = jsdom(); + Object.defineProperty(window, 'crypto', { + value: new WebCrypto(), + writeable: false, + }); + const key = $.PrivateBin.CryptTool.getSymmetricKey(), + result = (key !== '' && keys.indexOf(key) === -1); + keys.push(key); + clean(); + return result; + } + ), + {tests: 10}); + }); }); }); - diff --git a/js/test/Helper.js b/js/test/Helper.js index 95ae5709..a9ae41ab 100644 --- a/js/test/Helper.js +++ b/js/test/Helper.js @@ -229,30 +229,30 @@ describe('Helper', function () { cleanup(); }); +/* TODO test fails since jsDOM version 17 - document.cookie remains empty jsc.property( 'returns the requested cookie', jsc.nearray(jsc.nearray(common.jscAlnumString())), jsc.nearray(jsc.nearray(common.jscAlnumString())), function (labels, values) { - var selectedKey = '', selectedValue = '', - cookieArray = []; + let selectedKey = '', selectedValue = ''; + const clean = jsdom(); labels.forEach(function(item, i) { - var key = item.join(''), + const key = item.join(''), value = (values[i] || values[0]).join(''); - cookieArray.push(key + '=' + value); + document.cookie = key + '=' + value; if (Math.random() < 1 / i || selectedKey === key) { selectedKey = key; selectedValue = value; } }); - var clean = jsdom('', {cookie: cookieArray}), - result = $.PrivateBin.Helper.getCookie(selectedKey); + const result = $.PrivateBin.Helper.getCookie(selectedKey); $.PrivateBin.Helper.reset(); clean(); return result === selectedValue; } - ); + ); */ }); describe('baseUri', function () { @@ -290,5 +290,44 @@ describe('Helper', function () { } ); }); + + describe('formatBytes', function () { + jsc.property('returns 0 B for 0 bytes', function () { + return $.PrivateBin.Helper.formatBytes(0) === '0 B'; + }); + + jsc.property('formats bytes < 1000 as B', function () { + return $.PrivateBin.Helper.formatBytes(500) === '500 B'; + }); + + jsc.property('formats kibibytes correctly', function () { + return $.PrivateBin.Helper.formatBytes(1500) === '1.46 KiB'; + }); + + jsc.property('formats mebibytes correctly', function () { + return $.PrivateBin.Helper.formatBytes(2 * 1000 * 1000) === '1.91 MiB'; + }); + + jsc.property('formats gibibytes correctly', function () { + return $.PrivateBin.Helper.formatBytes(3.45 * 1000 * 1000 * 1000) === '3.21 GiB'; + }); + + jsc.property('rounds to two decimal places', function () { + return $.PrivateBin.Helper.formatBytes(1234567) === '1.18 MiB'; + }); + }); + + + describe('isBootstrap5', function () { + jsc.property('Bootstrap 5 has been detected', function () { + global.bootstrap = {}; + return $.PrivateBin.Helper.isBootstrap5() === true; + }); + + jsc.property('Bootstrap 5 has not been detected', function () { + delete global.bootstrap; + return $.PrivateBin.Helper.isBootstrap5() === false; + }); + }); }); diff --git a/js/test/Model.js b/js/test/Model.js index db2198ba..77adbead 100644 --- a/js/test/Model.js +++ b/js/test/Model.js @@ -94,7 +94,6 @@ describe('Model', function () { url.query = queryStart.concat(pasteId, queryEnd); const pasteIdString = pasteId.join(''), clean = jsdom('', {url: common.urlToString(url)}); - global.URL = require('jsdom-url').URL; const result = $.PrivateBin.Model.getPasteId(); $.PrivateBin.Model.reset(); clean(); @@ -107,7 +106,6 @@ describe('Model', function () { function (url) { let clean = jsdom('', {url: common.urlToString(url)}), result = false; - global.URL = require('jsdom-url').URL; try { $.PrivateBin.Model.getPasteId(); } @@ -131,7 +129,7 @@ describe('Model', function () { 'returns the fragment of a v1 URL', common.jscUrl(), function (url) { - url.fragment = common.btoa(url.fragment.padStart(32, '\u0000')); + url.fragment = '0OIl'; // any non-base58 string const clean = jsdom('', {url: common.urlToString(url)}), result = $.PrivateBin.Model.getPasteKey(); $.PrivateBin.Model.reset(); @@ -140,17 +138,17 @@ describe('Model', function () { } ); jsc.property( - 'returns the v1 fragment stripped of trailing query parts', + 'returns the fragment stripped of trailing query parts', common.jscUrl(), jsc.array(common.jscHashString()), function (url, trail) { - const fragmentString = common.btoa(url.fragment.padStart(32, '\u0000')); - url.fragment = fragmentString + '&' + trail.join(''); + const fragment = url.fragment.padStart(32, '\u0000'); + url.fragment = $.PrivateBin.CryptTool.base58encode(fragment) + '&' + trail.join(''); const clean = jsdom('', {url: common.urlToString(url)}), result = $.PrivateBin.Model.getPasteKey(); $.PrivateBin.Model.reset(); clean(); - return fragmentString === result; + return fragment === result; } ); jsc.property( diff --git a/js/test/PasteStatus.js b/js/test/PasteStatus.js index a233bb48..bb24840b 100644 --- a/js/test/PasteStatus.js +++ b/js/test/PasteStatus.js @@ -30,11 +30,11 @@ describe('PasteStatus', function () { const expected1 = common.urlToString(url1).replace(/&(gt|lt)$/, '&$1a'), expected2 = common.urlToString(url2).replace(/&(gt|lt)$/, '&$1a'), clean = jsdom(); - $('body').html('
'); + $('body').html(''); $.PrivateBin.PasteStatus.init(); $.PrivateBin.PasteStatus.createPasteNotification(expected1, expected2); const result1 = $('#pasteurl')[0].href, - result2 = $('#deletelink a')[0].href; + result2 = $('#deletelink')[0].href; clean(); return result1 === expected1 && result2 === expected2; } @@ -155,7 +155,7 @@ describe('PasteStatus', function () { '\t\tPrivateBin\n' + '\t\n' + '\t\n' + - '\t\t

Your paste is ' + shortUrlString + ' (Hit [Ctrl]+[c] to copy)

\n' + + '\t\t

Your paste is ' + shortUrlString + ' (Hit Ctrl+c to copy)

\n' + '\t\n' + '', clean = jsdom(); @@ -255,4 +255,3 @@ describe('PasteStatus', function () { ); }); }); - diff --git a/js/test/Prompt.js b/js/test/Prompt.js index e7c88501..afcb9866 100644 --- a/js/test/Prompt.js +++ b/js/test/Prompt.js @@ -2,8 +2,6 @@ require('../common'); describe('Prompt', function () { - // TODO: this does not test the prompt() fallback, since that isn't available - // in nodejs -> replace the prompt in the "page" template with a modal describe('requestPassword & getPassword', function () { this.timeout(30000); @@ -11,7 +9,7 @@ describe('Prompt', function () { 'returns the password fed into the dialog', 'string', function (password) { - password = password.replace(/\r+/g, ''); + password = password.replace(/\r+|\n+/g, ''); var clean = jsdom('', {url: 'ftp://example.com/?0000000000000000'}); $('body').html( '