Compare commits
251 Commits
Author | SHA1 | Date |
---|---|---|
El RIDO | 74ac3350a3 | |
PrivateBin Translator Bot | 5a52f71bb7 | |
El RIDO | f0794e3c0b | |
El RIDO | db287a10fe | |
Aaron Sherber | 7a4c6c010f | |
Aaron Sherber | 7c9cc7754f | |
El RIDO | 6eb5fdcc06 | |
El RIDO | e1e0e8399c | |
El RIDO | 89a5d07b94 | |
El RIDO | 5f00587d71 | |
El RIDO | 53d2d3334d | |
Aaron Sherber | fd7d9f4715 | |
Aaron Sherber | 8abf6ae9cb | |
El RIDO | a62f4babbf | |
El RIDO | d52b8af0f5 | |
dependabot[bot] | 6474c374e2 | |
PrivateBin Translator Bot | b15571ae4a | |
El RIDO | c162f04384 | |
Florian | 6999ed3f4b | |
El RIDO | 03e7f6a9a7 | |
PrivateBin Translator Bot | a1095d0d21 | |
El RIDO | 7576459135 | |
rugk | cb117d6797 | |
El RIDO | 244703babb | |
PrivateBin Translator Bot | b00085f30f | |
PrivateBin Translator Bot | fc1b1ae0ca | |
PrivateBin Translator Bot | 45e335eca6 | |
PrivateBin Translator Bot | f03bccd31e | |
PrivateBin Translator Bot | 04da6db079 | |
PrivateBin Translator Bot | 580a034189 | |
PrivateBin Translator Bot | 6c5a500fcd | |
PrivateBin Translator Bot | da4ad06758 | |
PrivateBin Translator Bot | 2f394a4714 | |
PrivateBin Translator Bot | 39949cea34 | |
PrivateBin Translator Bot | a9d287874b | |
PrivateBin Translator Bot | 2381e30dc4 | |
PrivateBin Translator Bot | 0255f72ae0 | |
PrivateBin Translator Bot | 900200c35f | |
PrivateBin Translator Bot | 860b4b183e | |
PrivateBin Translator Bot | e585aeacda | |
PrivateBin Translator Bot | a4820618dd | |
PrivateBin Translator Bot | d957d344d1 | |
PrivateBin Translator Bot | c9c99f7535 | |
PrivateBin Translator Bot | 516a4c7d13 | |
PrivateBin Translator Bot | 2ccc90798f | |
PrivateBin Translator Bot | 647ddebb5c | |
PrivateBin Translator Bot | f40f3dd3a5 | |
PrivateBin Translator Bot | ce4f3a1b09 | |
PrivateBin Translator Bot | 888b3cb49c | |
PrivateBin Translator Bot | 6e0bc8bceb | |
PrivateBin Translator Bot | 43d396efd9 | |
PrivateBin Translator Bot | 3b6ebfdf02 | |
PrivateBin Translator Bot | f3df151a8c | |
PrivateBin Translator Bot | e4329b623d | |
PrivateBin Translator Bot | e18ec99aa9 | |
PrivateBin Translator Bot | 6d2d19c38c | |
PrivateBin Translator Bot | 532f85c6b7 | |
PrivateBin Translator Bot | 0dc7b1f6fc | |
PrivateBin Translator Bot | f0cc0e878a | |
PrivateBin Translator Bot | 2f775c218c | |
PrivateBin Translator Bot | 98b3d0e2ae | |
PrivateBin Translator Bot | 7ba642c0ad | |
PrivateBin Translator Bot | 63b63354d7 | |
PrivateBin Translator Bot | 569b47ee62 | |
PrivateBin Translator Bot | 050917f035 | |
PrivateBin Translator Bot | eff7eb5e23 | |
PrivateBin Translator Bot | 326feb1808 | |
PrivateBin Translator Bot | 3ed954fef4 | |
PrivateBin Translator Bot | ebe997bd02 | |
PrivateBin Translator Bot | a90a874d82 | |
PrivateBin Translator Bot | dd49b8e694 | |
PrivateBin Translator Bot | fec82754bb | |
PrivateBin Translator Bot | 24bd804d38 | |
PrivateBin Translator Bot | d0d77325de | |
PrivateBin Translator Bot | a8b4bf84c4 | |
PrivateBin Translator Bot | a398b1ff59 | |
PrivateBin Translator Bot | 3e2fc24e11 | |
PrivateBin Translator Bot | e6acab38d8 | |
PrivateBin Translator Bot | bcd899b3c4 | |
PrivateBin Translator Bot | 196e5046ac | |
PrivateBin Translator Bot | 64a209483a | |
PrivateBin Translator Bot | a5725d503e | |
PrivateBin Translator Bot | 14a73ddc61 | |
PrivateBin Translator Bot | 1503fb8aa7 | |
PrivateBin Translator Bot | 5291e381c8 | |
PrivateBin Translator Bot | a412a85ad0 | |
PrivateBin Translator Bot | 64e533ba8c | |
PrivateBin Translator Bot | 57a03839fa | |
PrivateBin Translator Bot | 7d8f57ffe8 | |
PrivateBin Translator Bot | a14151b85c | |
PrivateBin Translator Bot | 76affbc63b | |
El RIDO | 253e078263 | |
PrivateBin Translator Bot | 8b66612622 | |
PrivateBin Translator Bot | bfddc388b9 | |
PrivateBin Translator Bot | a68d81b10b | |
PrivateBin Translator Bot | c37ca3f495 | |
PrivateBin Translator Bot | 4048e2f45d | |
PrivateBin Translator Bot | 024bbc246e | |
PrivateBin Translator Bot | 25318facd7 | |
PrivateBin Translator Bot | 1e9c5cb812 | |
PrivateBin Translator Bot | cab26c619b | |
PrivateBin Translator Bot | cabfa18a35 | |
PrivateBin Translator Bot | 629faeea8d | |
PrivateBin Translator Bot | 0a9770ae51 | |
PrivateBin Translator Bot | 5c76cc9203 | |
PrivateBin Translator Bot | 7710a6066c | |
PrivateBin Translator Bot | 94f0808996 | |
PrivateBin Translator Bot | 494623eec7 | |
PrivateBin Translator Bot | 7174be4dfb | |
PrivateBin Translator Bot | af72f0694d | |
PrivateBin Translator Bot | 126d08933a | |
PrivateBin Translator Bot | 5ec102a75c | |
PrivateBin Translator Bot | cd33a4824b | |
PrivateBin Translator Bot | 966d0f5d64 | |
PrivateBin Translator Bot | 37c57e5815 | |
PrivateBin Translator Bot | 5854770286 | |
PrivateBin Translator Bot | 40df875334 | |
PrivateBin Translator Bot | 120fe77e1e | |
PrivateBin Translator Bot | 5bf7c04e04 | |
PrivateBin Translator Bot | 9f623b4130 | |
PrivateBin Translator Bot | 41b20da78b | |
PrivateBin Translator Bot | 3547e67cc6 | |
PrivateBin Translator Bot | 4eb55be55e | |
PrivateBin Translator Bot | c3d143f9ba | |
PrivateBin Translator Bot | 7467c7998c | |
PrivateBin Translator Bot | 979dc58575 | |
PrivateBin Translator Bot | 41a3748656 | |
El RIDO | c5704b445a | |
El RIDO | c172cde994 | |
El RIDO | 7d070fe3a4 | |
PrivateBin Translator Bot | 28a05abfc5 | |
PrivateBin Translator Bot | 456e62f29b | |
El RIDO | 63b2526ee7 | |
El RIDO | dd8aa4f8fb | |
El RIDO | 6dddf808c6 | |
El RIDO | eb59f3a4f3 | |
El RIDO | aad975a721 | |
El RIDO | 5c29619fee | |
El RIDO | a3ee624d3a | |
El RIDO | 1eee8032c7 | |
PrivateBin Translator Bot | f3fba1c0f5 | |
PrivateBin Translator Bot | a54a55a9a1 | |
PrivateBin Translator Bot | 56f0ec7d52 | |
PrivateBin Translator Bot | 208c922e04 | |
El RIDO | 4db0db320b | |
PrivateBin Translator Bot | 772ab96364 | |
PrivateBin Translator Bot | dc2db9e622 | |
PrivateBin Translator Bot | 6d559c3043 | |
PrivateBin Translator Bot | 096a5118d1 | |
PrivateBin Translator Bot | 5084ab7a07 | |
PrivateBin Translator Bot | fbe4ac5a6c | |
PrivateBin Translator Bot | 4e21e980de | |
PrivateBin Translator Bot | a3243b3165 | |
PrivateBin Translator Bot | 223ef02a43 | |
PrivateBin Translator Bot | c7da424ef9 | |
PrivateBin Translator Bot | e1c74457e5 | |
PrivateBin Translator Bot | 1a6c3dd8d8 | |
PrivateBin Translator Bot | 146b2513c1 | |
PrivateBin Translator Bot | 5ec8a57c60 | |
PrivateBin Translator Bot | cd67d81ae3 | |
PrivateBin Translator Bot | 218e68a604 | |
PrivateBin Translator Bot | 9611991748 | |
PrivateBin Translator Bot | b613d9558c | |
PrivateBin Translator Bot | 5523ba9a45 | |
PrivateBin Translator Bot | 421342396f | |
PrivateBin Translator Bot | 4e3b469c08 | |
PrivateBin Translator Bot | cb0edf4f2b | |
PrivateBin Translator Bot | a0f8e0a566 | |
PrivateBin Translator Bot | 089652382a | |
PrivateBin Translator Bot | a1408601d9 | |
PrivateBin Translator Bot | 3d4887e5f0 | |
PrivateBin Translator Bot | 5c876df2ea | |
PrivateBin Translator Bot | fe4a64529a | |
PrivateBin Translator Bot | a25bfd4cce | |
PrivateBin Translator Bot | 53639b913e | |
PrivateBin Translator Bot | 9379a73632 | |
PrivateBin Translator Bot | efd6c3f8c4 | |
PrivateBin Translator Bot | 51f68f0c78 | |
PrivateBin Translator Bot | ad2de3a135 | |
PrivateBin Translator Bot | ea7f1fca6e | |
El RIDO | 57b1890815 | |
El RIDO | 7bb913acdf | |
El RIDO | 25de89c954 | |
El RIDO | 950c0b56b4 | |
El RIDO | 070ae2e5ec | |
El RIDO | 239f6da73c | |
El RIDO | 257fc5d2b6 | |
El RIDO | 03d2291ec7 | |
El RIDO | 56f5b2386c | |
El RIDO | d0e03e5167 | |
El RIDO | 0d2376cd88 | |
El RIDO | df703dfe4b | |
dependabot[bot] | 3ff3db72a1 | |
El RIDO | a27cb0cffc | |
dependabot[bot] | ba25ab8fa9 | |
El RIDO | d091382313 | |
Tobias Gurtzick | 2a508cb7bf | |
Tobias Gurtzick | 8516a3f4a4 | |
Tobias Gurtzick | 2cc2cf0de7 | |
Tobias Gurtzick | e1e8618015 | |
Tobias Gurtzick | 7fddefeb05 | |
El RIDO | 4e62e1f6ef | |
El RIDO | 405479642f | |
El RIDO | fd82b937a9 | |
El RIDO | d493ba7337 | |
El RIDO | 37ee3b1c7c | |
PrivateBin Translator Bot | 7ab20c23e9 | |
PrivateBin Translator Bot | cc5c81afbc | |
El RIDO | 9fb7aee589 | |
El RIDO | ba17e94c5e | |
El RIDO | c3331070cb | |
El RIDO | cc0b6e387a | |
El RIDO | a80bd4e4ea | |
PrivateBin Translator Bot | b3b97b69c6 | |
El RIDO | 8427c1136c | |
El RIDO | 7cb1f8ca67 | |
El RIDO | 9a707e288a | |
El RIDO | 83a1de271a | |
PrivateBin Translator Bot | c264904f77 | |
El RIDO | 712715caba | |
El RIDO | 2985305dbb | |
El RIDO | 0581522414 | |
El RIDO | dc8cb66adc | |
El RIDO | 54585549e0 | |
El RIDO | d49be80ffb | |
El RIDO | a17529c7e1 | |
El RIDO | 0a7a341fda | |
El RIDO | d88945663e | |
El RIDO | 255fd4b12b | |
rugk | 43d162f452 | |
El RIDO | 9b07e3ff62 | |
El RIDO | d0420fb418 | |
El RIDO | 3b17dfc6ef | |
dependabot[bot] | 03e3e4fa06 | |
El RIDO | 879c7400bf | |
El RIDO | 46d8d7d781 | |
El RIDO | 684924e9e5 | |
El RIDO | a7f720d825 | |
El RIDO | 826444bef7 | |
Joe Skeen | 10c6841f8a | |
Joe Skeen | 49a87c6038 | |
Joe Skeen | 7a5036d957 | |
El RIDO | f8c2f58604 | |
El RIDO | edec91de1c | |
El RIDO | 8131518ba1 | |
PrivateBin Translator Bot | bb89eb7fba | |
El RIDO | 94d1908777 | |
PrivateBin Translator Bot | 5b2f788e48 | |
PrivateBin Translator Bot | 33e9025d09 | |
dependabot[bot] | 6133f6c35c | |
J. Fernando LAGRANGE | f797311650 |
|
@ -40,11 +40,7 @@
|
|||
"forwardPorts": [
|
||||
8080
|
||||
],
|
||||
"postCreateCommand": [
|
||||
"composer install --no-dev --optimize-autoloader",
|
||||
"sudo chmod a+x \"$(pwd)\" && sudo rm -rf /var/www/html && sudo ln -s \"$(pwd)\" /var/www/html",
|
||||
"npm install --global nyc"
|
||||
],
|
||||
"postCreateCommand": ".devcontainer/postCreateCommand.sh",
|
||||
// alternatiuve: apache2ctl start (but requires root)
|
||||
"postAttachCommand": "php -S 0.0.0.0:8080"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/sh
|
||||
|
||||
composer install --no-dev --optimize-autoloader
|
||||
sudo chmod a+x "$(pwd)" && sudo rm -rf /var/www/html && sudo ln -s "$(pwd)" /var/www/html
|
||||
npm install --global nyc
|
|
@ -26,8 +26,6 @@ js/test/ export-ignore
|
|||
.vscode export-ignore
|
||||
codacy-analysis.yml export-ignore
|
||||
crowdin.yml export-ignore
|
||||
composer.json export-ignore
|
||||
composer.lock export-ignore
|
||||
BADGES.md export-ignore
|
||||
CODE_OF_CONDUCT.md export-ignore
|
||||
Makefile export-ignore
|
||||
|
|
|
@ -37,7 +37,7 @@ jobs:
|
|||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
|
@ -46,4 +46,4 @@ jobs:
|
|||
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
|
|
@ -34,7 +34,7 @@ jobs:
|
|||
- name: Generate hashes
|
||||
shell: bash
|
||||
id: hash
|
||||
run: echo "hashes=$(sha256sum ${GITHUB_REF_NAME} | base64 -w0)" >> "$GITHUB_OUTPUT"
|
||||
run: echo "hashes=$(sha256sum ${GITHUB_REF_NAME}.* | base64 -w0)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
provenance:
|
||||
needs:
|
||||
|
|
|
@ -24,6 +24,6 @@ jobs:
|
|||
with:
|
||||
args: --sarif-file-output=snyk.sarif
|
||||
- name: Upload result to GitHub Code Scanning
|
||||
uses: github/codeql-action/upload-sarif@v2
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: snyk.sarif
|
||||
|
|
|
@ -41,7 +41,7 @@ jobs:
|
|||
key: ${{ runner.os }}-${{ env.extensions-cache-key }}
|
||||
|
||||
- name: Cache extensions
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ steps.extcache.outputs.dir }}
|
||||
key: ${{ steps.extcache.outputs.key }}
|
||||
|
@ -76,7 +76,7 @@ jobs:
|
|||
shell: bash
|
||||
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-${{ steps.get-date.outputs.date }}-${{ hashFiles('**/composer.json') }}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"files.associations": {
|
||||
"**/cfg/conf*.php": "ini"
|
||||
}
|
||||
}
|
26
CHANGELOG.md
26
CHANGELOG.md
|
@ -1,12 +1,36 @@
|
|||
# PrivateBin version history
|
||||
|
||||
## 1.7.2 (not yet released)
|
||||
* ADDED: Allow use of `shortenviayourls` in query parameters (#1267)
|
||||
* CHANGED: "Send" button now labeled "Create" (#946)
|
||||
* FIXED: Add cache control headers also to API calls (#1263)
|
||||
* FIXED: Shortened paste URL does not appear in email (#606)
|
||||
|
||||
## 1.7.1 (2024-02-11)
|
||||
* FIXED: zlib 1.3.1 wasm file reference
|
||||
|
||||
## 1.7.0 (2024-02-11)
|
||||
* ADDED: Translations for Romanian
|
||||
* ADDED: Detect and report on damaged pastes (#1218)
|
||||
* CHANGED: Ask for confirmation, before loading burn after reading pastes (#1237)
|
||||
* CHANGED: Focus on password input in modal dialog
|
||||
* CHANGED: Upgrading libraries to: DOMpurify 3.0.8 & zlib 1.3.1
|
||||
* FIXED: Support more types of valid URLs for shorteners, incl. IDN ones (#1224)
|
||||
* FIXED: Email timezone buttons overlapping in some languages (#1039)
|
||||
* FIXED: Changing language mangles URL (#1191)
|
||||
* FIXED: Needless reload when visiting default URL
|
||||
|
||||
## 1.6.2 (2023-12-15)
|
||||
* FIXED: English not selectable when `languageselection` enabled (#1208)
|
||||
* FIXED: SRI mismatch due to cached file having changed (#1207)
|
||||
|
||||
## 1.6.1 (2023-12-04)
|
||||
* ADDED: Right-To-Left (RTL) support for Arabic & Hebrew (#1174)
|
||||
* CHANGED: Upgrading libraries to: DOMpurify 3.0.6
|
||||
|
||||
## 1.6.0 (2023-09-11)
|
||||
* ADDED: Translations for Japanese & Arabic
|
||||
* ADDED: Configuration option to disable Email button (#1164)
|
||||
* ADDED: Configuration option to disable email button (#1164)
|
||||
* CHANGED: Minimum required PHP version is 7.3, due to upgrading PHPunit (#707)
|
||||
* CHANGED: Removed PHP 5 polyfill for random_bytes()
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
* Felix J. Ogris - S3 Storage backend, script for data backend migrations, dropped singleton behaviour of data backends
|
||||
* Mounir Idrassi & J. Mozdzen - secure YOURLS integration
|
||||
* Felipe Nakandakari - enabled AWS SDK to use default credential provider chain in the S3 Storage backend
|
||||
* Aaron Sherber - cache control headers for API calls & use of `shortenviayourls` in query parameters
|
||||
|
||||
## Translations
|
||||
* Hexalyse - French
|
||||
|
@ -65,3 +66,4 @@
|
|||
* jaideejung007 - Thai
|
||||
* Nicolas Le Gall - Japanese
|
||||
* lazerns - Arabic
|
||||
* Edward205 - Romanian
|
||||
|
|
6
Makefile
6
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.6.1
|
||||
VERSION ?= 1.6.2
|
||||
CURRENT_VERSION = 1.7.1
|
||||
VERSION ?= 1.7.2
|
||||
VERSION_FILES = index.php bin/ cfg/ *.md doc/Installation.md css/ i18n/ img/ js/package.json js/privatebin.js lib/ Makefile tpl/ tst/
|
||||
REGEX_CURRENT_VERSION := $(shell echo $(CURRENT_VERSION) | sed "s/\./\\\./g")
|
||||
REGEX_VERSION := $(shell echo $(VERSION) | sed "s/\./\\\./g")
|
||||
|
@ -17,7 +17,7 @@ coverage-js: ## Run JS unit tests and generate code coverage reports.
|
|||
cd js && nyc mocha
|
||||
|
||||
coverage-php: ## Run PHP unit tests and generate code coverage reports.
|
||||
cd tst && phpunit 2> /dev/null
|
||||
cd tst && XDEBUG_MODE=coverage phpunit 2> /dev/null
|
||||
cd tst/log/php-coverage-report && sed -i "s#$(CURDIR)/##g" *.html */*.html
|
||||
|
||||
doc: doc-js doc-php ## Generate all code documentation.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# [![PrivateBin](https://cdn.rawgit.com/PrivateBin/assets/master/images/preview/logoSmall.png)](https://privatebin.info/)
|
||||
|
||||
*Current version: 1.6.1*
|
||||
*Current version: 1.7.1*
|
||||
|
||||
**PrivateBin** is a minimalist, open source online
|
||||
[pastebin](https://en.wikipedia.org/wiki/Pastebin)
|
||||
|
@ -55,7 +55,7 @@ without losing any data.
|
|||
paste (first) might still be disclosed via access logs.
|
||||
|
||||
- In case of a server breach your data is secure as it is only stored encrypted
|
||||
on the server. However, the server could be absused or the server admin could
|
||||
on the server. However, the server could be abused or the server admin could
|
||||
be legally forced into sending malicious code to their users, which logs
|
||||
the decryption key and sends it to a server when a user accesses a paste.
|
||||
Therefore, do not access any PrivateBin instance if you think it has been
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 1.6.1 | :heavy_check_mark: |
|
||||
| < 1.6.1 | :x: |
|
||||
| 1.7.1 | :heavy_check_mark: |
|
||||
| < 1.7.1 | :x: |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
|
|
|
@ -9,11 +9,12 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin;
|
||||
|
||||
use Exception;
|
||||
use PrivateBin\Configuration;
|
||||
use PrivateBin\Data\AbstractData;
|
||||
use PrivateBin\Model\Paste;
|
||||
|
@ -195,6 +196,7 @@ EOT, PHP_EOL;
|
|||
{
|
||||
$counters = array(
|
||||
'burn' => 0,
|
||||
'damaged' => 0,
|
||||
'discussion' => 0,
|
||||
'expired' => 0,
|
||||
'md' => 0,
|
||||
|
@ -217,7 +219,12 @@ EOT, PHP_EOL;
|
|||
|
||||
echo "Total:\t\t\t{$counters['total']}", PHP_EOL;
|
||||
foreach ($ids as $pasteid) {
|
||||
$paste = $this->_store->read($pasteid);
|
||||
try {
|
||||
$paste = $this->_store->read($pasteid);
|
||||
} catch (Exception $e) {
|
||||
echo "Error reading paste {$pasteid}: ", $e->getMessage(), PHP_EOL;
|
||||
++$counters['damaged'];
|
||||
}
|
||||
++$counters['progress'];
|
||||
|
||||
if (
|
||||
|
@ -271,6 +278,9 @@ Plain Text:\t\t{$counters['plain']}
|
|||
Source Code:\t\t{$counters['syntax']}
|
||||
Markdown:\t\t{$counters['md']}
|
||||
EOT, PHP_EOL;
|
||||
if ($counters['damaged'] > 0) {
|
||||
echo "Damaged:\t\t{$counters['damaged']}", PHP_EOL;
|
||||
}
|
||||
if ($counters['unknown'] > 0) {
|
||||
echo "Unknown format:\t\t{$counters['unknown']}", PHP_EOL;
|
||||
}
|
||||
|
@ -305,7 +315,12 @@ EOT, PHP_EOL;
|
|||
}
|
||||
|
||||
if ($this->_option('p', 'purge') !== null) {
|
||||
$this->_store->purge(PHP_INT_MAX);
|
||||
try {
|
||||
$this->_store->purge(PHP_INT_MAX);
|
||||
} catch (Exception $e) {
|
||||
echo 'Error purging pastes: ', $e->getMessage(), PHP_EOL,
|
||||
'Run the statistics to find damaged paste IDs and either delete them or restore them from backup.', PHP_EOL;
|
||||
}
|
||||
exit('purging of expired pastes concluded' . PHP_EOL);
|
||||
}
|
||||
|
||||
|
|
|
@ -254,8 +254,8 @@ dir = PATH "data"
|
|||
; Only use this if you allow short URL creation without credentials.
|
||||
; - Alternatively, using the parameters in this section ("signature" and
|
||||
; "apiurl"), "urlshortener" needs to point to the base URL of your PrivateBin
|
||||
; instance with "shortenviayourls?link=" appended. For example:
|
||||
; urlshortener = "${basepath}shortenviayourls?link="
|
||||
; instance with "?shortenviayourls&link=" appended. For example:
|
||||
; urlshortener = "${basepath}?shortenviayourls&link="
|
||||
; This URL will in turn call YOURLS on the server side, using the URL from
|
||||
; "apiurl" and the "access signature" from the "signature" parameters below.
|
||||
|
||||
|
|
|
@ -24,10 +24,10 @@
|
|||
"docs" : "https://privatebin.info/codedoc/"
|
||||
},
|
||||
"require" : {
|
||||
"php" : "^7.3 || ^8.0",
|
||||
"yzalis/identicon" : "2.0.0",
|
||||
"mlocati/ip-lib" : "1.18.0",
|
||||
"jdenticon/jdenticon": "1.0.2"
|
||||
"php": "^7.3 || ^8.0",
|
||||
"jdenticon/jdenticon": "1.0.2",
|
||||
"mlocati/ip-lib": "1.18.0",
|
||||
"yzalis/identicon": "2.0.0"
|
||||
},
|
||||
"suggest" : {
|
||||
"google/cloud-storage" : "1.32.0",
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "96f9b3968855bf9f45813d12568f1cac",
|
||||
"content-hash": "b76c0c25f93dc79c4525cb3c86e5af99",
|
||||
"packages": [
|
||||
{
|
||||
"name": "jdenticon/jdenticon",
|
||||
|
@ -316,16 +316,16 @@
|
|||
},
|
||||
{
|
||||
"name": "nikic/php-parser",
|
||||
"version": "v4.17.1",
|
||||
"version": "v4.18.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/nikic/PHP-Parser.git",
|
||||
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d"
|
||||
"reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
|
||||
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
|
||||
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999",
|
||||
"reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -366,9 +366,9 @@
|
|||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/nikic/PHP-Parser/issues",
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1"
|
||||
"source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0"
|
||||
},
|
||||
"time": "2023-08-13T19:53:39+00:00"
|
||||
"time": "2023-12-10T21:03:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phar-io/manifest",
|
||||
|
@ -483,23 +483,23 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
"version": "9.2.29",
|
||||
"version": "9.2.30",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
|
||||
"reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76"
|
||||
"reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76",
|
||||
"reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089",
|
||||
"reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-dom": "*",
|
||||
"ext-libxml": "*",
|
||||
"ext-xmlwriter": "*",
|
||||
"nikic/php-parser": "^4.15",
|
||||
"nikic/php-parser": "^4.18 || ^5.0",
|
||||
"php": ">=7.3",
|
||||
"phpunit/php-file-iterator": "^3.0.3",
|
||||
"phpunit/php-text-template": "^2.0.2",
|
||||
|
@ -549,7 +549,7 @@
|
|||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
|
||||
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29"
|
||||
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -557,7 +557,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2023-09-19T04:57:46+00:00"
|
||||
"time": "2023-12-22T06:47:57+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-file-iterator",
|
||||
|
@ -802,16 +802,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "9.6.14",
|
||||
"version": "9.6.17",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "43653e6ad7adc22e7b667dd561bf8fcb74c10cf0"
|
||||
"reference": "1a156980d78a6666721b7e8e8502fe210b587fcd"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43653e6ad7adc22e7b667dd561bf8fcb74c10cf0",
|
||||
"reference": "43653e6ad7adc22e7b667dd561bf8fcb74c10cf0",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1a156980d78a6666721b7e8e8502fe210b587fcd",
|
||||
"reference": "1a156980d78a6666721b7e8e8502fe210b587fcd",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -885,7 +885,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.14"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.17"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -901,7 +901,7 @@
|
|||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2023-12-01T06:10:48+00:00"
|
||||
"time": "2024-02-23T13:14:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/cli-parser",
|
||||
|
@ -1146,20 +1146,20 @@
|
|||
},
|
||||
{
|
||||
"name": "sebastian/complexity",
|
||||
"version": "2.0.2",
|
||||
"version": "2.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/complexity.git",
|
||||
"reference": "739b35e53379900cc9ac327b2147867b8b6efd88"
|
||||
"reference": "25f207c40d62b8b7aa32f5ab026c53561964053a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88",
|
||||
"reference": "739b35e53379900cc9ac327b2147867b8b6efd88",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a",
|
||||
"reference": "25f207c40d62b8b7aa32f5ab026c53561964053a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"nikic/php-parser": "^4.7",
|
||||
"nikic/php-parser": "^4.18 || ^5.0",
|
||||
"php": ">=7.3"
|
||||
},
|
||||
"require-dev": {
|
||||
|
@ -1191,7 +1191,7 @@
|
|||
"homepage": "https://github.com/sebastianbergmann/complexity",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/complexity/issues",
|
||||
"source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2"
|
||||
"source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1199,7 +1199,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-10-26T15:52:27+00:00"
|
||||
"time": "2023-12-22T06:19:30+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/diff",
|
||||
|
@ -1473,20 +1473,20 @@
|
|||
},
|
||||
{
|
||||
"name": "sebastian/lines-of-code",
|
||||
"version": "1.0.3",
|
||||
"version": "1.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/lines-of-code.git",
|
||||
"reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc"
|
||||
"reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc",
|
||||
"reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5",
|
||||
"reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"nikic/php-parser": "^4.6",
|
||||
"nikic/php-parser": "^4.18 || ^5.0",
|
||||
"php": ">=7.3"
|
||||
},
|
||||
"require-dev": {
|
||||
|
@ -1518,7 +1518,7 @@
|
|||
"homepage": "https://github.com/sebastianbergmann/lines-of-code",
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
|
||||
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3"
|
||||
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
|
@ -1526,7 +1526,7 @@
|
|||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2020-11-28T06:42:11+00:00"
|
||||
"time": "2023-12-22T06:20:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/object-enumerator",
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
body {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
/* When there is no script at all other */
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
/* CSS Reset from YUI 3.4.1 (build 4118) - Copyright 2011 Yahoo! Inc. All rights reserved.
|
||||
|
|
|
@ -201,7 +201,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.6.1');
|
||||
INSERT INTO prefix_config VALUES('VERSION', '1.7.1');
|
||||
```
|
||||
|
||||
In **PostgreSQL**, the `data`, `attachment`, `nickname` and `vizhash` columns
|
||||
|
@ -213,11 +213,30 @@ to be `CLOB` and not `BLOB` or `MEDIUMBLOB`, the `id` column in the `config`
|
|||
table needs to be `VARCHAR2(16)` and the `meta` column in the `paste` table
|
||||
and the `value` column in the `config` table need to be `VARCHAR2(4000)`.
|
||||
|
||||
### Cloud Storage Backends
|
||||
|
||||
Due to the large size of the respective cloud SDKs required for these, we didn't
|
||||
include these in the `vendor` directory shipped in our release archives. To use
|
||||
these in your manual installation, you will need [composer installed](https://getcomposer.org/)
|
||||
and require the used library (see instructions below).
|
||||
|
||||
This is not required if using the dedicated container images that have these SDKs
|
||||
preinstalled.
|
||||
|
||||
#### Using Google Cloud Storage
|
||||
If you want to deploy PrivateBin in a serverless manner in the Google Cloud, you
|
||||
can choose the `GoogleCloudStorage` as backend. To use this backend, you create
|
||||
a GCS bucket and specify the name as the model option `bucket`. Alternatively,
|
||||
you can set the name through the environment variable `PRIVATEBIN_GCS_BUCKET`.
|
||||
can choose the `GoogleCloudStorage` as backend.
|
||||
|
||||
To use this backend, you first have to install the SDK from the installation
|
||||
directory of PrivateBin:
|
||||
|
||||
```console
|
||||
composer require --no-update google/cloud-storage
|
||||
composer update --no-dev --optimize-autoloader
|
||||
```
|
||||
|
||||
You have to create a GCS bucket and specify the name as the model option `bucket`.
|
||||
Alternatively, you can set the name through the environment variable `PRIVATEBIN_GCS_BUCKET`.
|
||||
|
||||
The default prefix for pastes stored in the bucket is `pastes`. To change the
|
||||
prefix, specify the option `prefix`.
|
||||
|
@ -226,15 +245,20 @@ Google Cloud Storage buckets may be significantly slower than a `FileSystem` or
|
|||
`Database` backend. The big advantage is that the deployment on Google Cloud
|
||||
Platform using Google Cloud Run is easy and cheap.
|
||||
|
||||
To use the Google Cloud Storage backend you have to install the suggested
|
||||
library using the command `composer require google/cloud-storage`.
|
||||
|
||||
#### Using S3 Storage
|
||||
Similar to Google Cloud Storage, you can choose S3 as storage backend. It uses
|
||||
the AWS SDK for PHP, but can also talk to a Rados gateway as part of a CEPH
|
||||
cluster. To use this backend, you first have to install the SDK in the
|
||||
document root of PrivateBin: `composer require aws/aws-sdk-php`. You have to
|
||||
create the S3 bucket on the CEPH cluster before using the S3 backend.
|
||||
the AWS SDK for PHP, but can also talk to a Rados gateway as part of a Ceph
|
||||
cluster.
|
||||
|
||||
To use this backend, you first have to install the SDK from the installation
|
||||
directory of PrivateBin:
|
||||
|
||||
```console
|
||||
composer require --no-update aws/aws-sdk-php
|
||||
composer update --no-dev --optimize-autoloader
|
||||
```
|
||||
|
||||
You have to create an S3 bucket on the Ceph cluster before using the S3 backend.
|
||||
|
||||
In the `[model]` section of cfg/conf.php, set `class` to `S3Storage`.
|
||||
|
||||
|
@ -256,7 +280,7 @@ data beneath this prefix.
|
|||
For AWS, you have to provide at least `region`, `bucket`, `accesskey`, and
|
||||
`secretkey`.
|
||||
|
||||
For CEPH, follow this example:
|
||||
For Ceph, follow this example:
|
||||
|
||||
```
|
||||
region = ""
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
# Release
|
||||
|
||||
## Overview of Supply-Chain Security
|
||||
|
||||
As of the PrivateBin 1.0 release we [cryptographically sign](https://git-scm.com/book/uz/v2/Git-Tools-Signing-Your-Work) our git commits and tags, so that you can verify we actually developed the software. Later, we also [started signing the release archives on GitHub](https://github.com/PrivateBin/PrivateBin/issues/219) and retroactively signed all releases from 1.0 forward.
|
||||
|
||||
Since [release 1.6.2](https://github.com/PrivateBin/PrivateBin/releases/tag/1.6.2) our release assets additionally also are [verified with the SLSA (Supply-chain Levels for Software Artifacts) framework](https://slsa.dev/), providing an in-toto manifest of the release archive.
|
||||
|
||||
This achieves the following:
|
||||
1. It ensures no maintainer has gone rogue and has modified/tampered with the source code before “building” the release.
|
||||
2. It ensures the release is build exactly according to the source as defined by the branch that was used for the release.
|
||||
This includes the workflow file defining how the release is done itself.
|
||||
3. Our release should achieve [SLSA build level 3](https://slsa.dev/spec/v1.0/levels#build-l3) as it [runs on GitHub](https://slsa.dev/spec/v1.0/threats). Some more properties [are thus achieved](https://slsa.dev/spec/v1.0/threats).
|
||||
|
||||
For more information [see the corresponding issue](https://github.com/PrivateBin/PrivateBin/issues/1169) and [the GitHub workflow file](/.github/workflows/release.yml).
|
||||
|
||||
## Reproducible builds
|
||||
|
||||
All releases `.tar.gz` and `.zip` archives since 1.0 come with corresponding `.asc` signatures that can be used to confirm the authenticity of the fact that the release has been issued by a PrivateBin maintainer.
|
||||
|
||||
This uses traditional [PGP](https://en.wikipedia.org/wiki/Pretty_Good_Privacy) signatures.
|
||||
|
||||
## Verification
|
||||
|
||||
You can use the gpg signatures for verifying the reproducibility and that a maintainer in posession with that PGP private key created the release with that content:
|
||||
|
||||
```
|
||||
$ gpg2 --verify 1.6.2.tar.gz.asc
|
||||
gpg: assuming signed data in '1.6.2.tar.gz'
|
||||
gpg: Signature made Fri Dec 15 06:21:08 2023 UTC
|
||||
gpg: using RSA key 28CA7C964938EA5C1481D42AE11B7950E9E183DB
|
||||
gpg: Good signature from "PrivateBin release (solely used for signing releases)" [unknown]
|
||||
gpg: WARNING: This key is not certified with a trusted signature!
|
||||
gpg: There is no indication that the signature belongs to the owner.
|
||||
Primary key fingerprint: 28CA 7C96 4938 EA5C 1481 D42A E11B 7950 E9E1 83DB
|
||||
```
|
||||
|
||||
For a more step-by-step guide in detail [see this FAQ](https://github.com/PrivateBin/PrivateBin/wiki/FAQ#how-can-i-securely-clonedownload-your-project).
|
||||
|
||||
SLSA verification can be performed using the [SLSA verifier](https://github.com/slsa-framework/slsa-verifier?tab=readme-ov-file#verification-for-github-builders).
|
||||
|
||||
## Release process
|
||||
|
||||
The release process is outlined in the [release checklist](https://github.com/PrivateBin/PrivateBin/wiki/Release-Checklist). The key manual steps are performed using a [Makefile](https://github.com/PrivateBin/PrivateBin/blob/master/Makefile#L31-L43) and using a [shell script](https://github.com/rugk/gittools/blob/master/signrelease.sh).
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "جافاسكرِبت (JavaScript) مطلوب %s للعمل. نأسف للإزعاج.",
|
||||
"%s requires a modern browser to work.": "%s يتطلب متصفحًا حديثًا للعمل.",
|
||||
"New": "جديد",
|
||||
"Send": "إرسال",
|
||||
"Create": "أنشِئ",
|
||||
"Clone": "استنساخ",
|
||||
"Raw text": "نص خام",
|
||||
"Expires": "تنتهي",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"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\" أو \"التوقيع\" الخاطئ أو المفقود.",
|
||||
"Error parsing YOURLS response.": "خطأ في تحليل استجابة YOURLS."
|
||||
"Error parsing YOURLS response.": "خطأ في تحليل استجابة YOURLS.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "لا يمكن عرض اللصق احرقه بعد قراءته إلا مرة واحدة عند تحميله. هل تريد فتحه الآن؟",
|
||||
"Yes, load it": "نعم، حمله"
|
||||
}
|
||||
|
|
10
i18n/bg.json
10
i18n/bg.json
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Услугата %s се нуждае от JavaScript, за да работи. Съжаляваме за неудобството.",
|
||||
"%s requires a modern browser to work.": "%s се нуждае от съвременен браузър за да работи.",
|
||||
"New": "Създаване",
|
||||
"Send": "Изпрати",
|
||||
"Create": "Създай",
|
||||
"Clone": "Дублирай",
|
||||
"Raw text": "Чист текст",
|
||||
"Expires": "Изтича",
|
||||
|
@ -199,10 +199,10 @@
|
|||
"Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.",
|
||||
"Retry": "Нов опит",
|
||||
"Showing raw text…": "Showing raw text…",
|
||||
"Notice:": "Notice:",
|
||||
"Notice:": "Известие:",
|
||||
"This link will expire after %s.": "This link will expire after %s.",
|
||||
"This link can only be accessed once, do not use back or refresh button in your browser.": "This link can only be accessed once, do not use back or refresh button in your browser.",
|
||||
"Link:": "Link:",
|
||||
"Link:": "Връзка:",
|
||||
"Recipient may become aware of your timezone, convert time to UTC?": "Recipient may become aware of your timezone, convert time to UTC?",
|
||||
"Use Current Timezone": "Use Current Timezone",
|
||||
"Convert To UTC": "Convert To UTC",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Cal JavaScript perquè %s funcioni. Em sap greu les molèsties.",
|
||||
"%s requires a modern browser to work.": "%s requereix un navegador modern per funcionar.",
|
||||
"New": "Nou",
|
||||
"Send": "Enviar",
|
||||
"Create": "Crear",
|
||||
"Clone": "Clona",
|
||||
"Raw text": "Text sense processar",
|
||||
"Expires": "Caducitat",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript hè richiestu per fà funziunà %s. Scusate per stu penseru.",
|
||||
"%s requires a modern browser to work.": "%s richiede un navigatore mudernu per funziunà.",
|
||||
"New": "Novu",
|
||||
"Send": "Mandà",
|
||||
"Create": "Creà",
|
||||
"Clone": "Duppione",
|
||||
"Raw text": "Testu grossu",
|
||||
"Expires": "Scadenza",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"Your IP is not authorized to create pastes.": "U vostru indirizzu IP ùn hè micca auturizatu à creà l’appiccichi.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Pruvate d’ammuzzà un indirizzu web chì ùn punta micca versu a vostra instanza.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Sbagliu à a chjama di YOURLS. Seria forse una cunfigurazione gattiva, tale una \"apiurl\" o \"signature\" falsa o assente.",
|
||||
"Error parsing YOURLS response.": "Sbagliu durante l’analisa di a risposta di YOURLS."
|
||||
"Error parsing YOURLS response.": "Sbagliu durante l’analisa di a risposta di YOURLS.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Si pò affissà l’appiccichi « Squassà dopu a lettura » solu dopu u so caricamentu. Vulete aprelu subitu ?",
|
||||
"Yes, load it": "Iè, caricatelu"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Pro fungování %s je vyžadován JavaScript. Omlouváme se za nepříjemnosti.",
|
||||
"%s requires a modern browser to work.": "%%s requires a modern browser to work.",
|
||||
"New": "Nový",
|
||||
"Send": "Odeslat",
|
||||
"Create": "Vytvořit",
|
||||
"Clone": "Klonovat",
|
||||
"Raw text": "Pouze Text",
|
||||
"Expires": "Expirace",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"Your IP is not authorized to create pastes.": "Vaše IP adresa nemá oprávnění k vytvoření vložení.",
|
||||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript ist eine Voraussetzung, um %s zu nutzen. Bitte entschuldige die Unannehmlichkeiten.",
|
||||
"%s requires a modern browser to work.": "%s setzt einen modernen Browser voraus, um funktionieren zu können.",
|
||||
"New": "Neu",
|
||||
"Send": "Senden",
|
||||
"Create": "Erstellen",
|
||||
"Clone": "Klonen",
|
||||
"Raw text": "Reiner Text",
|
||||
"Expires": "Ablaufzeit",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"Your IP is not authorized to create pastes.": "Deine IP ist nicht berechtigt, Texte zu erstellen.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Versuch eine URL zu verkürzen, die nicht auf unsere Instanz zeigt.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Fehler beim Aufruf von YOURLS. Wahrscheinlich ein Konfigurationsproblem, wie eine falsche oder fehlende \"apiurl\" oder \"signature\".",
|
||||
"Error parsing YOURLS response.": "Fehler beim Verarbeiten der YOURLS-Antwort."
|
||||
"Error parsing YOURLS response.": "Fehler beim Verarbeiten der YOURLS-Antwort.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Texte des \"Einmal\"-Typs können nach dem Öffnen nur einmal angezeigt werden. Möchtest Du ihn jetzt öffnen?",
|
||||
"Yes, load it": "Ja, jetzt öffnen"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Η JavaScript είναι απαραίτητη για να λειτουργήσει το %s. Συγγνώμη για την ταλαιπωρία.",
|
||||
"%s requires a modern browser to work.": "%s απαιτεί σύγχρονο φυλλομετρητή (browser) για να λειτουργήσει.",
|
||||
"New": "Νέο",
|
||||
"Send": "Αποστολή",
|
||||
"Create": "Δημιουργία",
|
||||
"Clone": "Κλωνοποίηση",
|
||||
"Raw text": "Κείμενο",
|
||||
"Expires": "Λήγει",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"Your IP is not authorized to create pastes.": "Η IP σας δεν επιτρέπεται να δημιουργεί επικολλήσεις.",
|
||||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.",
|
||||
"%s requires a modern browser to work.": "%s requires a modern browser to work.",
|
||||
"New": "New",
|
||||
"Send": "Send",
|
||||
"Create": "Create",
|
||||
"Clone": "Clone",
|
||||
"Raw text": "Raw text",
|
||||
"Expires": "Expires",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript es necesario para que %s funcione. Sentimos los inconvenientes ocasionados.",
|
||||
"%s requires a modern browser to work.": "%s requiere un navegador moderno para funcionar.",
|
||||
"New": "Nuevo",
|
||||
"Send": "Enviar",
|
||||
"Create": "Crear",
|
||||
"Clone": "Clonar",
|
||||
"Raw text": "Texto sin formato",
|
||||
"Expires": "Caducar en",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"Your IP is not authorized to create pastes.": "Tu IP no está autorizada para crear contenido.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Intentando acortar una URL que no apunta a nuestra instancia.",
|
||||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
12
i18n/et.json
12
i18n/et.json
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript on vajalik %s'i töötamiseks. Vabandame ebamugavuste pärast.",
|
||||
"%s requires a modern browser to work.": "%s vajab töötamiseks kaasaegset brauserit.",
|
||||
"New": "Uus",
|
||||
"Send": "Saada",
|
||||
"Create": "Loo",
|
||||
"Clone": "Klooni",
|
||||
"Raw text": "Lähtetekst",
|
||||
"Expires": "Aegub",
|
||||
|
@ -211,8 +211,10 @@
|
|||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Kirja nägemiseks külasta seda linki. Teistele URL-i andmine lubab ka neil ligi pääseda kirjale.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL-i lühendaja võib paljastada sinu dekrüpteerimisvõtme URL-is.",
|
||||
"Save paste": "Salvesta kleebe",
|
||||
"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."
|
||||
"Your IP is not authorized to create pastes.": "Su IP-l ei ole lubatud kleepeid luua.",
|
||||
"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.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
12
i18n/fi.json
12
i18n/fi.json
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "%s vaatii JavaScriptiä toimiakseen. Anteeksi haitasta.",
|
||||
"%s requires a modern browser to work.": "%s vaatii modernin selaimen toimiakseen.",
|
||||
"New": "Uusi",
|
||||
"Send": "Lähetä",
|
||||
"Create": "Luo",
|
||||
"Clone": "Kloonaa",
|
||||
"Raw text": "Raaka teksti",
|
||||
"Expires": "Vanhenee",
|
||||
|
@ -208,11 +208,13 @@
|
|||
"Convert To UTC": "Muuta UTC:ksi",
|
||||
"Close": "Sulje",
|
||||
"Encrypted note on %s": "Salattu viesti %sissä",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Käy tässä linkissä nähdäksesi viestin. URL:n antaminen kenellekään antaa heidänkin päästä katsomeen viestiä. ",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Vieraile tässä linkissä nähdäksesi viestin. URL:n antaminen kenellekään antaa heidänkin päästä katsomaan viestiä.",
|
||||
"URL shortener may expose your decrypt key in URL.": "URL-lyhentäjä voi paljastaa purkuavaimesi URL:ssä.",
|
||||
"Save paste": "Tallenna paste",
|
||||
"Your IP is not authorized to create pastes.": "IP:llesi ei ole annettu oikeutta luoda pasteja.",
|
||||
"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."
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Yritetään lyhentää URL-osoite, joka ei osoita meidän instanssiiin.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Virhe kutsuttaessa YOURLS. Luultavasti asetusongelma kuten väärä tai puuttuuva \"apiurl\" tai \"signature\".",
|
||||
"Error parsing YOURLS response.": "Virhe jäsennettäessä YOURLS-vastausta.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
10
i18n/fr.json
10
i18n/fr.json
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript est requis pour faire fonctionner %s. Désolé pour cet inconvénient.",
|
||||
"%s requires a modern browser to work.": "%s nécessite un navigateur moderne pour fonctionner.",
|
||||
"New": "Nouveau",
|
||||
"Send": "Envoyer",
|
||||
"Create": "Créer",
|
||||
"Clone": "Cloner",
|
||||
"Raw text": "Texte brut",
|
||||
"Expires": "Expire",
|
||||
|
@ -212,7 +212,9 @@
|
|||
"URL shortener may expose your decrypt key in URL.": "Raccourcir l'URL peut exposer votre clé de déchiffrement dans l'URL.",
|
||||
"Save paste": "Sauver le paste",
|
||||
"Your IP is not authorized to create pastes.": "Votre adresse IP n'est pas autorisée à créer des 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."
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Essayer de raccourcir une URL qui ne pointe pas vers notre instance.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Erreur lors de l'appel de YOURLS. Peut-être un problème de configuration, comme \"apiurl\" ou \"signature\" manquant.",
|
||||
"Error parsing YOURLS response.": "Erreur d'analyse de la réponse YOURLS.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Les pastes de type \"Effacer après la lecture\" ne peuvent être affichés qu'une seule fois. Voulez-vous l'ouvrir maintenant ?",
|
||||
"Yes, load it": "Oui, chargez-le"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "צריך JavaScript כדי לאפשר ל־%s לפעול. סליחה על חוסר הנוחות.",
|
||||
"%s requires a modern browser to work.": "%s דורש דפדפן מודרני כדי לפעול.",
|
||||
"New": "חדש",
|
||||
"Send": "שליחה",
|
||||
"Create": "צור",
|
||||
"Clone": "שכפול",
|
||||
"Raw text": "טקסט גולמי",
|
||||
"Expires": "Expires",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.",
|
||||
"%s requires a modern browser to work.": "%s requires a modern browser to work.",
|
||||
"New": "New",
|
||||
"Send": "Send",
|
||||
"Create": "Create",
|
||||
"Clone": "Clone",
|
||||
"Raw text": "Raw text",
|
||||
"Expires": "Expires",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript szükséges a %s működéséhez. Elnézést a fennakadásért.",
|
||||
"%s requires a modern browser to work.": "A %s működéséhez a jelenleginél újabb böngészőre van szükség.",
|
||||
"New": "Új",
|
||||
"Send": "Beküldöm!",
|
||||
"Create": "Létrehozás",
|
||||
"Clone": "Másol",
|
||||
"Raw text": "A nyers szöveg",
|
||||
"Expires": "Lejárati idő",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript diperlukan agar %s bekerja. Maaf untuk ketidaknyamanannya.",
|
||||
"%s requires a modern browser to work.": "%s memerlukan sebuah browser modern untuk bekerja.",
|
||||
"New": "Baru",
|
||||
"Send": "Kirim",
|
||||
"Create": "Buat baru",
|
||||
"Clone": "Klon",
|
||||
"Raw text": "Teks mentah",
|
||||
"Expires": "Kadaluarsa",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "%s funziona solo con JavaScript attivo. Ci dispiace per l'inconveniente.",
|
||||
"%s requires a modern browser to work.": "%s richiede un browser moderno e aggiornato per funzionare.",
|
||||
"New": "Nuovo",
|
||||
"Send": "Invia",
|
||||
"Create": "Crea",
|
||||
"Clone": "Clona",
|
||||
"Raw text": "Testo Raw",
|
||||
"Expires": "Scade",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"Your IP is not authorized to create pastes.": "Il tuo IP non è autorizzato a creare dei messaggi.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Tantativo in corso di accorciare un URL che non punta alla nostra istanza.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Errore nella chiamata a YOURLS. Probabilmente un problema di configurazione, come un \"apiurl\" o una \"signature\" sbagliati o mancanti.",
|
||||
"Error parsing YOURLS response.": "Errore nell'analizzare la risposta YOURLS."
|
||||
"Error parsing YOURLS response.": "Errore nell'analizzare la risposta YOURLS.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Messaggi di tipo Distruggi-dopo-lettura piovono essere visualizzata solo una volta al caricamento. Vuoi aprirle ora?",
|
||||
"Yes, load it": "Sì, caricalo"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "%s の動作にはJavaScriptが必要です。ご迷惑をおかけして申し訳ありません。",
|
||||
"%s requires a modern browser to work.": "%s の動作には最近のブラウザが必要です。",
|
||||
"New": "新規",
|
||||
"Send": "送信",
|
||||
"Create": "作成",
|
||||
"Clone": "複製",
|
||||
"Raw text": "未加工テキスト",
|
||||
"Expires": "有効期限",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"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レスポンスの解析中にエラーが発生しました。"
|
||||
"Error parsing YOURLS response.": "YOURLSレスポンスの解析中にエラーが発生しました。",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.",
|
||||
"%s requires a modern browser to work.": "%s requires a modern browser to work.",
|
||||
"New": "cnino",
|
||||
"Send": "benji",
|
||||
"Create": "benji",
|
||||
"Clone": "fukpi",
|
||||
"Raw text": "vlapoi nalselrucyzu'e",
|
||||
"Expires": "vimcu",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.",
|
||||
"%s requires a modern browser to work.": "%s requires a modern browser to work.",
|
||||
"New": "New",
|
||||
"Send": "Send",
|
||||
"Create": "Create",
|
||||
"Clone": "Clone",
|
||||
"Raw text": "Raw text",
|
||||
"Expires": "Expires",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.",
|
||||
"%s requires a modern browser to work.": "%s requires a modern browser to work.",
|
||||
"New": "New",
|
||||
"Send": "Send",
|
||||
"Create": "Create",
|
||||
"Clone": "Clone",
|
||||
"Raw text": "Raw text",
|
||||
"Expires": "Expires",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "%s darbui reikalinga JavaScript. Atsiprašome už nepatogumus.",
|
||||
"%s requires a modern browser to work.": "%s savo darbui reikalauja šiuolaikinės naršyklės.",
|
||||
"New": "Naujas",
|
||||
"Send": "Siųsti",
|
||||
"Create": "Kurti",
|
||||
"Clone": "Dubliuoti",
|
||||
"Raw text": "Neapdorotas tekstas",
|
||||
"Expires": "Baigs galioti po",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"Your IP is not authorized to create pastes.": "Jūsų IP adresas neturi įgaliojimų kurti įdėjimų.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Bandoma sutrumpinti URL adresą, kuris nenurodo į mūsų egzempliorių.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Klaida iškviečiant YOURLS. Tikriausiai, konfigūracijos klaida, pavyzdžiui, neteisingi „apiurl“ ar „signature“, arba jų nėra.",
|
||||
"Error parsing YOURLS response.": "Klaida nagrinėjant YOURLS atsaką."
|
||||
"Error parsing YOURLS response.": "Klaida nagrinėjant YOURLS atsaką.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript vereist om %s te laten werken. Sorry voor het ongemak.",
|
||||
"%s requires a modern browser to work.": "%s vereist een moderne browser om te kunnen werken.",
|
||||
"New": "Nieuw",
|
||||
"Send": "Verzenden",
|
||||
"Create": "Maak",
|
||||
"Clone": "Klonen",
|
||||
"Raw text": "Onbewerkte tekst",
|
||||
"Expires": "Verloopt",
|
||||
|
@ -180,7 +180,7 @@
|
|||
"Options": "Opties",
|
||||
"Shorten URL": "URL verkorten",
|
||||
"Editor": "Editor",
|
||||
"Preview": "Preview",
|
||||
"Preview": "Voorbeeld",
|
||||
"%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s vereist dat PATH eindigt in een '%s'. a.u.b. PATH updaten in je index.php.",
|
||||
"Decrypt": "Decoderen",
|
||||
"Enter password": "Voer het wachtwoord in",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"Your IP is not authorized to create pastes.": "Je IP-adres is niet gemachtigd om pastes te maken.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Proberen om een URL te verkorten dat niet naar ons systeem wijst.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Foutmelding ophalen YOURLS. Waarschijnlijk een configuratiefout, zoals een verkeerde of missende \"apiurl\" of \"signature\".",
|
||||
"Error parsing YOURLS response.": "Foutmelding bij parsen van YOURLS respons."
|
||||
"Error parsing YOURLS response.": "Foutmelding bij parsen van YOURLS respons.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Brand na het lezen van de plagen kan slechts eenmaal worden weergegeven wanneer deze worden geladen. Wilt u het nu openen?",
|
||||
"Yes, load it": "Ja, laad het"
|
||||
}
|
||||
|
|
12
i18n/no.json
12
i18n/no.json
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Javascript kreves for at %s skal fungere. Beklager.",
|
||||
"%s requires a modern browser to work.": "%s krever en moderne nettleser for å fungere.",
|
||||
"New": "Ny",
|
||||
"Send": "Send",
|
||||
"Create": "Opprette",
|
||||
"Clone": "Kopier",
|
||||
"Raw text": "Ren tekst",
|
||||
"Expires": "Utgår",
|
||||
|
@ -211,8 +211,10 @@
|
|||
"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.": "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."
|
||||
"Your IP is not authorized to create pastes.": "Din IP er ikke autorisert til å opprette advarsler.",
|
||||
"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 parsing YOURLS response.": "Feil ved analyse av YOURLS svar.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Brenne etter lesing av pasta kan kun vises når den lastes inn. Vil du åpne den nå?",
|
||||
"Yes, load it": "Ja, last den"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript es requesit per far foncionar %s. O planhèm per l’inconvenient.",
|
||||
"%s requires a modern browser to work.": "%s requerís un navigator modèrn per foncionar.",
|
||||
"New": "Nòu",
|
||||
"Send": "Mandar",
|
||||
"Create": "Mandar",
|
||||
"Clone": "Clonar",
|
||||
"Raw text": "Tèxte brut",
|
||||
"Expires": "Expira",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"Your IP is not authorized to create pastes.": "Vòstra adreça IP a pas l’autorizacion de crear de tèxtes.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Ensag d’abracar una URL que mena pas a nòstra instància.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error en cridant YOURLS. Es probablament un problèma de configuracion, quicòm coma « apirul » o « signature » marrit o absent.",
|
||||
"Error parsing YOURLS response.": "Error d'analisi de la responsa YOURLS."
|
||||
"Error parsing YOURLS response.": "Error d'analisi de la responsa YOURLS.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Do działania %sa jest wymagany JavaScript. Przepraszamy za tę niedogodność.",
|
||||
"%s requires a modern browser to work.": "%s wymaga do działania nowoczesnej przeglądarki.",
|
||||
"New": "Nowa",
|
||||
"Send": "Wyślij",
|
||||
"Create": "Stwórz",
|
||||
"Clone": "Sklonuj",
|
||||
"Raw text": "Czysty tekst",
|
||||
"Expires": "Wygasa za",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript é necessário para que %s funcione. Pedimos desculpas pela inconveniência.",
|
||||
"%s requires a modern browser to work.": "%s requer um navegador moderno para funcionar.",
|
||||
"New": "Novo",
|
||||
"Send": "Enviar",
|
||||
"Create": "Criar",
|
||||
"Clone": "Clonar",
|
||||
"Raw text": "Texto sem formato",
|
||||
"Expires": "Expirar em",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"Your IP is not authorized to create pastes.": "Seu IP não está autorizado a criar cópias.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Tentando encurtar uma URL que não aponta para a nossa instância.",
|
||||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,220 @@
|
|||
{
|
||||
"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 este un pastebin online, minimalist și cu sursă deschisă unde serverul are zero acces la datele introduse. Datele sunt criptate/decriptate %sîn browser%s folosind AES cu 256 de biți.",
|
||||
"More information on the <a href=\"https://privatebin.info/\">project page</a>.": "Mai multe informații pe <a href=\"https://privatebin.info/\">pagina proiectului</a>.",
|
||||
"Because ignorance is bliss": "Ignoranța este o binecuvântare",
|
||||
"Paste does not exist, has expired or has been deleted.": "Paste-ul nu există, a expirat sau a fost șters.",
|
||||
"%s requires php %s or above to work. Sorry.": "%s necesită php %s sau mai nou pentru a funcționa. Scuze.",
|
||||
"%s requires configuration section [%s] to be present in configuration file.": "%s necesită ca secțiunea de configurare [%s] să fie prezentă în fișierul de configurare.",
|
||||
"Please wait %d seconds between each post.": [
|
||||
"Vă rugăm să așteptați %d secundă între fiecare postare",
|
||||
"Vă rugăm să așteptați %d secunde între fiecare postare",
|
||||
"Vă rugăm să așteptați %d de secunde între fiecare postare",
|
||||
"Vă rugăm să așteptați %d de secunde între fiecare postare",
|
||||
"Vă rugăm să așteptați %d de secunde între fiecare postare",
|
||||
"Vă rugăm să așteptați %d de secunde între fiecare postare"
|
||||
],
|
||||
"Paste is limited to %s of encrypted data.": "Paste-ul este limitat la %s de date criptate.",
|
||||
"Invalid data.": "Date invalide.",
|
||||
"You are unlucky. Try again.": "Ați avut ghinion. Încercați din nou.",
|
||||
"Error saving comment. Sorry.": "Eroare la salvarea comentariului. Ne pare rău.",
|
||||
"Error saving paste. Sorry.": "Eroare la salvarea paste-ului. Ne pare rău.",
|
||||
"Invalid paste ID.": "ID paste invalid.",
|
||||
"Paste is not of burn-after-reading type.": "Paste-ul nu se șterge după citire.",
|
||||
"Wrong deletion token. Paste was not deleted.": "Token de ștergere incorect. Paste-ul nu a fost șters.",
|
||||
"Paste was properly deleted.": "Paste-ul a fost șters cu succes.",
|
||||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript este necesar pentru ca %s să funcționeze. Ne cerem scuze pentru neplăceri.",
|
||||
"%s requires a modern browser to work.": "%s necesită un browser modern pentru a funcționa.",
|
||||
"New": "Nou",
|
||||
"Create": "Creează",
|
||||
"Clone": "Clonați",
|
||||
"Raw text": "Text brut",
|
||||
"Expires": "Expiră",
|
||||
"Burn after reading": "Ștergere după citire",
|
||||
"Open discussion": "Deschideți discuția",
|
||||
"Password (recommended)": "Parolă (recomandată)",
|
||||
"Discussion": "Discuție",
|
||||
"Toggle navigation": "Comutați navigarea",
|
||||
"%d seconds": [
|
||||
"%d secundă",
|
||||
"%d secunde",
|
||||
"%d de secunde",
|
||||
"%d de secunde",
|
||||
"%d de secunde",
|
||||
"%d de secunde"
|
||||
],
|
||||
"%d minutes": [
|
||||
"%d minut",
|
||||
"%d minute",
|
||||
"%d de minute",
|
||||
"%d de secunde",
|
||||
"%d de secunde",
|
||||
"%d de secunde"
|
||||
],
|
||||
"%d hours": [
|
||||
"%d oră",
|
||||
"%d ore",
|
||||
"%d de ore",
|
||||
"%d de ore",
|
||||
"%d de ore",
|
||||
"%d de ore"
|
||||
],
|
||||
"%d days": [
|
||||
"%d zi",
|
||||
"%d zile",
|
||||
"%d de zile",
|
||||
"%d de zile",
|
||||
"%d de zile",
|
||||
"%d de zile"
|
||||
],
|
||||
"%d weeks": [
|
||||
"%d săptămână",
|
||||
"%d săptămână",
|
||||
"%d săptămâni",
|
||||
"%d de săptămâni",
|
||||
"%d de săptămâni",
|
||||
"%d de săptămâni"
|
||||
],
|
||||
"%d months": [
|
||||
"%d lună",
|
||||
"%d luni",
|
||||
"%d de luni",
|
||||
"%d de luni",
|
||||
"%d de luni",
|
||||
"%d de luni"
|
||||
],
|
||||
"%d years": [
|
||||
"%d an",
|
||||
"%d ani",
|
||||
"%d de ani",
|
||||
"%d de ani",
|
||||
"%d de ani",
|
||||
"%d de ani"
|
||||
],
|
||||
"Never": "Niciodată",
|
||||
"Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "Notă: Acesta este un serviciu de test: Datele ar putea fi șterse oricând. Vor muri niște pisicuțe dacă abuzați acest serviciu.",
|
||||
"This document will expire in %d seconds.": [
|
||||
"Acest document va expira în %d secundă.",
|
||||
"Acest document va expira în %d secunde.",
|
||||
"Acest document va expira în %d de secunde.",
|
||||
"Acest document va expira în %d de secunde.",
|
||||
"Acest document va expira în %d de secunde.",
|
||||
"Acest document va expira în %d de secunde."
|
||||
],
|
||||
"This document will expire in %d minutes.": [
|
||||
"Acest document va expira în %d minut.",
|
||||
"Acest document va expira în %d minute.",
|
||||
"Acest document va expira în %d de minute.",
|
||||
"Acest document va expira în %d de minute.",
|
||||
"Acest document va expira în %d de minute.",
|
||||
"Acest document va expira în %d de minute."
|
||||
],
|
||||
"This document will expire in %d hours.": [
|
||||
"Acest document va expira în %d oră.",
|
||||
"Acest document va expira în %d ore.",
|
||||
"Acest document va expira în %d de ore.",
|
||||
"Acest document va expira în %d de ore.",
|
||||
"Acest document va expira în %d de ore.",
|
||||
"Acest document va expira în %d de ore."
|
||||
],
|
||||
"This document will expire in %d days.": [
|
||||
"Acest document va expira în %d zi.",
|
||||
"Acest document va expira în %d zile.",
|
||||
"Acest document va expira în %d de zile.",
|
||||
"Acest document va expira în %d de zile.",
|
||||
"Acest document va expira în %d de zile.",
|
||||
"Acest document va expira în %d de zile."
|
||||
],
|
||||
"This document will expire in %d months.": [
|
||||
"Acest document va expira în %d lună.",
|
||||
"Acest document va expira în %d luni.",
|
||||
"Acest document va expira în %d de luni.",
|
||||
"Acest document va expira în %d de luni.",
|
||||
"Acest document va expira în %d de luni.",
|
||||
"Acest document va expira în %d de luni."
|
||||
],
|
||||
"Please enter the password for this paste:": "Va rugăm să introduceți parola pentru acest paste:",
|
||||
"Could not decrypt data (Wrong key?)": "Nu s-au putut decripta datele (Cheie gresită?)",
|
||||
"Could not delete the paste, it was not stored in burn after reading mode.": "Nu s-a putut șterge paste-ul, nu a fost stocat în modul de ștergere după citire.",
|
||||
"FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "NUMAI PENTRU OCHII DVS. Nu închideți această fereastră, acest mesaj nu poate fi afișat din nou.",
|
||||
"Could not decrypt comment; Wrong key?": "Nu s-a putut decripta comentariul; Cheie greșită?",
|
||||
"Reply": "Răspundeți",
|
||||
"Anonymous": "Anonim",
|
||||
"Avatar generated from IP address": "Avatar generat din adresa IP",
|
||||
"Add comment": "Adăugați un comentariu",
|
||||
"Optional nickname…": "Poreclă opțională…",
|
||||
"Post comment": "Postați comentariul",
|
||||
"Sending comment…": "Se trimite comentariul…",
|
||||
"Comment posted.": "Comentariul a fost postat.",
|
||||
"Could not refresh display: %s": "Nu s-a putut actualiza afișarea: %s",
|
||||
"unknown status": "stare necunoscută",
|
||||
"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 <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>": "Paste-ul dvs. este <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Apăsați [Ctrl]+[c] pentru a copia)</span>",
|
||||
"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?)",
|
||||
"B": "B",
|
||||
"KiB": "KiB",
|
||||
"MiB": "MiB",
|
||||
"GiB": "GiB",
|
||||
"TiB": "TiB",
|
||||
"PiB": "PiB",
|
||||
"EiB": "EiB",
|
||||
"ZiB": "ZiB",
|
||||
"YiB": "YiB",
|
||||
"Format": "Formatare",
|
||||
"Plain Text": "Text neformatat",
|
||||
"Source Code": "Cod sursă",
|
||||
"Markdown": "Markdown",
|
||||
"Download attachment": "Descărcați fișierul atașat",
|
||||
"Cloned: '%s'": "S-a clonat: '%s'",
|
||||
"The cloned file '%s' was attached to this paste.": "Fișierul clonat '%s' a fost atașat la acest paste.",
|
||||
"Attach a file": "Atașați un fișier",
|
||||
"alternatively drag & drop a file or paste an image from the clipboard": "alternativ, trageți și plasați un fișier sau lipiți o imagine din clipboard",
|
||||
"File too large, to display a preview. Please download the attachment.": "Fișierul este prea mare pentru a afișa o previzualizare. Vă rugăm să descărcaţi fișierul.",
|
||||
"Remove attachment": "Eliminați fișierul atașat",
|
||||
"Your browser does not support uploading encrypted files. Please use a newer browser.": "Browserul dvs. nu acceptă încărcarea fișierelor criptate. Vă rugăm să folosiți un browser mai nou.",
|
||||
"Invalid attachment.": "Fișier invalid.",
|
||||
"Options": "Opţiuni",
|
||||
"Shorten URL": "Scurtați URL-ul",
|
||||
"Editor": "Editor",
|
||||
"Preview": "Previzualizare",
|
||||
"%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s necesită ca PATH să se termine cu \"%s\". Vă rugăm să actualizați PATH în index.php.",
|
||||
"Decrypt": "Decriptare",
|
||||
"Enter password": "Introduceţi parola",
|
||||
"Loading…": "Se încarcă…",
|
||||
"Decrypting paste…": "Se decriptează paste-ul…",
|
||||
"Preparing new paste…": "Se pregătește un paste nou…",
|
||||
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.": "În cazul în care acest mesaj nu dispare niciodată, vă rugăm să aruncaţi o privire la <a href=\"%s\">acest FAQ pentru informații de depanare</a>.",
|
||||
"+++ no paste text +++": "+++ fără text +++",
|
||||
"Could not get paste data: %s": "Nu s-a putut obține datele paste-ului: %s",
|
||||
"QR code": "Cod QR",
|
||||
"This website is using an insecure HTTP connection! Please use it only for testing.": "Acest website folosește o conexiune HTTP nesigură! Vă rugăm să îl folosiți doar pentru teste.",
|
||||
"For more information <a href=\"%s\">see this FAQ entry</a>.": "Pentru mai multe informații <a href=\"%s\">a se vedea secțiunea FAQ</a>.",
|
||||
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Este posibil ca browserul dvs. să necesite o conexiune HTTPS pentru a suporta API-ul WebCrypto. Încercați să <a href=\"%s\">comutați la HTTPS</a>.",
|
||||
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Browserul dvs. nu acceptă WebAssembly folosit pentru compresia zlib. Puteți crea documente necompresate, dar nu le puteți citi pe cele compresate.",
|
||||
"waiting on user to provide a password": "se așteaptă ca utilizatorul să furnizeze o parolă",
|
||||
"Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Nu s-au putut decripta datele. Ați introdus parola greșită? Reîncercați folosind butonul de sus.",
|
||||
"Retry": "Reîncercați",
|
||||
"Showing raw text…": "Se afișează textul brut…",
|
||||
"Notice:": "Observaţie:",
|
||||
"This link will expire after %s.": "Acest link va expira după %s.",
|
||||
"This link can only be accessed once, do not use back or refresh button in your browser.": "Acest link poate fi accesat o singură dată, nu folosiți butonul înapoi sau reîmprospătare din browserul dvs.",
|
||||
"Link:": "Link:",
|
||||
"Recipient may become aware of your timezone, convert time to UTC?": "Destinatarul vă poate afla fusul dvs. orar, convertiți timpul în UTC?",
|
||||
"Use Current Timezone": "Se folosește fusul orar actual",
|
||||
"Convert To UTC": "Convertire la UTC",
|
||||
"Close": "Închideți",
|
||||
"Encrypted note on %s": "Notă criptată pe %s",
|
||||
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Accesați acest link pentru a vedea nota. Nota poate fi accesată de către oricine care are acest URL.",
|
||||
"URL shortener may expose your decrypt key in URL.": "Scurtătorul de URL ar putea să vă expună cheia de decriptare din URL.",
|
||||
"Save paste": "Salvați paste-ul",
|
||||
"Your IP is not authorized to create pastes.": "Adresa dvs. IP nu este autorizată să creeze paste-uri.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Încercarea de a scurta un URL care nu direcționează spre instanța noastră.",
|
||||
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Eroare la apelarea YOURLS. Probabil o problemă de configurare, cum ar fi \"apiurl\" sau \"signature\" greșite sau lipsă.",
|
||||
"Error parsing YOURLS response.": "Eroare la analizarea răspunsului YOURLS.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Paste-urile care se șterg după citire pot fi afișate numai o dată după încărcare. Doriți să o deschideți acum?",
|
||||
"Yes, load it": "Da, deschide-o"
|
||||
}
|
10
i18n/ru.json
10
i18n/ru.json
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Для работы %s требуется включенный JavaScript. Приносим извинения за неудобства.",
|
||||
"%s requires a modern browser to work.": "Для работы %s требуется более современный браузер.",
|
||||
"New": "Новая запись",
|
||||
"Send": "Отправить",
|
||||
"Create": "Создать",
|
||||
"Clone": "Дублировать",
|
||||
"Raw text": "Исходный текст",
|
||||
"Expires": "Удалить через",
|
||||
|
@ -212,7 +212,9 @@
|
|||
"URL shortener may expose your decrypt key in URL.": "Сервис сокращения ссылок может получить ваш ключ расшифровки из ссылки.",
|
||||
"Save paste": "Сохранить запись",
|
||||
"Your IP is not authorized to create pastes.": "Вашему IP адресу не разрешено создавать записи.",
|
||||
"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."
|
||||
"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.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Записи, удаляемые после прочтения, могут быть отображены после загрузки только один раз. Вы хотите открыть её сейчас?",
|
||||
"Yes, load it": "Да, загрузить"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Na fungovanie %s je potrebný JavaScript. Ospravedlňujeme sa za nepríjemnosti.",
|
||||
"%s requires a modern browser to work.": "%s vyžaduje na fungovanie moderný prehliadač.",
|
||||
"New": "Nový",
|
||||
"Send": "Odoslať",
|
||||
"Create": "Vytvoriť",
|
||||
"Clone": "Klonovať",
|
||||
"Raw text": "Surový text",
|
||||
"Expires": "Expirácia",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"Your IP is not authorized to create pastes.": "Vaša IP adresa nie je oprávnená vytvárať príspevky.",
|
||||
"Trying to shorten a URL that isn't pointing at our instance.": "Pokúšate sa skrátiť adresu URL, ktorá neukazuje na túto inštanciu.",
|
||||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Da %s deluje, moraš vklopiti JavaScript. Oprosti za povročene nevšečnosti.",
|
||||
"%s requires a modern browser to work.": "%s za svoje delovanje potrebuje moderen brskalnik.",
|
||||
"New": "Nov prilepek",
|
||||
"Send": "Pošlji",
|
||||
"Create": "Ustvari",
|
||||
"Clone": "Kloniraj",
|
||||
"Raw text": "Surov tekst",
|
||||
"Expires": "Poteče",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.",
|
||||
"%s requires a modern browser to work.": "%s requires a modern browser to work.",
|
||||
"New": "New",
|
||||
"Send": "Send",
|
||||
"Create": "Skapa",
|
||||
"Clone": "Clone",
|
||||
"Raw text": "Raw text",
|
||||
"Expires": "Expires",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "จำเป็นต้องใช้ JavaScript เพื่อให้ %s สามารถทำงานได้ ขออภัยในความไม่สะดวก",
|
||||
"%s requires a modern browser to work.": "%s ต้องใช้เบราว์เซอร์สมัยใหม่ถึงจะสามารถใช้งานได้",
|
||||
"New": "ใหม่",
|
||||
"Send": "ส่ง",
|
||||
"Create": "สร้าง",
|
||||
"Clone": "โคลน",
|
||||
"Raw text": "ข้อความล้วน",
|
||||
"Expires": "หมดอายุ",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"Your IP is not authorized to create pastes.": "IP ของคุณไม่ได้รับอนุญาตให้สร้างการฝากโค้ด",
|
||||
"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"
|
||||
"Error parsing YOURLS response.": "เกิดข้อผิดพลาดในการแยกวิเคราะห์การตอบสนองของ YOURLS",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript %s 'in çalışması için gereklidir. Rahatsızlıktan dolayı özür dileriz.",
|
||||
"%s requires a modern browser to work.": "%s çalışmak için çağdaş bir tarayıcı gerektirir.",
|
||||
"New": "Yeni",
|
||||
"Send": "Gönder",
|
||||
"Create": "Oluştur",
|
||||
"Clone": "Kopyala",
|
||||
"Raw text": "Açık yazı",
|
||||
"Expires": "Süre Sonu",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"Your IP is not authorized to create pastes.": "IP adresinizin yazı oluşturmaya yetkisi yoktur.",
|
||||
"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."
|
||||
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
|
||||
"Yes, load it": "Yes, load it"
|
||||
}
|
||||
|
|
10
i18n/uk.json
10
i18n/uk.json
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Для роботи %s потрібен увімкнутий JavaScript. Вибачте.",
|
||||
"%s requires a modern browser to work.": "Для роботи %s потрібен більш сучасний переглядач.",
|
||||
"New": "Новий допис",
|
||||
"Send": "Відправити",
|
||||
"Create": "Створити",
|
||||
"Clone": "Дублювати",
|
||||
"Raw text": "Початковий текст",
|
||||
"Expires": "Вилучити через",
|
||||
|
@ -212,7 +212,9 @@
|
|||
"URL shortener may expose your decrypt key in 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.": "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."
|
||||
"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.",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Спалити після вставки читання можна вивести лише один раз під час завантаження. Відкрити його зараз?",
|
||||
"Yes, load it": "Так, завантажити"
|
||||
}
|
||||
|
|
|
@ -2,7 +2,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 是一个极简、开源、对粘贴内容毫不知情的在线粘贴板,数据%s在浏览器内%s进行 AES-256 加密和解密。",
|
||||
"More information on the <a href=\"https://privatebin.info/\">project page</a>.": "更多信息请查看<a href=\"https://privatebin.info/\">项目主页</a>。",
|
||||
"Because ignorance is bliss": "因为无知是福",
|
||||
"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 及以上版本才能运行。",
|
||||
"%s requires configuration section [%s] to be present in configuration file.": "%s 需要设置配置文件中的 [%s] 部分。",
|
||||
|
@ -26,7 +26,7 @@
|
|||
"JavaScript is required for %s to work. Sorry for the inconvenience.": "%s 需要 JavaScript 来进行加解密。 给你带来的不便敬请谅解。",
|
||||
"%s requires a modern browser to work.": "%s 需要在现代浏览器上工作。",
|
||||
"New": "新建",
|
||||
"Send": "送出",
|
||||
"Create": "创建",
|
||||
"Clone": "复制",
|
||||
"Raw text": "纯文本",
|
||||
"Expires": "有效期",
|
||||
|
@ -214,5 +214,7 @@
|
|||
"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 响应时出错。"
|
||||
"Error parsing YOURLS response.": "解析 YOURLS 响应时出错。",
|
||||
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "读取粘贴后只能在加载时显示一次。您想现在打开吗?",
|
||||
"Yes, load it": "是的,加载它"
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
// change this, if your php files and data is outside of your webservers document root
|
||||
|
|
31
js/common.js
31
js/common.js
|
@ -12,12 +12,12 @@ global.WebCrypto = require('@peculiar/webcrypto').Crypto;
|
|||
// application libraries to test
|
||||
global.$ = global.jQuery = require('./jquery-3.7.0');
|
||||
global.RawDeflate = require('./rawinflate-0.3').RawDeflate;
|
||||
global.zlib = require('./zlib-1.2.13').zlib;
|
||||
global.zlib = require('./zlib-1.3.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.0.6');
|
||||
global.DOMPurify = require('./purify-3.0.8');
|
||||
global.baseX = require('./base-x-4.0.0').baseX;
|
||||
global.Legacy = require('./legacy').Legacy;
|
||||
require('./bootstrap-3.4.1');
|
||||
|
@ -37,7 +37,7 @@ var a2zString = ['a','b','c','d','e','f','g','h','i','j','k','l','m',
|
|||
})
|
||||
),
|
||||
schemas = ['ftp','http','https'],
|
||||
supportedLanguages = ['de', 'es', 'fr', 'it', 'no', 'pl', 'pt', 'oc', 'ru', 'sl', 'zh'],
|
||||
supportedLanguages = ['ar', 'bg', 'ca', 'co', 'cs', 'de', 'el', 'es', 'et', 'fi', 'fr', 'he', 'hu', 'id', 'it', 'ja', 'jbo', 'lt', 'no', 'nl', 'pl', 'pt', 'oc', 'ru', 'sk', 'sl', 'th', 'tr', 'uk', 'zh'],
|
||||
mimeTypes = ['image/png', 'application/octet-stream'],
|
||||
formats = ['plaintext', 'markdown', 'syntaxhighlighting'],
|
||||
mimeFile = fs.createReadStream('/etc/mime.types'),
|
||||
|
@ -113,8 +113,8 @@ exports.jscBase64String = function() {
|
|||
};
|
||||
|
||||
// provides a random URL schema supported by the whatwg-url library
|
||||
exports.jscSchemas = function() {
|
||||
return jsc.elements(schemas);
|
||||
exports.jscSchemas = function(withFtp = true) {
|
||||
return jsc.elements(withFtp ? schemas : schemas.slice(1));
|
||||
};
|
||||
|
||||
// provides a random supported language string
|
||||
|
@ -131,3 +131,24 @@ exports.jscMimeTypes = function() {
|
|||
exports.jscFormats = function() {
|
||||
return jsc.elements(formats);
|
||||
};
|
||||
|
||||
// provides random URLs
|
||||
exports.jscUrl = function(withFragment = true, withQuery = true) {
|
||||
let url = {
|
||||
schema: exports.jscSchemas(),
|
||||
address: jsc.nearray(exports.jscA2zString()),
|
||||
};
|
||||
if (withFragment) {
|
||||
url.fragment = jsc.string;
|
||||
}
|
||||
if(withQuery) {
|
||||
url.query = jsc.array(exports.jscQueryString());
|
||||
}
|
||||
return jsc.record(url);
|
||||
};
|
||||
|
||||
exports.urlToString = function (url) {
|
||||
return url.schema + '://' + url.address.join('') + '/' + (url.query ? '?' +
|
||||
encodeURI(url.query.join('').replace(/^&+|&+$/gm,'')) : '') +
|
||||
(url.fragment ? '#' + encodeURI(url.fragment) : '');
|
||||
};
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "privatebin",
|
||||
"version": "1.5.2",
|
||||
"version": "1.6.2",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "privatebin",
|
||||
"version": "1.5.2",
|
||||
"version": "1.6.2",
|
||||
"license": "zlib-acknowledgement",
|
||||
"devDependencies": {
|
||||
"@peculiar/webcrypto": "^1.1.1",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "privatebin",
|
||||
"version": "1.6.1",
|
||||
"version": "1.7.1",
|
||||
"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": {
|
||||
|
|
158
js/privatebin.js
158
js/privatebin.js
|
@ -6,7 +6,7 @@
|
|||
* @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.6.1
|
||||
* @version 1.7.1
|
||||
* @name PrivateBin
|
||||
* @namespace
|
||||
*/
|
||||
|
@ -77,6 +77,13 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* URL fragment prefix requiring load confirmation
|
||||
*
|
||||
* @private
|
||||
*/
|
||||
const loadConfirmPrefix = '#-';
|
||||
|
||||
/**
|
||||
* CryptoData class
|
||||
*
|
||||
|
@ -228,7 +235,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'\'': ''',
|
||||
'/': '/',
|
||||
'`': '`',
|
||||
'=': '='
|
||||
|
@ -627,7 +634,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
* @prop {string[]}
|
||||
* @readonly
|
||||
*/
|
||||
const supportedLanguages = ['ar', 'bg', 'ca', 'co', 'cs', 'de', 'el', 'es', 'et', 'fi', 'fr', 'he', 'hu', 'id', 'it', 'ja', 'jbo', 'lt', 'no', 'nl', 'pl', 'pt', 'oc', 'ru', 'sk', 'sl', 'th', 'tr', 'uk', 'zh'];
|
||||
const supportedLanguages = ['ar', 'bg', 'ca', 'co', 'cs', 'de', 'el', 'es', 'et', 'fi', 'fr', 'he', 'hu', 'id', 'it', 'ja', 'jbo', 'lt', 'no', 'nl', 'pl', 'pt', 'oc', 'ro', 'ru', 'sk', 'sl', 'th', 'tr', 'uk', 'zh'];
|
||||
|
||||
/**
|
||||
* built in language
|
||||
|
@ -836,6 +843,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
return n % 10 === 1 && n % 100 !== 11 ? 0 : ((n % 10 >= 2 && n % 100 < 10 || n % 100 >= 20) ? 1 : 2);
|
||||
case 'pl':
|
||||
return n === 1 ? 0 : (n % 10 >= 2 && n %10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2);
|
||||
case 'ro':
|
||||
return n === 1 ? 0 : ((n === 0 || (n % 100 > 0 && n % 100 < 20)) ? 1 : 2);
|
||||
case 'ru':
|
||||
case 'uk':
|
||||
return n % 10 === 1 && n % 100 !== 11 ? 0 : (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2);
|
||||
|
@ -1512,10 +1521,11 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
me.getPasteKey = function()
|
||||
{
|
||||
if (symmetricKey === null) {
|
||||
let newKey = window.location.hash.substring(1);
|
||||
if (newKey === '') {
|
||||
throw 'no encryption key given';
|
||||
let startPos = 1;
|
||||
if(window.location.hash.startsWith(loadConfirmPrefix)) {
|
||||
startPos = loadConfirmPrefix.length;
|
||||
}
|
||||
let newKey = window.location.hash.substring(startPos);
|
||||
|
||||
// Some web 2.0 services and redirectors add data AFTER the anchor
|
||||
// (such as &utm_source=...). We will strip any additional data.
|
||||
|
@ -1524,6 +1534,9 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
{
|
||||
newKey = newKey.substring(0, ampersandPos);
|
||||
}
|
||||
if (newKey === '') {
|
||||
throw 'no encryption key given';
|
||||
}
|
||||
|
||||
// version 2 uses base58, version 1 uses base64 without decoding
|
||||
try {
|
||||
|
@ -2035,29 +2048,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
xhrFields: {
|
||||
withCredentials: false
|
||||
},
|
||||
success: function(response) {
|
||||
let responseString = response;
|
||||
if (typeof responseString === 'object') {
|
||||
responseString = JSON.stringify(responseString);
|
||||
}
|
||||
if (typeof responseString === 'string' && responseString.length > 0) {
|
||||
const shortUrlMatcher = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g;
|
||||
const shortUrl = (responseString.match(shortUrlMatcher) || []).sort(function(a, b) {
|
||||
return a.length - b.length;
|
||||
})[0];
|
||||
if (typeof shortUrl === 'string' && shortUrl.length > 0) {
|
||||
// we disable the button to avoid calling shortener again
|
||||
$shortenButton.addClass('buttondisabled');
|
||||
// update link
|
||||
$pasteUrl.text(shortUrl);
|
||||
$pasteUrl.prop('href', shortUrl);
|
||||
// we pre-select the link so that the user only has to [Ctrl]+[c] the link
|
||||
Helper.selectText($pasteUrl[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Alert.showError('Cannot parse response from URL shortener.');
|
||||
}
|
||||
success: PasteStatus.extractUrl
|
||||
})
|
||||
.fail(function(data, textStatus, errorThrown) {
|
||||
console.error(textStatus, errorThrown);
|
||||
|
@ -2123,6 +2114,50 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
Helper.selectText($pasteUrl[0]);
|
||||
};
|
||||
|
||||
/**
|
||||
* extracts URLs from given string
|
||||
*
|
||||
* if at least one is found, it disables the shortener button and
|
||||
* replaces the paste URL
|
||||
*
|
||||
* @name PasteStatus.extractUrl
|
||||
* @function
|
||||
* @param {string} response
|
||||
*/
|
||||
me.extractUrl = function(response)
|
||||
{
|
||||
if (typeof response === 'object') {
|
||||
response = JSON.stringify(response);
|
||||
}
|
||||
if (typeof response === 'string' && response.length > 0) {
|
||||
const shortUrlMatcher = /https?:\/\/[^\s"<]+/g; // JSON API will have URL in quotes, XML in tags
|
||||
const shortUrl = (response.match(shortUrlMatcher) || []).filter(function(urlRegExMatch) {
|
||||
if (typeof URL.canParse === 'function') {
|
||||
return URL.canParse(urlRegExMatch);
|
||||
}
|
||||
// polyfill for older browsers (< 120) & node (< 19.9 & < 18.17)
|
||||
try {
|
||||
return !!new URL(urlRegExMatch);
|
||||
} catch (error) {
|
||||
return false;
|
||||
}
|
||||
}).sort(function(a, b) {
|
||||
return a.length - b.length; // shortest first
|
||||
})[0];
|
||||
if (typeof shortUrl === 'string' && shortUrl.length > 0) {
|
||||
// we disable the button to avoid calling shortener again
|
||||
$shortenButton.addClass('buttondisabled');
|
||||
// update link
|
||||
$pasteUrl.text(shortUrl);
|
||||
$pasteUrl.prop('href', shortUrl);
|
||||
// we pre-select the link so that the user only has to [Ctrl]+[c] the link
|
||||
Helper.selectText($pasteUrl[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Alert.showError('Cannot parse response from URL shortener.');
|
||||
};
|
||||
|
||||
/**
|
||||
* shows the remaining time
|
||||
*
|
||||
|
@ -2228,6 +2263,34 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
PasteDecrypter.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Request users confirmation to load possibly burn after reading paste
|
||||
*
|
||||
* @name Prompt.requestLoadConfirmation
|
||||
* @function
|
||||
*/
|
||||
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');
|
||||
} else {
|
||||
if (window.confirm(
|
||||
I18n._('Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?')
|
||||
)) {
|
||||
PasteDecrypter.run();
|
||||
} else {
|
||||
Controller.newPaste();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ask the user for the password and set it
|
||||
*
|
||||
|
@ -2242,6 +2305,12 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
backdrop: 'static',
|
||||
keyboard: false
|
||||
});
|
||||
// focus password input
|
||||
$passwordDecrypt.focus();
|
||||
// then re-focus it, when modal causes it to loose focus again
|
||||
setTimeout(function () {
|
||||
$passwordDecrypt.focus();
|
||||
}, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2301,13 +2370,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
$passwordForm = $('#passwordform');
|
||||
$passwordModal = $('#passwordmodal');
|
||||
|
||||
// bind events
|
||||
|
||||
// focus password input when it is shown
|
||||
$passwordModal.on('shown.bs.Model', function () {
|
||||
$passwordDecrypt.focus();
|
||||
});
|
||||
// handle Model password submission
|
||||
// bind events - handle Model password submission
|
||||
$passwordForm.submit(submitPasswordModal);
|
||||
};
|
||||
|
||||
|
@ -3541,7 +3604,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
if (fadeOut === true) {
|
||||
setTimeout(function () {
|
||||
$comment.removeClass('highlight');
|
||||
|
||||
}, 300);
|
||||
}
|
||||
};
|
||||
|
@ -3789,6 +3851,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
{
|
||||
document.cookie = 'lang=' + $(event.target).data('lang') + ';secure';
|
||||
UiHelper.reloadHome();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -3902,7 +3965,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
}
|
||||
emailBody += I18n._('Link:');
|
||||
emailBody += EOL;
|
||||
emailBody += `${window.location.href}`;
|
||||
emailBody += $('#pasteurl').attr('href'); // might have been shortened
|
||||
return emailBody;
|
||||
}
|
||||
|
||||
|
@ -3944,10 +4007,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
const $emailconfirmmodal = $('#emailconfirmmodal');
|
||||
if ($emailconfirmmodal.length > 0) {
|
||||
if (expirationDate !== null) {
|
||||
I18n._(
|
||||
$emailconfirmmodal.find('#emailconfirm-display'),
|
||||
'Recipient may become aware of your timezone, convert time to UTC?'
|
||||
);
|
||||
const $emailconfirmTimezoneCurrent = $emailconfirmmodal.find('#emailconfirm-timezone-current');
|
||||
const $emailconfirmTimezoneUtc = $emailconfirmmodal.find('#emailconfirm-timezone-utc');
|
||||
$emailconfirmTimezoneCurrent.off('click.sendEmailCurrentTimezone');
|
||||
|
@ -4802,7 +4861,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
|
||||
// show notification
|
||||
const baseUri = Helper.baseUri() + '?',
|
||||
url = baseUri + data.id + '#' + CryptTool.base58encode(data.encryptionKey),
|
||||
url = baseUri + data.id + (TopNav.getBurnAfterReading() ? loadConfirmPrefix : '#') + CryptTool.base58encode(data.encryptionKey),
|
||||
deleteUrl = baseUri + 'pasteid=' + data.id + '&deletetoken=' + data.deletetoken;
|
||||
PasteStatus.createPasteNotification(url, deleteUrl);
|
||||
|
||||
|
@ -5221,7 +5280,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
Alert.hideMessages();
|
||||
Alert.showLoading('Decrypting paste…', 'cloud-download');
|
||||
|
||||
if (typeof paste === 'undefined') {
|
||||
if (typeof paste === 'undefined' || paste.type === 'click') {
|
||||
// get cipher data and wait until it is available
|
||||
Model.getPasteData(me.run);
|
||||
return;
|
||||
|
@ -5328,7 +5387,10 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
AttachmentViewer.removeAttachmentData();
|
||||
|
||||
Alert.hideLoading();
|
||||
history.pushState({type: 'create'}, document.title, Helper.baseUri());
|
||||
// only push new state if we are coming from a different one
|
||||
if (Helper.baseUri() != window.location) {
|
||||
history.pushState({type: 'create'}, document.title, Helper.baseUri());
|
||||
}
|
||||
|
||||
// clear discussion
|
||||
DiscussionViewer.prepareNewDiscussion();
|
||||
|
@ -5354,6 +5416,12 @@ jQuery.PrivateBin = (function($, RawDeflate) {
|
|||
}
|
||||
}
|
||||
|
||||
// check if we should request loading confirmation
|
||||
if(window.location.hash.startsWith(loadConfirmPrefix)) {
|
||||
Prompt.requestLoadConfirmation();
|
||||
return;
|
||||
}
|
||||
|
||||
// show proper elements on screen
|
||||
PasteDecrypter.run();
|
||||
};
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -96,36 +96,34 @@ describe('Helper', function () {
|
|||
jsc.property(
|
||||
'replaces URLs with anchors',
|
||||
'string',
|
||||
jsc.elements(['http', 'https', 'ftp']),
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.array(common.jscQueryString()),
|
||||
common.jscUrl(),
|
||||
jsc.array(common.jscHashString()),
|
||||
'string',
|
||||
function (prefix, schema, address, query, fragment, postfix) {
|
||||
query = query.join('');
|
||||
fragment = fragment.join('');
|
||||
function (prefix, url, fragment, postfix) {
|
||||
prefix = prefix.replace(/\r|\f/g, '\n').replace(/\u0000/g, '').replace(/\u000b/g, '');
|
||||
postfix = ' ' + postfix.replace(/\r/g, '\n').replace(/\u0000/g, '');
|
||||
let url = schema + '://' + address.join('') + '/?' + query + '#' + fragment,
|
||||
url.fragment = fragment.join('');
|
||||
let urlString = common.urlToString(url),
|
||||
clean = jsdom();
|
||||
$('body').html('<div id="foo"></div>');
|
||||
let e = $('#foo');
|
||||
|
||||
// special cases: When the query string and fragment imply the beginning of an HTML entity, eg. � or &#x
|
||||
if (
|
||||
query.slice(-1) === '&' &&
|
||||
(parseInt(fragment.substring(0, 1), 10) >= 0 || fragment.charAt(0) === 'x' )
|
||||
)
|
||||
{
|
||||
url = schema + '://' + address.join('') + '/?' + query.substring(0, query.length - 1);
|
||||
url.query[-1] === '&' &&
|
||||
(parseInt(url.fragment.charAt(0), 10) >= 0 || url.fragment.charAt(0) === 'x')
|
||||
) {
|
||||
url.query.pop();
|
||||
urlString = common.urlToString(url);
|
||||
postfix = '';
|
||||
}
|
||||
e.text(prefix + url + postfix);
|
||||
e.text(prefix + urlString + postfix);
|
||||
$.PrivateBin.Helper.urls2links(e);
|
||||
let result = e.html();
|
||||
clean();
|
||||
url = $('<div />').text(url).html();
|
||||
return $('<div />').text(prefix).html() + '<a href="' + url + '" target="_blank" rel="nofollow noopener noreferrer">' + url + '</a>' + $('<div />').text(postfix).html() === result;
|
||||
urlString = $('<div />').text(urlString).html();
|
||||
const expected = $('<div />').text(prefix).html() + '<a href="' + urlString + '" target="_blank" rel="nofollow noopener noreferrer">' + urlString + '</a>' + $('<div />').text(postfix).html();
|
||||
return $('<div />').text(prefix).html() + '<a href="' + urlString + '" target="_blank" rel="nofollow noopener noreferrer">' + urlString + '</a>' + $('<div />').text(postfix).html() === result;
|
||||
}
|
||||
);
|
||||
jsc.property(
|
||||
|
@ -261,16 +259,16 @@ describe('Helper', function () {
|
|||
this.timeout(30000);
|
||||
jsc.property(
|
||||
'returns the URL without query & fragment',
|
||||
jsc.elements(['http', 'https']),
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.array(common.jscA2zString()),
|
||||
jsc.array(common.jscQueryString()),
|
||||
'string',
|
||||
function (schema, address, path, query, fragment) {
|
||||
common.jscSchemas(false),
|
||||
common.jscUrl(),
|
||||
function (schema, url) {
|
||||
url.schema = schema;
|
||||
const fullUrl = common.urlToString(url);
|
||||
delete(url.query);
|
||||
delete(url.fragment);
|
||||
$.PrivateBin.Helper.reset();
|
||||
var path = path.join('') + (path.length > 0 ? '/' : ''),
|
||||
expected = schema + '://' + address.join('') + '/' + path,
|
||||
clean = jsdom('', {url: expected + '?' + query.join('') + '#' + fragment}),
|
||||
const expected = common.urlToString(url),
|
||||
clean = jsdom('', {url: fullUrl}),
|
||||
result = $.PrivateBin.Helper.baseUri();
|
||||
clean();
|
||||
return expected === result;
|
||||
|
|
112
js/test/Model.js
112
js/test/Model.js
|
@ -80,23 +80,22 @@ describe('Model', function () {
|
|||
|
||||
jsc.property(
|
||||
'returns the query string without separator, if any',
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
common.jscUrl(true, false),
|
||||
jsc.tuple(new Array(16).fill(common.jscHexString)),
|
||||
jsc.array(common.jscQueryString()),
|
||||
jsc.array(common.jscQueryString()),
|
||||
'string',
|
||||
function (schema, address, pasteId, queryStart, queryEnd, fragment) {
|
||||
var pasteIdString = pasteId.join(''),
|
||||
queryStartString = queryStart.join('') + (queryStart.length > 0 ? '&' : ''),
|
||||
queryEndString = (queryEnd.length > 0 ? '&' : '') + queryEnd.join(''),
|
||||
queryString = queryStartString + pasteIdString + queryEndString,
|
||||
clean = jsdom('', {
|
||||
url: schema.join('') + '://' + address.join('') +
|
||||
'/?' + queryString + '#' + fragment
|
||||
});
|
||||
global.URL = require('jsdom-url').URL;
|
||||
var result = $.PrivateBin.Model.getPasteId();
|
||||
function (url, pasteId, queryStart, queryEnd) {
|
||||
if (queryStart.length > 0) {
|
||||
queryStart.push('&');
|
||||
}
|
||||
if (queryEnd.length > 0) {
|
||||
queryEnd.unshift('&');
|
||||
}
|
||||
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();
|
||||
return pasteIdString === result;
|
||||
|
@ -104,14 +103,9 @@ describe('Model', function () {
|
|||
);
|
||||
jsc.property(
|
||||
'throws exception on empty query string',
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
'string',
|
||||
function (schema, address, fragment) {
|
||||
var clean = jsdom('', {
|
||||
url: schema.join('') + '://' + address.join('') +
|
||||
'/#' + fragment
|
||||
}),
|
||||
common.jscUrl(true, false),
|
||||
function (url) {
|
||||
let clean = jsdom('', {url: common.urlToString(url)}),
|
||||
result = false;
|
||||
global.URL = require('jsdom-url').URL;
|
||||
try {
|
||||
|
@ -135,35 +129,24 @@ describe('Model', function () {
|
|||
|
||||
jsc.property(
|
||||
'returns the fragment of a v1 URL',
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.array(common.jscQueryString()),
|
||||
'nestring',
|
||||
function (schema, address, query, fragment) {
|
||||
const fragmentString = common.btoa(fragment.padStart(32, '\u0000'));
|
||||
let clean = jsdom('', {
|
||||
url: schema.join('') + '://' + address.join('') +
|
||||
'/?' + query.join('') + '#' + fragmentString
|
||||
}),
|
||||
common.jscUrl(),
|
||||
function (url) {
|
||||
url.fragment = common.btoa(url.fragment.padStart(32, '\u0000'));
|
||||
const clean = jsdom('', {url: common.urlToString(url)}),
|
||||
result = $.PrivateBin.Model.getPasteKey();
|
||||
$.PrivateBin.Model.reset();
|
||||
clean();
|
||||
return fragmentString === result;
|
||||
return url.fragment === result;
|
||||
}
|
||||
);
|
||||
jsc.property(
|
||||
'returns the v1 fragment stripped of trailing query parts',
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.array(common.jscQueryString()),
|
||||
'nestring',
|
||||
common.jscUrl(),
|
||||
jsc.array(common.jscHashString()),
|
||||
function (schema, address, query, fragment, trail) {
|
||||
const fragmentString = common.btoa(fragment.padStart(32, '\u0000'));
|
||||
let clean = jsdom('', {
|
||||
url: schema.join('') + '://' + address.join('') + '/?' +
|
||||
query.join('') + '#' + fragmentString + '&' + trail.join('')
|
||||
}),
|
||||
function (url, trail) {
|
||||
const fragmentString = common.btoa(url.fragment.padStart(32, '\u0000'));
|
||||
url.fragment = fragmentString + '&' + trail.join('');
|
||||
const clean = jsdom('', {url: common.urlToString(url)}),
|
||||
result = $.PrivateBin.Model.getPasteKey();
|
||||
$.PrivateBin.Model.reset();
|
||||
clean();
|
||||
|
@ -172,18 +155,12 @@ describe('Model', function () {
|
|||
);
|
||||
jsc.property(
|
||||
'returns the fragment of a v2 URL',
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.array(common.jscQueryString()),
|
||||
'nestring',
|
||||
function (schema, address, query, fragment) {
|
||||
common.jscUrl(),
|
||||
function (url) {
|
||||
// base58 strips leading NULL bytes, so the string is padded with these if not found
|
||||
fragment = fragment.padStart(32, '\u0000');
|
||||
let fragmentString = $.PrivateBin.CryptTool.base58encode(fragment),
|
||||
clean = jsdom('', {
|
||||
url: schema.join('') + '://' + address.join('') +
|
||||
'/?' + query.join('') + '#' + fragmentString
|
||||
}),
|
||||
const fragment = url.fragment.padStart(32, '\u0000');
|
||||
url.fragment = $.PrivateBin.CryptTool.base58encode(fragment);
|
||||
const clean = jsdom('', {url: common.urlToString(url)}),
|
||||
result = $.PrivateBin.Model.getPasteKey();
|
||||
$.PrivateBin.Model.reset();
|
||||
clean();
|
||||
|
@ -192,19 +169,13 @@ describe('Model', function () {
|
|||
);
|
||||
jsc.property(
|
||||
'returns the v2 fragment stripped of trailing query parts',
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.array(common.jscQueryString()),
|
||||
'nestring',
|
||||
common.jscUrl(),
|
||||
jsc.array(common.jscHashString()),
|
||||
function (schema, address, query, fragment, trail) {
|
||||
function (url, trail) {
|
||||
// base58 strips leading NULL bytes, so the string is padded with these if not found
|
||||
fragment = fragment.padStart(32, '\u0000');
|
||||
let fragmentString = $.PrivateBin.CryptTool.base58encode(fragment),
|
||||
clean = jsdom('', {
|
||||
url: schema.join('') + '://' + address.join('') + '/?' +
|
||||
query.join('') + '#' + 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();
|
||||
|
@ -213,14 +184,9 @@ describe('Model', function () {
|
|||
);
|
||||
jsc.property(
|
||||
'throws exception on empty fragment of the URL',
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.array(common.jscQueryString()),
|
||||
function (schema, address, query) {
|
||||
var clean = jsdom('', {
|
||||
url: schema.join('') + '://' + address.join('') +
|
||||
'/?' + query.join('')
|
||||
}),
|
||||
common.jscUrl(false),
|
||||
function (url) {
|
||||
let clean = jsdom('', {url: common.urlToString(url)}),
|
||||
result = false;
|
||||
try {
|
||||
$.PrivateBin.Model.getPasteKey();
|
||||
|
|
|
@ -1,32 +1,39 @@
|
|||
'use strict';
|
||||
var common = require('../common');
|
||||
|
||||
function urlStrings(schema, longUrl, shortUrl) {
|
||||
longUrl.schema = schema;
|
||||
shortUrl.schema = schema;
|
||||
let longUrlString = common.urlToString(longUrl),
|
||||
shortUrlString = common.urlToString(shortUrl);
|
||||
// ensure the two random URLs actually are sorted as expected
|
||||
if (longUrlString.length <= shortUrlString.length) {
|
||||
if (longUrlString.length === shortUrlString.length) {
|
||||
longUrl.address.unshift('a');
|
||||
longUrlString = common.urlToString(longUrl);
|
||||
} else {
|
||||
[longUrlString, shortUrlString] = [shortUrlString, longUrlString];
|
||||
}
|
||||
}
|
||||
return [longUrlString, shortUrlString];
|
||||
}
|
||||
|
||||
describe('PasteStatus', function () {
|
||||
describe('createPasteNotification', function () {
|
||||
this.timeout(30000);
|
||||
|
||||
jsc.property(
|
||||
'creates a notification after a successfull paste upload',
|
||||
common.jscSchemas(),
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.array(common.jscQueryString()),
|
||||
'string',
|
||||
common.jscSchemas(),
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.array(common.jscQueryString()),
|
||||
function (
|
||||
schema1, address1, query1, fragment1,
|
||||
schema2, address2, query2
|
||||
) {
|
||||
var expected1 = schema1 + '://' + address1.join('') + '/?' +
|
||||
encodeURI(query1.join('').replace(/^&+|&+$/gm,'') + '#' + fragment1),
|
||||
expected2 = schema2 + '://' + address2.join('') + '/?' +
|
||||
encodeURI(query2.join('').replace(/^&+|&+$/gm,'')),
|
||||
common.jscUrl(),
|
||||
common.jscUrl(false),
|
||||
function (url1, url2) {
|
||||
const expected1 = common.urlToString(url1).replace(/&(gt|lt)$/, '&$1a'),
|
||||
expected2 = common.urlToString(url2).replace(/&(gt|lt)$/, '&$1a'),
|
||||
clean = jsdom();
|
||||
$('body').html('<div><div id="deletelink"></div><div id="pastelink"></div></div>');
|
||||
$.PrivateBin.PasteStatus.init();
|
||||
$.PrivateBin.PasteStatus.createPasteNotification(expected1, expected2);
|
||||
var result1 = $('#pasteurl')[0].href,
|
||||
const result1 = $('#pasteurl')[0].href,
|
||||
result2 = $('#deletelink a')[0].href;
|
||||
clean();
|
||||
return result1 === expected1 && result2 === expected2;
|
||||
|
@ -34,6 +41,138 @@ describe('PasteStatus', function () {
|
|||
);
|
||||
});
|
||||
|
||||
describe('extractUrl', function () {
|
||||
this.timeout(30000);
|
||||
|
||||
jsc.property(
|
||||
'extracts and updates IDN URLs found in given response',
|
||||
common.jscSchemas(false),
|
||||
'nestring',
|
||||
common.jscUrl(),
|
||||
function (schema, domain, url) {
|
||||
domain = domain.replace(/\P{Letter}|[\u00AA-\u00BA]/gu, '').toLowerCase();
|
||||
if (domain.length === 0) {
|
||||
domain = 'a';
|
||||
}
|
||||
url.schema = schema;
|
||||
url.address.unshift('.');
|
||||
url.address = domain.split('').concat(url.address);
|
||||
const urlString = common.urlToString(url),
|
||||
expected = urlString.substring((schema + '://' + domain).length),
|
||||
clean = jsdom();
|
||||
|
||||
$('body').html('<div><div id="pastelink"></div></div>');
|
||||
$.PrivateBin.PasteStatus.init();
|
||||
$.PrivateBin.PasteStatus.createPasteNotification('', '');
|
||||
$.PrivateBin.PasteStatus.extractUrl(urlString);
|
||||
|
||||
const result = $('#pasteurl')[0].href;
|
||||
clean();
|
||||
|
||||
return result.endsWith(expected) && (
|
||||
result.startsWith(schema + '://xn--') ||
|
||||
result.startsWith(schema + '://' + domain)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// YOURLS API samples from: https://yourls.org/readme.html#API;apireturn
|
||||
jsc.property(
|
||||
'extracts and updates URLs found in YOURLS API JSON response',
|
||||
common.jscSchemas(false),
|
||||
common.jscUrl(),
|
||||
common.jscUrl(false),
|
||||
function (schema, longUrl, shortUrl) {
|
||||
const [longUrlString, shortUrlString] = urlStrings(schema, longUrl, shortUrl),
|
||||
yourlsResponse = {
|
||||
url: {
|
||||
keyword: longUrl.address.join(''),
|
||||
url: longUrlString,
|
||||
title: "example title",
|
||||
date: "2014-10-24 16:01:39",
|
||||
ip: "127.0.0.1"
|
||||
},
|
||||
status: "success",
|
||||
message: longUrlString + " added to database",
|
||||
title: "example title",
|
||||
shorturl: shortUrlString,
|
||||
statusCode: 200
|
||||
},
|
||||
clean = jsdom();
|
||||
|
||||
$('body').html('<div><div id="pastelink"></div></div>');
|
||||
$.PrivateBin.PasteStatus.init();
|
||||
$.PrivateBin.PasteStatus.createPasteNotification('', '');
|
||||
$.PrivateBin.PasteStatus.extractUrl(JSON.stringify(yourlsResponse, undefined, 4));
|
||||
|
||||
const result = $('#pasteurl')[0].href;
|
||||
clean();
|
||||
|
||||
return result === shortUrlString;
|
||||
}
|
||||
);
|
||||
jsc.property(
|
||||
'extracts and updates URLs found in YOURLS API XML response',
|
||||
common.jscSchemas(false),
|
||||
common.jscUrl(),
|
||||
common.jscUrl(false),
|
||||
function (schema, longUrl, shortUrl) {
|
||||
const [longUrlString, shortUrlString] = urlStrings(schema, longUrl, shortUrl),
|
||||
yourlsResponse = '<result>\n' +
|
||||
' <keyword>' + longUrl.address.join('') + '</keyword>\n' +
|
||||
' <shorturl>' + shortUrlString + '</shorturl>\n' +
|
||||
' <longurl>' + longUrlString + '</longurl>\n' +
|
||||
' <message>success</message>\n' +
|
||||
' <statusCode>200</statusCode>\n' +
|
||||
'</result>',
|
||||
clean = jsdom();
|
||||
|
||||
$('body').html('<div><div id="pastelink"></div></div>');
|
||||
$.PrivateBin.PasteStatus.init();
|
||||
$.PrivateBin.PasteStatus.createPasteNotification('', '');
|
||||
$.PrivateBin.PasteStatus.extractUrl(yourlsResponse);
|
||||
|
||||
const result = $('#pasteurl')[0].href;
|
||||
clean();
|
||||
|
||||
return result === shortUrlString;
|
||||
}
|
||||
);
|
||||
jsc.property(
|
||||
'extracts and updates URLs found in YOURLS proxy HTML response',
|
||||
common.jscSchemas(false),
|
||||
common.jscUrl(),
|
||||
common.jscUrl(false),
|
||||
function (schema, longUrl, shortUrl) {
|
||||
const [longUrlString, shortUrlString] = urlStrings(schema, longUrl, shortUrl),
|
||||
yourlsResponse = '<!DOCTYPE html>\n' +
|
||||
'<html lang="en">\n' +
|
||||
'\t<head>\n' +
|
||||
'\t\t<meta charset="utf-8" />\n' +
|
||||
'\t\t<meta http-equiv="Content-Security-Policy" content="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">\n' +
|
||||
'\t\t<meta name="robots" content="noindex" />\n' +
|
||||
'\t\t<meta name="google" content="notranslate">\n' +
|
||||
'\t\t<title>PrivateBin</title>\n' +
|
||||
'\t</head>\n' +
|
||||
'\t<body>\n' +
|
||||
'\t\t<p>Your paste is <a id="pasteurl" href="' + shortUrlString + '">' + shortUrlString + '</a> <span id="copyhint">(Hit [Ctrl]+[c] to copy)</span></p>\n' +
|
||||
'\t</body>\n' +
|
||||
'</html>',
|
||||
clean = jsdom();
|
||||
|
||||
$('body').html('<div><div id="pastelink"></div></div>');
|
||||
$.PrivateBin.PasteStatus.init();
|
||||
$.PrivateBin.PasteStatus.createPasteNotification('', '');
|
||||
$.PrivateBin.PasteStatus.extractUrl(yourlsResponse);
|
||||
|
||||
const result = $('#pasteurl')[0].href;
|
||||
clean();
|
||||
|
||||
return result === shortUrlString;
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
describe('showRemainingTime', function () {
|
||||
this.timeout(30000);
|
||||
|
||||
|
@ -41,18 +180,9 @@ describe('PasteStatus', function () {
|
|||
'shows burn after reading message or remaining time v1',
|
||||
'bool',
|
||||
'nat',
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.nearray(common.jscQueryString()),
|
||||
'string',
|
||||
function (
|
||||
burnafterreading, remainingTime,
|
||||
schema, address, query, fragment
|
||||
) {
|
||||
var clean = jsdom('', {
|
||||
url: schema.join('') + '://' + address.join('') +
|
||||
'/?' + query.join('') + '#' + fragment
|
||||
}),
|
||||
common.jscUrl(),
|
||||
function (burnafterreading, remainingTime, url) {
|
||||
let clean = jsdom('', {url: common.urlToString(url)}),
|
||||
result;
|
||||
$('body').html('<div id="remainingtime" class="hidden"></div>');
|
||||
$.PrivateBin.PasteStatus.init();
|
||||
|
@ -79,18 +209,9 @@ describe('PasteStatus', function () {
|
|||
'shows burn after reading message or remaining time v2',
|
||||
'bool',
|
||||
'nat',
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.nearray(common.jscQueryString()),
|
||||
'string',
|
||||
function (
|
||||
burnafterreading, remainingTime,
|
||||
schema, address, query, fragment
|
||||
) {
|
||||
var clean = jsdom('', {
|
||||
url: schema.join('') + '://' + address.join('') +
|
||||
'/?' + query.join('') + '#' + fragment
|
||||
}),
|
||||
common.jscUrl(),
|
||||
function (burnafterreading, remainingTime, url) {
|
||||
let clean = jsdom('', {url: common.urlToString(url)}),
|
||||
result;
|
||||
$('body').html('<div id="remainingtime" class="hidden"></div>');
|
||||
$.PrivateBin.PasteStatus.init();
|
||||
|
|
|
@ -77,7 +77,7 @@ describe('TopNav', function () {
|
|||
'<li id="attach" class="hidden">Attach a file</li><li>' +
|
||||
'<a id="formatter" href="#" class="hidden">Format</a>' +
|
||||
'</li><li><button id="sendbutton" type="button" ' +
|
||||
'class="hidden">Send</button></li></ul></div></nav>'
|
||||
'class="hidden">Create</button></li></ul></div></nav>'
|
||||
);
|
||||
$.PrivateBin.TopNav.init();
|
||||
results.push(
|
||||
|
|
|
@ -13,10 +13,9 @@ describe('UiHelper', function () {
|
|||
|
||||
jsc.property(
|
||||
'redirects to home, when the state is null',
|
||||
common.jscSchemas(),
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
function (schema, address) {
|
||||
var expected = schema + '://' + address.join('') + '/',
|
||||
common.jscUrl(false, false),
|
||||
function (url) {
|
||||
const expected = common.urlToString(url),
|
||||
clean = jsdom('', {url: expected});
|
||||
|
||||
// make window.location.href writable
|
||||
|
@ -34,13 +33,11 @@ describe('UiHelper', function () {
|
|||
|
||||
jsc.property(
|
||||
'does not redirect to home, when a new paste is created',
|
||||
common.jscSchemas(),
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.array(common.jscQueryString()),
|
||||
common.jscUrl(false),
|
||||
jsc.nearray(common.jscBase64String()),
|
||||
function (schema, address, query, fragment) {
|
||||
var expected = schema + '://' + address.join('') + '/?' +
|
||||
query.join('') + '#' + fragment.join(''),
|
||||
function (url, fragment) {
|
||||
url.fragment = fragment.join('');
|
||||
const expected = common.urlToString(url),
|
||||
clean = jsdom('', {url: expected});
|
||||
|
||||
// make window.location.href writable
|
||||
|
@ -67,15 +64,12 @@ describe('UiHelper', function () {
|
|||
|
||||
jsc.property(
|
||||
'redirects to home',
|
||||
common.jscSchemas(),
|
||||
jsc.nearray(common.jscA2zString()),
|
||||
jsc.array(common.jscQueryString()),
|
||||
jsc.nearray(common.jscBase64String()),
|
||||
function (schema, address, query, fragment) {
|
||||
var expected = schema + '://' + address.join('') + '/',
|
||||
clean = jsdom('', {
|
||||
url: expected + '?' + query.join('') + '#' + fragment.join('')
|
||||
});
|
||||
common.jscUrl(),
|
||||
function (url) {
|
||||
const clean = jsdom('', {url: common.urlToString(url)});
|
||||
delete(url.query);
|
||||
delete(url.fragment);
|
||||
const expected = common.urlToString(url);
|
||||
|
||||
// make window.location.href writable
|
||||
Object.defineProperty(window.location, 'href', {
|
||||
|
|
|
@ -26,9 +26,9 @@
|
|||
|
||||
let buff;
|
||||
if (typeof fs === 'object') {
|
||||
buff = fs.readFileSync('zlib-1.2.13.wasm');
|
||||
buff = fs.readFileSync('zlib-1.3.1.wasm');
|
||||
} else {
|
||||
const resp = await fetch('js/zlib-1.2.13.wasm');
|
||||
const resp = await fetch('js/zlib-1.3.1.wasm');
|
||||
buff = await resp.arrayBuffer();
|
||||
}
|
||||
const module = await WebAssembly.compile(buff);
|
Binary file not shown.
|
@ -7,7 +7,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin;
|
||||
|
@ -28,7 +28,7 @@ class Controller
|
|||
*
|
||||
* @const string
|
||||
*/
|
||||
const VERSION = '1.6.1';
|
||||
const VERSION = '1.7.1';
|
||||
|
||||
/**
|
||||
* minimal required PHP version
|
||||
|
@ -111,10 +111,12 @@ class Controller
|
|||
public function __construct()
|
||||
{
|
||||
if (version_compare(PHP_VERSION, self::MIN_PHP_VERSION) < 0) {
|
||||
throw new Exception(I18n::_('%s requires php %s or above to work. Sorry.', I18n::_('PrivateBin'), self::MIN_PHP_VERSION), 1);
|
||||
error_log(I18n::_('%s requires php %s or above to work. Sorry.', I18n::_('PrivateBin'), self::MIN_PHP_VERSION));
|
||||
return;
|
||||
}
|
||||
if (strlen(PATH) < 0 && substr(PATH, -1) !== DIRECTORY_SEPARATOR) {
|
||||
throw new Exception(I18n::_('%s requires the PATH to end in a "%s". Please update the PATH in your index.php.', I18n::_('PrivateBin'), DIRECTORY_SEPARATOR), 5);
|
||||
error_log(I18n::_('%s requires the PATH to end in a "%s". Please update the PATH in your index.php.', I18n::_('PrivateBin'), DIRECTORY_SEPARATOR));
|
||||
return;
|
||||
}
|
||||
|
||||
// load config from ini file, initialize required classes
|
||||
|
@ -141,6 +143,8 @@ class Controller
|
|||
break;
|
||||
}
|
||||
|
||||
$this->_setCacheHeaders();
|
||||
|
||||
// output JSON or HTML
|
||||
if ($this->_request->isJsonApiCall()) {
|
||||
header('Content-type: ' . Request::MIME_JSON);
|
||||
|
@ -176,6 +180,22 @@ class Controller
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Turn off browser caching
|
||||
*
|
||||
* @access private
|
||||
*/
|
||||
private function _setCacheHeaders()
|
||||
{
|
||||
// set headers to disable caching
|
||||
$time = gmdate('D, d M Y H:i:s \G\M\T');
|
||||
header('Cache-Control: no-store, no-cache, no-transform, must-revalidate');
|
||||
header('Pragma: no-cache');
|
||||
header('Expires: ' . $time);
|
||||
header('Last-Modified: ' . $time);
|
||||
header('Vary: Accept');
|
||||
}
|
||||
|
||||
/**
|
||||
* Store new paste or comment
|
||||
*
|
||||
|
@ -250,7 +270,14 @@ class Controller
|
|||
}
|
||||
// The user posts a standard paste.
|
||||
else {
|
||||
$this->_model->purge();
|
||||
try {
|
||||
$this->_model->purge();
|
||||
} catch (Exception $e) {
|
||||
error_log('Error purging pastes: ' . $e->getMessage() . PHP_EOL .
|
||||
'Use the administration scripts statistics to find ' .
|
||||
'damaged paste IDs and either delete them or restore them ' .
|
||||
'from backup.');
|
||||
}
|
||||
$paste = $this->_model->getPaste();
|
||||
try {
|
||||
$paste->setData($data);
|
||||
|
@ -334,13 +361,6 @@ class Controller
|
|||
*/
|
||||
private function _view()
|
||||
{
|
||||
// set headers to disable caching
|
||||
$time = gmdate('D, d M Y H:i:s \G\M\T');
|
||||
header('Cache-Control: no-store, no-cache, no-transform, must-revalidate');
|
||||
header('Pragma: no-cache');
|
||||
header('Expires: ' . $time);
|
||||
header('Last-Modified: ' . $time);
|
||||
header('Vary: Accept');
|
||||
header('Content-Security-Policy: ' . $this->_conf->getKey('cspheader'));
|
||||
header('Cross-Origin-Resource-Policy: same-origin');
|
||||
header('Cross-Origin-Embedder-Policy: require-corp');
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin\Data;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin\Data;
|
||||
|
@ -55,7 +55,6 @@ class Database extends AbstractData
|
|||
* @access public
|
||||
* @param array $options
|
||||
* @throws Exception
|
||||
* @return
|
||||
*/
|
||||
public function __construct(array $options)
|
||||
{
|
||||
|
|
|
@ -7,12 +7,13 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin\Data;
|
||||
|
||||
use Exception;
|
||||
use GlobIterator;
|
||||
use PrivateBin\Json;
|
||||
|
||||
/**
|
||||
|
@ -65,7 +66,6 @@ class Filesystem extends AbstractData
|
|||
*
|
||||
* @access public
|
||||
* @param array $options
|
||||
* @return
|
||||
*/
|
||||
public function __construct(array $options)
|
||||
{
|
||||
|
@ -394,7 +394,7 @@ class Filesystem extends AbstractData
|
|||
public function getAllPastes()
|
||||
{
|
||||
$pastes = array();
|
||||
foreach (new \GlobIterator($this->_path . self::PASTE_FILE_PATTERN) as $file) {
|
||||
foreach (new GlobIterator($this->_path . self::PASTE_FILE_PATTERN) as $file) {
|
||||
if ($file->isFile()) {
|
||||
$pastes[] = $file->getBasename('.php');
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@ class GoogleCloudStorage extends AbstractData
|
|||
*
|
||||
* @access public
|
||||
* @param array $options
|
||||
* @return
|
||||
*/
|
||||
public function __construct(array $options)
|
||||
{
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* an S3 compatible data backend for PrivateBin with CEPH/RadosGW in mind
|
||||
* see https://docs.ceph.com/en/latest/radosgw/s3/php/
|
||||
* based on lib/Data/GoogleCloudStorage.php from PrivateBin version 1.6.1
|
||||
* based on lib/Data/GoogleCloudStorage.php from PrivateBin version 1.7.1
|
||||
*
|
||||
* @link https://github.com/PrivateBin/PrivateBin
|
||||
* @copyright 2022 Felix J. Ogris (https://ogris.de/)
|
||||
|
@ -78,7 +78,6 @@ class S3Storage extends AbstractData
|
|||
*
|
||||
* @access public
|
||||
* @param array $options
|
||||
* @return
|
||||
*/
|
||||
public function __construct(array $options)
|
||||
{
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin;
|
||||
|
|
43
lib/I18n.php
43
lib/I18n.php
|
@ -7,11 +7,14 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin;
|
||||
|
||||
use AppendIterator;
|
||||
use GlobIterator;
|
||||
|
||||
/**
|
||||
* I18n
|
||||
*
|
||||
|
@ -78,11 +81,11 @@ class I18n
|
|||
*
|
||||
* @access public
|
||||
* @static
|
||||
* @param string $messageId
|
||||
* @param string|array $messageId
|
||||
* @param mixed $args one or multiple parameters injected into placeholders
|
||||
* @return string
|
||||
*/
|
||||
public static function _($messageId)
|
||||
public static function _($messageId, ...$args)
|
||||
{
|
||||
return forward_static_call_array('PrivateBin\I18n::translate', func_get_args());
|
||||
}
|
||||
|
@ -92,16 +95,16 @@ class I18n
|
|||
*
|
||||
* @access public
|
||||
* @static
|
||||
* @param string $messageId
|
||||
* @param string|array $messageId
|
||||
* @param mixed $args one or multiple parameters injected into placeholders
|
||||
* @return string
|
||||
*/
|
||||
public static function translate($messageId)
|
||||
public static function translate($messageId, ...$args)
|
||||
{
|
||||
if (empty($messageId)) {
|
||||
return $messageId;
|
||||
}
|
||||
if (count(self::$_translations) === 0) {
|
||||
if (empty(self::$_translations)) {
|
||||
self::loadTranslations();
|
||||
}
|
||||
$messages = $messageId;
|
||||
|
@ -111,7 +114,7 @@ class I18n
|
|||
if (!array_key_exists($messageId, self::$_translations)) {
|
||||
self::$_translations[$messageId] = $messages;
|
||||
}
|
||||
$args = func_get_args();
|
||||
array_unshift($args, $messageId);
|
||||
if (is_array(self::$_translations[$messageId])) {
|
||||
$number = (int) $args[1];
|
||||
$key = self::_getPluralForm($number);
|
||||
|
@ -127,11 +130,9 @@ class I18n
|
|||
}
|
||||
// encode any non-integer arguments and the message ID, if it doesn't contain a link
|
||||
$argsCount = count($args);
|
||||
if ($argsCount > 1) {
|
||||
for ($i = 0; $i < $argsCount; ++$i) {
|
||||
if (($i > 0 && !is_int($args[$i])) || strpos($args[0], '<a') === false) {
|
||||
$args[$i] = self::encode($args[$i]);
|
||||
}
|
||||
for ($i = 0; $i < $argsCount; ++$i) {
|
||||
if ($i > 0 ? !is_int($args[$i]) : strpos($args[0], '<a') === false) {
|
||||
$args[$i] = self::encode($args[$i]);
|
||||
}
|
||||
}
|
||||
return call_user_func_array('sprintf', $args);
|
||||
|
@ -193,10 +194,14 @@ class I18n
|
|||
public static function getAvailableLanguages()
|
||||
{
|
||||
if (count(self::$_availableLanguages) == 0) {
|
||||
$i18n = dir(self::_getPath());
|
||||
while (false !== ($file = $i18n->read())) {
|
||||
if (preg_match('/^([a-z]{2,3}).json$/', $file, $match) === 1) {
|
||||
self::$_availableLanguages[] = $match[1];
|
||||
self::$_availableLanguages[] = 'en'; // en.json is not part of the release archive
|
||||
$languageIterator = new AppendIterator();
|
||||
$languageIterator->append(new GlobIterator(self::_getPath('??.json')));
|
||||
$languageIterator->append(new GlobIterator(self::_getPath('???.json'))); // for jbo
|
||||
foreach ($languageIterator as $file) {
|
||||
$language = $file->getBasename('.json');
|
||||
if ($language != 'en') {
|
||||
self::$_availableLanguages[] = $language;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -308,10 +313,10 @@ class I18n
|
|||
*/
|
||||
protected static function _getPath($file = '')
|
||||
{
|
||||
if (strlen(self::$_path) == 0) {
|
||||
if (empty(self::$_path)) {
|
||||
self::$_path = PUBLIC_PATH . DIRECTORY_SEPARATOR . 'i18n';
|
||||
}
|
||||
return self::$_path . (strlen($file) ? DIRECTORY_SEPARATOR . $file : '');
|
||||
return self::$_path . (empty($file) ? '' : DIRECTORY_SEPARATOR . $file);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -349,6 +354,8 @@ class I18n
|
|||
return $n % 10 === 1 && $n % 100 !== 11 ? 0 : (($n % 10 >= 2 && $n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
|
||||
case 'pl':
|
||||
return $n === 1 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
|
||||
case 'ro':
|
||||
return $n === 1 ? 0 : (($n === 0 || ($n % 100 > 0 && $n % 100 < 20)) ? 1 : 2);
|
||||
case 'ru':
|
||||
case 'uk':
|
||||
return $n % 10 === 1 && $n % 100 != 11 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin\Model;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin\Model;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin\Model;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin\Persistence;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin\Persistence;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin\Persistence;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin\Persistence;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin;
|
||||
|
@ -143,7 +143,7 @@ class Request
|
|||
} elseif (array_key_exists('jsonld', $this->_params) && !empty($this->_params['jsonld'])) {
|
||||
$this->_operation = 'jsonld';
|
||||
} elseif (array_key_exists('link', $this->_params) && !empty($this->_params['link'])) {
|
||||
if (strpos($this->getRequestUri(), '/shortenviayourls') !== false) {
|
||||
if (strpos($this->getRequestUri(), '/shortenviayourls') !== false || array_key_exists('shortenviayourls', $this->_params)) {
|
||||
$this->_operation = 'yourlsproxy';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* @link https://sebsauvage.net/wiki/doku.php?id=php:vizhash_gd
|
||||
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
|
||||
* @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
|
||||
* @version 0.0.5 beta PrivateBin 1.6.1
|
||||
* @version 0.0.5 beta PrivateBin 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* @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
|
||||
* @version 1.6.1
|
||||
* @version 1.7.1
|
||||
*/
|
||||
|
||||
namespace PrivateBin;
|
||||
|
|
|
@ -55,7 +55,7 @@ if ($ZEROBINCOMPATIBILITY) :
|
|||
<?php
|
||||
endif;
|
||||
?>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/zlib-1.2.13.js" integrity="sha512-Ltu/5qZMapdRIy4B3/iuLessSK6CvAui1C8txOX0z/uAFDJXXSwjvHsiFg9peQ2Gg/ga2tneKBfS0+00ndFsjQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/zlib-1.3.1.js" integrity="sha512-Z90oppVx/mn0DG2k9airjFVQuliELlXLeT3SRiO6MLiUSbhGlAq+UFwmYbG4i9mwW87dkG8fgJPapGwnUq7Osg==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/base-x-4.0.0.js" integrity="sha512-nNPg5IGCwwrveZ8cA/yMGr5HiRS5Ps2H+s0J/mKTPjCPWUgFGGw7M5nqdnPD3VsRwCVysUh3Y8OWjeSKGkEQJQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/rawinflate-0.3.js" integrity="sha512-g8uelGgJW9A/Z1tB6Izxab++oj5kdD7B4qC7DHwZkB6DGMXKyzx7v5mvap2HXueI2IIn08YlRYM56jwWdm2ucQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/bootstrap-3.4.1.js" integrity="sha512-oBTprMeNEKCnqfuqKd6sbvFzmFQtlXS3e0C/RGFV0hD6QzhHV+ODfaQbAlmY6/q0ubbwlAM/nCJjkrgA3waLzg==" crossorigin="anonymous"></script>
|
||||
|
@ -71,9 +71,9 @@ if ($MARKDOWN) :
|
|||
<?php
|
||||
endif;
|
||||
?>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/purify-3.0.6.js" integrity="sha512-N3y6/HOk3pbsw3lFh4O8CKKEVwu1B2CF8kinhjURf8Yqa5OfSUt+/arozxFW+TUPOPw3TsDCRT/0u7BGRTEVUw==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/purify-3.0.8.js" integrity="sha512-wWBDKh5wYGtJ1Df+PPZIn59jHVBnJ4/Yb2W/pVnzaXab8cmlZnHVx+FEBGu5JX39s3P2Qlt+aNQou0XnjW86hg==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LYos+qXHIRqFf5ZPNphvtTB0cgzHUizu2wwcOwcwz/VIpRv9lpcBgPYz4uq6jx0INwCAj6Fbnl5HoKiLufS2jg==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-Vhf93RhPJlAbV7jV1kizBzCDsx2xTrvneXe+9vdz6Ceg8wSfVZPzC6HWNdTWQLJIatlSVxd36rTra9M1uj5c+g==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-B5PWlo7wh39YRHm8rkP5KUyJkoBgL1/TY7ldx6d041+L20/0QLuCN3V2FUK0BpvOUl1CRb7IHbnS80HFMoGFrg==" crossorigin="anonymous"></script>
|
||||
<!-- icon -->
|
||||
<link rel="apple-touch-icon" href="<?php echo I18n::encode($BASEPATH); ?>img/apple-touch-icon.png" sizes="180x180" />
|
||||
<link rel="icon" type="image/png" href="img/favicon-32x32.png" sizes="32x32" />
|
||||
|
@ -123,22 +123,32 @@ if (count($class)) {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="loadconfirmmodal" tabindex="-1" class="modal fade" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="<?php echo I18n::_('Close') ?>"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title"><?php echo I18n::_('Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?') ?></h4>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<button id="loadconfirm-open-now" type="button" class="btn btn-success" data-dismiss="modal"><span class="glyphicon glyphicon-download"></span> <?php echo I18n::_('Yes, load it') ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
if ($QRCODE) :
|
||||
?>
|
||||
<div id="qrcodemodal" tabindex="-1" class="modal fade" aria-labelledby="qrcodemodalTitle" role="dialog" aria-hidden="true">
|
||||
<div id="qrcodemodal" tabindex="-1" class="modal fade" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="<?php echo I18n::_('Close') ?>"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title"><?php echo I18n::_('QR code') ?></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mx-auto" id="qrcode-display"></div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="btn-group col-xs-12">
|
||||
<span class="col-xs-12">
|
||||
<button type="button" class="btn btn-primary btn-block" data-dismiss="modal"><?php echo I18n::_('Close') ?></button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -146,23 +156,19 @@ if ($QRCODE) :
|
|||
endif;
|
||||
if ($EMAIL) :
|
||||
?>
|
||||
<div id="emailconfirmmodal" tabindex="-1" class="modal fade" aria-labelledby="emailconfirmmodalTitle" role="dialog" aria-hidden="true">
|
||||
<div id="emailconfirmmodal" tabindex="-1" class="modal fade" role="dialog" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-body">
|
||||
<div id="emailconfirm-display"></div>
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="<?php echo I18n::_('Close') ?>"><span aria-hidden="true">×</span></button>
|
||||
<h4 class="modal-title"><?php echo I18n::_('Recipient may become aware of your timezone, convert time to UTC?') ?></h4>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="btn-group col-xs-12" data-toggle="buttons">
|
||||
<span class="col-xs-12 col-md-4">
|
||||
<button id="emailconfirm-timezone-current" type="button" class="btn btn-danger btn-block" data-dismiss="modal"><?php echo I18n::_('Use Current Timezone') ?></button>
|
||||
</span>
|
||||
<span class="col-xs-12 col-md-4">
|
||||
<button id="emailconfirm-timezone-utc" type="button" class="btn btn-default btn-block" data-dismiss="modal"><?php echo I18n::_('Convert To UTC') ?></button>
|
||||
</span>
|
||||
<span class="col-xs-12 col-md-4">
|
||||
<button type="button" class="btn btn-primary btn-block" data-dismiss="modal"><?php echo I18n::_('Close') ?></button>
|
||||
</span>
|
||||
<div class="modal-body row">
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<button id="emailconfirm-timezone-current" type="button" class="btn btn-danger"><span class="glyphicon glyphicon-time"></span> <?php echo I18n::_('Use Current Timezone') ?></button>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6 text-right">
|
||||
<button id="emailconfirm-timezone-utc" type="button" class="btn btn-success"><span class="glyphicon glyphicon-globe"></span> <?php echo I18n::_('Convert To UTC') ?></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -203,7 +209,7 @@ endif;
|
|||
if ($isPage) :
|
||||
?>
|
||||
<button id="sendbutton" type="button" class="hidden btn btn-<?php echo $isDark ? 'warning' : 'primary'; ?> navbar-btn">
|
||||
<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?php echo I18n::_('Send'), PHP_EOL;
|
||||
<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?php echo I18n::_('Create'), PHP_EOL;
|
||||
else :
|
||||
?>
|
||||
<button id="newbutton" type="button" class="hidden btn btn-<?php echo $isDark ? 'warning' : 'default'; ?> navbar-btn">
|
||||
|
@ -555,7 +561,7 @@ if ($isPage) :
|
|||
else :
|
||||
?>
|
||||
<button id="sendbutton" type="button" class="hidden btn btn-<?php echo $isDark ? 'warning' : 'primary'; ?>">
|
||||
<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?php echo I18n::_('Send'), PHP_EOL;
|
||||
<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?php echo I18n::_('Create'), PHP_EOL;
|
||||
endif;
|
||||
?>
|
||||
</button>
|
||||
|
|
|
@ -34,7 +34,7 @@ if ($ZEROBINCOMPATIBILITY):
|
|||
<?php
|
||||
endif;
|
||||
?>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/zlib-1.2.13.js" integrity="sha512-Ltu/5qZMapdRIy4B3/iuLessSK6CvAui1C8txOX0z/uAFDJXXSwjvHsiFg9peQ2Gg/ga2tneKBfS0+00ndFsjQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/zlib-1.3.1.js" integrity="sha512-Z90oppVx/mn0DG2k9airjFVQuliELlXLeT3SRiO6MLiUSbhGlAq+UFwmYbG4i9mwW87dkG8fgJPapGwnUq7Osg==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/base-x-4.0.0.js" integrity="sha512-nNPg5IGCwwrveZ8cA/yMGr5HiRS5Ps2H+s0J/mKTPjCPWUgFGGw7M5nqdnPD3VsRwCVysUh3Y8OWjeSKGkEQJQ==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/rawinflate-0.3.js" integrity="sha512-g8uelGgJW9A/Z1tB6Izxab++oj5kdD7B4qC7DHwZkB6DGMXKyzx7v5mvap2HXueI2IIn08YlRYM56jwWdm2ucQ==" crossorigin="anonymous"></script>
|
||||
<?php
|
||||
|
@ -49,9 +49,9 @@ if ($MARKDOWN):
|
|||
<?php
|
||||
endif;
|
||||
?>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/purify-3.0.6.js" integrity="sha512-N3y6/HOk3pbsw3lFh4O8CKKEVwu1B2CF8kinhjURf8Yqa5OfSUt+/arozxFW+TUPOPw3TsDCRT/0u7BGRTEVUw==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/purify-3.0.8.js" integrity="sha512-wWBDKh5wYGtJ1Df+PPZIn59jHVBnJ4/Yb2W/pVnzaXab8cmlZnHVx+FEBGu5JX39s3P2Qlt+aNQou0XnjW86hg==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LYos+qXHIRqFf5ZPNphvtTB0cgzHUizu2wwcOwcwz/VIpRv9lpcBgPYz4uq6jx0INwCAj6Fbnl5HoKiLufS2jg==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-Vhf93RhPJlAbV7jV1kizBzCDsx2xTrvneXe+9vdz6Ceg8wSfVZPzC6HWNdTWQLJIatlSVxd36rTra9M1uj5c+g==" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-B5PWlo7wh39YRHm8rkP5KUyJkoBgL1/TY7ldx6d041+L20/0QLuCN3V2FUK0BpvOUl1CRb7IHbnS80HFMoGFrg==" crossorigin="anonymous"></script>
|
||||
<!-- icon -->
|
||||
<link rel="apple-touch-icon" href="img/apple-touch-icon.png?<?php echo rawurlencode($VERSION); ?>" sizes="180x180" />
|
||||
<link rel="icon" type="image/png" href="img/favicon-32x32.png?<?php echo rawurlencode($VERSION); ?>" sizes="32x32" />
|
||||
|
@ -125,7 +125,7 @@ endif;
|
|||
<div id="toolbar">
|
||||
<button id="newbutton" class="reloadlink hidden"><img src="img/icon_new.png" width="11" height="15" alt="" /><?php echo I18n::_('New'); ?></button>
|
||||
<button id="retrybutton" class="reloadlink hidden"><?php echo I18n::_('Retry'), PHP_EOL; ?></button>
|
||||
<button id="sendbutton" class="hidden"><img src="img/icon_send.png" width="18" height="15" alt="" /><?php echo I18n::_('Send'); ?></button>
|
||||
<button id="sendbutton" class="hidden"><img src="img/icon_send.png" width="18" height="15" alt="" /><?php echo I18n::_('Create'); ?></button>
|
||||
<button id="clonebutton" class="hidden"><img src="img/icon_clone.png" width="15" height="17" alt="" /><?php echo I18n::_('Clone'); ?></button>
|
||||
<button id="rawtextbutton" class="hidden"><img src="img/icon_raw.png" width="15" height="15" alt="" /><?php echo I18n::_('Raw text'); ?></button>
|
||||
<button id="downloadtextbutton" class="hidden"><?php echo I18n::_('Save paste'), PHP_EOL; ?></button>
|
||||
|
|
|
@ -3,6 +3,24 @@
|
|||
use PHPUnit\Framework\TestCase;
|
||||
use PrivateBin\I18n;
|
||||
|
||||
class I18nMock extends I18n
|
||||
{
|
||||
public static function resetAvailableLanguages()
|
||||
{
|
||||
self::$_availableLanguages = array();
|
||||
}
|
||||
|
||||
public static function resetPath($path = '')
|
||||
{
|
||||
self::$_path = $path;
|
||||
}
|
||||
|
||||
public static function getPath($file = '')
|
||||
{
|
||||
return self::_getPath($file);
|
||||
}
|
||||
}
|
||||
|
||||
class I18nTest extends TestCase
|
||||
{
|
||||
private $_translations = array();
|
||||
|
@ -167,6 +185,38 @@ class I18nTest extends TestCase
|
|||
$this->assertEquals($result . $result, I18n::_($input . '%s', $input), 'encodes message ID as well, when no link');
|
||||
}
|
||||
|
||||
public function testFallbackAlwaysPresent()
|
||||
{
|
||||
$path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_i18n';
|
||||
if (!is_dir($path)) {
|
||||
mkdir($path);
|
||||
}
|
||||
|
||||
$languageIterator = new AppendIterator();
|
||||
$languageIterator->append(new GlobIterator(I18nMock::getPath('??.json')));
|
||||
$languageIterator->append(new GlobIterator(I18nMock::getPath('???.json'))); // for jbo
|
||||
$languageCount = 0;
|
||||
foreach ($languageIterator as $file) {
|
||||
++$languageCount;
|
||||
$this->assertTrue(copy($file, $path . DIRECTORY_SEPARATOR . $file->getBasename()));
|
||||
}
|
||||
|
||||
I18nMock::resetPath($path);
|
||||
$languagesDevelopment = I18nMock::getAvailableLanguages();
|
||||
$this->assertEquals($languageCount, count($languagesDevelopment), 'all copied languages detected');
|
||||
$this->assertTrue(in_array('en', $languagesDevelopment), 'English fallback present');
|
||||
|
||||
unlink($path . DIRECTORY_SEPARATOR . 'en.json');
|
||||
I18nMock::resetAvailableLanguages();
|
||||
$languagesDeployed = I18nMock::getAvailableLanguages();
|
||||
$this->assertEquals($languageCount, count($languagesDeployed), 'all copied languages detected, plus fallback');
|
||||
$this->assertTrue(in_array('en', $languagesDeployed), 'English fallback still present');
|
||||
|
||||
I18nMock::resetAvailableLanguages();
|
||||
I18nMock::resetPath();
|
||||
Helper::rmDir($path);
|
||||
}
|
||||
|
||||
public function testMessageIdsExistInAllLanguages()
|
||||
{
|
||||
$messageIds = array();
|
||||
|
|
|
@ -285,26 +285,39 @@ class JsonApiTest extends TestCase
|
|||
|
||||
/**
|
||||
* @runInSeparateProcess
|
||||
* @dataProvider baseUriProvider
|
||||
*/
|
||||
public function testShortenViaYourls()
|
||||
public function testShortenViaYourls($baseUri)
|
||||
{
|
||||
$mock_yourls_service = $this->_path . DIRECTORY_SEPARATOR . 'yourls.json';
|
||||
$options = parse_ini_file(CONF, true);
|
||||
$options['main']['basepath'] = 'https://example.com/path'; // missing slash gets added by Configuration constructor
|
||||
$options['main']['urlshortener'] = 'https://example.com/path/shortenviayourls?link=';
|
||||
$options['main']['urlshortener'] = 'https://example.com' . $baseUri . 'link=';
|
||||
$options['yourls']['apiurl'] = $mock_yourls_service;
|
||||
Helper::createIniFile(CONF, $options);
|
||||
|
||||
// the real service answer is more complex, but we only look for the shorturl & statusCode
|
||||
file_put_contents($mock_yourls_service, '{"shorturl":"https:\/\/example.com\/1","statusCode":200}');
|
||||
|
||||
$_SERVER['REQUEST_URI'] = '/path/shortenviayourls?link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar';
|
||||
$_SERVER['REQUEST_URI'] = $baseUri . 'link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar';
|
||||
$_GET['link'] = 'https://example.com/path/?foo#bar';
|
||||
if (strpos($baseUri, '?shortenviayourls') !== false) {
|
||||
$_GET['shortenviayourls'] = null;
|
||||
}
|
||||
ob_start();
|
||||
new Controller;
|
||||
$content = ob_get_contents();
|
||||
ob_end_clean();
|
||||
$this->assertStringContainsString('id="pasteurl" href="https://example.com/1"', $content, 'outputs shortened URL correctly');
|
||||
$this->assertStringContainsString('id="pasteurl" href="https://example.com/1"', $content, "'{$baseUri}' outputs shortened URL correctly");
|
||||
}
|
||||
|
||||
public function baseUriProvider()
|
||||
{
|
||||
return array(
|
||||
array('/path/shortenviayourls?'),
|
||||
array('/path/index.php/shortenviayourls?'),
|
||||
array('/path?shortenviayourls&'),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue