110 Commits
1.3.1 ... 1.3.3

Author SHA1 Message Date
El RIDO
adece1d784 incrementing version 2020-02-16 11:15:51 +01:00
El RIDO
e74d786a68 update change log 2020-02-16 07:23:20 +01:00
El RIDO
12c83a13c7 addressing false positive jsverify rngState 85f362db8950cea741 2020-02-05 19:06:45 +01:00
El RIDO
aa377038a0 fixing DOMpurify 2.0.8 SRI after removing map line in file (which causes unnecessary requests to missing files in the browser) 2020-02-05 19:05:37 +01:00
El RIDO
7038fd5712 Revert "add 7.4 to travis CI tests"
This reverts commit 81194f6bd6.

Found that the trusty based php 7.4 in TravisCI doesn't include the GD module, that we need, plus there is an issue with the Filter::slowEquals() function that only remains for php 5.5 support that doesn't yet contain hash_compare().
2020-02-05 18:52:53 +01:00
El RIDO
81194f6bd6 add 7.4 to travis CI tests 2020-02-05 16:50:08 +01:00
El RIDO
bab95cce1b addressing false positive jsverify rngState 8bf7605ea139db4c28 2020-02-04 18:58:24 +01:00
El RIDO
00438ec1ab upgrade DOMpurify to 2.0.8 2020-02-04 18:43:35 +01:00
El RIDO
87423abd7c Fix ARIA for Editor/preview tabs. 2020-02-04 18:29:14 +01:00
El RIDO
347e7e03e1 Merge pull request #582 from RoiArthurB/patch-1
Update fr.json
2020-02-04 11:24:59 +01:00
Arthur Brugiere
6e08d8a497 Update fr.json
Fix missing translate + invalid translations
2020-02-04 14:54:47 +07:00
El RIDO
3fdd42487a fix FAQ links, tweaking the subtext display, add link to modern browser FAQ, fixes #577 2020-02-02 07:35:33 +01:00
El RIDO
2cbb8bf3ca in translation, allow links to be inserted unencoded into href attribute, simplfy sanitation by allowing only <a> tags in DOMpurify for plain text and comments and avoid DOMpurify removing magnet links, fixes #579 2020-02-02 07:08:38 +01:00
El RIDO
3996f82404 relax encoding of slashes just for plaintext display, so links can be detected 2020-02-01 16:30:41 +01:00
El RIDO
d7fd6667fd Merge branch 'displayEncoding2' 2020-02-01 16:16:05 +01:00
El RIDO
21ca30af3c apply StyleCI recommendation 2020-02-01 09:39:14 +01:00
El RIDO
1b206e8495 ensuring consistent use of php side encoding, testing all encoding cases, correctly report the language in the <html> tag 2020-02-01 09:15:14 +01:00
El RIDO
cc0920fc09 add HTML entity encoding to PHP translation logic, remove exception to allow <br/> tags in DOMpurify by eliminating the single case that made use of it 2020-02-01 08:46:59 +01:00
El RIDO
428ea2f34e adding test that expects parameters of php translation to get HTML entities to get encoded 2020-02-01 08:09:30 +01:00
El RIDO
f940f17bba Merge branch 'displayEncoding' 2020-02-01 07:53:32 +01:00
El RIDO
91003d6597 Merge remote-tracking branch 'origin/master' into displayEncoding 2020-02-01 07:52:48 +01:00
El RIDO
9a4018bffe jsverify rngState 8270695ec83abf412d was a false positive, due to incorrect test logic 2020-02-01 07:40:14 +01:00
El RIDO
8a6415ef5f fixing jsverify rngStates 0220439df7ec68a15b, 015c81b7afd06e4293 & 041e3d57692b08fc4a 2020-01-31 22:42:42 +01:00
El RIDO
b674c187a0 Merge pull request #578 from imtms/master
Update Chinese translation.
2020-01-31 21:34:34 +01:00
R4SAS
665192e27e Merge pull request #580 from mkromar/footer-link-fix-sl
Fixed info link in page footer of sl translation.
2020-01-31 19:02:31 +00:00
mkromar
b4256a986a Fixed info link in page footer of sl translation. 2020-01-31 19:47:24 +00:00
TMs
13b30608cb Update Chinese translation. 2020-01-31 12:36:02 +08:00
El RIDO
a86dd35ac3 Merge pull request #574 from PrivateBin/rugk-php-runner
Test PHP Composer runner of GitHub
2020-01-29 13:06:40 +01:00
rugk
19d0cace13 Merge branch 'readmeupdate' 2020-01-27 21:13:47 +01:00
rugk
d0589e77d4 Feature FAQ link in Readme & remove legacy things
* remove old ZeroBin 0.19 guide, this is so old already, few people will benefit from a direct link in the Readme. It stays in the wiki for those, who need it.
* add direct link to the FAQ - it's one of our best documentation/sources, so it's a shame it is not featured more prominently 😉
2020-01-27 15:28:40 +01:00
rugk
271c954f9a Test PHP Composer runner of GitHub
GitHub has these new CI/CD features, so let's test whether this makes sense.

I guess this PHP thing just installs the project via composer… 🤔
2020-01-26 23:25:24 +01:00
Erion
3f8cf1792d Switch to single quotes. 2020-01-26 18:08:59 +01:00
Erion
f6899785a9 Fix ARIA for Editor/preview tabs. 2020-01-25 18:47:18 +01:00
El RIDO
2d11d7b29e re-applying sprintf simplification and rephrased jsdoc block 2020-01-25 09:16:14 +01:00
El RIDO
29efc14aa7 Revert "implement simplified translation logic, forcing the use of safe application via jQuery element"
This reverts commit 62365880b4. The unit tests showed that the text2string function completely undid the XSS fix, so it was always unsafe to use it. Also the logic simplifications were smaller then expected.
2020-01-25 09:07:29 +01:00
El RIDO
62365880b4 implement simplified translation logic, forcing the use of safe application via jQuery element 2020-01-25 09:07:06 +01:00
El RIDO
aa3f1206b2 rewriting translations to pass jQuery element where easily possible 2020-01-25 08:13:36 +01:00
El RIDO
b160e5d1f8 Merge branch 'tupaschoal-translate-pt' 2020-01-22 20:15:20 +01:00
Tulio Leao
56ad0273e4 Update pt translation 2020-01-21 22:47:17 -03:00
El RIDO
83c29165ad Merge branch 'ensag-dev-master' 2020-01-21 19:02:05 +01:00
ensag-dev
39ee46caee Update for e-mail function 2020-01-21 08:11:16 +00:00
ensag-dev
774fea9230 Small corrections 2020-01-21 08:05:17 +00:00
El RIDO
1d8b0d6189 Merge branch 'rylebrun-mail_fr_translation' 2020-01-20 19:39:13 +01:00
El RIDO
72e96c7147 german translation of send to mail messages 2020-01-20 19:38:52 +01:00
El RIDO
1ae4f4f0fc updating all languages with missing translation, addresses failing unit test in previous commit 2020-01-20 19:24:28 +01:00
rylebrun
28c387074f Add mail fr translation for buttons 2020-01-20 12:11:03 +01:00
rylebrun
3993b47e06 Add mail fr translation 2020-01-20 12:03:11 +01:00
El RIDO
42130e0468 prevent potentially non-encoded string from getting returned 2020-01-18 10:53:58 +01:00
El RIDO
685c354d0e several changes:
- added tests for all 4 cases: output to string or into element vs first param contains link or not
- cleaned up logic - skip HTML entity encoding only if we can ensure insertion to text node / when output to string, we always encode
- DOMpurify sanitizes gopher, ws & wss links, which we previosly had tested for
2020-01-18 10:44:35 +01:00
El RIDO
fa9d3037ba fixing logic & indentation 2020-01-18 07:44:32 +01:00
El RIDO
7b87dc3ca9 cleanup revert 2020-01-18 07:36:43 +01:00
El RIDO
0d08edbe55 Revert "getting rid of htmlEntities (except for tests)" a0740ff79f 2020-01-18 07:30:01 +01:00
El RIDO
cec5cb41d7 Partial revert "Do not double-encode HTML in i18n", only revert the removal of required encoding logic - still has to be moved
This reverts commit 01414e43ca.
2020-01-18 07:20:05 +01:00
El RIDO
76eff6a87a Revert "[TEST] Try to disallow vulnerable cases" to remove accidentally committed file and statement that breaks the tests
This reverts commit ebc2d649c4.
2020-01-18 07:12:03 +01:00
El RIDO
fd4492f229 ensuring that both critical branches get tested 2020-01-18 07:09:56 +01:00
El RIDO
5daba16333 Merge branch 'ensag-dev-master' 2020-01-16 05:28:17 +01:00
rugk
eb549d70d1 Invert conatainsLink logic 2020-01-15 17:52:51 +01:00
ensag-dev
9f6c02276a Update Occitan translation 2020-01-14 16:24:53 +01:00
rugk
ebc2d649c4 [TEST] Try to disallow vulnerable cases 2020-01-13 19:56:15 +01:00
rugk
01414e43ca Do not double-encode HTML in i18n
This issue got introduced in 4bf7f86 due to double

Fixes https://github.com/PrivateBin/PrivateBin/issues/557
Fixes https://github.com/PrivateBin/PrivateBin/issues/558

Also _inverted_ the logic/variable name for containsNoLinks to
the more logical one "containsLinks" to avoid too many negations.

Also verified that the attachment name is stil properly displayed
when you clone a paste.
2020-01-13 19:17:30 +01:00
El RIDO
9aac073a49 clarifying for #525 that none is a string, as PHP might evaluate it to NULL instead 2020-01-09 05:42:42 +01:00
El RIDO
599264e167 partially address #556 - now comments can only be added after successfull decryption 2020-01-08 19:48:42 +01:00
El RIDO
ed590ee557 incrementing version 2020-01-08 19:31:06 +01:00
El RIDO
d73f8468d8 documenting changes for 1.2.2 2020-01-08 19:23:33 +01:00
El RIDO
ef8943d838 upgrading base-x library to 3.0.7 2020-01-07 20:11:12 +01:00
El RIDO
2fd649db14 upgrading showdown to released 1.9.1 version 2020-01-07 19:58:05 +01:00
El RIDO
11a7ac4e2b address new fixer in StyleCI causing false positives in templates 2020-01-07 19:39:22 +01:00
El RIDO
a9bf667f8e address error, displayed when paste has attachment, but configuration has them disabled 2020-01-04 13:33:03 +01:00
El RIDO
4bf7f863dc more general solution addressing #554, kudos @rugk for the suggestions 2020-01-04 13:14:53 +01:00
El RIDO
8d0ac336d2 addressing jsverifyRngState 8b8f0d4ec2a67139b5, fixes HTML injection via filename, closes #554 2019-12-25 09:14:32 +01:00
El RIDO
ddaee6486d Merge branch 'm1cr0man-master' 2019-12-25 08:16:33 +01:00
El RIDO
3485922366 documenting change 2019-12-25 08:16:17 +01:00
El RIDO
0efe6f7a8e simplify logic, fullfills the unit test 2019-12-25 08:11:25 +01:00
El RIDO
07a6e3094d adding unit tests for the new confi file env variable 2019-12-25 07:58:14 +01:00
Lucas Savva
7d9ec9509b Handle previously renamed CONFIG_PATH gracefully 2019-12-24 19:12:08 +00:00
Lucas Savva
d5d13fa831 Add logic to rename insecure CONFIG_PATH 2019-12-24 18:51:47 +00:00
Lucas Savva
13fb849973 Add CONFIG_PATH notes to INSTALL.md 2019-12-20 14:28:43 +00:00
Lucas Savva
b5c86e290f squashme: fix code style issue 2019-12-20 10:42:59 +00:00
Lucas Savva
6b0468ebff Add support for a CONFIG_PATH variable 2019-12-19 23:06:32 +00:00
El RIDO
825f6884be updating German translations 2019-12-07 08:26:51 +01:00
El RIDO
ee9e340de0 Merge branch 'qianmengnet-master' 2019-12-07 08:22:44 +01:00
El RIDO
2cbb86cefc adding missing translation IDs, kudos @qianmengnet for finding these 2019-12-07 08:22:29 +01:00
El RIDO
3923817f2b formatting of JSON, unicode tilde 2019-12-07 08:18:13 +01:00
Alex Lee
b00d8e4ad8 Update zh.json 2019-12-05 08:34:42 +08:00
Alex Lee
aa75e596c8 Update zh.json 2019-12-04 12:20:23 +08:00
El RIDO
787daccb78 Merge branch 'Haocen-543' 2019-11-29 19:12:36 +01:00
Haocen Xu
87cf61c39b Update SRI 2019-11-21 17:49:21 -05:00
Haocen Xu
853fd906cb Fix unnecessary closure capture 2019-11-21 17:43:10 -05:00
El RIDO
af8d963fd2 updating DOMpurify library, fixes #523 2019-11-02 17:31:45 +01:00
El RIDO
0ed238a775 Merge branch 'AndriiZ-master' 2019-11-02 17:21:22 +01:00
El RIDO
8cf0c86ebb simplify case statement, update documentation 2019-11-02 17:18:22 +01:00
El RIDO
b23fd48d49 Merge branch 'master' of https://github.com/AndriiZ/PrivateBin into AndriiZ-master 2019-11-02 17:11:05 +01:00
El RIDO
ffe26a8841 Merge branch 'Haocen-398' 2019-11-02 17:04:19 +01:00
El RIDO
0b6139fb42 updating change log and optimizing png 2019-11-02 17:03:40 +01:00
Haocen Xu
7d7ff34d83 Update SRI 2019-10-31 15:07:24 -04:00
Haocen Xu
e079f6c830 Implement Email button 2019-10-31 15:07:13 -04:00
Haocen Xu
63fdd2eba3 Fix missing semi colon 2019-10-30 14:04:10 -04:00
El RIDO
759113f453 Merge branch 'Haocen-527' 2019-10-26 06:04:39 +02:00
El RIDO
7255cd29a7 documenting change 2019-10-26 06:04:21 +02:00
El RIDO
13afa7fe21 Merge branch '527' of https://github.com/Haocen/PrivateBin-Contribute into Haocen-527 2019-10-26 06:01:39 +02:00
El RIDO
00a9e36c59 incrementing version 2019-10-26 06:01:24 +02:00
Haocen Xu
6fc4303acc Update SRI 2019-10-25 13:09:07 -04:00
Haocen Xu
56222d6cfb Bugfix when password is disabled in config no new paste can be
created
2019-10-25 13:05:09 -04:00
Andriy Zhuk
65b7077756 Added plural rules for ukrainian 2019-10-18 12:31:40 +03:00
Andriy Zhuk
03138bcde5 Fixed ... with … 2019-10-18 12:27:40 +03:00
Andriy Zhuk
7e9e3155a8 Fixed few typos 2019-10-17 17:20:00 +03:00
Andriy Zhuk
2b3b47c59d Removed line 2019-10-17 16:03:37 +03:00
Andriy Zhuk
8fc85bc39c Added line 2019-10-17 15:33:12 +03:00
Andriy Zhuk
92571512bf Added ukrainian localization 2019-10-17 15:24:33 +03:00
El RIDO
d3153b5e38 trying to fix travis on PHP 5 by removing composer.lock that depends on imcompatible phpunit version 2019-09-22 22:04:17 +02:00
73 changed files with 1549 additions and 474 deletions

23
.github/workflows/php.yml vendored Normal file
View File

@@ -0,0 +1,23 @@
name: PHP Composer
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Validate composer.json and composer.lock
run: composer validate
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-suggest
# Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit"
# Docs: https://getcomposer.org/doc/articles/scripts.md
# - name: Run test suite
# run: composer run-script test

View File

@@ -19,6 +19,7 @@ disabled:
- heredoc_to_nowdoc
- method_argument_space
- new_with_braces
- no_alternative_syntax
- phpdoc_align
- phpdoc_no_access
- phpdoc_separation

View File

@@ -16,6 +16,7 @@ install:
- source ~/.nvm/nvm.sh && nvm install --lts
before_script:
- rm composer.lock
- composer install -n
- npm install -g mocha
- cd js && npm install

View File

@@ -1,6 +1,20 @@
# PrivateBin version history
* **1.4 (not yet released)**
* CHANGED: Upgrading libraries to: DOMpurify 2.0.8
* CHANGED: Several translations got updated with missing messages
* CHANGED: Introduce HTML entity encoding on server side (#581)
* FIXED: HTML entity double encoding issues introduced in 1.3.2 (#560)
* **1.3.2 (2020-01-11)**
* ADDED: Translation for Ukrainian (#533)
* ADDED: Option to send a mail with the link, when creating a paste (#398)
* ADDED: Add support for CONFIG_PATH environment variable (#552)
* CHANGED: Upgrading libraries to: base-x 3.0.7, DOMpurify 2.0.7 & Showdown 1.9.1
* FIXED: HTML injection via unescaped attachment filename (#554)
* FIXED: Password disabling option (#527)
* **1.2.2 (2020-01-11)**
* CHANGED: Upgrading libraries to: bootstrap 3.4.1, DOMpurify 2.0.7, jQuery 3.4.1, kjua 0.6.0, Showdown 1.9.1 & SJCL 1.0.8
* FIXED: HTML injection via unescaped attachment filename (#554)
* **1.3.1 (2019-09-22)**
* ADDED: Translation for Bulgarian (#455)
* CHANGED: Improved mobile UI - obscured send button and hard to click shortener button (#477)

View File

@@ -26,6 +26,7 @@ Sébastien Sauvage - original idea and main developer
* thororm - Display of video, audio & PDF, drag & drop, preview of attachments
* Harald Leithner - base58 encoding of key
* Haocen - lots of bugfixes and UI improvements
* Lucas Savva - configurable config file location, NixOS packaging
## Translations
* Hexalyse - French
@@ -43,4 +44,5 @@ Sébastien Sauvage - original idea and main developer
* Michael van Schaik - Dutch
* Péter Tabajdi - Hungarian
* info-path - Czech
* BigWax - Bulgarian
* BigWax - Bulgarian
* AndriiZ - Ukrainian

View File

@@ -18,7 +18,7 @@ options](#configuration) to adjust as you see fit.
- open_basedir access to `/dev/urandom`
- mcrypt extension
- com_dotnet extension
Mcrypt needs to be able to access `/dev/urandom`. This means if `open_basedir` is set, it must include this file.
- GD extension
- some disk space or (optionally) a database supported by [PDO](https://secure.php.net/manual/book.pdo.php)
@@ -43,13 +43,34 @@ process (see also
>
> The full path of PrivateBin on your webserver is:
> /home/example.com/htdocs/paste
>
>
> When setting the path like this:
> define('PATH', '../../secret/privatebin/');
>
> PrivateBin will look for your includes / data here:
> /home/example.com/secret/privatebin
### Changing the config path only
In situations where you want to keep the PrivateBin static files separate from the
rest of your data, or you want to reuse the installation files on multiple vhosts,
you may only want to change the `conf.php`. In this instance, you can set the
`CONFIG_PATH` environment variable to the absolute path to the `conf.php` file.
This can be done in your web server's virtual host config, the PHP config, or in
the index.php if you choose to customize it.
Note that your PHP process will need read access to the config wherever it may be.
> #### CONFIG_PATH example
> Setting the value in an Apache Vhost:
> SetEnv CONFIG_PATH /var/lib/privatebin/conf.php
>
> In a php-fpm pool config:
> env[CONFIG_PATH] = /var/lib/privatebin/conf.php
>
> In the index.php, near the top:
> putenv('CONFIG_PATH=/var/lib/privatebin/conf.php');
### Transport security
When setting up PrivateBin, also set up HTTPS, if you haven't already. Without HTTPS
@@ -66,8 +87,9 @@ See [this FAQ item](https://github.com/PrivateBin/PrivateBin/wiki/FAQ#what-are-t
In the file `cfg/conf.php` you can configure PrivateBin. A `cfg/conf.sample.php`
is provided containing all options and default values. You can copy it to
`cfg/conf.php` and adapt it as needed. The config file is divided into multiple
sections, which are enclosed in square brackets.
`cfg/conf.php` and adapt it as needed. Alternatively you can copy it anywhere and
set the `CONFIG_PATH` environment variable (see above notes). The config file is
divided into multiple sections, which are enclosed in square brackets.
In the `[main]` section you can enable or disable the discussion feature, set
the limit of stored pastes and comments in bytes. The `[traffic]` section lets
@@ -165,7 +187,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.3.1');
INSERT INTO prefix_config VALUES('VERSION', '1.3.3');
```
In **PostgreSQL**, the data, attachment, nickname and vizhash columns needs to be TEXT and not BLOB or MEDIUMBLOB.

View File

@@ -1,6 +1,6 @@
# [![PrivateBin](https://cdn.rawgit.com/PrivateBin/assets/master/images/preview/logoSmall.png)](https://privatebin.info/)
*Current version: 1.3.1*
*Current version: 1.3.3*
**PrivateBin** is a minimalist, open source online [pastebin](https://en.wikipedia.org/wiki/Pastebin)
where the server has zero knowledge of pasted data.
@@ -95,9 +95,9 @@ file](https://github.com/PrivateBin/PrivateBin/wiki/Configuration):
## Further resources
* [Installation guide](https://github.com/PrivateBin/PrivateBin/blob/master/INSTALL.md#installation)
* [FAQ](https://github.com/PrivateBin/PrivateBin/wiki/FAQ)
* [Upgrading from ZeroBin 0.19 Alpha](https://github.com/PrivateBin/PrivateBin/wiki/Upgrading-from-ZeroBin-0.19-Alpha)
* [Installation guide](https://github.com/PrivateBin/PrivateBin/blob/master/INSTALL.md#installation)
* [Configuration guide](https://github.com/PrivateBin/PrivateBin/wiki/Configuration)

View File

@@ -4,8 +4,8 @@
| Version | Supported |
| ------- | ------------------ |
| 1.3.1 | :heavy_check_mark: |
| < 1.3.1 | :x: |
| 1.3.3 | :heavy_check_mark: |
| < 1.3.3 | :x: |
## Reporting a Vulnerability

View File

@@ -60,8 +60,8 @@ languageselection = false
; a different user when the same username was used in a comment. It might be
; used to get the IP of a non anonymous comment poster if the server salt is
; leaked and a SHA256 HMAC rainbow table is generated for all (relevant) IPs.
; Can be set to one these values: none / vizhash / identicon (default).
; icon = none
; Can be set to one these values: "none" / "vizhash" / "identicon" (default).
; icon = "none"
; Content Security Policy headers allow a website to restrict what sources are
; allowed to be accessed in its context. You need to change this if you added
@@ -95,8 +95,8 @@ languageselection = false
; Pick compression algorithm or disable it. Only applies to pastes/comments
; created after changing the setting.
; Can be set to one these values: none / zlib (default).
; compression = zlib
; Can be set to one these values: "none" / "zlib" (default).
; compression = "zlib"
[expire]
; expire value that is selected per default

View File

@@ -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.3.1
* @version 1.3.3
*/
body {
@@ -180,3 +180,28 @@ li.L0, li.L1, li.L2, li.L3, li.L5, li.L6, li.L7, li.L8 {
padding-right: 4ch;
}
}
.modal-dialog {
margin: auto !important;
}
/* makeup for the original margin on modal-dialog */
@media (min-width: 768px) {
.modal-content {
margin: 30px 0;
}
}
.modal-content {
margin: 10px;
}
.modal-body {
display: flex;
justify-content: center;
align-items: center;
}
.modal .modal-content button {
margin: 0.5em 0;
}

View File

@@ -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.3.1
* @version 1.3.3
*/
/* When there is no script at all other */

View File

@@ -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.3.1
* @version 1.3.3
*/
/* CSS Reset from YUI 3.4.1 (build 4118) - Copyright 2011 Yahoo! Inc. All rights reserved.

View File

@@ -31,8 +31,8 @@
"Невалиден код за изтриване. Информацията Ви не беше изтрита.",
"Paste was properly deleted.":
"Информацията Ви е изтрита.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"Услугата %s се нуждае от JavaScript, за да работи.<br />Съжаляваме за неудобството.",
"JavaScript is required for %s to work. Sorry for the inconvenience.":
"Услугата %s се нуждае от JavaScript, за да работи. Съжаляваме за неудобството.",
"%s requires a modern browser to work.":
"%s се нуждае от съвременен браузър за да работи.",
"New":
@@ -160,5 +160,29 @@
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Браузъра ви може да се нуждае от HTTPS връзка за да използва WebCrypto API. Пробвай <a href=\"%s\">да минеш на HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.",
"waiting on user to provide a password":
"waiting on user to provide a password",
"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":
"Retry",
"Showing raw text…":
"Showing raw text…",
"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:",
"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",
"Close":
"Close"
}

View File

@@ -31,8 +31,8 @@
"Wrong deletion token. Paste was not deleted.",
"Paste was properly deleted.":
"Paste was properly deleted.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.",
"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":
@@ -160,5 +160,29 @@
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.",
"waiting on user to provide a password":
"waiting on user to provide a password",
"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":
"Retry",
"Showing raw text…":
"Showing raw text…",
"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:",
"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",
"Close":
"Close"
}

View File

@@ -31,8 +31,8 @@
"Falscher Lösch-Code. Text wurde nicht gelöscht.",
"Paste was properly deleted.":
"Text wurde erfolgreich gelöscht.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"JavaScript ist eine Voraussetzung, um %s zu nutzen.<br />Bitte entschuldige die Unannehmlichkeiten.",
"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":
@@ -160,5 +160,29 @@
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Dein Browser benötigt möglicherweise eine HTTPS Verbindung um das WebCrypto API nutzen zu können. Versuche <a href=\"%s\">auf HTTPS zu wechseln</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Dein Browser unterstützt WebAssembly nicht, welches für zlib Komprimierung benötigt wird. Du kannst unkomprimierte Dokumente erzeugen, aber keine komprimierten lesen."
"Dein Browser unterstützt WebAssembly nicht, welches für zlib Komprimierung benötigt wird. Du kannst unkomprimierte Dokumente erzeugen, aber keine komprimierten lesen.",
"waiting on user to provide a password":
"warte auf Passworteingabe durch Benutzer",
"Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.":
"Konnte Daten nicht entschlüsseln. Hast Du das falsche Passwort eingegeben? Wiederhole den Vorgang mit dem oben stehenden Knopf.",
"Retry":
"Wiederholen",
"Showing raw text…":
"Zeige reinen Text an…",
"Notice:":
"Hinweis:",
"This link will expire after %s.":
"Dieser Link wird in %s ablaufen.",
"This link can only be accessed once, do not use back or refresh button in your browser.":
"Dieser Link kann nur einmal geöffnet werden, verwende nicht den \"Zurück\" oder \"Neu laden\" Knopf Deines Browsers.",
"Link:":
"Link:",
"Recipient may become aware of your timezone, convert time to UTC?":
"Der Empfänger könnte Deine Zeitzone erfahren, möchtest Du die Zeit in UTC umwandeln?",
"Use Current Timezone":
"Aktuelle Zeitzone verwenden",
"Convert To UTC":
"In UTC Umwandeln",
"Close":
"Schliessen"
}

View File

@@ -31,8 +31,8 @@
"Token de eliminación erróneo. El \"paste\" no fue eliminado.",
"Paste was properly deleted.":
"El \"paste\" se ha eliminado correctamente.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"JavaScript es necesario para que %s funcione.<br />Sentimos los inconvenientes ocasionados.",
"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":
@@ -160,5 +160,29 @@
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.",
"waiting on user to provide a password":
"waiting on user to provide a password",
"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":
"Retry",
"Showing raw text…":
"Showing raw text…",
"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:",
"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",
"Close":
"Close"
}

View File

@@ -31,8 +31,8 @@
"Jeton de suppression incorrect. Le paste n'a pas été supprimé.",
"Paste was properly deleted.":
"Le paste a été correctement supprimé.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"JavaScript est requis pour faire fonctionner %s. <br />Désolé pour cet inconvénient.",
"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":
@@ -137,12 +137,12 @@
"Cloned: '%s'": "Cloner '%s'",
"The cloned file '%s' was attached to this paste.": "Le fichier cloné '%s' a été attaché à ce paste.",
"Attach a file": "Attacher un fichier ",
"alternatively drag & drop a file or paste an image from the clipboard": "alternativement, glisser & déposer un fichier ou coller une image à partir du presse-papiers",
"alternatively drag & drop a file or paste an image from the clipboard": "au choix, glisser & déposer un fichier ou coller une image à partir du presse-papiers",
"File too large, to display a preview. Please download the attachment.": "Fichier trop volumineux, pour afficher un aperçu. Veuillez télécharger la pièce jointe.",
"Remove attachment": "Enlever l'attachement",
"Remove attachment": "Enlever la pièce jointe",
"Your browser does not support uploading encrypted files. Please use a newer browser.":
"Votre navigateur ne supporte pas l'envoi de fichiers chiffrés. Merci d'utiliser un navigateur plus récent.",
"Invalid attachment.": "Attachement invalide.",
"Invalid attachment.": "Pièce jointe invalide.",
"Options": "Options",
"Shorten URL": "Raccourcir URL",
"Editor": "Éditer",
@@ -158,7 +158,7 @@
"Preparing new paste…": "Préparation du paste…",
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.":
"Si ce message ne disparaîssait pas, jetez un oeil à <a href=\"%s\">cette FAQ pour des idées de résolution</a> (en Anglais).",
"+++ no paste text +++": "+++ pas de paste-text +++",
"+++ no paste text +++": "+++ pas de texte copié +++",
"Could not get paste data: %s":
"Impossible d'obtenir les données du paste: %s",
"QR code": "QR code",
@@ -169,5 +169,29 @@
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Votre navigateur peut nécessiter une connexion HTTPS pour prendre en charge lAPI WebCrypto. Essayez <a href=\"%s\">de passer en HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
"Votre navigateur ne prend pas en charge WebAssembly, utilisé pour la compression zlib. Vous pouvez créer des documents non compressés, mais vous ne pouvez pas lire les documents compressés.",
"waiting on user to provide a password":
"en attendant que l'utilisateur fournisse un mot de passe",
"Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.":
"Impossible de décrypter les données. Vous avez saisi un mot de passe incorrect ? Réessayez avec le bouton en haut.",
"Retry":
"Réessayer",
"Showing raw text…":
"Affichage du texte brut…",
"Notice:":
"Avertissement:",
"This link will expire after %s.":
"Ce lien expire après le %s.",
"This link can only be accessed once, do not use back or refresh button in your browser.":
"Vous ne pouvez accéder à ce lien qu'une seule fois, n'utilisez pas le bouton précédent ou rafraîchir de votre navigateur.",
"Link:":
"Lien:",
"Recipient may become aware of your timezone, convert time to UTC?":
"Le destinataire peut connaître votre fuseau horaire, convertir l'heure au format UTC?",
"Use Current Timezone":
"Conserver l'actuel",
"Convert To UTC":
"Convertir en UTC",
"Close":
"Fermer"
}

View File

@@ -31,7 +31,7 @@
"Hibás törlési azonosító. A bejegyzés nem lett törölve.",
"Paste was properly deleted.":
"A bejegyzés sikeresen törölve.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"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.",
@@ -160,5 +160,29 @@
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.",
"waiting on user to provide a password":
"waiting on user to provide a password",
"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":
"Retry",
"Showing raw text…":
"Showing raw text…",
"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:",
"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",
"Close":
"Close"
}

View File

@@ -31,8 +31,8 @@
"Codice cancellazione errato. Il messaggio NON è stato cancellato.",
"Paste was properly deleted.":
"Il messaggio è stato correttamente cancellato.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"%s funziona solo con JavaScript attivo.<br />Ci dispiace per l'inconveniente.",
"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":
@@ -160,5 +160,29 @@
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.",
"waiting on user to provide a password":
"waiting on user to provide a password",
"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":
"Retry",
"Showing raw text…":
"Showing raw text…",
"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:",
"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",
"Close":
"Close"
}

View File

@@ -31,8 +31,8 @@
"Foutieve verwijdercode. Geplakte tekst is niet verwijderd.",
"Paste was properly deleted.":
"Geplakte tekst is correct verwijderd.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"JavaScript vereist om %s te laten werken.<br />Sorry voor het ongemak.",
"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":
@@ -160,5 +160,29 @@
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.",
"waiting on user to provide a password":
"waiting on user to provide a password",
"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":
"Retry",
"Showing raw text…":
"Showing raw text…",
"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:",
"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",
"Close":
"Close"
}

View File

@@ -31,8 +31,8 @@
"Feil slettingsnøkkel. Innlegg ble ikke fjernet.",
"Paste was properly deleted.":
"Innlegget er slettet.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"Javascript kreves for at %s skal fungere<br />Beklager.",
"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":
@@ -160,5 +160,29 @@
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Din nettleser har behov for HTTPS tilkobling for å støtte WebCrypto biblioteket. Prøv å <a href=\"%s\">bytt til HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.",
"waiting on user to provide a password":
"waiting on user to provide a password",
"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":
"Retry",
"Showing raw text…":
"Showing raw text…",
"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:",
"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",
"Close":
"Close"
}

View File

@@ -31,8 +31,8 @@
"Geton de supression incorrècte. Lo tèxte es pas estat suprimit.",
"Paste was properly deleted.":
"Lo tèxte es estat corrèctament suprimit.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"JavaScript es requesit per far foncionar %s. <br />O planhèm per linconvenient.",
"JavaScript is required for %s to work. Sorry for the inconvenience.":
"JavaScript es requesit per far foncionar %s. O planhèm per linconvenient.",
"%s requires a modern browser to work.":
"%s necessita un navigator modèrn per foncionar.",
"New":
@@ -169,5 +169,29 @@
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Se pòt que vòstre navigator faga besonh duna connexion HTTPS per èsser compatible amb lAPI WebCrypto. Ensajatz de <a href=\"%s\">passar al HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
"Vòstre navigator es pas compatible amb WebAssembly, utilizat per la compression zlib. Podètz crear de documents pas compressat, mas ne podètz pas legir de compressats.",
"waiting on user to provide a password":
"en espèra que lutilizaire fornisca un senhal",
"Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.":
"Deschiframent de las donadas impossible. Avètz picat un marrit senhal? Tornatz ensajar amb lo boton ennaut.",
"Retry":
"Tornar ensajar",
"Showing raw text…":
"Afichatge del tèxte brut…",
"Notice:":
"Avertiment:",
"This link will expire after %s.":
"Aqueste ligam expirarà aprèp %s.",
"This link can only be accessed once, do not use back or refresh button in your browser.":
"Òm pòt pas quaccedir a aqueste ligam quun còp, utilizetz pas lo boton precedent o actualizar del navigator.",
"Link:":
"Ligam:",
"Recipient may become aware of your timezone, convert time to UTC?":
"Lo destinatari pòt savisar de vòstre fus orari, convertir en UTC?",
"Use Current Timezone":
"Utilizar lactual",
"Convert To UTC":
"Convertir en UTC",
"Close":
"Tampar"
}

View File

@@ -31,7 +31,7 @@
"Nieprawidłowy token usuwania. Wklejka nie została usunięta.",
"Paste was properly deleted.":
"Wklejka usunięta poprawnie.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"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.",
@@ -160,5 +160,29 @@
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.",
"waiting on user to provide a password":
"waiting on user to provide a password",
"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":
"Retry",
"Showing raw text…":
"Showing raw text…",
"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:",
"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",
"Close":
"Close"
}

View File

@@ -31,8 +31,8 @@
"Token de remoção inválido. A cópia não foi excluída.",
"Paste was properly deleted.":
"A cópia foi devidamente excluída.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"JavaScript é necessário para que %s funcione.<br />Pedimos desculpas pela inconveniência.",
"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":
@@ -151,14 +151,38 @@
"Caso essa mensagem nunca desapareça, por favor veja <a href=\"%s\">este FAQ para saber como resolver os problemas</a>.",
"+++ no paste text +++": "+++ sem texto de cópia +++",
"Could not get paste data: %s":
"Could not get paste data: %s",
"QR code": "QR code",
"Não foi possível obter dados de cópia: %s",
"QR code": "Código QR",
"This website is using an insecure HTTP connection! Please use it only for testing.":
"This website is using an insecure HTTP connection! Please use it only for testing.",
"Esse site usa uma conexão HTTP insegura! Use-o apenas para testes.",
"For more information <a href=\"%s\">see this FAQ entry</a>.":
"For more information <a href=\"%s\">see this FAQ entry</a>.",
"Para mais informações <a href=\"%s\">veja esse item do FAQ</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
"Seu navegador pode exigir uma conexão HTTPS para dar suporte à API WebCrypto. Tente <a href=\"%s\">mudar para HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
"Seu navagador não suporta WebAssembly, usado para compressão zlib. Você pode criar documentos não compactados, mas não pode lê-los.",
"waiting on user to provide a password":
"esperando que o usuário digite uma senha",
"Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.":
"Não foi possível decifrar os dados. Você digitou a senha corretamente? Tente novamente com o botão ao topo.",
"Retry":
"Tentar Novamente",
"Showing raw text…":
"Mostrando texto bruto…",
"Notice:":
"Aviso:",
"This link will expire after %s.":
"Esse link vai expirar após %s.",
"This link can only be accessed once, do not use back or refresh button in your browser.":
"Esse link só pode ser acessado uma vez, não utilize o botão de voltar ou atualizar do seu navegador.",
"Link:":
"Link:",
"Recipient may become aware of your timezone, convert time to UTC?":
"O recipiente pode ter ciência de seu fuso horário, converter hora para UTC?",
"Use Current Timezone":
"Usar Fuso Horário Atual",
"Convert To UTC":
"Converter para UTC",
"Close":
"Fechar"
}

View File

@@ -31,8 +31,8 @@
"Неверный ключ удаления записи. Запись не удалена.",
"Paste was properly deleted.":
"Запись была успешно удалена.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"Для работы %s требуется включенный JavaScript.<br />Приносим извинения за неудобства.",
"JavaScript is required for %s to work. Sorry for the inconvenience.":
"Для работы %s требуется включенный JavaScript. Приносим извинения за неудобства.",
"%s requires a modern browser to work.":
"Для работы %s требуется более современный браузер.",
"New":
@@ -170,5 +170,29 @@
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Ваш браузер требует использования HTTPS подключения для поддержки WebCrypto API. Попробуйте <a href=\"%s\">переключиться на HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.",
"waiting on user to provide a password":
"waiting on user to provide a password",
"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":
"Retry",
"Showing raw text…":
"Showing raw text…",
"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:",
"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",
"Close":
"Close"
}

View File

@@ -1,7 +1,7 @@
{
"PrivateBin": "PrivateBin",
"%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted <i>in the browser</i> using 256 bits AES. More information on the <a href=\"https://privatebin.info/\">project page</a>.":
"%s je minimalističen, odprtokodni spletni 'pastebin', kjer server ne ve ničesar o prilepljenih podatkih. Podatki so zakodirani/odkodirani <i>v brskalniku</i> z uporabo 256 bitnega AES. Več informacij na < href=\"https://privatebin.info/\">spletni strani projekta.</a>.",
"%s je minimalističen, odprtokodni spletni 'pastebin', kjer server ne ve ničesar o prilepljenih podatkih. Podatki so zakodirani/odkodirani <i>v brskalniku</i> z uporabo 256 bitnega AES. Več informacij na <a href=\"https://privatebin.info/\">spletni strani projekta.</a>.",
"Because ignorance is bliss":
"Ker kar ne veš ne boli.",
"en": "sl",
@@ -31,8 +31,8 @@
"Napačen token za izbris. Prilepek ni bil izbrisan..",
"Paste was properly deleted.":
"Prilepek je uspešno izbrisan.",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"Da %s deluje, moraš vklopiti JavaScript.<br />Oprosti za povročene nevšečnosti.",
"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":
@@ -169,5 +169,29 @@
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.",
"waiting on user to provide a password":
"waiting on user to provide a password",
"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":
"Retry",
"Showing raw text…":
"Showing raw text…",
"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:",
"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",
"Close":
"Close"
}

198
i18n/uk.json Normal file
View File

@@ -0,0 +1,198 @@
{
"PrivateBin": "PrivateBin",
"%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted <i>in the browser</i> using 256 bits AES. More information on the <a href=\"https://privatebin.info/\">project page</a>.":
"%s це мінімалістичний Open Source проєкт для створення нотаток, де сервер не знає нічого про дані, що зберігаються. Дані шифруються/розшифровуються <i>у переглядачі</i> з використанням 256-бітного шифрувания AES. Подробиці можна дізнатися на <a href=\"https://privatebin.info/\">сайті проєкту</a>.",
"Because ignorance is bliss":
"Бо незнання - благо",
"en": "uk",
"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] в конфігураційному файлі.",
"Please wait %d seconds between each post.":
["Будь ласка, зачекайте %d секунду між дописами.", "Будь ласка, зачекайте %d секунди між дописами.", "Будь ласка, зачекайте %d секунд між дописами."],
"Paste is limited to %s of encrypted data.":
"Розмір допису обмежений %s зашифрованих даних.",
"Invalid data.":
"Неправильні дані.",
"You are unlucky. Try again.":
"Вам не пощастило. Спробуйте ще раз.",
"Error saving comment. Sorry.":
"Помилка при збереженні коментаря. Вибачте.",
"Error saving paste. Sorry.":
"Помилка при збереженні допису. Вибачте.",
"Invalid paste ID.":
"Неправильний ID допису.",
"Paste is not of burn-after-reading type.":
"Тип допису не \"Знищити після прочитання\".",
"Wrong deletion token. Paste was not deleted.":
"Неправильний ключ вилучення допису. Допис не вилучено.",
"Paste was properly deleted.":
"Допис був вилучений повністю.",
"JavaScript is required for %s to work. Sorry for the inconvenience.":
"Для роботи %s потрібен увімкнутий JavaScript. Вибачте.",
"%s requires a modern browser to work.":
"Для роботи %s потрібен більш сучасний переглядач.",
"New":
"Новий допис",
"Send":
"Відправити",
"Clone":
"Дублювати",
"Raw text":
"Початковий текст",
"Expires":
"Вилучити через",
"Burn after reading":
"Знищити після прочитання",
"Open discussion":
"Відкрити обговорення",
"Password (recommended)":
"Пароль (рекомендується)",
"Discussion":
"Обговорення",
"Toggle navigation":
"Перемкнути навігацію",
"%d seconds": ["%d секунду", "%d секунди", "%d секунд"],
"%d minutes": ["%d хвилину", "%d хвилини", "%d хвилин"],
"%d hours": ["%d годину", "%d години", "%d годин"],
"%d days": ["%d день", "%d дні", "%d днів"],
"%d weeks": ["%d тиждень", "%d тижні", "%d тижнів"],
"%d months": ["%d місяць", "%d місяці", "%d місяців"],
"%d years": ["%d рік", "%d роки", "%d років"],
"Never":
"Ніколи",
"Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.":
"Примітка: Це тестовий сервіс: Дані можуть бути вилучені в будь який момент. Кошенята помруть, якщо ви будете зловживати сервісом.",
"This document will expire in %d seconds.":
["Документ буде вилучений через %d секунду.", "Документ буде вилучений через %d секунди.", "Документ буде вилучений через %d секунд."],
"This document will expire in %d minutes.":
["Документ буде вилучений через %d хвилину.", "Документ буде вилучений через %d хвилини.", "Документ буде вилучений через %d хвилин."],
"This document will expire in %d hours.":
["Документ буде вилучений через %d годину.", "Документ буде вилучений через %d години.", "Документ буде вилучений через %d годин."],
"This document will expire in %d days.":
["Документ буде вилучений через %d день.", "Документ буде вилучений через %d дні.", "Документ буде вилучений через %d днів."],
"This document will expire in %d months.":
["Документ буде вилучений через %d місяць.", "Документ буде вилучений через %d місяці.", "Документ буде вилучений через %d місяців."],
"Please enter the password for this paste:":
"Будь ласка, введіть пароль від допису:",
"Could not decrypt data (Wrong key?)":
"Неможливо розшифрувати дані (Неправильний ключ?)",
"Could not delete the paste, it was not stored in burn after reading mode.":
"Неможливо вилучити допис, він не був збережений в режимі знищити після прочитання.",
"FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.":
"ЛИШЕ ДЛЯ ВАШИХ ОЧЕЙ. Не закривайте це вікно, це повідомлення не може бути показано знову.",
"Could not decrypt comment; Wrong key?":
"Неможливо розшифрувати коментар; Неправильний ключ?",
"Reply":
"Відповісти",
"Anonymous":
"Анонім",
"Avatar generated from IP address":
"Аватар зґенерований з IP-адреси",
"Add comment":
"Додати коментар",
"Optional nickname…":
"Необов’язкове прізвисько…",
"Post comment":
"Відправити коментар",
"Sending comment…":
"Відправка коментаря…",
"Comment posted.":
"Коментар опублікований.",
"Could not refresh display: %s":
"Не вдалося оновити екран: %s",
"unknown status":
"невідома причина",
"server error or not responding":
"помилка на сервері чи немає відповіді",
"Could not post comment: %s":
"Не вдалося опублікувати коментар: %s",
"Sending paste…":
"Відправка допису…",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>":
"Посилання на допис <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Тисніть [Ctrl]+[c], щоб скопіювати посилання)</span>",
"Delete data":
"Видалити допис",
"Could not create paste: %s":
"Не вдалося опублікувати допис: %s",
"Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)":
"Неможливо розшифрувати запис: Ключ дешифрування відсутній в посиланні (Можливо, ви використовуєте скорочувач посилань, що видаляє частину посилання?)",
"B": "байт",
"KiB": "Кбайт",
"MiB": "Мбайт",
"GiB": "Гбайт",
"TiB": "Тбайт",
"PiB": "Пбайт",
"EiB": "Ебайт",
"ZiB": "Збайт",
"YiB": "Йбайт",
"Format": "Формат",
"Plain Text": "Звичайний текст",
"Source Code": "Джерельний код",
"Markdown": "Мова розмітки",
"Download attachment": "Звантажити прикріплений файл",
"Cloned: '%s'": "Дубльовано: '%s'",
"The cloned file '%s' was attached to this paste.":
"Дублікат файлу '%s' був прикріплений до цього запису.",
"Attach a file": "Прикріпити файл",
"alternatively drag & drop a file or paste an image from the clipboard": "також можна перенести файл у вікно переглядача чи вставити зображення з буфера",
"File too large, to display a preview. Please download the attachment.": "Файл завеликий для відображення передогляду. Будь ласка, звантажте прикріплений файл.",
"Remove attachment": "Видалити вкладення",
"Your browser does not support uploading encrypted files. Please use a newer browser.":
"Ваш переглядач не підтримує відправлення зашифрованих файлів. Використовуйте сучасніший переглядач.",
"Invalid attachment.": "Невідоме вкладення.",
"Options": "Опції",
"Shorten URL": "Коротке посилання",
"Editor": "Редактор",
"Preview": "Передогляд",
"%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.":
"Змінна PATH необхідна %s в конці \"%s\". Будь ласка, оновіть змінну PATH у вашому index.php.",
"Decrypt":
"Розшифрувати",
"Enter password":
"Введіть пароль",
"Loading…": "Завантаження…",
"Decrypting paste…": "Розшифровування допису…",
"Preparing new paste…": "Приготування нового допису…",
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.":
"Якщо це повідомлення не зникатиме тривалий час, подивіться <a href=\"%s\">цей FAQ з інформацією про можливе вирішення проблеми</a>.",
"+++ no paste text +++": "+++ у дописі немає тексту +++",
"Could not get paste data: %s":
"Не вдалося отримати дані допису: %s",
"QR code": "QR код",
"This website is using an insecure HTTP connection! Please use it only for testing.":
"Цей сайт використовує незахищене HTTP підключення! Будь ласка, використовуйте його лише для тестування.",
"For more information <a href=\"%s\">see this FAQ entry</a>.":
"Для подробиць <a href=\"%s\">дивіться інформацію в FAQ</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Ваш переглядач вимагає підключення HTTPS для підтримки WebCrypto API. Спробуйте <a href=\"%s\">перемкнутися на HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Ваш переглядач не підтримує WebAssembly, що використовується для стиснення zlib. Ви можете створювати нестиснені документи, але не зможете читати стиснені.",
"waiting on user to provide a password":
"waiting on user to provide a password",
"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":
"Retry",
"Showing raw text…":
"Showing raw text…",
"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:",
"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",
"Close":
"Close"
}

View File

@@ -31,8 +31,8 @@
"错误的删除token粘贴内容没有被删除。",
"Paste was properly deleted.":
"粘贴内容已被正确删除。",
"JavaScript is required for %s to work.<br />Sorry for the inconvenience.":
"%s需要JavaScript来进行加解密。<br />给你带来的不便敬请谅解。",
"JavaScript is required for %s to work. Sorry for the inconvenience.":
"%s需要JavaScript来进行加解密。 给你带来的不便敬请谅解。",
"%s requires a modern browser to work.":
"%s需要在现代浏览器上工作。",
"New":
@@ -154,11 +154,35 @@
"无法获取粘贴数据:%s",
"QR code": "二维码",
"This website is using an insecure HTTP connection! Please use it only for testing.":
"This website is using an insecure HTTP connection! Please use it only for testing.",
"该网站使用了不安全的HTTP连接 请仅将其用于测试。",
"For more information <a href=\"%s\">see this FAQ entry</a>.":
"For more information <a href=\"%s\">see this FAQ entry</a>.",
"有关更多信息,<a href=\"%s\">请参阅此常见问题解答</a>",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.":
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
"您的浏览器可能需要HTTPS连接才能支持WebCrypto API。 尝试<a href=\"%s\">切换到HTTPS </a>",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.":
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones."
"您的浏览器不支持用于zlib压缩的WebAssembly。 您可以创建未压缩的文档,但不能读取压缩的文档。",
"waiting on user to provide a password":
"请输入密码",
"Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.":
"无法解密数据。 您输入了错误的密码吗? 点顶部的按钮重试。",
"Retry":
"重试",
"Showing raw text…":
"显示原始文字…",
"Notice:":
"注意:",
"This link will expire after %s.":
"这个链接将会在 %s 过期。",
"This link can only be accessed once, do not use back or refresh button in your browser.":
"这个链接只能被访问一次,请勿使用浏览器中的返回和刷新按钮。",
"Link:":
"链接地址:",
"Recipient may become aware of your timezone, convert time to UTC?":
"收件人可能会知道您的时区将时间转换为UTC",
"Use Current Timezone":
"使用当前时区",
"Convert To UTC":
"转换为UTC",
"Close":
"关闭"
}

BIN
img/icon_email.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

View File

@@ -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.3
* @version 1.3.3
*/
// change this, if your php files and data is outside of your webservers document root

View File

@@ -1,151 +0,0 @@
// base-x encoding / decoding
// based on https://github.com/cryptocoinjs/base-x 3.0.5
// modification: removed Buffer dependency and node.modules entry
// Copyright (c) 2018 base-x contributors
// Copyright (c) 2014-2018 The Bitcoin Core developers (base58.cpp)
// Distributed under the MIT software license, see the accompanying
// file LICENSE or http://www.opensource.org/licenses/mit-license.php.
(function(){
'use strict';
this.baseX = function base (ALPHABET) {
if (ALPHABET.length >= 255) throw new TypeError('Alphabet too long')
const BASE_MAP = new Uint8Array(256)
BASE_MAP.fill(255)
for (let i = 0; i < ALPHABET.length; i++) {
const x = ALPHABET.charAt(i)
const xc = x.charCodeAt(0)
if (BASE_MAP[xc] !== 255) throw new TypeError(x + ' is ambiguous')
BASE_MAP[xc] = i
}
const BASE = ALPHABET.length
const LEADER = ALPHABET.charAt(0)
const FACTOR = Math.log(BASE) / Math.log(256) // log(BASE) / log(256), rounded up
const iFACTOR = Math.log(256) / Math.log(BASE) // log(256) / log(BASE), rounded up
function encode (source) {
if (source.length === 0) return ''
// Skip & count leading zeroes.
let zeroes = 0
let length = 0
let pbegin = 0
const pend = source.length
while (pbegin !== pend && source[pbegin] === 0) {
pbegin++
zeroes++
}
// Allocate enough space in big-endian base58 representation.
const size = ((pend - pbegin) * iFACTOR + 1) >>> 0
const b58 = new Uint8Array(size)
// Process the bytes.
while (pbegin !== pend) {
let carry = source[pbegin]
// Apply "b58 = b58 * 256 + ch".
let i = 0
for (let it = size - 1; (carry !== 0 || i < length) && (it !== -1); it--, i++) {
carry += (256 * b58[it]) >>> 0
b58[it] = (carry % BASE) >>> 0
carry = (carry / BASE) >>> 0
}
if (carry !== 0) throw new Error('Non-zero carry')
length = i
pbegin++
}
// Skip leading zeroes in base58 result.
let it = size - length
while (it !== size && b58[it] === 0) {
it++
}
// Translate the result into a string.
let str = LEADER.repeat(zeroes)
for (; it < size; ++it) str += ALPHABET.charAt(b58[it])
return str
}
function decodeUnsafe (source) {
if (typeof source !== 'string') throw new TypeError('Expected String')
if (source.length === 0) return ''
let psz = 0
// Skip leading spaces.
if (source[psz] === ' ') return
// Skip and count leading '1's.
let zeroes = 0
let length = 0
while (source[psz] === LEADER) {
zeroes++
psz++
}
// Allocate enough space in big-endian base256 representation.
const size = (((source.length - psz) * FACTOR) + 1) >>> 0 // log(58) / log(256), rounded up.
const b256 = new Uint8Array(size)
// Process the characters.
while (source[psz]) {
// Decode character
let carry = BASE_MAP[source.charCodeAt(psz)]
// Invalid character
if (carry === 255) return
let i = 0
for (let it = size - 1; (carry !== 0 || i < length) && (it !== -1); it--, i++) {
carry += (BASE * b256[it]) >>> 0
b256[it] = (carry % 256) >>> 0
carry = (carry / 256) >>> 0
}
if (carry !== 0) throw new Error('Non-zero carry')
length = i
psz++
}
// Skip trailing spaces.
if (source[psz] === ' ') return
// Skip leading zeroes in b256.
let it = size - length
while (it !== size && b256[it] === 0) {
it++
}
var vch = [];
let j = zeroes
while (it !== size) {
vch[j++] = b256[it++]
}
return vch
}
function decode (string) {
const buffer = decodeUnsafe(string)
if (buffer) return buffer
throw new Error('Non-base' + BASE + ' character')
}
return {
encode: encode,
decodeUnsafe: decodeUnsafe,
decode: decode
}
}
}).call(this);

120
js/base-x-3.0.7.js Normal file
View File

@@ -0,0 +1,120 @@
'use strict';
// base-x encoding / decoding
// based on https://github.com/cryptocoinjs/base-x 3.0.7
// modification: removed Buffer dependency and node.modules entry
// Copyright (c) 2018 base-x contributors
// Copyright (c) 2014-2018 The Bitcoin Core developers (base58.cpp)
// Distributed under the MIT software license, see the accompanying
// file LICENSE or http://www.opensource.org/licenses/mit-license.php.
(function(){
this.baseX = function base (ALPHABET) {
if (ALPHABET.length >= 255) { throw new TypeError('Alphabet too long') }
var BASE_MAP = new Uint8Array(256)
BASE_MAP.fill(255)
for (var i = 0; i < ALPHABET.length; i++) {
var x = ALPHABET.charAt(i)
var xc = x.charCodeAt(0)
if (BASE_MAP[xc] !== 255) { throw new TypeError(x + ' is ambiguous') }
BASE_MAP[xc] = i
}
var BASE = ALPHABET.length
var LEADER = ALPHABET.charAt(0)
var FACTOR = Math.log(BASE) / Math.log(256) // log(BASE) / log(256), rounded up
var iFACTOR = Math.log(256) / Math.log(BASE) // log(256) / log(BASE), rounded up
function encode (source) {
if (source.length === 0) { return '' }
// Skip & count leading zeroes.
var zeroes = 0
var length = 0
var pbegin = 0
var pend = source.length
while (pbegin !== pend && source[pbegin] === 0) {
pbegin++
zeroes++
}
// Allocate enough space in big-endian base58 representation.
var size = ((pend - pbegin) * iFACTOR + 1) >>> 0
var b58 = new Uint8Array(size)
// Process the bytes.
while (pbegin !== pend) {
var carry = source[pbegin]
// Apply "b58 = b58 * 256 + ch".
var i = 0
for (var it1 = size - 1; (carry !== 0 || i < length) && (it1 !== -1); it1--, i++) {
carry += (256 * b58[it1]) >>> 0
b58[it1] = (carry % BASE) >>> 0
carry = (carry / BASE) >>> 0
}
if (carry !== 0) { throw new Error('Non-zero carry') }
length = i
pbegin++
}
// Skip leading zeroes in base58 result.
var it2 = size - length
while (it2 !== size && b58[it2] === 0) {
it2++
}
// Translate the result into a string.
var str = LEADER.repeat(zeroes)
for (; it2 < size; ++it2) { str += ALPHABET.charAt(b58[it2]) }
return str
}
function decodeUnsafe (source) {
if (typeof source !== 'string') { throw new TypeError('Expected String') }
if (source.length === 0) { return '' }
var psz = 0
// Skip leading spaces.
if (source[psz] === ' ') { return }
// Skip and count leading '1's.
var zeroes = 0
var length = 0
while (source[psz] === LEADER) {
zeroes++
psz++
}
// Allocate enough space in big-endian base256 representation.
var size = (((source.length - psz) * FACTOR) + 1) >>> 0 // log(58) / log(256), rounded up.
var b256 = new Uint8Array(size)
// Process the characters.
while (source[psz]) {
// Decode character
var carry = BASE_MAP[source.charCodeAt(psz)]
// Invalid character
if (carry === 255) { return }
var i = 0
for (var it3 = size - 1; (carry !== 0 || i < length) && (it3 !== -1); it3--, i++) {
carry += (BASE * b256[it3]) >>> 0
b256[it3] = (carry % 256) >>> 0
carry = (carry / 256) >>> 0
}
if (carry !== 0) { throw new Error('Non-zero carry') }
length = i
psz++
}
// Skip trailing spaces.
if (source[psz] === ' ') { return }
// Skip leading zeroes in b256.
var it4 = size - length
while (it4 !== size && b256[it4] === 0) {
it4++
}
var vch = []
var j = zeroes
while (it4 !== size) {
vch[j++] = b256[it4++]
}
return vch
}
function decode (string) {
var buffer = decodeUnsafe(string)
if (buffer) { return buffer }
throw new Error('Non-base' + BASE + ' character')
}
return {
encode: encode,
decodeUnsafe: decodeUnsafe,
decode: decode
}
}
}).call(this);

View File

@@ -17,8 +17,8 @@ require('./prettify');
global.prettyPrint = window.PR.prettyPrint;
global.prettyPrintOne = window.PR.prettyPrintOne;
global.showdown = require('./showdown-1.9.1');
global.DOMPurify = require('./purify-2.0.1');
global.baseX = require('./base-x-3.0.5.1').baseX;
global.DOMPurify = require('./purify-2.0.8');
global.baseX = require('./base-x-3.0.7').baseX;
global.Legacy = require('./legacy').Legacy;
require('./bootstrap-3.3.7');
require('./privatebin');
@@ -36,25 +36,10 @@ var a2zString = ['a','b','c','d','e','f','g','h','i','j','k','l','m',
return c.toUpperCase();
})
),
schemas = ['ftp','gopher','http','https','ws','wss'],
schemas = ['ftp','http','https'],
supportedLanguages = ['de', 'es', 'fr', 'it', 'no', 'pl', 'pt', 'oc', 'ru', 'sl', 'zh'],
mimeTypes = ['image/png', 'application/octet-stream'],
formats = ['plaintext', 'markdown', 'syntaxhighlighting'],
/**
* character to HTML entity lookup table
*
* @see {@link https://github.com/janl/mustache.js/blob/master/mustache.js#L60}
*/
entityMap = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
'/': '&#x2F;',
'`': '&#x60;',
'=': '&#x3D;'
},
mimeFile = fs.createReadStream('/etc/mime.types'),
mimeLine = '';
@@ -97,22 +82,6 @@ function parseMime(line) {
exports.atob = atob;
exports.btoa = btoa;
/**
* convert all applicable characters to HTML entities
*
* @see {@link https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet#RULE_.231_-_HTML_Escape_Before_Inserting_Untrusted_Data_into_HTML_Element_Content}
* @name htmlEntities
* @function
* @param {string} str
* @return {string} escaped HTML
*/
exports.htmlEntities = function(str) {
return String(str).replace(
/[&<>"'`=\/]/g, function(s) {
return entityMap[s];
});
};
// provides random lowercase characters from a to z
exports.jscA2zString = function() {
return jsc.elements(a2zString);

View File

@@ -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.3.1
* @version 1.3.3
* @name PrivateBin
* @namespace
*/
@@ -189,6 +189,26 @@ jQuery.PrivateBin = (function($, RawDeflate) {
const Helper = (function () {
const me = {};
/**
* character to HTML entity lookup table
*
* @see {@link https://github.com/janl/mustache.js/blob/master/mustache.js#L60}
* @name Helper.entityMap
* @private
* @enum {Object}
* @readonly
*/
const entityMap = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
'/': '&#x2F;',
'`': '&#x60;',
'=': '&#x3D;'
};
/**
* cache for script location
*
@@ -302,19 +322,12 @@ jQuery.PrivateBin = (function($, RawDeflate) {
let format = args[0],
i = 1;
return format.replace(/%(s|d)/g, function (m) {
// m is the matched format, e.g. %s, %d
let val = args[i];
// A switch statement so that the formatter can be extended.
switch (m)
{
case '%d':
val = parseFloat(val);
if (isNaN(val)) {
val = 0;
}
break;
default:
// Default is %s
if (m === '%d') {
val = parseFloat(val);
if (isNaN(val)) {
val = 0;
}
}
++i;
return val;
@@ -392,6 +405,62 @@ jQuery.PrivateBin = (function($, RawDeflate) {
return new Comment(data);
};
/**
* convert all applicable characters to HTML entities
*
* @see {@link https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html}
* @name Helper.htmlEntities
* @function
* @param {string} str
* @return {string} escaped HTML
*/
me.htmlEntities = function(str) {
return String(str).replace(
/[&<>"'`=\/]/g, function(s) {
return entityMap[s];
}
);
}
/**
* calculate expiration date given initial date and expiration period
*
* @name Helper.calculateExpirationDate
* @function
* @param {Date} initialDate - may not be empty
* @param {string|number} expirationDisplayStringOrSecondsToExpire - may not be empty
* @return {Date}
*/
me.calculateExpirationDate = function(initialDate, expirationDisplayStringOrSecondsToExpire) {
let expirationDate = new Date(initialDate);
const expirationDisplayStringToSecondsDict = {
'5min': 300,
'10min': 600,
'1hour': 3500,
'1day': 86400,
'1week': 604800,
'1month': 2592000,
'1year': 31536000,
'never': 0
};
let secondsToExpiration = expirationDisplayStringOrSecondsToExpire;
if (typeof expirationDisplayStringOrSecondsToExpire === 'string') {
secondsToExpiration = expirationDisplayStringToSecondsDict[expirationDisplayStringOrSecondsToExpire];
}
if (typeof secondsToExpiration !== 'number') {
throw new Error('Cannot calculate expiration date.');
}
if (secondsToExpiration === 0) {
return null;
}
expirationDate = expirationDate.setUTCSeconds(expirationDate.getUTCSeconds() + secondsToExpiration);
return expirationDate;
};
/**
* resets state, used for unit testing
*
@@ -433,7 +502,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
* @prop {string[]}
* @readonly
*/
const supportedLanguages = ['bg', 'cs', 'de', 'es', 'fr', 'it', 'hu', 'no', 'nl', 'pl', 'pt', 'oc', 'ru', 'sl', 'zh'];
const supportedLanguages = ['bg', 'cs', 'de', 'es', 'fr', 'it', 'hu', 'no', 'nl', 'pl', 'pt', 'oc', 'ru', 'sl', 'uk', 'zh'];
/**
* built in language
@@ -473,10 +542,14 @@ jQuery.PrivateBin = (function($, RawDeflate) {
*
* Optionally pass a jQuery element as the first parameter, to automatically
* let the text of this element be replaced. In case the (asynchronously
* loaded) language is not downloadet yet, this will make sure the string
* is replaced when it is actually loaded.
* So for easy translations passing the jQuery object to apply it to is
* more save, especially when they are loaded in the beginning.
* loaded) language is not downloaded yet, this will make sure the string
* is replaced when it eventually gets loaded. Using this is both simpler
* and more secure, as it avoids potential XSS when inserting text.
* The next parameter is the message ID, matching the ones found in
* the translation files under the i18n directory.
* Any additional parameters will get inserted into the message ID in
* place of %s (strings) or %d (digits), applying the appropriate plural
* in case of digits. See also Helper.sprintf().
*
* @name I18n.translate
* @function
@@ -553,17 +626,40 @@ jQuery.PrivateBin = (function($, RawDeflate) {
args[0] = translations[messageId];
}
// messageID may contain links, but should be from a trusted source (code or translation JSON files)
let containsLinks = args[0].indexOf('<a') !== -1;
// prevent double encoding, when we insert into a text node
if (containsLinks || $element === null) {
for (let i = 0; i < args.length; ++i) {
// parameters (i > 0) may never contain HTML as they may come from untrusted parties
if ((containsLinks ? i > 1 : i > 0) || !containsLinks) {
args[i] = Helper.htmlEntities(args[i]);
}
}
}
// format string
let output = Helper.sprintf.apply(this, args);
// if $element is given, apply text to element
if (containsLinks) {
// only allow tags/attributes we actually use in translations
output = DOMPurify.sanitize(
output, {
ALLOWED_TAGS: ['a', 'i', 'span'],
ALLOWED_ATTR: ['href', 'id']
}
);
}
// if $element is given, insert translation
if ($element !== null) {
// avoid HTML entity encoding if translation contains link
if (output.indexOf('<a') === -1) {
$element.text(output);
} else {
if (containsLinks) {
$element.html(output);
} else {
// text node takes care of entity encoding
$element.text(output);
}
return '';
}
return output;
@@ -590,6 +686,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
case 'pl':
return n === 1 ? 0 : (n % 10 >= 2 && n %10 <=4 && (n % 100 < 10 || 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);
case 'sl':
return n % 100 === 1 ? 1 : (n % 100 === 2 ? 2 : (n % 100 === 3 || n % 100 === 4 ? 3 : 0));
@@ -1795,11 +1892,10 @@ jQuery.PrivateBin = (function($, RawDeflate) {
return a.length - b.length;
})[0];
if (typeof shortUrl === 'string' && shortUrl.length > 0) {
$('#pastelink').html(
I18n._(
'Your paste is <a id="pasteurl" href="%s">%s</a> <span id="copyhint">(Hit [Ctrl]+[c] to copy)</span>',
shortUrl, shortUrl
)
I18n._(
$('#pastelink'),
'Your paste is <a id="pasteurl" href="%s">%s</a> <span id="copyhint">(Hit [Ctrl]+[c] to copy)</span>',
shortUrl, shortUrl
);
// we disable the button to avoid calling shortener again
$shortenButton.addClass('buttondisabled');
@@ -1822,7 +1918,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
`${$shortenButton.data('shortener')}${encodeURIComponent($pasteUrl.attr('href'))}`,
'_blank',
'noopener, noreferrer'
)
);
});
}
@@ -1854,11 +1950,10 @@ jQuery.PrivateBin = (function($, RawDeflate) {
*/
me.createPasteNotification = function(url, deleteUrl)
{
$('#pastelink').html(
I18n._(
'Your paste is <a id="pasteurl" href="%s">%s</a> <span id="copyhint">(Hit [Ctrl]+[c] to copy)</span>',
url, url
)
I18n._(
$('#pastelink'),
'Your paste is <a id="pasteurl" href="%s">%s</a> <span id="copyhint">(Hit [Ctrl]+[c] to copy)</span>',
url, url
);
// save newly created element
$pasteUrl = $('#pasteurl');
@@ -1866,7 +1961,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
$pasteUrl.click(pasteLinkClick);
// delete link
$('#deletelink').html('<a href="' + deleteUrl + '">' + I18n._('Delete data') + '</a>');
$('#deletelink').html('<a href="' + deleteUrl + '"></a>');
I18n._($('#deletelink a').first(), 'Delete data');
// enable shortener button
$shortenButton.removeClass('buttondisabled');
@@ -2124,6 +2220,9 @@ jQuery.PrivateBin = (function($, RawDeflate) {
$messageEdit.addClass('active');
$messagePreview.removeClass('active');
$('#messageedit').attr('aria-selected','true');
$('#messagepreview').attr('aria-selected','false');
PasteViewer.hide();
// reshow input
@@ -2153,6 +2252,9 @@ jQuery.PrivateBin = (function($, RawDeflate) {
$messageEdit.removeClass('active');
$messagePreview.addClass('active');
$('#messageedit').attr('aria-selected','false');
$('#messagepreview').attr('aria-selected','true');
// hide input as now preview is shown
$message.addClass('hidden');
@@ -2321,10 +2423,13 @@ jQuery.PrivateBin = (function($, RawDeflate) {
}
// escape HTML entities, link URLs, sanitize
const escapedLinkedText = Helper.urls2links(
$('<div />').text(text).html()
),
sanitizedLinkedText = DOMPurify.sanitize(escapedLinkedText);
const escapedLinkedText = Helper.urls2links(text),
sanitizedLinkedText = DOMPurify.sanitize(
escapedLinkedText, {
ALLOWED_TAGS: ['a'],
ALLOWED_ATTR: ['href', 'rel']
}
);
$plainText.html(sanitizedLinkedText);
$prettyPrint.html(sanitizedLinkedText);
@@ -2755,7 +2860,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
// move elemement to new place
$attachmentLink.appendTo($element);
// update text
// update text - ensuring no HTML is inserted into the text node
I18n._($attachmentLink, label, $attachmentLink.attr('download'));
};
@@ -3007,8 +3112,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
$attachment = $('#attachment');
$dragAndDropFileName = $('#dragAndDropFileName');
$dropzone = $('#dropzone');
$attachmentLink = $('#attachment a') || $('<a>');
if($attachment.length) {
$attachmentLink = $('#attachment a');
$attachmentPreview = $('#attachmentPreview');
$fileInput = $('#file');
@@ -3138,7 +3243,10 @@ jQuery.PrivateBin = (function($, RawDeflate) {
// set & parse text
$commentEntryData.html(
DOMPurify.sanitize(
Helper.urls2links(commentText)
Helper.urls2links(commentText), {
ALLOWED_TAGS: ['a'],
ALLOWED_ATTR: ['href', 'rel']
}
)
);
@@ -3332,9 +3440,10 @@ jQuery.PrivateBin = (function($, RawDeflate) {
$passwordInput,
$rawTextButton,
$qrCodeLink,
$emailLink,
$sendButton,
$retryButton,
pasteExpiration = '1week',
pasteExpiration = null,
retryButtonCallback;
/**
@@ -3453,7 +3562,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
for (let i = 0; i < $head.length; ++i) {
newDoc.write($head[i].outerHTML);
}
newDoc.write('</head><body><pre>' + DOMPurify.sanitize($('<div />').text(paste).html()) + '</pre></body></html>');
newDoc.write('</head><body><pre>' + DOMPurify.sanitize(Helper.htmlEntities(paste)) + '</pre></body></html>');
newDoc.close();
}
@@ -3542,6 +3651,130 @@ jQuery.PrivateBin = (function($, RawDeflate) {
$('#qrcode-display').html(qrCanvas);
}
/**
* Template Email body.
*
* @name TopNav.templateEmailBody
* @private
* @param {string} expirationDateString
* @param {bool} isBurnafterreading
*/
function templateEmailBody(expirationDateString, isBurnafterreading)
{
const EOL = '\n';
const BULLET = ' - ';
let emailBody = '';
if (expirationDateString !== null || isBurnafterreading) {
emailBody += I18n._('Notice:');
emailBody += EOL;
if (expirationDateString !== null) {
emailBody += EOL;
emailBody += BULLET;
emailBody += I18n._(
'This link will expire after %s.',
expirationDateString
);
}
if (isBurnafterreading) {
emailBody += EOL;
emailBody += BULLET;
emailBody += I18n._(
'This link can only be accessed once, do not use back or refresh button in your browser.'
);
}
emailBody += EOL;
emailBody += EOL;
}
emailBody += I18n._('Link:');
emailBody += EOL;
emailBody += `${window.location.href}`;
return emailBody;
}
/**
* Trigger Email send.
*
* @name TopNav.triggerEmailSend
* @private
* @param {string} emailBody
*/
function triggerEmailSend(emailBody)
{
window.open(
`mailto:?body=${encodeURIComponent(emailBody)}`,
'_self',
'noopener, noreferrer'
);
}
/**
* Send Email with current paste (URL).
*
* @name TopNav.sendEmail
* @private
* @function
* @param {Date|null} expirationDate date of expiration
* @param {bool} isBurnafterreading whether it is burn after reading
*/
function sendEmail(expirationDate, isBurnafterreading)
{
const expirationDateRoundedToSecond = new Date(expirationDate);
// round down at least 30 seconds to make up for the delay of request
expirationDateRoundedToSecond.setUTCSeconds(
expirationDateRoundedToSecond.getUTCSeconds() - 30
);
expirationDateRoundedToSecond.setUTCSeconds(0);
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');
$emailconfirmTimezoneCurrent.on('click.sendEmailCurrentTimezone', () => {
const emailBody = templateEmailBody(expirationDateRoundedToSecond.toLocaleString(), isBurnafterreading);
$emailconfirmmodal.modal('hide');
triggerEmailSend(emailBody);
});
$emailconfirmTimezoneUtc.off('click.sendEmailUtcTimezone');
$emailconfirmTimezoneUtc.on('click.sendEmailUtcTimezone', () => {
const emailBody = templateEmailBody(expirationDateRoundedToSecond.toLocaleString(
undefined,
// we don't use Date.prototype.toUTCString() because we would like to avoid GMT
{ timeZone: 'UTC', dateStyle: 'long', timeStyle: 'long' }
), isBurnafterreading);
$emailconfirmmodal.modal('hide');
triggerEmailSend(emailBody);
});
$emailconfirmmodal.modal('show');
} else {
triggerEmailSend(templateEmailBody(null, isBurnafterreading));
}
} else {
let emailBody = '';
if (expirationDate !== null) {
const expirationDateString = window.confirm(
I18n._('Recipient may become aware of your timezone, convert time to UTC?')
) ? expirationDateRoundedToSecond.toLocaleString(
undefined,
// we don't use Date.prototype.toUTCString() because we would like to avoid GMT
{ timeZone: 'UTC', dateStyle: 'long', timeStyle: 'long' }
) : expirationDateRoundedToSecond.toLocaleString();
emailBody = templateEmailBody(expirationDateString, isBurnafterreading);
} else {
emailBody = templateEmailBody(null, isBurnafterreading);
}
triggerEmailSend(emailBody);
}
}
/**
* Shows all navigation elements for viewing an existing paste
*
@@ -3578,6 +3811,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
$newButton.addClass('hidden');
$rawTextButton.addClass('hidden');
$qrCodeLink.addClass('hidden');
me.hideEmailButton();
viewButtonsDisplayed = false;
};
@@ -3675,6 +3909,46 @@ jQuery.PrivateBin = (function($, RawDeflate) {
$retryButton.addClass('hidden');
}
/**
* show the "email" button
*
* @name TopNav.showEmailbutton
* @function
* @param {int|undefined} optionalRemainingTimeInSeconds
*/
me.showEmailButton = function(optionalRemainingTimeInSeconds)
{
try {
// we cache expiration date in closure to avoid inaccurate expiration datetime
const expirationDate = Helper.calculateExpirationDate(
new Date(),
typeof optionalRemainingTimeInSeconds === 'number' ? optionalRemainingTimeInSeconds : TopNav.getExpiration()
);
const isBurnafterreading = TopNav.getBurnAfterReading();
$emailLink.removeClass('hidden');
$emailLink.off('click.sendEmail');
$emailLink.on('click.sendEmail', () => {
sendEmail(expirationDate, isBurnafterreading);
});
} catch (error) {
console.error(error);
Alert.showError('Cannot calculate expiration date.');
}
}
/**
* hide the "email" button
*
* @name TopNav.hideEmailButton
* @function
*/
me.hideEmailButton = function()
{
$emailLink.addClass('hidden');
$emailLink.off('click.sendEmail');
}
/**
* only hides the clone button
*
@@ -3697,6 +3971,30 @@ jQuery.PrivateBin = (function($, RawDeflate) {
$rawTextButton.addClass('hidden');
};
/**
* only hides the qr code button
*
* @name TopNav.hideQrCodeButton
* @function
*/
me.hideQrCodeButton = function()
{
$qrCodeLink.addClass('hidden');
}
/**
* hide all irrelevant buttons when viewing burn after reading paste
*
* @name TopNav.hideBurnAfterReadingButtons
* @function
*/
me.hideBurnAfterReadingButtons = function()
{
me.hideCloneButton();
me.hideQrCodeButton();
me.hideEmailButton();
}
/**
* hides the file selector in attachment
*
@@ -3784,7 +4082,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
/**
* returns the state of the burn after reading checkbox
*
* @name TopNav.getExpiration
* @name TopNav.getBurnAfterReading
* @function
* @return {bool}
*/
@@ -3814,7 +4112,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
*/
me.getPassword = function()
{
return $passwordInput.val();
// when password is disabled $passwordInput.val() will return undefined
return $passwordInput.val() || '';
};
/**
@@ -3913,6 +4212,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
$retryButton = $('#retrybutton');
$sendButton = $('#sendbutton');
$qrCodeLink = $('#qrcodelink');
$emailLink = $('#emaillink');
// bootstrap template drop down
$('#language ul.dropdown-menu li a').click(setLanguage);
@@ -4257,6 +4557,10 @@ jQuery.PrivateBin = (function($, RawDeflate) {
history.pushState({type: 'newpaste'}, document.title, url);
TopNav.showViewButtons();
// this cannot be grouped with showViewButtons due to remaining time calculation
TopNav.showEmailButton();
TopNav.hideRawButton();
Editor.hide();
@@ -4648,7 +4952,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
plaintexts[i][1]
);
}
DiscussionViewer.finishDiscussion();
});
}
@@ -4697,8 +5000,17 @@ jQuery.PrivateBin = (function($, RawDeflate) {
// discourage cloning (it cannot really be prevented)
if (paste.isBurnAfterReadingEnabled()) {
TopNav.hideCloneButton();
TopNav.hideBurnAfterReadingButtons();
} else {
// we have to pass in remaining_time here
TopNav.showEmailButton(paste.getTimeToLive());
}
// only offer adding comments, after paste was successfully decrypted
if (paste.isDiscussionEnabled()) {
DiscussionViewer.finishDiscussion();
}
})
.catch((err) => {
// wait for the user to type in the password,
@@ -4911,7 +5223,17 @@ jQuery.PrivateBin = (function($, RawDeflate) {
// first load translations
I18n.loadTranslations();
DOMPurify.setConfig({SAFE_FOR_JQUERY: true});
DOMPurify.setConfig({
ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|magnet):)/i,
SAFE_FOR_JQUERY: true
});
// center all modals
$('.modal').on('show.bs.modal', function(e) {
$(e.target).css({
display: 'flex'
});
});
// initialize other modules/"classes"
Alert.init();

File diff suppressed because one or more lines are too long

1
js/purify-2.0.8.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -67,10 +67,6 @@ describe('Alert', function () {
});
describe('showWarning', function () {
before(function () {
cleanup();
});
jsc.property(
'shows a warning message (basic)',
jsc.array(common.jscAlnumString()),
@@ -136,10 +132,6 @@ describe('Alert', function () {
});
describe('showError', function () {
before(function () {
cleanup();
});
jsc.property(
'shows an error message (basic)',
jsc.array(common.jscAlnumString()),
@@ -205,10 +197,6 @@ describe('Alert', function () {
});
describe('showRemaining', function () {
before(function () {
cleanup();
});
jsc.property(
'shows remaining time (basic)',
jsc.array(common.jscAlnumString()),
@@ -254,10 +242,6 @@ describe('Alert', function () {
});
describe('showLoading', function () {
before(function () {
cleanup();
});
jsc.property(
'shows a loading message (basic)',
jsc.array(common.jscAlnumString()),
@@ -310,10 +294,6 @@ describe('Alert', function () {
});
describe('hideLoading', function () {
before(function () {
cleanup();
});
it(
'hides the loading message',
function() {
@@ -335,10 +315,6 @@ describe('Alert', function () {
});
describe('hideMessages', function () {
before(function () {
cleanup();
});
it(
'hides all messages',
function() {
@@ -361,10 +337,6 @@ describe('Alert', function () {
});
describe('setCustomHandler', function () {
before(function () {
cleanup();
});
jsc.property(
'calls a given handler function',
'nat 3',

View File

@@ -4,9 +4,6 @@ var common = require('../common');
describe('AttachmentViewer', function () {
describe('setAttachment, showAttachment, removeAttachment, hideAttachment, hideAttachmentPreview, hasAttachment, getAttachment & moveAttachmentTo', function () {
this.timeout(30000);
before(function () {
cleanup();
});
jsc.property(
'displays & hides data as requested',
@@ -16,7 +13,7 @@ describe('AttachmentViewer', function () {
'string',
'string',
function (mimeType, rawdata, filename, prefix, postfix) {
var clean = jsdom(),
let clean = jsdom(),
data = 'data:' + mimeType + ';base64,' + btoa(rawdata),
previewSupported = (
mimeType.substring(0, 6) === 'image/' ||
@@ -24,8 +21,9 @@ describe('AttachmentViewer', function () {
mimeType.substring(0, 6) === 'video/' ||
mimeType.match(/\/pdf/i)
),
results = [];
prefix = prefix.replace(/%(s|d)/g, '%%');
results = [],
result = '';
prefix = prefix.replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%');
$('body').html(
'<div id="attachment" role="alert" class="hidden alert ' +
@@ -57,7 +55,7 @@ describe('AttachmentViewer', function () {
}
// beyond this point we will get the blob URL instead of the data
data = window.URL.createObjectURL(data);
var attachment = $.PrivateBin.AttachmentViewer.getAttachment();
const attachment = $.PrivateBin.AttachmentViewer.getAttachment();
results.push(
$.PrivateBin.AttachmentViewer.hasAttachment() &&
$('#attachment').hasClass('hidden') &&
@@ -84,13 +82,24 @@ describe('AttachmentViewer', function () {
!$('#attachment').hasClass('hidden') &&
(previewSupported ? !$('#attachmentPreview').hasClass('hidden') : $('#attachmentPreview').hasClass('hidden'))
);
var element = $('<div></div>');
let element = $('<div>');
$.PrivateBin.AttachmentViewer.moveAttachmentTo(element, prefix + '%s' + postfix);
// messageIDs with links get a relaxed treatment
if (prefix.indexOf('<a') === -1 && postfix.indexOf('<a') === -1) {
result = $('<textarea>').text((prefix + filename + postfix)).text();
} else {
result = DOMPurify.sanitize(
prefix + $.PrivateBin.Helper.htmlEntities(filename) + postfix, {
ALLOWED_TAGS: ['a', 'i', 'span'],
ALLOWED_ATTR: ['href', 'id']
}
);
}
if (filename.length) {
results.push(
element.children()[0].href === data &&
element.children()[0].getAttribute('download') === filename &&
element.children()[0].text === prefix + filename + postfix
element.children()[0].text === result
);
} else {
results.push(element.children()[0].href === data);

View File

@@ -5,9 +5,6 @@ var common = require('../common');
describe('Check', function () {
describe('init', function () {
this.timeout(30000);
before(function () {
cleanup();
});
it('returns false and shows error, if a bot UA is detected', function () {
jsc.assert(jsc.forall(

View File

@@ -4,9 +4,6 @@ var common = require('../common');
describe('DiscussionViewer', function () {
describe('handleNotification, prepareNewDiscussion, addComment, finishDiscussion, getReplyMessage, getReplyNickname, getReplyCommentId & highlightComment', function () {
this.timeout(30000);
before(function () {
cleanup();
});
jsc.property(
'displays & hides comments as requested',

View File

@@ -4,9 +4,6 @@ require('../common');
describe('Editor', function () {
describe('show, hide, getText, setText & isPreview', function () {
this.timeout(30000);
before(function () {
cleanup();
});
jsc.property(
'returns text fed into the textarea, handles editor tabs',

View File

@@ -3,10 +3,6 @@ var common = require('../common');
describe('Helper', function () {
describe('secondsToHuman', function () {
after(function () {
cleanup();
});
jsc.property('returns an array with a number and a word', 'integer', function (number) {
var result = $.PrivateBin.Helper.secondsToHuman(number);
return Array.isArray(result) &&
@@ -57,11 +53,11 @@ describe('Helper', function () {
'nearray string',
function (ids, contents) {
var html = '',
result = true;
result = true,
clean = jsdom(html);
ids.forEach(function(item, i) {
html += '<div id="' + item.join('') + '">' + common.htmlEntities(contents[i] || contents[0]) + '</div>';
html += '<div id="' + item.join('') + '">' + $.PrivateBin.Helper.htmlEntities(contents[i] || contents[0]) + '</div>';
});
var clean = jsdom(html);
// TODO: As per https://github.com/tmpvar/jsdom/issues/321 there is no getSelection in jsdom, yet.
// Once there is one, uncomment the block below to actually check the result.
/*
@@ -77,8 +73,8 @@ describe('Helper', function () {
});
describe('urls2links', function () {
after(function () {
cleanup();
before(function () {
cleanup = jsdom();
});
jsc.property(
@@ -97,11 +93,11 @@ describe('Helper', function () {
jsc.array(common.jscHashString()),
'string',
function (prefix, schema, address, query, fragment, postfix) {
var query = query.join(''),
fragment = fragment.join(''),
url = schema + '://' + address.join('') + '/?' + query + '#' + fragment,
prefix = common.htmlEntities(prefix),
postfix = ' ' + common.htmlEntities(postfix);
query = query.join('');
fragment = fragment.join('');
prefix = $.PrivateBin.Helper.htmlEntities(prefix);
postfix = ' ' + $.PrivateBin.Helper.htmlEntities(postfix);
let url = schema + '://' + address.join('') + '/?' + query + '#' + fragment;
// special cases: When the query string and fragment imply the beginning of an HTML entity, eg. &#0 or &#x
if (
@@ -122,19 +118,15 @@ describe('Helper', function () {
jsc.array(common.jscQueryString()),
'string',
function (prefix, query, postfix) {
var url = 'magnet:?' + query.join('').replace(/^&+|&+$/gm,''),
prefix = common.htmlEntities(prefix),
postfix = common.htmlEntities(postfix);
prefix = $.PrivateBin.Helper.htmlEntities(prefix);
postfix = $.PrivateBin.Helper.htmlEntities(postfix);
let url = 'magnet:?' + query.join('').replace(/^&+|&+$/gm,'');
return prefix + '<a href="' + url + '" rel="nofollow">' + url + '</a> ' + postfix === $.PrivateBin.Helper.urls2links(prefix + url + ' ' + postfix);
}
);
});
describe('sprintf', function () {
after(function () {
cleanup();
});
jsc.property(
'replaces %s in strings with first given parameter',
'string',
@@ -211,7 +203,7 @@ describe('Helper', function () {
describe('getCookie', function () {
this.timeout(30000);
after(function () {
before(function () {
cleanup();
});
@@ -263,16 +255,16 @@ describe('Helper', function () {
});
describe('htmlEntities', function () {
after(function () {
cleanup();
before(function () {
cleanup = jsdom();
});
jsc.property(
'removes all HTML entities from any given string',
'string',
function (string) {
var result = common.htmlEntities(string);
return !(/[<>"'`=\/]/.test(result)) && !(string.indexOf('&') > -1 && !(/&amp;/.test(result)));
var result = $.PrivateBin.Helper.htmlEntities(string);
return !(/[<>]/.test(result)) && !(string.indexOf('&') > -1 && !(/&amp;/.test(result)));
}
);
});

View File

@@ -3,6 +3,7 @@ var common = require('../common');
describe('I18n', function () {
describe('translate', function () {
this.timeout(30000);
before(function () {
$.PrivateBin.I18n.reset();
});
@@ -32,13 +33,41 @@ describe('I18n', function () {
var fakeAlias = $.PrivateBin.I18n._(fake);
$.PrivateBin.I18n.reset();
if (messageId.indexOf('<a') === -1) {
messageId = $.PrivateBin.Helper.htmlEntities(messageId);
} else {
messageId = DOMPurify.sanitize(
messageId, {
ALLOWED_TAGS: ['a', 'i', 'span'],
ALLOWED_ATTR: ['href', 'id']
}
);
}
return messageId === result && messageId === alias &&
messageId === pluralResult && messageId === pluralAlias &&
messageId === fakeResult && messageId === fakeAlias;
}
);
jsc.property(
'replaces %s in strings with first given parameter',
'replaces %s in strings with first given parameter, encoding all, when no link is in the messageID',
'string',
'(small nearray) string',
'string',
function (prefix, params, postfix) {
prefix = prefix.replace(/%(s|d)/g, '%%').replace(/<a/g, '');
params[0] = params[0].replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%').replace(/<a/g, '');
const translation = $.PrivateBin.Helper.htmlEntities(prefix + params[0] + postfix);
params.unshift(prefix + '%s' + postfix);
const result = $.PrivateBin.I18n.translate.apply(this, params);
$.PrivateBin.I18n.reset();
const alias = $.PrivateBin.I18n._.apply(this, params);
$.PrivateBin.I18n.reset();
return translation === result && translation === alias;
}
);
jsc.property(
'replaces %s in strings with first given parameter, encoding params only, when a link is part of the messageID',
'string',
'(small nearray) string',
'string',
@@ -46,15 +75,83 @@ describe('I18n', function () {
prefix = prefix.replace(/%(s|d)/g, '%%');
params[0] = params[0].replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%');
var translation = prefix + params[0] + postfix;
params.unshift(prefix + '%s' + postfix);
var result = $.PrivateBin.I18n.translate.apply(this, params);
const translation = DOMPurify.sanitize(
prefix + '<a href="' + params[0] + '"></a>' + postfix, {
ALLOWED_TAGS: ['a', 'i', 'span'],
ALLOWED_ATTR: ['href', 'id']
}
);
params.unshift(prefix + '<a href="%s"></a>' + postfix);
const result = $.PrivateBin.I18n.translate.apply(this, params);
$.PrivateBin.I18n.reset();
var alias = $.PrivateBin.I18n._.apply(this, params);
const alias = $.PrivateBin.I18n._.apply(this, params);
$.PrivateBin.I18n.reset();
return translation === result && translation === alias;
}
);
jsc.property(
'replaces %s in strings with first given parameter into an element, encoding all, when no link is in the messageID',
'string',
'(small nearray) string',
'string',
function (prefix, params, postfix) {
prefix = prefix.replace(/%(s|d)/g, '%%').replace(/<a/g, '');
params[0] = params[0].replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%').replace(/<a/g, '');
const translation = $('<textarea>').text((prefix + params[0] + postfix)).text();
let args = Array.prototype.slice.call(params);
args.unshift(prefix + '%s' + postfix);
let clean = jsdom();
$('body').html('<div id="i18n"></div>');
args.unshift($('#i18n'));
$.PrivateBin.I18n.translate.apply(this, args);
const result = $('#i18n').text();
$.PrivateBin.I18n.reset();
clean();
clean = jsdom();
$('body').html('<div id="i18n"></div>');
args[0] = $('#i18n');
$.PrivateBin.I18n._.apply(this, args);
const alias = $('#i18n').text();
$.PrivateBin.I18n.reset();
clean();
return translation === result && translation === alias;
}
);
jsc.property(
'replaces %s in strings with first given parameter into an element, encoding params only, when a link is part of the messageID inserted',
'string',
'(small nearray) string',
'string',
function (prefix, params, postfix) {
prefix = prefix.replace(/%(s|d)/g, '%%').trim();
params[0] = params[0].replace(/%(s|d)/g, '%%').trim();
postfix = postfix.replace(/%(s|d)/g, '%%').trim();
const translation = DOMPurify.sanitize(
prefix + '<a href="' + params[0] + '"></a>' + postfix, {
ALLOWED_TAGS: ['a', 'i', 'span'],
ALLOWED_ATTR: ['href', 'id']
}
);
let args = Array.prototype.slice.call(params);
args.unshift(prefix + '<a href="%s"></a>' + postfix);
let clean = jsdom();
$('body').html('<div id="i18n"></div>');
args.unshift($('#i18n'));
$.PrivateBin.I18n.translate.apply(this, args);
const result = $('#i18n').html();
$.PrivateBin.I18n.reset();
clean();
clean = jsdom();
$('body').html('<div id="i18n"></div>');
args[0] = $('#i18n');
$.PrivateBin.I18n._.apply(this, args);
const alias = $('#i18n').html();
$.PrivateBin.I18n.reset();
clean();
return translation === result && translation === alias;
}
);
});
describe('getPluralForm', function () {

View File

@@ -5,18 +5,18 @@ describe('Model', function () {
describe('getExpirationDefault', function () {
before(function () {
$.PrivateBin.Model.reset();
cleanup();
cleanup = jsdom();
});
jsc.property(
'returns the contents of the element with id "pasteExpiration"',
'array asciinestring',
'nearray asciinestring',
'string',
'small nat',
function (keys, value, key) {
keys = keys.map(common.htmlEntities);
value = common.htmlEntities(value);
var content = keys.length > key ? keys[key] : (keys.length > 0 ? keys[0] : 'null'),
keys = keys.map($.PrivateBin.Helper.htmlEntities);
value = $.PrivateBin.Helper.htmlEntities(value);
var content = keys.length > key ? keys[key] : keys[0],
contents = '<select id="pasteExpiration" name="pasteExpiration">';
keys.forEach(function(item) {
contents += '<option value="' + item + '"';
@@ -27,7 +27,7 @@ describe('Model', function () {
});
contents += '</select>';
$('body').html(contents);
var result = common.htmlEntities(
var result = $.PrivateBin.Helper.htmlEntities(
$.PrivateBin.Model.getExpirationDefault()
);
$.PrivateBin.Model.reset();
@@ -39,18 +39,20 @@ describe('Model', function () {
describe('getFormatDefault', function () {
before(function () {
$.PrivateBin.Model.reset();
});
after(function () {
cleanup();
});
jsc.property(
'returns the contents of the element with id "pasteFormatter"',
'array asciinestring',
'nearray asciinestring',
'string',
'small nat',
function (keys, value, key) {
keys = keys.map(common.htmlEntities);
value = common.htmlEntities(value);
var content = keys.length > key ? keys[key] : (keys.length > 0 ? keys[0] : 'null'),
keys = keys.map($.PrivateBin.Helper.htmlEntities);
value = $.PrivateBin.Helper.htmlEntities(value);
var content = keys.length > key ? keys[key] : keys[0],
contents = '<select id="pasteFormatter" name="pasteFormatter">';
keys.forEach(function(item) {
contents += '<option value="' + item + '"';
@@ -61,7 +63,7 @@ describe('Model', function () {
});
contents += '</select>';
$('body').html(contents);
var result = common.htmlEntities(
var result = $.PrivateBin.Helper.htmlEntities(
$.PrivateBin.Model.getFormatDefault()
);
$.PrivateBin.Model.reset();
@@ -74,7 +76,6 @@ describe('Model', function () {
this.timeout(30000);
beforeEach(function () {
$.PrivateBin.Model.reset();
cleanup();
});
jsc.property(
@@ -130,7 +131,6 @@ describe('Model', function () {
this.timeout(30000);
beforeEach(function () {
$.PrivateBin.Model.reset();
cleanup();
});
jsc.property(
@@ -238,7 +238,6 @@ describe('Model', function () {
describe('getTemplate', function () {
beforeEach(function () {
$.PrivateBin.Model.reset();
cleanup();
});
jsc.property(

View File

@@ -36,9 +36,6 @@ describe('PasteStatus', function () {
describe('showRemainingTime', function () {
this.timeout(30000);
before(function () {
cleanup();
});
jsc.property(
'shows burn after reading message or remaining time v1',
@@ -121,10 +118,6 @@ describe('PasteStatus', function () {
});
describe('hideMessages', function () {
before(function () {
cleanup();
});
it(
'hides all messages',
function() {

View File

@@ -4,9 +4,6 @@ var common = require('../common');
describe('PasteViewer', function () {
describe('run, hide, getText, setText, getFormat, setFormat & isPrettyPrinted', function () {
this.timeout(30000);
before(function () {
cleanup();
});
jsc.property(
'displays text according to format',

View File

@@ -6,10 +6,6 @@ describe('Prompt', function () {
// in nodejs -> replace the prompt in the "page" template with a modal
describe('requestPassword & getPassword', function () {
this.timeout(30000);
before(function () {
$.PrivateBin.Model.reset();
cleanup();
});
jsc.property(
'returns the password fed into the dialog',
@@ -26,6 +22,7 @@ describe('Prompt', function () {
'password"></div><button type="submit">Decrypt</button>' +
'</form></div></div></div></div>'
);
$.PrivateBin.Model.reset();
$.PrivateBin.Model.init();
$.PrivateBin.Prompt.init();
$.PrivateBin.Prompt.requestPassword();

View File

@@ -326,7 +326,7 @@ describe('TopNav', function () {
'returns the currently selected expiration date',
function () {
$.PrivateBin.TopNav.init();
assert.ok($.PrivateBin.TopNav.getExpiration() === '1week');
assert.ok($.PrivateBin.TopNav.getExpiration() === null);
}
);
});

View File

@@ -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.3.1
* @version 1.3.3
*/
namespace PrivateBin;
@@ -102,8 +102,9 @@ class Configuration
public function __construct()
{
$config = array();
$configFile = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.php';
$configIni = PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini';
$basePath = (getenv('CONFIG_PATH') !== false ? getenv('CONFIG_PATH') : PATH . 'cfg') . DIRECTORY_SEPARATOR;
$configIni = $basePath . 'conf.ini';
$configFile = $basePath . 'conf.php';
// rename INI files to avoid configuration leakage
if (is_readable($configIni)) {
@@ -112,7 +113,7 @@ class Configuration
// cleanup sample, too
$configIniSample = $configIni . '.sample';
if (is_readable($configIniSample)) {
DataStore::prependRename($configIniSample, PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.sample.php', ';');
DataStore::prependRename($configIniSample, $basePath . 'conf.sample.php', ';');
}
}

View File

@@ -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.3.1
* @version 1.3.3
*/
namespace PrivateBin;
@@ -28,7 +28,7 @@ class Controller
*
* @const string
*/
const VERSION = '1.3.1';
const VERSION = '1.3.3';
/**
* minimal required PHP version

View File

@@ -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.3.1
* @version 1.3.3
*/
namespace PrivateBin\Data;

View File

@@ -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.3.1
* @version 1.3.3
*/
namespace PrivateBin\Data;
@@ -770,7 +770,7 @@ class Database extends AbstractData
" MODIFY COLUMN data $attachmentType;"
);
}
// no break, continue with updates for 1.3.1 and later
// no break, continue with updates for all newer versions
default:
self::_exec(
'UPDATE ' . self::_sanitizeIdentifier('config') .

View File

@@ -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.3.1
* @version 1.3.3
*/
namespace PrivateBin\Data;

View File

@@ -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.3.1
* @version 1.3.3
*/
namespace PrivateBin;

View File

@@ -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.3.1
* @version 1.3.3
*/
namespace PrivateBin;

View File

@@ -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.3.1
* @version 1.3.3
*/
namespace PrivateBin;
@@ -125,9 +125,31 @@ class I18n
} else {
$args[0] = self::$_translations[$messageId];
}
// 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]);
}
}
}
return call_user_func_array('sprintf', $args);
}
/**
* encode HTML entities for output into an HTML5 document
*
* @access public
* @static
* @param string $string
* @return string
*/
public static function encode($string)
{
return htmlspecialchars($string, ENT_QUOTES | ENT_HTML5 | ENT_DISALLOWED, 'UTF-8', false);
}
/**
* loads translations
*
@@ -303,6 +325,7 @@ class I18n
case 'pl':
return $n == 1 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $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);
case 'sl':
return $n % 100 == 1 ? 1 : ($n % 100 == 2 ? 2 : ($n % 100 == 3 || $n % 100 == 4 ? 3 : 0));

View File

@@ -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.3.1
* @version 1.3.3
*/
namespace PrivateBin;

View File

@@ -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.3.1
* @version 1.3.3
*/
namespace PrivateBin;

View File

@@ -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.3.1
* @version 1.3.3
*/
namespace PrivateBin\Model;

View File

@@ -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.3.1
* @version 1.3.3
*/
namespace PrivateBin\Model;

View File

@@ -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.3.1
* @version 1.3.3
*/
namespace PrivateBin\Model;

View File

@@ -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.3.1
* @version 1.3.3
*/
namespace PrivateBin\Persistence;

View File

@@ -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.3.1
* @version 1.3.3
*/
namespace PrivateBin\Persistence;

View File

@@ -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.3.1
* @version 1.3.3
*/
namespace PrivateBin\Persistence;

View File

@@ -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.3.1
* @version 1.3.3
*/
namespace PrivateBin\Persistence;

View File

@@ -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.3.1
* @version 1.3.3
*/
namespace PrivateBin;

View File

@@ -7,7 +7,7 @@
* @link https://github.com/PrivateBin/PrivateBin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license http://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 1.3.1
* @version 1.3.3
*/
namespace PrivateBin;

View File

@@ -8,7 +8,7 @@
* @link http://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.3.1
* @version 0.0.5 beta PrivateBin 1.3.3
*/
namespace PrivateBin;

View File

@@ -4,7 +4,7 @@ $isCpct = substr($template, 9, 8) === '-compact';
$isDark = substr($template, 9, 5) === '-dark';
$isPage = substr($template, -5) === '-page';
?><!DOCTYPE html>
<html>
<html lang="<?php echo I18n::_('en'); ?>">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge">
@@ -55,7 +55,7 @@ if ($ZEROBINCOMPATIBILITY):
endif;
?>
<script type="text/javascript" data-cfasync="false" src="js/zlib-1.2.11.js" integrity="sha512-Yey/0yoaVmSbqMEyyff3DIu8kCPwpHvHf7tY1AuZ1lrX9NPCMg87PwzngMi+VNbe4ilCApmePeuKT869RTcyCQ==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/base-x-3.0.5.1.js" integrity="sha512-/zL3MWKMtl1IBF0URx3laql2jUw+rWfFFabNlILY/Qm+hUsQR/XULjUyNHkW/FkrV7A0sMQ7tsppH7sj5ht8wA==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/base-x-3.0.7.js" integrity="sha512-/Bi1AJIP0TtxEB+Jh6Hk809H1G7vn4iJV80qagslf0+Hm0UjUi1s3qNrn1kZULjzUYuaf6ck0ndLGJ7MxWLmgQ==" 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.3.7.js" integrity="sha512-iztkobsvnjKfAtTNdHkGVjAYTrrtlC7mGp/54c40wowO7LhURYl3gVzzcEqGl/qKXQltJ2HwMrdLcNUdo+N/RQ==" crossorigin="anonymous"></script>
<?php
@@ -66,13 +66,13 @@ if ($SYNTAXHIGHLIGHTING):
endif;
if ($MARKDOWN):
?>
<script type="text/javascript" data-cfasync="false" src="js/showdown-1.9.1.js" integrity="sha512-VeINC2WUWLyxgeQ56SsYFjQ5+d7RLvLPYOEYDFtEDd3AyVsgIsHYsWZ6WwgALwB6YR6qrVEM3IH4Bck96IfbMw==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/showdown-1.9.1.js" integrity="sha512-nRri7kqh3iRLdHbhtjfe8w9eAQPmt+ubH5U88UZyKbz6O9Q0q4haaXF0krOUclKmRJou/kKZYulgBHvHXPqOvg==" crossorigin="anonymous"></script>
<?php
endif;
?>
<script type="text/javascript" data-cfasync="false" src="js/purify-2.0.1.js" integrity="sha512-ddI36MdUoXp/o7yhQtr9/qj4G3oFwCRga4jCGaoUYtORg0PPmFKVKG4Ess3fIknYzxwwKMlrIL9o4NwuPTCc1Q==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/purify-2.0.8.js" integrity="sha512-QwcEKGuEmKtMguCO9pqNtUtZqq9b/tJ8gNr5qhY8hykq3zKTlDOvpZAmf6Rs8yH35Bz1ZdctUjj2qEWxT5aXCg==" 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-iZeao0p5riUgentjlrI2cY7Y8KRLTO42bQ4VGy6ky5FS0UjqXW4UkEJQcvR01SxbUFUz7h5AwzC8CVnUHDwRUg==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-enOoc3FEmX00nbC+28Qrhjc2shbso/DWmeHVbLDy+a0jvXXweYXCr/B1PRqnXJzTBdPqVBYLVM1u6peVlTwNxg==" crossorigin="anonymous"></script>
<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" />
<link rel="icon" type="image/png" href="img/favicon-16x16.png?<?php echo rawurlencode($VERSION); ?>" sizes="16x16" />
@@ -118,13 +118,41 @@ if ($QRCODE):
<div class="modal-body">
<div class="mx-auto" id="qrcode-display"></div>
</div>
<button type="button" class="btn btn-primary btn-block" data-dismiss="modal"><?php echo I18n::_('Close') ?></button>
<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>
<?php
endif;
?>
<div id="emailconfirmmodal" tabindex="-1" class="modal fade" aria-labelledby="emailconfirmmodalTitle" 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>
<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>
</div>
</div>
</div>
</div>
<nav class="navbar navbar-<?php echo $isDark ? 'inverse' : 'default'; ?> navbar-<?php echo $isCpct ? 'fixed' : 'static'; ?>-top"><?php
if ($isCpct):
?><div class="container"><?php
@@ -171,6 +199,9 @@ endif;
<button id="rawtextbutton" type="button" class="hidden btn btn-<?php echo $isDark ? 'warning' : 'default'; ?> navbar-btn">
<span class="glyphicon glyphicon-text-background" aria-hidden="true"></span> <?php echo I18n::_('Raw text'), PHP_EOL; ?>
</button>
<button id="emaillink" type="button" class="hidden btn btn-<?php echo $isDark ? 'warning' : 'default'; ?> navbar-btn">
<span class="glyphicon glyphicon-envelope" aria-hidden="true"></span> <?php echo I18n::_('Email'), PHP_EOL; ?>
</button>
<?php
if ($QRCODE):
?>
@@ -409,7 +440,7 @@ if (strlen($NOTICE)):
?>
<div role="alert" class="alert alert-info">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
<?php echo htmlspecialchars($NOTICE), PHP_EOL; ?>
<?php echo I18n::encode($NOTICE), PHP_EOL; ?>
</div>
<?php
endif;
@@ -429,16 +460,16 @@ endif;
?>
<div id="status" role="alert" class="alert alert-info<?php echo empty($STATUS) ? ' hidden' : '' ?>">
<span class="glyphicon glyphicon-info-sign" aria-hidden="true"></span>
<?php echo htmlspecialchars($STATUS), PHP_EOL; ?>
<?php echo I18n::encode($STATUS), PHP_EOL; ?>
</div>
<div id="errormessage" role="alert" class="<?php echo empty($ERROR) ? 'hidden' : '' ?> alert alert-danger">
<span class="glyphicon glyphicon-alert" aria-hidden="true"></span>
<?php echo htmlspecialchars($ERROR), PHP_EOL; ?>
<?php echo I18n::encode($ERROR), PHP_EOL; ?>
</div>
<noscript>
<div id="noscript" role="alert" class="alert alert-<?php echo $isDark ? 'error' : 'warning'; ?>">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
<?php echo I18n::_('JavaScript is required for %s to work.<br />Sorry for the inconvenience.', I18n::_($NAME)), PHP_EOL; ?>
<?php echo I18n::_('JavaScript is required for %s to work. Sorry for the inconvenience.', I18n::_($NAME)), PHP_EOL; ?>
</div>
</noscript>
<div id="oldnotice" role="alert" class="hidden alert alert-danger">
@@ -446,7 +477,8 @@ endif;
<?php echo I18n::_('%s requires a modern browser to work.', I18n::_($NAME)), PHP_EOL; ?>
<a href="https://www.mozilla.org/firefox/">Firefox</a>,
<a href="https://www.opera.com/">Opera</a>,
<a href="https://www.google.com/chrome">Chrome</a>…
<a href="https://www.google.com/chrome">Chrome</a>…<br />
<span class="small"><?php echo I18n::_('For more information <a href="%s">see this FAQ entry</a>.', 'https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-it-show-me-the-error-privatebin-requires-a-modern-browser-to-work'); ?></span>
</div>
<?php
if ($HTTPWARNING):
@@ -473,7 +505,7 @@ endif;
if (strlen($URLSHORTENER)):
?>
<p>
<button id="shortenbutton" data-shortener="<?php echo htmlspecialchars($URLSHORTENER); ?>" type="button" class="btn btn-<?php echo $isDark ? 'warning' : 'primary'; ?> btn-block">
<button id="shortenbutton" data-shortener="<?php echo I18n::encode($URLSHORTENER); ?>" type="button" class="btn btn-<?php echo $isDark ? 'warning' : 'primary'; ?> btn-block">
<span class="glyphicon glyphicon-send" aria-hidden="true"></span> <?php echo I18n::_('Shorten URL'), PHP_EOL; ?>
</button>
</p>
@@ -486,8 +518,8 @@ endif;
?>
</div>
<ul id="editorTabs" class="nav nav-tabs hidden">
<li role="presentation" class="active"><a id="messageedit" href="#"><?php echo I18n::_('Editor'); ?></a></li>
<li role="presentation"><a id="messagepreview" href="#"><?php echo I18n::_('Preview'); ?></a></li>
<li role="presentation" class="active"><a role="tab" aria-selected="true" aria-controls="editorTabs" id="messageedit" href="#"><?php echo I18n::_('Editor'); ?></a></li>
<li role="presentation"><a role="tab" aria-selected="false" aria-controls="editorTabs" id="messagepreview" href="#"><?php echo I18n::_('Preview'); ?></a></li>
<li role="presentation" class="pull-right">
<?php
if ($isPage):
@@ -525,7 +557,7 @@ endif;
<div id="noscript" role="alert" class="alert alert-info noscript-hide">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
<?php echo I18n::_('Loading…'); ?><br />
<span class="small"><?php echo I18n::_('In case this message never disappears please have a look at <a href="%s">this FAQ for information to troubleshoot</a>.', 'https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away'); ?></span>
<span class="small"><?php echo I18n::_('In case this message never disappears please have a look at <a href="%s">this FAQ for information to troubleshoot</a>.', 'https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-the-loading-message-not-go-away'); ?></span>
</div>
</section>
<footer class="container">

View File

@@ -1,7 +1,7 @@
<?php
use PrivateBin\I18n;
?><!DOCTYPE html>
<html lang="en">
<html lang="<?php echo I18n::_('en'); ?>">
<head>
<meta charset="utf-8" />
<meta name="robots" content="noindex" />
@@ -34,7 +34,7 @@ if ($ZEROBINCOMPATIBILITY):
endif;
?>
<script type="text/javascript" data-cfasync="false" src="js/zlib-1.2.11.js" integrity="sha512-Yey/0yoaVmSbqMEyyff3DIu8kCPwpHvHf7tY1AuZ1lrX9NPCMg87PwzngMi+VNbe4ilCApmePeuKT869RTcyCQ==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/base-x-3.0.5.1.js" integrity="sha512-/zL3MWKMtl1IBF0URx3laql2jUw+rWfFFabNlILY/Qm+hUsQR/XULjUyNHkW/FkrV7A0sMQ7tsppH7sj5ht8wA==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/base-x-3.0.7.js" integrity="sha512-/Bi1AJIP0TtxEB+Jh6Hk809H1G7vn4iJV80qagslf0+Hm0UjUi1s3qNrn1kZULjzUYuaf6ck0ndLGJ7MxWLmgQ==" 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
if ($SYNTAXHIGHLIGHTING):
@@ -44,13 +44,13 @@ if ($SYNTAXHIGHLIGHTING):
endif;
if ($MARKDOWN):
?>
<script type="text/javascript" data-cfasync="false" src="js/showdown-1.9.1.js" integrity="sha512-VeINC2WUWLyxgeQ56SsYFjQ5+d7RLvLPYOEYDFtEDd3AyVsgIsHYsWZ6WwgALwB6YR6qrVEM3IH4Bck96IfbMw==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/showdown-1.9.1.js" integrity="sha512-nRri7kqh3iRLdHbhtjfe8w9eAQPmt+ubH5U88UZyKbz6O9Q0q4haaXF0krOUclKmRJou/kKZYulgBHvHXPqOvg==" crossorigin="anonymous"></script>
<?php
endif;
?>
<script type="text/javascript" data-cfasync="false" src="js/purify-2.0.1.js" integrity="sha512-ddI36MdUoXp/o7yhQtr9/qj4G3oFwCRga4jCGaoUYtORg0PPmFKVKG4Ess3fIknYzxwwKMlrIL9o4NwuPTCc1Q==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/purify-2.0.8.js" integrity="sha512-QwcEKGuEmKtMguCO9pqNtUtZqq9b/tJ8gNr5qhY8hykq3zKTlDOvpZAmf6Rs8yH35Bz1ZdctUjj2qEWxT5aXCg==" 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-iZeao0p5riUgentjlrI2cY7Y8KRLTO42bQ4VGy6ky5FS0UjqXW4UkEJQcvR01SxbUFUz7h5AwzC8CVnUHDwRUg==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-enOoc3FEmX00nbC+28Qrhjc2shbso/DWmeHVbLDy+a0jvXXweYXCr/B1PRqnXJzTBdPqVBYLVM1u6peVlTwNxg==" crossorigin="anonymous"></script>
<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" />
<link rel="icon" type="image/png" href="img/favicon-16x16.png?<?php echo rawurlencode($VERSION); ?>" sizes="16x16" />
@@ -67,24 +67,26 @@ endif;
<?php
if (strlen($NOTICE)):
?>
<span class="blink">▶</span> <?php echo htmlspecialchars($NOTICE);
<span class="blink">▶</span> <?php echo I18n::encode($NOTICE);
endif;
?>
</div>
<h1 class="title reloadlink"><?php echo I18n::_($NAME); ?></h1><br />
<h2 class="title"><?php echo I18n::_('Because ignorance is bliss'); ?></h2><br />
<h3 class="title"><?php echo $VERSION; ?></h3>
<noscript><div id="noscript" class="nonworking"><?php echo I18n::_('JavaScript is required for %s to work.<br />Sorry for the inconvenience.', I18n::_($NAME)); ?></div></noscript>
<div id="oldnotice" class="nonworking hidden"><?php echo I18n::_('%s requires a modern browser to work.', I18n::_($NAME)), PHP_EOL; ?>
<noscript><div id="noscript" class="nonworking"><?php echo I18n::_('JavaScript is required for %s to work. Sorry for the inconvenience.', I18n::_($NAME)); ?></div></noscript>
<div id="oldnotice" class="nonworking hidden">
<?php echo I18n::_('%s requires a modern browser to work.', I18n::_($NAME)), PHP_EOL; ?>
<a href="https://www.mozilla.org/firefox/">Firefox</a>,
<a href="https://www.opera.com/">Opera</a>,
<a href="https://www.google.com/chrome">Chrome</a>…
<a href="https://www.google.com/chrome">Chrome</a>…<br />
<span class="small"><?php echo I18n::_('For more information <a href="%s">see this FAQ entry</a>.', 'https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-it-show-me-the-error-privatebin-requires-a-modern-browser-to-work'); ?></span>
</div>
<?php
if ($HTTPWARNING):
?>
<div id="httpnotice" class="errorMessage hidden">
<?php echo I18n::_('This website is using an insecure connection! Please only use it for testing.'); ?>
<?php echo I18n::_('This website is using an insecure connection! Please only use it for testing.'); ?><br />
<span class="small"><?php echo I18n::_('For more information <a href="%s">see this FAQ entry</a>.', 'https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-it-show-me-an-error-about-an-insecure-connection'); ?></span>
</div>
<div id="insecurecontextnotice" class="errorMessage hidden">
@@ -97,14 +99,15 @@ endif;
<section>
<article>
<div id="loadingindicator" class="hidden"><?php echo I18n::_('Loading…'); ?></div>
<div id="status"><?php echo htmlspecialchars($STATUS); ?></div>
<div id="errormessage" class="hidden"><?php echo htmlspecialchars($ERROR); ?></div>
<div id="status"><?php echo I18n::encode($STATUS); ?></div>
<div id="errormessage" class="hidden"><?php echo I18n::encode($ERROR); ?></div>
<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="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="emaillink" class="hidden"><img src="img/icon_email.png" width="15" height="15" alt="" /><?php echo I18n::_('Email'); ?></button>
<?php
if ($QRCODE):
?>
@@ -206,7 +209,7 @@ endif;
<?php
if (strlen($URLSHORTENER)):
?>
<button id="shortenbutton" data-shortener="<?php echo htmlspecialchars($URLSHORTENER); ?>"><img src="img/icon_shorten.png" width="13" height="15" /><?php echo I18n::_('Shorten URL'); ?></button>
<button id="shortenbutton" data-shortener="<?php echo I18n::encode($URLSHORTENER); ?>"><img src="img/icon_shorten.png" width="13" height="15" /><?php echo I18n::_('Shorten URL'); ?></button>
<?php
endif;
?>
@@ -265,7 +268,7 @@ endif;
<section class="container">
<div id="noscript" role="alert" class="nonworking alert alert-info noscript-hide"><span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true">
<span> <?php echo I18n::_('Loading…'); ?></span><br>
<span class="small"><?php echo I18n::_('In case this message never disappears please have a look at <a href="https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away">this FAQ for information to troubleshoot</a>.'); ?></span>
<span class="small"><?php echo I18n::_('In case this message never disappears please have a look at <a href="%s">this FAQ for information to troubleshoot</a>.', 'https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-the-loading-message-not-go-away'); ?></span>
</div>
</section>
</body>

View File

@@ -4,24 +4,31 @@ use PrivateBin\Configuration;
class ConfigurationTest extends PHPUnit_Framework_TestCase
{
private $_minimalConfig;
private $_options;
private $_minimalConfig;
private $_path;
public function setUp()
{
/* Setup Routine */
Helper::confBackup();
$this->_minimalConfig = '[main]' . PHP_EOL . '[model]' . PHP_EOL . '[model_options]';
$this->_options = Configuration::getDefaults();
$this->_options['model_options']['dir'] = PATH . $this->_options['model_options']['dir'];
$this->_options['traffic']['dir'] = PATH . $this->_options['traffic']['dir'];
$this->_options['purge']['dir'] = PATH . $this->_options['purge']['dir'];
$this->_minimalConfig = '[main]' . PHP_EOL . '[model]' . PHP_EOL . '[model_options]';
$this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_cfg';
if (!is_dir($this->_path)) {
mkdir($this->_path);
}
}
public function tearDown()
{
/* Tear Down Routine */
Helper::rmDir($this->_path);
if (is_file(CONF)) {
unlink(CONF);
}
@@ -177,4 +184,49 @@ class ConfigurationTest extends PHPUnit_Framework_TestCase
$this->assertFileExists(CONF, 'old configuration file gets converted');
$this->assertFileNotExists(PATH . 'cfg' . DIRECTORY_SEPARATOR . 'conf.ini', 'old configuration file gets removed');
}
public function testConfigPath()
{
// setup
$configFile = $this->_path . DIRECTORY_SEPARATOR . 'conf.php';
$options = $this->_options;
$options['main']['name'] = 'OtherBin';
Helper::createIniFile($configFile, $options);
// test
putenv('CONFIG_PATH=' . $this->_path);
$conf = new Configuration;
$this->assertEquals('OtherBin', $conf->getKey('name'), 'changing config path is supported');
// cleanup environment
if (is_file($configFile)) {
unlink($configFile);
}
putenv('CONFIG_PATH');
}
public function testConfigPathIni()
{
// setup
$configFile = $this->_path . DIRECTORY_SEPARATOR . 'conf.ini';
$configMigrated = $this->_path . DIRECTORY_SEPARATOR . 'conf.php';
$options = $this->_options;
$options['main']['name'] = 'OtherBin';
Helper::createIniFile($configFile, $options);
$this->assertFileNotExists(CONF, 'configuration in the default location is non existing');
// test
putenv('CONFIG_PATH=' . $this->_path);
$conf = new Configuration;
$this->assertEquals('OtherBin', $conf->getKey('name'), 'changing config path is supported for ini files as well');
$this->assertFileExists($configMigrated, 'old configuration file gets converted');
$this->assertFileNotExists($configFile, 'old configuration file gets removed');
$this->assertFileNotExists(CONF, 'configuration is not created in the default location');
// cleanup environment
if (is_file($configFile)) {
unlink($configFile);
}
putenv('CONFIG_PATH');
}
}

View File

@@ -155,6 +155,17 @@ class I18nTest extends PHPUnit_Framework_TestCase
$this->assertEquals('some string + 1', I18n::_('some %s + %d', 'string', 1), 'browser language en');
}
public function testHtmlEntityEncoding()
{
$_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'foobar';
I18n::loadTranslations();
$input = '&<>"\'/`=';
$result = htmlspecialchars($input, ENT_QUOTES | ENT_HTML5 | ENT_DISALLOWED, 'UTF-8', false);
$this->assertEquals($result, I18n::encode($input), 'encodes HTML entities');
$this->assertEquals('<a>some ' . $result . ' + 1</a>', I18n::_('<a>some %s + %d</a>', $input, 1), 'encodes parameters in translations');
$this->assertEquals($result . $result, I18n::_($input . '%s', $input), 'encodes message ID as well, when no link');
}
public function testMessageIdsExistInAllLanguages()
{
$messageIds = array();