445 Commits

Author SHA1 Message Date
rugk
470e0fc33c Add missing break in switch 2020-03-06 10:03:27 +01:00
rugk
f13a5d0a55 Cleanup variables/logic
It only assigns and DomPurfies things once, instead of doing
it again and again.
Also uses less variables and cleans up the logic.
2020-03-04 14:32:04 +01:00
rugk
552e0cac3a Fix .getText of PasteViewer to return original text string
The issue was that I reused an existing module variable.

Now we have (yet another one) temp var for that.

Practically this fixes the "clone paste" button by using the original text.
2020-03-04 13:44:57 +01:00
rugk
294b8804a4 Fix source code escaping in comments
Also fix comments.
2020-03-04 13:29:06 +01:00
rugk
005d223c0d Fix source code being not rendered
If special characters were included the source code (HTML-like ones like < and >) is was not rendered.

Fixes https://github.com/PrivateBin/PrivateBin/issues/588

It includes a change in the RegEx for URLs because that was broken when a
& character later followed at any time after a link (even after a newline).
(with a negative lookahead)

Test with https://regex101.com/r/i7bZ73/1

Now the RegEx does not check for _all_ chars after a link, but just for the
one following the link.
(So the lookahead is not * anymore. I guess thsi behaviour was
the expectation when it has been implemented.)
2020-03-04 11:45:56 +01:00
El RIDO
879a2a9255 tweaking German translation for email strings 2020-03-01 08:55:24 +01:00
El RIDO
f391773c65 generalize date string handling, replacing hardcoded lookups, fixes #586 2020-03-01 08:54:48 +01:00
El RIDO
b0800060c2 fix change log 2020-02-16 13:33:48 +01:00
El RIDO
15f66870d1 Merge branch 'php7.4-ci' 2020-02-16 13:27:16 +01:00
El RIDO
afd82ac34d Merge branch 'master' into php7.4-ci 2020-02-16 13:23:11 +01:00
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
f190317d95 remove obsolete sudo key 2020-02-05 19:35:46 +01:00
El RIDO
5d54006c9e update minimum required PHP version to 5.6 and replace slowEquals() with native hash_equals() function 2020-02-05 19:30:14 +01:00
El RIDO
2870023e9c updating composer requirements und identicon library 2020-02-05 19:17:22 +01:00
El RIDO
df7a06315f drop php 5.5 tests, allowing us to use current ubuntu bionic based environment and adding php 7.4 incl. GD library 2020-02-05 19:15:43 +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
El RIDO
71797d1dd4 changes required for jsdoc, adding legacy.js to code coverage 2019-09-22 21:18:19 +02:00
El RIDO
476b9c90e2 updating PHP dependencies (they remain unchanged), committing lock for github dependency graph support 2019-09-22 19:52:25 +02:00
El RIDO
2d4edfe401 incrementing version number in preparation of release 2019-09-22 19:42:04 +02:00
El RIDO
ced5f30280 Merge branch 'cryptomilk-master-htaccess' 2019-09-20 07:06:38 +02:00
El RIDO
d5aeba60ca increase default size limit to 10 MiB, documenting change 2019-09-20 07:04:26 +02:00
El RIDO
5c0012cf51 adding database migration to increase data to MEDIUMBLOB on MySQL by default 2019-09-20 06:57:54 +02:00
El RIDO
091dc14074 Merge branch 'master-htaccess' of https://github.com/cryptomilk/PrivateBin into cryptomilk-master-htaccess 2019-09-20 06:28:07 +02:00
El RIDO
a3f793fec7 documenting changes 2019-09-20 06:27:07 +02:00
El RIDO
b496ae42fd Merge branch 'better-feature-detection' 2019-09-20 06:18:10 +02:00
El RIDO
e9eeeacdf0 addressing jsverifyRngState 0f5ea3f961827b0c4d 2019-09-19 20:48:05 +02:00
El RIDO
8da382f7c6 Merge branch 'master' into better-feature-detection 2019-09-19 20:19:35 +02:00
El RIDO
28d70a1b18 upgrading DOMpurify, fixes #520 2019-09-19 20:13:47 +02:00
El RIDO
c1f6e5663b Merge branch 'master' into better-feature-detection 2019-09-19 20:02:00 +02:00
El RIDO
bf0be09f09 removing old IE warning, as it is ignored by IE. The modern warning does get displayed, so let's use this more generic warning instead. 2019-09-19 20:01:10 +02:00
El RIDO
955317d924 make codacy a bit happier 2019-09-19 19:47:19 +02:00
El RIDO
8e27dbff15 clarify the use of 'unsafe-eval' and what the impact removing it has - Firefox users may not care and disable it to improve security 2019-09-19 19:24:28 +02:00
El RIDO
7c61f59dcd removing untranslated string for non-human entities, moving insecure notice to template, so it can remains translated 2019-09-19 19:14:48 +02:00
El RIDO
70c38db81d adding ES6 and async feature detection to correctly flag old chromes and operas with the modern browser error 2019-09-18 07:47:26 +02:00
El RIDO
4332d0edb0 making legacy.js work even on IE 6 by avoiding jQuery 2019-09-18 07:31:32 +02:00
El RIDO
5810f17c31 fixing HTTP only error detection in Chrome and Android by ensuring all logic is contained in legacy.js 2019-09-17 21:41:25 +02:00
El RIDO
15b3d67ba7 adding browserstack badge in order to be elegible for their OpenSource program (https://www.browserstack.com/open-source?ref=pricing) 2019-09-16 20:51:49 +02:00
El RIDO
1a42158dd1 address Codacy's concern about missing semicolons 2019-09-14 09:53:22 +02:00
El RIDO
713ce148a4 address Codacy's concern that i is already defined 2019-09-14 09:50:47 +02:00
El RIDO
63426d6f8b splitting out PrivateBin.InitialCheck class into Legacy.Check and working on making it compatible with IE 11 2019-09-14 09:41:52 +02:00
El RIDO
a363b2ff95 eslint env cleanup 2019-09-08 09:12:56 +02:00
El RIDO
c2962af4f8 trying different approach to convince codacy about false positive 2019-09-08 09:08:21 +02:00
El RIDO
ae11d168ce trying to convince codacy about the eslint changes 2019-09-08 09:02:15 +02:00
El RIDO
7b029d3657 trying to convince codacy about the eslint changes 2019-09-08 08:55:19 +02:00
El RIDO
b1c9ca65fa trying to address eslint false positives 2019-09-08 08:39:28 +02:00
El RIDO
5471757fa7 making webassembly optional, ensuring retry button works when wrong password is provided
Tested configurations:
- browser with WASM support (Firefox 68.0.2)
  - creates paste with zlib compression, no password
  - creates paste with zlib compression, with password
  - reads paste with zlib compression, no password
  - reads paste with zlib compression, with password + retry button works
  - reads paste without compression, no password
  - reads paste without compression, with password + retry button works
- browser without WASM support (Chromium 76.0.3809.100, started via `chromium-browser --js-flags=--noexpose_wasm`)
  - creates paste without compression, no password, but shows WASM warning
  - creates paste without compression, with password, but shows WASM warning
  - fails to read paste with zlib compression, no password + shows WASM error
  - fails to read paste with zlib compression, with password + shows WASM error
  - reads paste without compression, no password
  - reads paste without compression, with password + retry button works
2019-09-08 08:21:54 +02:00
El RIDO
7a85900b7c Merge branch 'master' into better-feature-detection 2019-09-07 11:25:50 +02:00
El RIDO
269def8300 Merge branch 'idarlund-patch-6' 2019-09-07 11:23:20 +02:00
Idar Lund
c992d10833 Update no.json
updated new lines to Norwegian
2019-09-04 12:21:04 +02:00
El RIDO
813e72d871 don't encode HTML entities in translations if they contain links 2019-08-28 20:37:14 +02:00
El RIDO
50881a75e6 ensure bots are prohibited completely from indexing 2019-08-28 20:36:26 +02:00
El RIDO
c56d777c11 fixing logic when there are no icons and warning icons, add more test cases 2019-08-28 20:29:23 +02:00
El RIDO
7f65fe9218 fixing conflicting icons when using error message div for warnings in bootstrap template 2019-08-28 19:25:11 +02:00
El RIDO
ad570c391a extend Alert class unit testing 2019-08-28 19:23:58 +02:00
El RIDO
a6aef109cc making feature detection work as intended in chrome 2019-08-27 23:16:06 +02:00
El RIDO
6fcd82fb85 making the feature detection more robust, let users with no WASM create uncompressed pastes, remove dead & duplicate code 2019-08-27 07:38:27 +02:00
El RIDO
ff68043c9f Merge branch 'Haocen-505-patch' 2019-08-25 18:16:17 +02:00
Haocen Xu
5877111ccb Update SRI 2019-08-25 12:03:37 -04:00
Haocen Xu
00b886c492 Refactor attachment editable logic to avoid undesired assumption 2019-08-25 12:00:59 -04:00
El RIDO
e242d87427 Merge branch 'Haocen-489,491,493,494' 2019-08-25 17:30:20 +02:00
El RIDO
271d4b680a updating changelog 2019-08-25 17:29:52 +02:00
El RIDO
ad096b80a1 refactoring logic, to make intention more clear and reduce complexity 2019-08-25 17:24:22 +02:00
Haocen Xu
b912c07cd1 Update SRI 2019-08-25 02:17:29 -04:00
Haocen Xu
ab75b183fb Fix click on new paste on clone paste editing view not removing custom
attachment

Fix cloning paste with attachment

Update CSP in sample and default configuration

Ensure clone paste also clone format

Fix clone button hiding logic when paste is burn after read

Remove attachment name when new paste clicked on

Enable file operation only when editing
2019-08-25 02:16:58 -04:00
El RIDO
121b1e75d2 remove debug statement, fixes #462 2019-08-24 08:42:33 +02:00
El RIDO
c77726b917 Merge branch 'Haocen-495', fixes #495 2019-08-23 07:02:54 +02:00
Haocen Xu
649c7aaa78 Fix bootstrap 3 support for modern high res monitors 2019-08-22 14:04:42 -04:00
Haocen Xu
6a79519641 Allow textarea to be resized vertically only 2019-08-22 13:55:52 -04:00
El RIDO
e4a0a8e82c Merge branch 'Haocen-317' 2019-08-21 19:04:16 +02:00
El RIDO
72565e48ff Merge branch '317' of https://github.com/Haocen/PrivateBin-Contribute into Haocen-317 2019-08-21 19:03:54 +02:00
Haocen Xu
ffac1adad6 Dropzone should be fixed to viewport, instead of fixed to sibling
element
2019-08-21 02:24:56 -04:00
El RIDO
d317cfbcc0 update SRI hashes 2019-08-21 07:17:24 +02:00
El RIDO
388655fdd1 Merge branch 'Haocen-317', fixes #317, fixes #487 2019-08-21 07:15:09 +02:00
El RIDO
b7b7aa3a47 credit were credit is due 2019-08-21 07:14:46 +02:00
Haocen Xu
2eed7a8a1c Update SRI
Remove dejavu
2019-08-17 15:39:13 -04:00
Haocen Xu
078b8d8fd6 Clear attachment if user cancel file select 2019-08-17 15:14:40 -04:00
Haocen Xu
3a9730f883 Improve file upload UX
Fix incorrect highlight logic

Fix transition on fileupload highlight

Handle drag leave

Fix draghover

Minor style improvements
2019-08-17 15:13:58 -04:00
El RIDO
30ddcacca6 fixing unit tests 2019-08-17 10:20:46 +02:00
El RIDO
1de315619b Merge branch 'macropin', fixes #485 2019-08-17 10:07:16 +02:00
El RIDO
e7fab8439d documenting showdown fix and incrementing library version to circumvent browser caching 2019-08-17 10:04:54 +02:00
El RIDO
f22449ffd1 Merge branch 'fix-showdown' of https://github.com/macropin/PrivateBin into macropin 2019-08-17 09:59:44 +02:00
El RIDO
962df90b24 Merge branch 'Haocen-479' 2019-08-17 09:40:43 +02:00
El RIDO
d351c7b734 documenting changes, fixes #354, fixes #479, fixes #484 2019-08-17 09:40:23 +02:00
El RIDO
84827e19c3 Merge branch '479' of https://github.com/Haocen/PrivateBin-Contribute into Haocen-479 2019-08-17 08:42:25 +02:00
El RIDO
b8196ee63c documented mobile UI change, fixes #477 2019-08-17 08:39:15 +02:00
El RIDO
e6e4facde0 Merge branch 'Haocen-477' 2019-08-17 08:31:07 +02:00
Haocen Xu
6ac425d468 Fix incorrect style on button 2019-08-15 14:58:27 -04:00
Andrew Cutler
49b358b1ee patch showdown.js to allow 100 nested spans. Ref https://github.com/PrivateBin/PrivateBin/issues/485 2019-08-15 13:41:41 +10:00
Haocen Xu
71931b0f18 Clear discussion if new/clone paste clicked 2019-08-14 20:40:50 -04:00
Haocen Xu
1af7b536a5 Fix an edge case where we cannot find any shortUrl 2019-08-14 00:06:51 -04:00
Haocen Xu
a5cd8696e6 Ensure shortener button re-enable after creating new paste 2019-08-13 21:55:35 -04:00
Haocen Xu
cd5ede5670 Enhance URL shortener integration, clear address bar when create new paste from existing paste 2019-08-13 21:44:53 -04:00
Haocen Xu
cb877e4494 447, Rework UX to address obscured send button and hard to click
shortener button
2019-08-13 19:21:26 -04:00
El RIDO
c66bff9d1b fixing travis CI builds for php 5.5, which require trusty 2019-07-27 08:19:01 +02:00
El RIDO
d63a0d10d3 fixing npm package version number 2019-07-27 08:11:29 +02:00
El RIDO
847c9e7355 better looking check mark 2019-07-27 07:47:03 +02:00
El RIDO
d33c89666d Merge branch 'security-md' 2019-07-27 07:43:41 +02:00
El RIDO
c8a9038f27 Merge branch 'master' into security-md 2019-07-27 07:43:16 +02:00
El RIDO
b65303dd71 update wording as suggested and version to latest release 2019-07-27 07:42:54 +02:00
El RIDO
8d323c1da4 document the applicability of RFC 1855 / Netiquette 2019-07-27 07:31:34 +02:00
Andreas Schneider
5c5de860e2 INSTALL: Creata a mediumblob for data in a paste
This allows to upload bigger pastes and pastes with attachments in the
v2 paste format.

Fixes #456
2019-07-12 10:07:22 +02:00
Andreas Schneider
da576baab9 Allow to upload bigger files
Signed-off-by: Andreas Schneider <asn@cryptomilk.org>
2019-07-12 09:03:14 +02:00
El RIDO
78225165ca Merge branch 'BigWax-patch-1' 2019-07-11 16:50:51 +02:00
El RIDO
b0d1a3949e add bulgarian to the supported languages 2019-07-11 16:50:32 +02:00
BigWax
1469d0c062 Create bg.json
Bulgarian translation
2019-07-10 16:06:55 +01:00
R4SAS
a1704b2dd9 [i18n] update russian translation 2019-07-10 02:43:00 +03:00
El RIDO
0780e5ace2 skip badges in release export 2019-07-08 20:05:58 +02:00
El RIDO
5d7658b58f switching to pre-rendered logo 2019-07-08 20:00:32 +02:00
El RIDO
1e2014b9fa fixing configuration test generator after PHP refactoring 2019-07-08 19:56:05 +02:00
El RIDO
07018e5876 incrementing version number in preparation of release 2019-07-08 18:35:34 +02:00
El RIDO
6df5127132 move badges to separate document due to data privacy concerns for visitors of the projects main page 2019-07-08 18:20:09 +02:00
El RIDO
8ae87d8653 translate new strings to German 2019-07-07 10:39:14 +02:00
El RIDO
d8ba1b1462 Merge branch 'Quenty31-master' 2019-07-07 10:09:25 +02:00
Quentí
07e0b267f9 Update and corrections
Use of è form for correctly corrèctament
Use of subjunctive after "in case", se per cas + subjectiu
2019-07-06 21:02:58 +02:00
El RIDO
ae456bf7a1 Merge branch 'yvisherve-patch-1' 2019-07-04 06:26:01 +02:00
El RIDO
57417c08cf revert formatting changes for better comparison 2019-07-04 06:25:21 +02:00
Hervé Yvis
943b6bdfc3 Upgrade french translation
Translation of untranslated sentences + Improved translation of one sentence
2019-07-02 01:08:47 +02:00
El RIDO
c707c87cac addressing rngState 0ef2c5e06719a8b43d 2019-06-27 21:37:40 +02:00
El RIDO
2cbf528894 fixing failing unit tests in travisCI 2019-06-27 21:18:46 +02:00
El RIDO
11375a4f59 moved referrer policy from CSP & meta to proper HTTP header to avoid browser console error message about unknown CSP header and to ensure it always applies before HTML is parsed, fixes #196 2019-06-27 20:31:10 +02:00
El RIDO
67b9b5f0d8 correcting old browser detection logic, fixes #446 2019-06-27 20:11:22 +02:00
El RIDO
fdc532b3c1 simplify npm install instructions 2019-06-24 07:41:12 +02:00
El RIDO
ddb1c550f5 remove alerts when missing showdown & prettify libraries, if the are missing it is intentionally done in the configuration, fixes #237 2019-06-23 19:55:25 +02:00
El RIDO
c2e060d464 made compression configurable, fixes #38 2019-06-23 19:45:40 +02:00
El RIDO
848d3563f4 making StyleCI & Scrutinizer happy 2019-06-23 16:10:05 +02:00
El RIDO
47944ba3b1 updating DOMpurify to 1.0.11, fixes #442 2019-06-23 12:15:36 +02:00
El RIDO
8dc9db90c9 added translation for Czech, provided by @info-path, fixes #424 2019-06-23 12:06:36 +02:00
El RIDO
c9680ed741 Merge branch 'brunob-patch-1' 2019-06-23 11:41:14 +02:00
El RIDO
5a1adea050 Merge branch 'patch-1' of https://github.com/brunob/PrivateBin into brunob-patch-1 2019-06-23 11:39:55 +02:00
El RIDO
f5fee9b44a Merge branch 'httpinsecure' 2019-06-23 11:34:18 +02:00
El RIDO
40493dfb3a simplify logic, adding test cases for all combinations of URLs that are regarded as secure context 2019-06-23 10:38:08 +02:00
El RIDO
61fde53de0 adding IPv6 localhost to exceptions 2019-06-23 09:56:18 +02:00
El RIDO
dc193f7555 Revert "removing exceptions - in these cases server admins can opt to disable the warning message in the configuration"
This reverts commit d0365faf76.
2019-06-23 09:54:48 +02:00
El RIDO
d9f27fb004 avoid instability of tests due to Alert callback testing, which can prevent notifications from getting displayed 2019-06-23 09:39:21 +02:00
El RIDO
603f7fd911 adding tests for all cases 2019-06-22 15:44:54 +02:00
El RIDO
59153633b8 adding test for bot UAs 2019-06-22 09:12:31 +02:00
El RIDO
d0365faf76 removing exceptions - in these cases server admins can opt to disable the warning message in the configuration 2019-06-22 08:39:46 +02:00
El RIDO
57bd65225d added new translation strings, moved URLs out of translations as they are static and it makes translation more compact 2019-06-22 07:52:18 +02:00
El RIDO
58fa7c987d password modal is used in all flavors of the bootstrap theme 2019-06-22 07:50:25 +02:00
rugk
b7db033bdd Adjust config text 2019-06-21 19:50:40 +02:00
rugk
e5974d4663 Prefer isSecureContext if available 2019-06-21 19:48:16 +02:00
rugk
a1b1efeae2 Adjust messages 2019-06-21 19:03:45 +02:00
b_b
59dc413829 Fix #443
fix expiration/formater dropdown with bootstrap-compact template
2019-06-21 17:21:40 +02:00
El RIDO
50cc6995e0 making use of the URL object in the existing tests 2019-06-20 22:30:49 +02:00
El RIDO
1958a55651 adding new dev dependency to support the URL object 2019-06-20 21:38:29 +02:00
El RIDO
77419ec2c1 Merge branch 'master' into httpinsecure 2019-06-20 21:01:00 +02:00
El RIDO
e9ce8ca1a0 fixing font paths 2019-06-18 22:54:21 +02:00
El RIDO
b1be74a56f support processing of Error types in notifications, adresses #441 2019-06-18 19:45:52 +02:00
El RIDO
42c2003220 made notice configurable, fixing a few CSS glitches 2019-06-17 21:40:37 +02:00
El RIDO
a67c9ab129 reworded the message, added the missing translation strings 2019-06-17 21:18:30 +02:00
El RIDO
fc914b4b84 moved bad bot check into InitialCheck, changed old ie notice into generic update warning, when unsupported user agent is detected and made the other IE alert show in all versions as it is now entirely unsupported 2019-06-17 21:09:21 +02:00
El RIDO
748b85e025 Merge branch master into httpinsecure 2019-06-17 19:51:33 +02:00
El RIDO
7ab6411f71 updated credits & change log 2019-06-16 13:38:03 +02:00
El RIDO
4d6897f063 increasing minimum PHP version to 5.5 as this is required by the yzalis/identicon library upgrade to version 1.2.0 2019-06-16 10:50:52 +02:00
El RIDO
8515c9d223 upgrading DOMpurify library 2019-06-16 10:23:14 +02:00
El RIDO
8a69411d50 upgrading showdown library 2019-06-16 10:19:44 +02:00
El RIDO
49e118a8b3 updated kjua library 2019-06-16 10:13:53 +02:00
El RIDO
3259cabfb3 revert bootstraps JS to 3.3.7 as 3.4.1 breaks the navbar toggle 2019-06-16 10:06:01 +02:00
El RIDO
b527bc6208 upgrade jQuery library 2019-06-16 09:30:59 +02:00
El RIDO
0a88b3043c upgrading bootstrap CSS 2019-06-16 09:27:11 +02:00
El RIDO
66cee9dbd2 adding icon generator comparison test script for reference in #148 2019-06-16 09:16:50 +02:00
El RIDO
db4ae09ee3 upgraded PHP libraries 2019-06-16 07:10:24 +02:00
El RIDO
362045c664 re-add data-URLs to CSP for img-src, as these are used for the comment icons 2019-06-16 07:06:58 +02:00
El RIDO
cd72110ea4 Merge branch 'blob-uri' 2019-06-15 09:49:20 +02:00
El RIDO
b4ceb4078d removed obsolete code and comments, tested with a PDF of 9 MiB and it works fine in Firefox and Chrome 2019-06-15 09:47:55 +02:00
El RIDO
f915af1a5a adjust CSP header to allow blob URLs 2019-06-15 09:36:09 +02:00
El RIDO
451a4817c4 replace data-URL method usage with blob-URL one 2019-06-15 09:35:26 +02:00
El RIDO
6cf52f4cf3 mocking window.URL.createObjectURL to have tests working with blob URLs 2019-06-15 08:56:47 +02:00
R4SAS
abd71413c3 Store Blob URL in variable 2019-06-12 06:29:36 +03:00
R4SAS
d3f9670bc2 Remove data length detection, because we work with URL 2019-06-12 06:05:55 +03:00
R4SAS
dcbefcc1c3 Use blob for previews 2019-06-12 05:29:19 +03:00
R4SAS
ff6b9bd8f9 Use blob URI for saving attachments (#432) 2019-06-12 04:37:17 +03:00
El RIDO
a459c4692c correcting API use, avoid history glitch 2019-06-01 23:49:40 +02:00
El RIDO
ebbb850b27 clone array instead of passing the reference, adresses #436 2019-05-31 07:05:40 +02:00
El RIDO
87c7719513 Merge branch 'webcrypto' 2019-05-26 21:07:21 +02:00
El RIDO
c4b84b2b6b extract version logic into paste & comment classes 2019-05-25 13:20:39 +02:00
El RIDO
d73c68ad85 insert Paste class to wrap the data, to be able to extend the paste with getters and format version handling 2019-05-25 10:10:59 +02:00
El RIDO
a270cd818a create security.md for new Github security feature 2019-05-23 17:06:33 +02:00
El RIDO
398fabd664 Chrome requires unsafe-eval for it to parse and evaluate WASM modules 2019-05-20 18:29:37 +02:00
El RIDO
b44e729a1a fixing display of version 1 pastes without attachments 2019-05-19 13:31:17 +02:00
El RIDO
12a9b2ff8e address Scrutinizer issues with the use of getParams method 2019-05-19 10:13:47 +02:00
El RIDO
1baa1c2b0a fixing API doc issue found by Scrutinizer 2019-05-19 10:05:04 +02:00
El RIDO
800a0df8e3 apply StyleCI patch 2019-05-19 10:01:41 +02:00
El RIDO
353d08daf6 handle regression due to base58 stripping NULL bytes, discovered via JSVerify RNG state 0dec6b2a5f04d19873 2019-05-19 09:54:40 +02:00
El RIDO
909ff2daa7 handle scrutinizer issues (mostly changes in API documentation) 2019-05-19 09:42:55 +02:00
El RIDO
8fd3e680e4 base58 will left trim NULL bytes, handling JSVerify RNG state 0dec6b2a5f04d19873 2019-05-19 09:05:56 +02:00
El RIDO
86b4e0e7a4 revert autoformatting applied by IDE 2019-05-19 08:43:07 +02:00
El RIDO
d785ada3fe apply StyleCI patch 2019-05-19 08:36:37 +02:00
El RIDO
3b0ab7e99f fixing regression handling v1 key format (un-decoded base64) 2019-05-19 08:36:18 +02:00
El RIDO
0e71211fad v2 paste can successfully en- and decrypt the particular message, fixes #260 2019-05-19 08:25:34 +02:00
El RIDO
7111e38898 Merge branch 'empty-paste' into webcrypto 2019-05-19 07:52:37 +02:00
El RIDO
6f480bf014 Merge branch 'master' into webcrypto, implementing base58, fixes #377 2019-05-15 21:20:54 +02:00
El RIDO
5779d87788 integrating compression test case that failed in rawdeflate in webcrypto + zlib testing, proving this fixes #328 2019-05-15 18:56:42 +02:00
El RIDO
e77eb1de13 Merge branch 'truncation' into webcrypto 2019-05-15 18:44:26 +02:00
El RIDO
09162a3c57 fix display of v2 pastes in JS, fixing parsing of comments in PHP, avoid exposing expiration date (we provide time_to_live, would allow calculation of creation date of paste) 2019-05-15 07:44:03 +02:00
El RIDO
cc1c55129f switching to full JSON API without POST array use, ensure all JSON operations are done with error detection 2019-05-13 22:31:52 +02:00
El RIDO
be1e7babc0 removing dead code and improving code coverage 2019-05-11 22:18:35 +02:00
El RIDO
5b67721a6a preventing tests being included in release 2019-05-11 20:56:35 +02:00
El RIDO
dfb16ea61d switching to JS code coverage nyc, maintained fork of istanbul 2019-05-11 20:51:18 +02:00
El RIDO
ccdcf4cefa fix formatting 2019-05-11 19:57:13 +02:00
El RIDO
50af37507f fixing v2 TTL 2019-05-11 10:46:30 +02:00
El RIDO
788ea67b49 fixing server interaction in JS, simple pastes now work 2019-05-11 10:39:42 +02:00
El RIDO
5b3286df4d making zlib usable in browsers 2019-05-11 10:38:14 +02:00
El RIDO
20befe4bd6 revert errors on STDOUT 2019-05-11 10:37:29 +02:00
El RIDO
a622c8f484 fix logic, avoid 5.5 2019-05-10 23:27:45 +02:00
El RIDO
c3719435a3 and fixing PHP 5.5 2019-05-10 23:09:35 +02:00
El RIDO
7598b28a4a handling older versions in testing 2019-05-10 22:57:55 +02:00
El RIDO
02f3cc739f documentation on fnv1a64 is lacking, but tests show it was only introduced with PHP 5.6 2019-05-10 22:46:39 +02:00
El RIDO
9b6b25dac0 revert scalar type hints to retain support for PHP < 7.0 2019-05-10 22:35:18 +02:00
El RIDO
76007b6ee9 fixing class compatibility (why is this no longer enforced in PHP > 7.1?) 2019-05-10 22:21:03 +02:00
El RIDO
f58cbefd1e revert scalar type hints to retain support for PHP < 7.0 2019-05-10 22:13:11 +02:00
El RIDO
fb0c9c595e remove further type hints for compatibility 2019-05-10 22:04:47 +02:00
El RIDO
b1d35057cc remove further type hints for compatibility 2019-05-10 22:00:34 +02:00
El RIDO
bd4dee0f3e fixing copy/paste errors 2019-05-10 21:52:14 +02:00
El RIDO
1e44902340 apply StyleCI patch 2019-05-10 21:45:34 +02:00
El RIDO
632d70412a revert scalar type hints to retain support for PHP < 7.0 2019-05-10 21:35:36 +02:00
El RIDO
0f42bd818f quiescing JS unit tests 2019-05-10 21:01:34 +02:00
El RIDO
700f8a0ea7 made all php unit tests pass again 2019-05-10 07:55:39 +02:00
El RIDO
59569bf9fc working on JsonApi tests 2019-05-08 22:11:21 +02:00
El RIDO
7f1afb2b3e unifying MIT licenses, diff showed them to be identical 2019-05-08 19:06:26 +02:00
El RIDO
fcf9cf63b5 Merge branch 'HLeithner-base58' 2019-05-08 19:01:02 +02:00
El RIDO
54d21a7803 making base-x compatible with node & browser 2019-05-08 19:00:22 +02:00
El RIDO
b12a099e29 updating license document to include base-x' MIT license 2019-05-08 18:32:45 +02:00
Harald Leithner
4aab3c0061 Encode key as base58 2019-05-08 15:25:42 +02:00
El RIDO
76dc01b959 finishing changes in models, removing last md5 test cases, tightening up allowed POST data 2019-05-06 22:15:21 +02:00
El RIDO
06b90ff48e sticking to arrays to reduce conversions, inversion of control to simplify logic 2019-05-05 21:03:58 +02:00
El RIDO
b7a03cfdb9 enforcing parameter types, avoiding unnecessary metadata in version 2 pastes 2019-05-05 18:22:57 +02:00
El RIDO
6e15903f1e make DatabaseTest work pass again, support reading & writing version 1 & 2 pastes & comments 2019-05-05 14:36:47 +02:00
El RIDO
bbdcb3fb0f remove duplicate code 2019-05-05 08:53:40 +02:00
El RIDO
3338bd792e implement version 2 format validation, changing ID checksum algorithm, resolves #49 2019-05-03 23:03:57 +02:00
El RIDO
ed676acac3 breaking all the things (by replacing v1 with v2 formats) 2019-05-03 20:51:01 +02:00
El RIDO
5652a43d1d adding js test to generate v2 example pastes to be used in the development of the server side logic, adding one of these into the helper class of the php tests 2019-04-16 07:45:04 +02:00
El RIDO
eeca365e18 Merge branch 'master' into webcrypto 2019-03-25 20:18:10 +01:00
El RIDO
0e18b5d0c1 Merge branch 'billux-master' 2019-03-25 20:13:29 +01:00
Romain Dessort
0033f39b85 Fix #413. Exclude Let's Encrypt bot from blacklisted bots 2019-03-24 09:50:04 -04:00
rugk
d8616d1e68 Merge branch 'AreYouLoco-master' 2019-03-10 11:13:35 +01:00
AreYouLoco
8ea7c4cda6 Update polish translation. 2019-03-08 23:03:07 +01:00
rugk
742add3d1e Merge branch 'Quenty31-patch-3' 2019-02-25 21:13:47 +01:00
Quentí
e01179653f Update: added QR code 2019-02-25 20:45:59 +01:00
El RIDO
a60b86691e Merge branch 'master' into webcrypto, fix nvm 2019-02-23 07:20:34 +01:00
El RIDO
ec698681aa Merge branch 'ff98sha-patch-1' 2019-02-23 07:17:56 +01:00
El RIDO
2a9d2f9993 Merge branch 'patch-1' of https://github.com/ff98sha/PrivateBin into ff98sha-patch-1 2019-02-23 07:15:20 +01:00
El RIDO
fd33cc8206 switch to newer node version, in an attempt to support mocha 6 2019-02-23 07:06:39 +01:00
ff98sha
9c3a4cebd4 Update zh.json
Modify translations and translate new strings.
2019-02-22 22:56:13 +08:00
rugk
ba3efefc7b Add warning for insecure HTTP 2019-02-13 11:59:07 +01:00
El RIDO
e418b083e8 Merge branch 'master' into webcrypto 2019-01-22 20:11:42 +01:00
El RIDO
48560e3d60 Merge branch 'fb-tracking-param-fix' 2019-01-22 20:06:04 +01:00
rugk
34c64acb75 Apply StyleCi recommendation 2019-01-22 00:14:31 +01:00
rugk
c2a46b7af7 Make JS function more robust 2019-01-22 00:07:28 +01:00
rugk
99d49a56ba Fix PHPunit tests 2019-01-21 23:49:33 +01:00
rugk
7cb942aca3 Make PHP paste ID function more robust 2019-01-21 23:19:41 +01:00
rugk
541fff199a Put PHP paste request into own function 2019-01-21 23:06:25 +01:00
El RIDO
6beea8f2f4 apply yet another StyleCI recommendations 2019-01-20 12:29:27 +01:00
El RIDO
e3d7ac4442 apply StyleCI recommendations 2019-01-20 12:28:03 +01:00
El RIDO
79a858f176 extracting only the 16 hex characters of the query string as paste ID, addressing #396 2019-01-20 12:20:37 +01:00
El RIDO
cc53d95ed1 extending test cases to reproduce the issue from #396, causing the existing logic to now fail the tests 2019-01-20 11:05:34 +01:00
El RIDO
5e4c6b5770 Merge branch 'master' into webcrypto 2019-01-07 21:29:14 +01:00
El RIDO
6bb599c81f Merge branch 'Ahuahuachi' 2019-01-07 21:18:49 +01:00
Alfredo Fabián Altamirano
8f52173ec3 Translate new parameters 2019-01-07 21:13:37 +01:00
Alfredo Fabián Altamirano
287130dd37 Add missing translation for "QR code" 2019-01-07 21:11:19 +01:00
El RIDO
ec68abe2b5 revert formatting changes, for easier comparison of changes 2019-01-07 21:02:51 +01:00
Alfredo Fabián Altamirano
ce87b1cc39 Improved Spanish translation 2019-01-05 16:08:43 -06:00
El RIDO
0ee86f33da key in version 2 is raw value instead of base64 (which reduces its complexity), made PasteDecryptor support both versions of the format, refactoring method names, replacing var by let / const, reducing zlib compression level from 9 to 7 to half the time spent on compression 2018-12-29 18:40:59 +01:00
El RIDO
be69e4a50f simplify password catenation in version 2, to avoid potential key derivation weakening 2018-12-28 05:49:34 +01:00
El RIDO
0ad5b3e900 implement zlib via web assembly, replacing rawdeflate library 2018-12-27 21:32:13 +01:00
El RIDO
5ce3aa2817 increase PBKDF2 iterations further, as suggested in #350 2018-12-25 20:19:57 +01:00
El RIDO
210870590c improving cleanup between tests in order to combat the frequent test failures seen recently 2018-12-25 20:16:41 +01:00
El RIDO
0ab06e34ec initial refactoring for support of version 2 paste format, some cleanup on the side 2018-12-25 17:34:39 +01:00
El RIDO
f3165f0cab suppress current jsDOMs errors 2018-12-25 17:17:49 +01:00
El RIDO
70007285bf remove console suppression, fixing I18n mock 2018-12-25 16:42:18 +01:00
El RIDO
4edbb66c91 re-add CreationTime, still used in comment 2018-12-24 08:20:39 +01:00
El RIDO
3883e3fb30 adjusting test to make it work in latest jsDOM versions that don't support arbitrary bytes in a URLs hash anymore 2018-12-24 08:19:58 +01:00
El RIDO
9348cbe2a1 address security concerns reg. paste creation date by removing it in the API, keep comment creation date exposed, displayed in discussion - resolves #390 2018-12-23 20:10:24 +01:00
El RIDO
2bb3df5bee adressing rngStates 013286cb47a0f51d9e & 83975e102a4db8f3c6 that frequently fail in latest jsDOM env, showing URL hashes can't contain certain unicode sequences after all 2018-12-18 06:04:17 +01:00
El RIDO
1de57c874e reduce duplication in format 2018-12-17 21:42:49 +01:00
El RIDO
e64eaf45ee Merge branch 'master' into webcrypto 2018-12-17 21:34:15 +01:00
El RIDO
c39e578f04 Merge branch 'micschwarz-patch-1' 2018-12-17 21:31:43 +01:00
El RIDO
c15351b793 designing v2 paste & comment format 2018-12-17 19:43:16 +01:00
El RIDO
cde96d8f24 fixing bug in jsonld processing with certain URL paths 2018-12-17 19:42:26 +01:00
Michael Schwarz
e220a97c8f Improve German Translation for more consistency 2018-11-27 11:03:12 +01:00
El RIDO
fe670dc94f Merge pull request #378 from PrivateBin/googlespy
Ask Google not to translate the page
2018-11-22 09:10:07 +01:00
rugk
ac9eac5ed6 Ask google not to translate the page
We already have i18n. Furthermore, Google may analyse sensitive content for
the purpose of recognising whether the page needs to be translated, see
https://support.google.com/webmasters/answer/79812?hl=en

Ref https://github.com/threema-ch/threema-web/pull/681
2018-11-21 23:32:06 +01:00
El RIDO
2303c81ce0 Merge branch 'master' into webcrypto 2018-11-19 13:15:11 +01:00
El RIDO
9ce41022cf correcting namespaces 2018-11-19 13:09:34 +01:00
El RIDO
b36b3d1a82 Merge branch 'master' into webcrypto 2018-11-16 18:36:07 +01:00
El RIDO
18151e6e9e Merge branch 'Quenty31-patch-2' 2018-11-16 18:05:26 +01:00
El RIDO
30bb34a4fe generate code docs for private interfaces, too 2018-11-16 18:04:09 +01:00
Quentí
7a5a97c6ae Update translation 2018-11-15 22:17:08 +01:00
rugk
8b803a1f5d Merge branch 'dan-nkl-patch-1' 2018-11-08 22:23:36 +01:00
rugk
3885047cb6 Update i18n/de.json
Co-Authored-By: dan-nkl <daniel@nikul.in>
2018-11-07 08:38:35 +01:00
Daniel Nikulin
419311dffa Update de.json
Better translations for German..
At least I think they are easier to understand.
2018-10-30 19:06:12 +01:00
rugk
9cce056cc8 Merge branch 'shrz-Fix-Ru-translation' 2018-10-28 20:04:16 +01:00
shrz
6f34626ad6 Fix Russian translation. 2018-10-28 18:20:54 +03:00
El RIDO
5b00f4ead7 further code deduplication 2018-10-20 23:08:13 +02:00
El RIDO
4c3fb3fe63 reduce code duplication 2018-10-20 22:34:36 +02:00
El RIDO
717e5b0e57 addressing issues found by codacy 2018-10-20 22:05:35 +02:00
El RIDO
0f76b9066d remove SJCL library 2018-10-20 19:53:21 +02:00
El RIDO
2d7996570e typos, documentation 2018-10-20 17:57:21 +02:00
El RIDO
2929d5c17a fixing async comment nicknames 2018-10-20 13:54:17 +02:00
El RIDO
a08fed1add ensure promises can be collected 2018-10-20 12:40:08 +02:00
El RIDO
35045bb69a improving error handling 2018-10-20 11:40:37 +02:00
El RIDO
100d955e1a address decryptComments() async compatibility 2018-10-20 10:20:32 +02:00
El RIDO
ff8ec5a1a0 address decryptOrPromptPassword(), decryptPaste() and decryptAttachment() async compatibility 2018-10-20 09:56:05 +02:00
El RIDO
c0d3b9062b updating SRI hashes 2018-10-20 08:40:48 +02:00
rugk
17131f3172 Add verys important return to ensure Promise chain works 2018-10-08 21:04:13 +02:00
rugk
746debf586 Adjust functions using Uploader.setData to handle promises 2018-10-08 21:03:10 +02:00
rugk
94a352e7f5 Fix eslint config and issues
Note EcmaScript 2017 looks recent amd also is, e.g. we loose suport for IE and we loose support for some Android browsers, also Android <5 built-in browser.
2018-10-08 20:36:50 +02:00
El RIDO
bc0fb5b91e Merge branch 'master' into webcrypto 2018-10-02 20:43:40 +02:00
El RIDO
00692a29d6 Merge branch 'SuperTux88-fix-dark-download-link' 2018-10-02 20:42:38 +02:00
Benjamin Neff
538462f134 Fix download-link color in dark boostrap themes
This makes the "Download attachment" link white in bootstrap-dark and
boostrap-dark-page. This is an upstream bug of darkstrap, but it's not
maintained anymore.
2018-10-02 02:06:44 +02:00
El RIDO
b62e259cfb Merge branch 'master' into webcrypto 2018-09-17 05:26:58 +02:00
El RIDO
034d60f966 Merge branch 'EmilKra-patch-1' 2018-09-17 05:26:15 +02:00
EmilKra
256a5b2450 Update pl.json 2018-09-16 16:50:44 +02:00
El RIDO
41c54325fa Merge branch 'master' into webcrypto 2018-09-16 16:24:15 +02:00
El RIDO
f9e0b7236c Merge branch 'EmilKra-patch-1' 2018-09-16 16:23:27 +02:00
EmilKra
dcee0c7d39 Update pl.json 2018-09-16 14:43:44 +02:00
El RIDO
762386efd7 reverting to promises, since done can cause timeouts, indicating that the async execution can be really slow 2018-09-02 12:12:55 +02:00
El RIDO
f3eaee206c using done() instead of promise, to enforce mocha to wait on the tests 2018-09-02 11:52:57 +02:00
El RIDO
176264f135 making tests use promises instead of async 2018-09-02 11:49:55 +02:00
El RIDO
b791157717 fix unit tests after merge from master, issues due to newly async tests that cause environment changes across test scripts 2018-09-02 11:33:27 +02:00
El RIDO
b191e2c437 Merge remote-tracking branch 'origin/master' into webcrypto 2018-09-02 10:07:57 +02:00
El RIDO
d66800b8ce docker is now provided via https://github.com/PrivateBin/docker-nginx-fpm-alpine 2018-09-02 09:22:55 +02:00
El RIDO
8b71cb0b2f properly escaping HTML in raw text mode, fixes #358 2018-09-02 09:14:36 +02:00
El RIDO
30b7be0781 async test, finding error for rngState 00b15fc0a8247e693d, due to failure in decompressing 2018-09-01 22:55:52 +02:00
El RIDO
b97ac08003 improving tests, correcting cipher 2018-09-01 22:22:10 +02:00
El RIDO
0dbbb61d11 implementing web crypto API for encryption 2018-09-01 19:42:22 +02:00
rugk
fe7fa09ce8 Merge branch 'idarlund-patch-5' 2018-08-14 17:56:18 +02:00
idarlund
5f8aeabea0 Update no.json
update missing text for getting paste data
2018-08-14 13:01:46 +02:00
El RIDO
bd6888687f Merge branch 'master' into webcrypto 2018-08-14 06:59:47 +02:00
El RIDO
c4fc7edc43 replacing Base64.js with browser built in's, except for legacy paste support 2018-08-05 08:56:03 +02:00
El RIDO
6f25d651b7 switching to client side libraries for key generation, remove legacy browser support 2018-08-04 22:30:01 +02:00
El RIDO
c9a3bb08ee remove dead code 2018-08-04 17:49:08 +02:00
El RIDO
4f332b7719 revert legacy browser support, dropped in favour of webcrypto API 2018-08-04 17:25:59 +02:00
El RIDO
c76957b3cb adding unit test for truncation issue #328 2018-06-26 22:31:26 +02:00
El RIDO
b40e6305ca Merge branch 'master' into empty-paste 2018-02-27 05:20:04 +01:00
El RIDO
5582c05414 decrypting a particular message encrypted with v1.1.1 fails (#260) 2017-12-10 07:04:54 +01:00
El RIDO
ee8ffdc51b en- & decrypting the particular message works without issues 2017-12-10 07:02:32 +01:00
155 changed files with 12046 additions and 5194 deletions

View File

@@ -1,18 +0,0 @@
# Documentation, might leak version number
CHANGELOG.md
LICENSE.md
CREDITS.md
INSTALL.md
README.md
doc/
# Dotfiles, pointless
.codeclimate.yml
.csslintrc
.editorconfig
.eslint*
.git*
.php_cs
.styleci.yml
.travis.yml
.github

View File

@@ -1,3 +1,7 @@
---
parserOptions:
ecmaVersion: 2017
ecmaFeatures:
modules: true
jsx: true
@@ -8,18 +12,16 @@ env:
es6: true
jquery: true
node: true
mocha: true
globals:
sjcl: false
DOMPurify: false
after: true
before: true
cleanup: true
describe: false
it: false
jsc: false
jsdom: true
kjua: true
DOMPurify: readonly
cleanup: writable
describe: readonly
jsc: readonly
jsdom: writable
kjua: writable
WebCrypto: writable
# http://eslint.org/docs/rules/
rules:

10
.gitattributes vendored
View File

@@ -1,10 +1,12 @@
doc/ export-ignore
tst/ export-ignore
img/browserstack.svg export-ignore
js/.istanbul.yml export-ignore
js/.nycrc.yml export-ignore
js/common.js export-ignore
js/test/ export-ignore
.codeclimate.yml export-ignore
.csslintrc export-ignore
.dockerignore export-ignore
.editorconfig export-ignore
.eslintignore export-ignore
.eslintrc export-ignore
@@ -16,7 +18,7 @@ js/test/ export-ignore
.php_cs export-ignore
.styleci.yml export-ignore
.travis.yml export-ignore
Dockerfile export-ignore
docker-compose.yml export-ignore
docker/ export-ignore
composer.json export-ignore
composer.lock export-ignore
BADGES.md export-ignore
CODE_OF_CONDUCT.md export-ignore

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

4
.gitignore vendored
View File

@@ -12,10 +12,6 @@ data/
doc/*
!doc/*.md
# Ignore developers composer status so it isn't accidentally checked in,
# see https://github.com/PrivateBin/PrivateBin/issues/84
composer.lock
# Ignore vendor dir of Composer except PHP files
vendor/*.*
vendor/*/*.*

View File

@@ -1,3 +1,12 @@
RewriteEngine on
RewriteCond !%{HTTP_USER_AGENT} "Let's Encrypt validation server" [NC]
RewriteCond %{HTTP_USER_AGENT} ^.*(bot|spider|crawl|https?://|WhatsApp|SkypeUriPreview|facebookexternalhit) [NC]
RewriteRule .* - [R=403,L]
<IfModule mod_php7.c>
php_value max_execution_time 30
php_value post_max_size 10M
php_value upload_max_size 10M
php_value upload_max_filesize 10M
php_value max_file_uploads 100
</IfModule>

View File

@@ -2,7 +2,7 @@
"bitwise": true,
"curly": true,
"eqeqeq": true,
"esversion": 5,
"esversion": 6,
"forin": true,
"freeze": true,
"futurehostile": true,
@@ -39,7 +39,6 @@
"window": true
},
"globals": {
"sjcl": true,
"DOMPurify": true,
"kjua": true
}

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

@@ -1,22 +1,22 @@
language: php
sudo: false
php:
- '5.4'
- '5.5'
- '5.6'
- '7.0'
- '7.1'
- '7.2'
- '7.3'
- '7.4'
# as this is a php project, node.js v4 (for JS unit testing) isn't installed
# as this is a php project, node.js (for JS unit testing) isn't installed
install:
- if [ ! -d "$HOME/.nvm" ]; then mkdir -p $HOME/.nvm && curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | NVM_METHOD=script bash; fi
- source ~/.nvm/nvm.sh && nvm install 4
- if [ ! -d "$HOME/.nvm" ]; then mkdir -p $HOME/.nvm && curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.34.0/install.sh | NVM_METHOD=script bash; fi
- source ~/.nvm/nvm.sh && nvm install --lts
before_script:
- rm composer.lock
- composer install -n
- npm install -g mocha
- cd js && npm install jsverify jsdom@9 jsdom-global@2 mime-types
- cd js && npm install
script:
- mocha

11
BADGES.md Normal file
View File

@@ -0,0 +1,11 @@
# Badges
[![Build Status](https://travis-ci.org/PrivateBin/PrivateBin.svg?branch=master)](https://travis-ci.org/PrivateBin/PrivateBin) [![Build Status](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/badges/build.png?b=master)](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/build-status/master)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/094500f62abf4c9aa0c8a8a4520e4789)](https://www.codacy.com/app/PrivateBin/PrivateBin)
[![Code Climate](https://codeclimate.com/github/PrivateBin/PrivateBin/badges/gpa.svg)](https://codeclimate.com/github/PrivateBin/PrivateBin)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/?branch=master)
[![SensioLabsInsight](https://insight.sensiolabs.com/projects/57c9e74e-c6f9-4de6-a876-df66ec2ea1ff/mini.png)](https://insight.sensiolabs.com/projects/57c9e74e-c6f9-4de6-a876-df66ec2ea1ff)
[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/094500f62abf4c9aa0c8a8a4520e4789)](https://www.codacy.com/app/PrivateBin/PrivateBin)
[![Test Coverage](https://codeclimate.com/github/PrivateBin/PrivateBin/badges/coverage.svg)](https://codeclimate.com/github/PrivateBin/PrivateBin/coverage) [![Code Coverage](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/?branch=master)
[![BrowserStack - cross browser testing](img/browserstack.svg)](https://www.browserstack.com/)

View File

@@ -1,6 +1,62 @@
# PrivateBin version history
* **1.3 (not yet released)**
* **1.4 (not yet released)**
* CHANGED: Minimum required PHP version is 5.6, due to a change in the identicon library and to use php's native hash_equals()
* CHANGED: Upgrading libraries to: identicon 2.0.0
* **1.3.3 (2020-02-16)**
* 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.2.3 (2020-02-16)**
* CHANGED: Upgrading libraries to: DOMpurify 2.0.8
* 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)
* CHANGED: Enhanced URL shortener integration (#479)
* CHANGED: Improved file upload drag & drop UI (#317)
* CHANGED: Increased default size limit from 2 to 10 MiB, switch data from BLOB to MEDIUMBLOB in MySQL (#458)
* CHANGED: Upgrading libraries to: DOMpurify 2.0.1
* FIXED: Enabling browsers without WASM to create pastes and read uncompressed ones (#454)
* FIXED: Cloning related issues (#489, #491, #493, #494)
* FIXED: Enable file operation only when editing (#497)
* FIXED: Clicking 'New' on a previously submitted paste does not blank address bar (#354)
* FIXED: Clear address bar when create new paste from existing paste (#479)
* FIXED: Discussion section not hiding when new/clone paste is clicked on (#484)
* FIXED: Showdown.js error when posting svg qrcode (#485)
* FIXED: Failed to handle the case where user cancelled attachment selection properly (#487)
* FIXED: Displaying the appropriate errors in older browsers (#508)
* **1.3 (2019-07-09)**
* ADDED: Translation for Czech (#424)
* ADDED: Threat modeled the application (#177)
* ADDED: Made compression configurable (#38)
* CHANGED: Minimum required PHP version is 5.5, due to a change in the identicon library
* CHANGED: Minimum required browser versions are Firefox 54, Chrome 57, Opera 44, Safari 11, Edge 16, due to use of WebCrypto API, async/await, ES6 & WebAssembly features - all Internet Explorer versions are incompatible
* CHANGED: JSON and encryption formats were changed to replace SJCL library by browser integrated WebCrypto API (#28, #74)
* CHANGED: Replaced rawdeflate.js with zlib.wasm to resolve decompression failures and gain compatibility with standard deflate implementations (#193, #260, #328, #434, #440)
* CHANGED: Increase PBKDF2 iterations to 100k (#350)
* CHANGED: Replaced last use of MD5 with FowlerNollVo checksum which produces the exact length we need for the paste ID (#49)
* CHANGED: Simplified some PHP code & renamed PrivateBin class into Controller, to make MVC pattern use more obvious (#342)
* CHANGED: Upgrading libraries to: identicon 1.2.0, random_compat 2.0.18, jQuery 3.4.1, Showdown 1.9.0, DOMpurify 1.0.11 & kjua 0.6.0
* FIXED: Prevent Chrome from sending content of paste to Google for translation (#378)
* FIXED: To support attachments larger then 2 MiB in newer Chrome versions, we switched to blob instead of data URIs (#432)
* FIXED: Since Outlook strips trailing equal signs in links, the key in URL hash is now base58 encoded, instead of base64 (#377)
* FIXED: Facebooks started injecting parameters into shared URLs for tracking that lead to inaccessible pastes (#396)
* FIXED: Properly escaped HTML in raw text mode (#358)
* FIXED: Made download links better readable in the dark bootstrap theme (#364)
* FIXED: Allow Letsencrypt bot to access on apache servers (#413)
* **1.2.1 (2018-08-11)**
* ADDED: Add support for mega.nz links in pastes and comments (#331)
* CHANGED: Added some missing Russian translations (#348)

9
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,9 @@
# Netiquette
As suggested by the current project hoster, we are hereby referring to
[RFC 1855](https://tools.ietf.org/html/rfc1855) as a minimum set of guidelines
of Network Etiquette for individuals interacting on this project.
The maintainers of this project reserve the right to remove unlawful or
disrupting content and block users that repeatedly disturb the project at their
discretion.

View File

@@ -3,7 +3,8 @@
## Active contributors
Simon Rupf - current developer and maintainer
rugk - security review, doc improvment, JS refactoring & various other stuff
rugk - security review, doc improvment, JS refactoring & various other stuff
R4SAS - python client, compression, blob URI to support larger attachments
## Past contributions
@@ -12,7 +13,7 @@ Sébastien Sauvage - original idea and main developer
* Alexey Gladkov - syntax highlighting
* Greg Knaddison - robots.txt
* MrKooky - HTML5 markup, CSS cleanup
* Simon Rupf - MVC refactoring, configuration, i18n and unit tests
* Simon Rupf - WebCrypto, unit tests, current docker containers, MVC, configuration, i18n
* Hexalyse - Password protection
* Viktor Stanchev - File upload support
* azlux - Tab character input support
@@ -21,8 +22,11 @@ Sébastien Sauvage - original idea and main developer
* Sobak - PSR-4 and PSR-2 refactoring
* Nathaniel Olsen - jQuery upgrade
* Alexander Demenshin - modal password dialog
* PunKeel - Dockerfile
* PunKeel - first docker container
* 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
@@ -39,3 +43,6 @@ Sébastien Sauvage - original idea and main developer
* Tulio Leao - Portuguese
* Michael van Schaik - Dutch
* Péter Tabajdi - Hungarian
* info-path - Czech
* BigWax - Bulgarian
* AndriiZ - Ukrainian

View File

@@ -1,26 +0,0 @@
FROM php:apache
RUN apt-get update && apt-get install -y \
libfreetype6-dev \
libjpeg62-turbo-dev \
libpng-dev \
wget \
zip \
unzip && \
# We install and enable php-gd
docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ &&\
docker-php-ext-install -j$(nproc) gd && \
# We enable Apache's mod_rewrite
a2enmod rewrite
# Copy app content
COPY . /var/www/html
# Copy start script
RUN mv /var/www/html/docker/entrypoint.sh / && \
rm -r /var/www/html/docker
VOLUME /var/www/html/data
CMD /entrypoint.sh

View File

@@ -11,14 +11,14 @@ options](#configuration) to adjust as you see fit.
### Minimal requirements
- PHP version 5.4 or above
- PHP version 5.5 or above
- _one_ of the following sources of cryptographically safe randomness is required:
- PHP 7 or higher
- [Libsodium](https://download.libsodium.org/libsodium/content/installation/) and it's [PHP extension](https://paragonie.com/book/pecl-libsodium/read/00-intro.md#installing-libsodium)
- 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
@@ -139,7 +161,7 @@ For reference or if you want to create the table schema for yourself to avoid ha
```sql
CREATE TABLE prefix_paste (
dataid CHAR(16) NOT NULL,
data BLOB,
data MEDIUMBLOB,
postdate INT,
expiredate INT,
opendiscussion INT,
@@ -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.2.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

@@ -2,15 +2,15 @@
PrivateBin consists of PHP and JS code which was originally written by Sébastien
Sauvage in 2012 and falls unter the Zlib/libpng license. Also included are
libraries that fall under the GPLv2 (SJCL, rawinflate, rawdeflate), BSD
2-clause (SJCL), BSD 3-clause (base64.js version 2.1.9, Showdown), MIT
(base64.js version 1.7, Bootstrap, Identicon, random_compat), Apache
(prettify.js) and CC-BY (favicon, icon, logo) licenses. All of these license
terms can be found here below:
libraries that fall under the GPLv2 (rawinflate), BSD 3-clause (Showdown), MIT
(base64.js version 1.7, Bootstrap, Identicon, random_compat, composer, kjua,
base-x), Apache (prettify.js) and CC-BY (favicon, icon, logo) licenses. All of
these license terms can be found here below:
## Zlib/libpng license for PrivateBin
## Zlib/libpng license for PrivateBin and zlib
Copyright © 2012 Sébastien Sauvage
Copyright © 1995-2017 Jean-loup Gailly and Mark Adler
This software is provided 'as-is', without any express or implied warranty. In
no event will the authors be held liable for any damages arising from the use
@@ -30,17 +30,7 @@ the following restrictions:
3. This notice may not be removed or altered from any source distribution.
### MIT license for kjua
Copyright (c) 2016 Lars Jung (https://larsjung.de)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
## GNU General Public License, version 2.0, for SJCL, rawdeflate and rawinflate
## GNU General Public License, version 2.0, for rawinflate
_Version 2, June 1991_
_Copyright © 1989, 1991 Free Software Foundation, Inc.,_
@@ -317,31 +307,6 @@ POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
## BSD 2-Clause License for SJCL
_Copyright © 2009-2015, Emily Stark, Mike Hamburg and Dan Boneh at Stanford University._
_All rights reserved._
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
## BSD 3-Clause License for Showdown
Showdown Copyright © 2007, John Fraser
@@ -377,61 +342,16 @@ any theory of liability, whether in contract, strict liability, or tort
(including negligence or otherwise) arising in any way out of the use of this
software, even if advised of the possibility of such damage.
## BSD 3-Clause License for base64.js version 2.1.9
Copyright © 2014, Dan Kogai
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* Neither the name of base64.js nor the names of its contributors may be used
to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
## MIT License for base64.js version 1.7
## MIT License for base64.js version 1.7, Bootstrap, Identicon, random_compat, Composer, kjua and base-x
Copyright © 2012 Dan Kogai
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
## MIT License for Bootstrap
Copyright © 2011-2016 Twitter, Inc.
Copyright © 2013 Benjamin Laugueux <benjamin@yzalis.com>
Copyright © 2015 Paragon Initiative Enterprises
Copyright © 2016 Nils Adermann, Jordi Boggiano
Copyright © 2016 Lars Jung (https://larsjung.de)
Copyright © 2018 base-x contributors
Copyright © 2014-2018 The Bitcoin Core developers
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -451,72 +371,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
## MIT License for Identicon
Copyright © 2013 Benjamin Laugueux <benjamin@yzalis.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
## MIT License for random_compat
Copyright © 2015 Paragon Initiative Enterprises
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
## MIT license for Composer
Copyright (c) 2016 Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
## Apache License for prettify.js
_Version 2.0, January 2004_

View File

@@ -1,13 +1,6 @@
# [<img alt="PrivateBin" src="https://cdn.rawgit.com/PrivateBin/assets/master/images/minified/logo.svg" width="500" />](https://privatebin.info/)
[![Build Status](https://travis-ci.org/PrivateBin/PrivateBin.svg?branch=master)](https://travis-ci.org/PrivateBin/PrivateBin) [![Build Status](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/badges/build.png?b=master)](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/build-status/master)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/094500f62abf4c9aa0c8a8a4520e4789)](https://www.codacy.com/app/PrivateBin/PrivateBin)
[![Code Climate](https://codeclimate.com/github/PrivateBin/PrivateBin/badges/gpa.svg)](https://codeclimate.com/github/PrivateBin/PrivateBin)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/?branch=master)
[![SensioLabsInsight](https://insight.sensiolabs.com/projects/57c9e74e-c6f9-4de6-a876-df66ec2ea1ff/mini.png)](https://insight.sensiolabs.com/projects/57c9e74e-c6f9-4de6-a876-df66ec2ea1ff)
[![Codacy Badge](https://api.codacy.com/project/badge/Coverage/094500f62abf4c9aa0c8a8a4520e4789)](https://www.codacy.com/app/PrivateBin/PrivateBin)
[![Test Coverage](https://codeclimate.com/github/PrivateBin/PrivateBin/badges/coverage.svg)](https://codeclimate.com/github/PrivateBin/PrivateBin/coverage) [![Code Coverage](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/badges/coverage.png?b=master)](https://scrutinizer-ci.com/g/PrivateBin/PrivateBin/?branch=master)
# [![PrivateBin](https://cdn.rawgit.com/PrivateBin/assets/master/images/preview/logoSmall.png)](https://privatebin.info/)
*Current version: 1.2.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.
@@ -102,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)

18
SECURITY.md Normal file
View File

@@ -0,0 +1,18 @@
# Security Policy
## Supported Versions
| Version | Supported |
| ------- | ------------------ |
| 1.3.3 | :heavy_check_mark: |
| < 1.3.3 | :x: |
## Reporting a Vulnerability
You can send us email at security@privatebin.org. You should be able to get
a response within a week (usually during the next weekend). The respondee will
reply from their personal address and can offer you their GPG public key to
support end-to-end encrypted communication on sensitive topics or attachments.
You can also contact us via the regular issue tracker if the risk of early
publication is low or you would request input from other PrivateBin users.

View File

@@ -29,8 +29,8 @@ defaultformatter = "plaintext"
; (optional) set a syntax highlighting theme, as found in css/prettify/
; syntaxhighlightingtheme = "sons-of-obsidian"
; size limit per paste or comment in bytes, defaults to 2 Mebibytes
sizelimit = 2097152
; size limit per paste or comment in bytes, defaults to 10 Mebibytes
sizelimit = 10485760
; template to include, default is "bootstrap" (tpl/bootstrap.php)
template = "bootstrap"
@@ -60,22 +60,43 @@ 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
; custom scripts from third-party domains to your templates, e.g. tracking
; scripts or run your site behind certain DDoS-protection services.
; Check the documentation at https://content-security-policy.com/
; Note: If you use a bootstrap theme, you can remove the allow-popups from the sandbox restrictions.
; By default this disallows to load images from third-party servers, e.g. when they are embedded in pastes. If you wish to allow that, you can adjust the policy here. See https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-it-load-embedded-images for details.
; cspheader = "default-src 'none'; manifest-src 'self'; connect-src *; script-src 'self'; style-src 'self'; font-src 'self'; img-src 'self' data:; media-src data:; object-src data:; Referrer-Policy: 'no-referrer'; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals"
; Notes:
; - If you use a bootstrap theme, you can remove the allow-popups from the
; sandbox restrictions.
; - By default this disallows to load images from third-party servers, e.g. when
; they are embedded in pastes. If you wish to allow that, you can adjust the
; policy here. See https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-it-load-embedded-images
; for details.
; - The 'unsafe-eval' is used in two cases; to check if the browser supports
; async functions and display an error if not and for Chrome to enable
; webassembly support (used for zlib compression). You can remove it if Chrome
; doesn't need to be supported and old browsers don't need to be warned.
; cspheader = "default-src 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'unsafe-eval'; style-src 'self'; font-src 'self'; img-src 'self' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals"
; stay compatible with PrivateBin Alpha 0.19, less secure
; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of
; sha256 in HMAC for the deletion token
zerobincompatibility = false
; zerobincompatibility = false
; Enable or disable the warning message when the site is served over an insecure
; connection (insecure HTTP instead of HTTPS), defaults to true.
; Secure transport methods like Tor and I2P domains are automatically whitelisted.
; It is **strongly discouraged** to disable this.
; See https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-it-show-me-an-error-about-an-insecure-connection for more information.
; httpwarning = true
; 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"
[expire]
; expire value that is selected per default

View File

@@ -1,32 +1,44 @@
{
"name": "privatebin/privatebin",
"description": "PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted in the browser using 256 bit AES in Galois Counter mode (GCM).",
"type": "project",
"keywords": ["private", "secure", "end-to-end-encrypted", "e2e", "paste", "pastebin", "zero", "zero-knowledge", "encryption", "encrypted", "AES"],
"homepage": "https://github.com/PrivateBin",
"license":"zlib-acknowledgement",
"support": {
"issues": "https://github.com/PrivateBin/PrivateBin/issues",
"wiki": "https://github.com/PrivateBin/PrivateBin/wiki",
"source": "https://github.com/PrivateBin/PrivateBin",
"docs": "https://zerobin.dssr.ch/documentation/"
},
"require": {
"php": "^5.4.0 || ^7.0",
"paragonie/random_compat": "2.0.15",
"yzalis/identicon": "1.1.0"
},
"require-dev": {
"codacy/coverage": "dev-master",
"codeclimate/php-test-reporter": "dev-master",
"phpunit/phpunit": "^4.6 || ^5.0"
},
"autoload": {
"psr-4": {
"PrivateBin\\": "lib/"
}
},
"config": {
"autoloader-suffix": "DontChange"
}
"name" : "privatebin/privatebin",
"description" : "PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted in the browser using 256 bit AES in Galois Counter mode (GCM).",
"type" : "project",
"keywords" : [
"private",
"secure",
"end-to-end-encrypted",
"e2e",
"paste",
"pastebin",
"zero",
"zero-knowledge",
"encryption",
"encrypted",
"AES"
],
"homepage" : "https://privatebin.info/",
"license" : "zlib-acknowledgement",
"support" : {
"issues" : "https://github.com/PrivateBin/PrivateBin/issues",
"wiki" : "https://github.com/PrivateBin/PrivateBin/wiki",
"source" : "https://github.com/PrivateBin/PrivateBin",
"docs" : "https://privatebin.info/codedoc/"
},
"require" : {
"php" : "^5.6.0 || ^7.0",
"paragonie/random_compat" : "2.0.18",
"yzalis/identicon" : "2.0.0"
},
"require-dev" : {
"codacy/coverage" : "dev-master",
"codeclimate/php-test-reporter" : "dev-master",
"phpunit/phpunit" : "^4.6 || ^5.0"
},
"autoload" : {
"psr-4" : {
"PrivateBin\\" : "lib/"
}
},
"config" : {
"autoloader-suffix" : "DontChange"
}
}

2699
composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

5
css/bootstrap/bootstrap-3.4.1.css vendored 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

@@ -315,8 +315,8 @@ th {
}
@font-face {
font-family: 'Glyphicons Halflings';
src: url(fonts/../fonts/glyphicons-halflings-regular.eot?1445975532);
src: url(fonts/../fonts/glyphicons-halflings-regular.eot?&1445975532#iefix) format("embedded-opentype"), url(fonts/../fonts/glyphicons-halflings-regular.woff2?1445975532) format("woff2"), url(fonts/../fonts/glyphicons-halflings-regular.woff?1445975532) format("woff"), url(fonts/../fonts/glyphicons-halflings-regular.ttf?1445975532) format("truetype"), url(fonts/../fonts/glyphicons-halflings-regular.svg?1445975532#glyphicons_halflingsregular) format("svg");
src: url(fonts/glyphicons-halflings-regular.eot?1445975532);
src: url(fonts/glyphicons-halflings-regular.eot?&1445975532#iefix) format("embedded-opentype"), url(fonts/glyphicons-halflings-regular.woff2?1445975532) format("woff2"), url(fonts/glyphicons-halflings-regular.woff?1445975532) format("woff"), url(fonts/glyphicons-halflings-regular.ttf?1445975532) format("truetype"), url(fonts/glyphicons-halflings-regular.svg?1445975532#glyphicons_halflingsregular) format("svg");
}
.glyphicon {
position: relative;

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.2.1
* @version 1.3.3
*/
body {
@@ -80,12 +80,30 @@ body.loading {
margin-bottom: 20px;
}
.dragAndDropFile{
color:#777;
font-size:1em;
display:inline;
#dropzone {
text-align: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1000;
opacity: 0.6;
background-color: #99ccff;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center;
background-size: 25vh;
outline: 2px dashed #228bff;
outline-offset: -50px;
}
.dragAndDropFile{
color: #777;
font-size: 1em;
display: inline;
white-space: normal;
}
#deletelink {
float: right;
@@ -113,8 +131,9 @@ body.loading {
margin-bottom: 10px;
}
#message {
#message, .replymessage {
font-family: monospace;
resize: vertical;
}
#nickname {
@@ -125,6 +144,10 @@ body.loading {
margin-bottom: 10px;
}
#filewrap {
transition: background-color 0.75s ease-out;
}
.comment {
border-left: 1px solid #ccc;
padding: 5px 0 5px 10px;
@@ -132,7 +155,7 @@ body.loading {
transition: background-color 0.75s ease-out;
}
.comment.highlight {
.highlight {
background-color: #ffdd86;
transition: background-color 0.2s ease-in;
}
@@ -144,3 +167,41 @@ footer h4 {
li.L0, li.L1, li.L2, li.L3, li.L5, li.L6, li.L7, li.L8 {
list-style-type: decimal !important;
}
.dark-theme .alert-info .alert-link {
color: #fff;
}
/* address 2K or 4K monitors when using bootstrap 3 */
@media (min-width: 1280px) {
.container {
width: 100%;
padding-left: 4ch;
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.2.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.2.1
* @version 1.3.3
*/
/* CSS Reset from YUI 3.4.1 (build 4118) - Copyright 2011 Yahoo! Inc. All rights reserved.
@@ -102,6 +102,7 @@ h3.title {
padding: 5px;
white-space: pre-wrap;
font-family: Consolas, "Lucida Console", "DejaVu Sans Mono", Monaco, monospace;
resize: vertical;
}
#attachmentPreview img {
@@ -115,10 +116,29 @@ h3.title {
margin-bottom: 20px;
}
#dropzone {
text-align: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1000;
opacity: 0.6;
background-color: #99ccff;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cpath d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM14 13v4h-4v-4H7l5-5 5 5h-3z'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: center;
background-size: 25vh;
outline: 2px dashed #228bff;
outline-offset: -50px;
}
.dragAndDropFile{
color:#777;
font-size:1em;
display:inline;
color: #777;
font-size: 1em;
display: inline;
white-space: normal;
}
#status {
@@ -290,9 +310,9 @@ input {
#ienotice a { color: #000; }
#oldienotice { display: none; }
#oldnotice, #httpnotice { display: none; }
.errorMessage {
#errormessage, .errorMessage {
background-color: #f77 !important;
color:#ff0;
}
@@ -405,6 +425,15 @@ h4.title {
.commentdate { color: #bfcede; }
#filewrap {
transition: background-color 0.75s ease-out;
}
.highlight {
background-color: #ffdd86;
transition: background-color 0.2s ease-in;
}
img.vizhash {
width: 16px;
height: 16px;

View File

@@ -20,7 +20,7 @@ $ sudo pear install phpdoc/phpDocumentor
To generate the documentation, change into the main directory and run phpdoc:
```console
$ cd PrivateBin
$ phpdoc -t doc/phpdoc -d lib/
$ phpdoc --visibility public,protected,private -t doc/phpdoc -d lib/
```
**Note:** When used with PHP 7, the prerelease of phpDocumentator 2.9 needs to be
@@ -55,6 +55,6 @@ $ ln -s /usr/bin/nodejs /usr/local/bin/node
To generate the documentation, change into the main directory and run phpdoc:
```console
$ cd PrivateBin
$ jsdoc -d doc/jsdoc js/privatebin.js
$ jsdoc -p -d doc/jsdoc js/privatebin.js js/legacy.js
```

View File

@@ -1,15 +0,0 @@
version: '3'
services:
privatebin:
build: .
ports:
- "3000:80"
volumes:
- data:/var/www/html/data
# Optionally mount a custom config file
#- /srv/docker/privatebin/conf.php:/var/www/html/cfg/conf.php
volumes:
data:

View File

@@ -1,4 +0,0 @@
#! /bin/sh
chown -R www-data /var/www/html/data
apache2-foreground

188
i18n/bg.json Normal file
View File

@@ -0,0 +1,188 @@
{
"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 е изчистен и изцяло достъпен като отворен код, онлайн \"paste\" услуга, където сървъра не знае подадената информация. Тя се шифрова/дешифрова <i>във браузъра</i> използвайки 256 битов AES алгоритъм. Повече информация може да намерите на <a href=\"https://privatebin.info/\">страницата на проекта (Английски)</a>",
"Because ignorance is bliss":
"Невежеството е блаженство",
"en": "bg",
"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 секунди между всяка публикация.",
"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.":
"Невалиден идентификационен код.",
"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 minutes": ["%d минути", "%d минута"],
"%d hours": ["%d часа", "%d час"],
"%d days": ["%d дни", "%d ден"],
"%d weeks": ["%d седмици", "%d седмица"],
"%d months": ["%d месеци", "%d месец"],
"%d years": ["%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 секунди."],
"This document will expire in %d minutes.":
["Този документ изтича след една минута.", "Този документ изтича след %d минути."],
"This document will expire in %d hours.":
["Този документ изтича след един час.", "Този документ изтича след %d часа."],
"This document will expire in %d days.":
["Този документ изтича след един ден.", "Този документ изтича след %d дни."],
"This document will expire in %d months.":
["Този документ изтича след една година.", "Този документ изтича след %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?)":
"Дешифроването на информацията беше неуспешно: Ключа за декриптиране липсва във връзката (Да не сте използвали услуга за пренасочване или скъсяване на връзката, което би изрязало части от нея?)",
"Format": "Format",
"Plain Text": "Чист текст",
"Source Code": "Изходен код",
"Markdown": "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\">Вижте тази страница</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.",
"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"
}

188
i18n/cs.json Normal file
View File

@@ -0,0 +1,188 @@
{
"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 minimalistický open source 'pastebin' server, který neanalyzuje vložená data. Data jsou šifrována <i>v prohlížeči</i> pomocí 256 bitů AES. Více informací na <a href=\"https://privatebin.info/\">stránce projetu</a>.",
"Because ignorance is bliss":
"Protože nevědomost je sladká",
"en": "cs",
"Paste does not exist, has expired or has been deleted.":
"Vložený text neexistuje, expiroval nebo byl odstraněn.",
"%s requires php %s or above to work. Sorry.":
"%s vyžaduje php %s nebo vyšší. Lituji.",
"%s requires configuration section [%s] to be present in configuration file.":
"%s requires configuration section [%s] to be present in configuration file.",
"Please wait %d seconds between each post.":
"Počet sekund do dalšího příspěvku: %d.",
"Paste is limited to %s of encrypted data.":
"Příspěvek je limitován na %s šífrovaných dat",
"Invalid data.":
"Chybná data.",
"You are unlucky. Try again.":
"Lituji, zkuste to znovu.",
"Error saving comment. Sorry.":
"Chyba při ukládání komentáře.",
"Error saving paste. Sorry.":
"Chyba při ukládání příspěvku.",
"Invalid paste ID.":
"Chybně vložené ID.",
"Paste is not of burn-after-reading type.":
"Paste is not of burn-after-reading type.",
"Wrong deletion token. Paste was not deleted.":
"Wrong deletion token. Paste was not deleted.",
"Paste was properly deleted.":
"Paste was properly deleted.",
"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":
"Nový",
"Send":
"Odeslat",
"Clone":
"Klonovat",
"Raw text":
"Pouze Text",
"Expires":
"Expirace",
"Burn after reading":
"Po přečtení smazat",
"Open discussion":
"Povolit komentáře",
"Password (recommended)":
"Heslo (doporučeno)",
"Discussion":
"Komentáře",
"Toggle navigation":
"Toggle navigation",
"%d seconds": ["%d sekuda", "%d sekundy", "%d sekund"],
"%d minutes": ["%d minuta", "%d minuty", "%d minut"],
"%d hours": ["%d hodin", "%d hodiny", "%d hodin"],
"%d days": ["%d den", "%d dny", "%d dní"],
"%d weeks": ["%d týden", "%d týdeny", "%d týdnů"],
"%d months": ["%d měsíc", "%d měsíce", "%d měsíců"],
"%d years": ["%d rok", "%d roky", "%d roků"],
"Never":
"Nikdy",
"Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.":
"Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.",
"This document will expire in %d seconds.":
["Tento dokument expiruje za %d sekundu.", "Tento dokument expiruje za %d sekundy.", "Tento dokument expiruje za %d sekund."],
"This document will expire in %d minutes.":
["Tento dokument expiruje za %d minutu.", "Tento dokument expiruje za %d minuty.", "Tento dokument expiruje za %d minut."],
"This document will expire in %d hours.":
["Tento dokument expiruje za %d hodinu.", "Tento dokument expiruje za %d hodiny.", "Tento dokument expiruje za %d hodin."],
"This document will expire in %d days.":
["Tento dokument expiruje za %d den.", "Tento dokument expiruje za %d dny.", "Tento dokument expiruje za %d dny."],
"This document will expire in %d months.":
["Tento dokument expiruje za %d měsíc.", "Tento dokument expiruje za %d měsíce.", "Tento dokument expiruje za %d měsíců."],
"Please enter the password for this paste:":
"Zadejte prosím heslo:",
"Could not decrypt data (Wrong key?)":
"Could not decrypt data (Wrong key?)",
"Could not delete the paste, it was not stored in burn after reading mode.":
"Could not delete the paste, it was not stored in burn after reading mode.",
"FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.":
"FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.",
"Could not decrypt comment; Wrong key?":
"Could not decrypt comment; Wrong key?",
"Reply":
"Reply",
"Anonymous":
"Anonym",
"Avatar generated from IP address":
"Avatar generated from IP address",
"Add comment":
"Přidat komentář",
"Optional nickname…":
"Volitelný nickname…",
"Post comment":
"Odeslat komentář",
"Sending comment…":
"Odesílání komentáře…",
"Comment posted.":
"Komentář odeslán.",
"Could not refresh display: %s":
"Could not refresh display: %s",
"unknown status":
"neznámý stav",
"server error or not responding":
"Chyba na serveru nebo server neodpovídá",
"Could not post comment: %s":
"Nelze odeslat komentář: %s",
"Sending paste…":
"Odesílání příspěvku…",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>":
"Váš link je <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Stiskněte [Ctrl]+[c] pro zkopírování)</span>",
"Delete data":
"Odstranit data",
"Could not create paste: %s":
"Nelze vytvořit příspěvek: %s",
"Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)":
"Nepodařilo se dešifrovat příspěvek: V adrese chybí dešifrovací klíč (Možnou příčinou může být URL shortener?)",
"Format": "Formát",
"Plain Text": "Prostý Text",
"Source Code": "Zdrojový kód",
"Markdown": "Markdown",
"Download attachment": "Stáhnout přílohu",
"Cloned: '%s'": "Klonováno: '%s'",
"The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.",
"Attach a file": "Připojit soubor",
"alternatively drag & drop a file or paste an image from the clipboard": "alternatively drag & drop a file or paste an image from the clipboard",
"File too large, to display a preview. Please download the attachment.": "Soubor je příliš velký pro zobrazení náhledu. Stáhněte si přílohu.",
"Remove attachment": "Odstranit přílohu",
"Your browser does not support uploading encrypted files. Please use a newer browser.":
"Váš prohlížeč nepodporuje nahrávání šifrovaných souborů. Použijte modernější verzi prohlížeče.",
"Invalid attachment.": "Chybná příloha.",
"Options": "Volby",
"Shorten URL": "Shorten URL",
"Editor": "Editor",
"Preview": "Náhled",
"%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.":
"%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.",
"Decrypt":
"Decrypt",
"Enter password":
"Zadejte heslo",
"Loading…": "Loading…",
"Decrypting paste…": "Decrypting paste…",
"Preparing new paste…": "Preparing new paste…",
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.":
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.",
"+++ no paste text +++": "+++ žádný vložený text +++",
"Could not get paste data: %s":
"Could not get paste data: %s",
"QR code": "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.",
"For more information <a href=\"%s\">see this FAQ entry</a>.":
"For more information <a href=\"%s\">see this FAQ entry</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>.",
"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,12 +31,10 @@
"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.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Du benutzt immer noch den Internet Explorer? Tu Dir einen Gefallen und wechsle zu einem moderneren Browser:",
"New":
"Neu",
"Send":
@@ -48,13 +46,13 @@
"Expires":
"Ablaufzeit",
"Burn after reading":
"Einmal-Text",
"Nach dem Lesen löschen",
"Open discussion":
"Diskussion eröffnen",
"Kommentare aktivieren",
"Password (recommended)":
"Passwort (empfohlen)",
"Discussion":
"Diskussion",
"Kommentare",
"Toggle navigation":
"Navigation umschalten",
"%d seconds": ["%d Sekunde", "%d Sekunden"],
@@ -105,23 +103,21 @@
"Comment posted.":
"Kommentar gesendet.",
"Could not refresh display: %s":
"Konnte Ansicht nicht aktualisieren: %s",
"Ansicht konnte nicht aktualisiert werden: %s",
"unknown status":
"Unbekannter Grund",
"server error or not responding":
"Fehler auf dem Server oder keine Antwort vom Server",
"Could not post comment: %s":
"Konnte Kommentar nicht senden: %s",
"Please move your mouse for more entropy…":
"Bitte bewege Deine Maus um die Entropie zu erhöhen…",
"Sending paste…":
"Sende Paste…",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>":
"Dein Paste ist unter <a id=\"pasteurl\" href=\"%s\">%s</a> zu finden <span id=\"copyhint\">(Drücke [Strg]+[c] um den Link zu kopieren)</span>",
"Dein Text ist unter <a id=\"pasteurl\" href=\"%s\">%s</a> zu finden <span id=\"copyhint\">(Drücke [Strg]+[c] um den Link zu kopieren)</span>",
"Delete data":
"Lösche Daten",
"Could not create paste: %s":
"Konnte Paste nicht erstellen: %s",
"Text konnte nicht erstellt werden: %s",
"Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)":
"Konnte Paste nicht entschlüsseln: Der Schlüssel fehlt in der Adresse (Hast du eine Umleitung oder einen URL-Verkürzer benutzt, der Teile der Adresse entfernt?)",
"Format": "Format",
@@ -149,11 +145,44 @@
"Enter password":
"Passwort eingeben",
"Loading…": "Lädt…",
"Decrypting paste…": "Entschlüssle Paste…",
"Preparing new paste…": "Bereite neues Paste vor…",
"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>.":
"Wenn diese Nachricht nicht mehr verschwindet, schau bitte in <a href=\"https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away\">die FAQ</a> (englisch), um zu sehen, wie der Fehler behoben werden kann.",
"Decrypting paste…": "Entschlüssle Text…",
"Preparing new paste…": "Bereite neuen Text vor…",
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.":
"Wenn diese Nachricht nicht mehr verschwindet, schau bitte in <a href=\"%s\">die FAQ</a> (englisch), um zu sehen, wie der Fehler behoben werden kann.",
"+++ no paste text +++": "+++ kein Paste-Text +++",
"Could not get paste data: %s":
"Konnte Paste nicht laden: %s"
}
"Text konnte nicht geladen werden: %s",
"QR code": "QR code",
"This website is using an insecure HTTP connection! Please use it only for testing.":
"Diese Webseite verwendet eine unsichere HTTP Verbindung! Bitte benutze sie nur zum Testen.",
"For more information <a href=\"%s\">see this FAQ entry</a>.":
"<a href=\"%s\">Besuche diesen FAQ Eintrag</a> für weitere Informationen dazu.",
"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.",
"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 um %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

@@ -1,12 +1,12 @@
{
"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 es un servicio de tipo \"Pastebin\" minimalista de código abierto, donde el servidor no tiene ningún conocimiento de los datos guardados. Los datos son cifrados/descifrados <i>en el navegador</i> usando 256 bits AES. Más información en la <a href=\"https://privatebin.info/\">página del proyecto</a>.",
"%s es un \"pastebin\" en línea minimalista de código abierto, donde el servidor no tiene ningún conocimiento de los datos guardados. Los datos son cifrados/descifrados <i>en el navegador</i> usando 256 bits AES. Más información en la <a href=\"https://privatebin.info/\">página del proyecto</a>.",
"Because ignorance is bliss":
"Porque la ignorancia es dicha",
"en": "es",
"Paste does not exist, has expired or has been deleted.":
"El texto no existe, ha caducado o ha sido eliminado.",
"El \"paste\" no existe, ha caducado o ha sido eliminado.",
"%s requires php %s or above to work. Sorry.":
"%s requiere php %s o superior para funcionar. Lo siento.",
"%s requires configuration section [%s] to be present in configuration file.":
@@ -14,7 +14,7 @@
"Please wait %d seconds between each post.":
"Por favor espere %d segundos entre cada publicación.",
"Paste is limited to %s of encrypted data.":
"El texto está limitado a %s de datos cifrados.",
"El \"paste\" está limitado a %s de datos cifrados.",
"Invalid data.":
"Datos inválidos.",
"You are unlucky. Try again.":
@@ -22,21 +22,19 @@
"Error saving comment. Sorry.":
"Error al guardar el comentario. Lo siento.",
"Error saving paste. Sorry.":
"Error al guardar el texto. Lo siento",
"Error al guardar el \"paste\". Lo siento",
"Invalid paste ID.":
"ID del texto inválido.",
"ID del \"paste\" inválido.",
"Paste is not of burn-after-reading type.":
"El texto no es del tipo \"destruir despues de leer\".",
"El \"paste\" no es del tipo \"destruir despues de leer\".",
"Wrong deletion token. Paste was not deleted.":
"Token de eliminación erróneo. El texto no fue eliminado.",
"Token de eliminación erróneo. El \"paste\" no fue eliminado.",
"Paste was properly deleted.":
"El texto 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.",
"El \"paste\" se ha eliminado correctamente.",
"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.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"¿Sigues usando Internet Explorer? Hazte un favor, cambia a un navegador moderno:",
"New":
"Nuevo",
"Send":
@@ -67,7 +65,7 @@
"Never":
"Nunca",
"Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.":
"Nota: Este es un servicio de prueba. Los datos pueden ser eliminados en cualquier momento. Gatitos morirán si se abusa de este servicio.",
"Nota: Este es un servicio de prueba. Los datos pueden ser eliminados en cualquier momento. Morirán gatitos si abusas de este servicio.",
"This document will expire in %d seconds.":
["Este documento caducará en un segundo.", "Este documento caducará en %d segundos."],
"This document will expire in %d minutes.":
@@ -79,13 +77,13 @@
"This document will expire in %d months.":
["Este documento caducará en un mes.", "Este documento caducará en %d meses."],
"Please enter the password for this paste:":
"Por favor ingrese la contraseña para este documento:",
"Por favor ingrese la contraseña para este \"paste\":",
"Could not decrypt data (Wrong key?)":
"No fue posible descifrar los datos (¿Clave errónea?)",
"Could not delete the paste, it was not stored in burn after reading mode.":
"No fue posible eliminar el documento, no fue guardado en modo \"destruir despues de leer\".",
"FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.":
"SÓLO PARA TUS OJOS. No cierre esta ventana, este mensaje no se puede volver a mostrar.",
"SÓLO PARA TUS OJOS. No cierres esta ventana, este mensaje no se puede volver a mostrar.",
"Could not decrypt comment; Wrong key?":
"No se pudo descifrar el comentario; ¿Llave incorrecta?",
"Reply":
@@ -112,10 +110,8 @@
"Error del servidor o el servidor no responde",
"Could not post comment: %s":
"No fue posible publicar comentario: %s",
"Please move your mouse for more entropy…":
"Por favor, mueva el ratón para mayor entropía…",
"Sending paste…":
"Enviando texto…",
"Enviando \"paste\"…",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>":
"Su texto está en <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Presione [Ctrl]+[c] para copiar)</span>",
"Delete data":
@@ -149,11 +145,44 @@
"Enter password":
"Ingrese contraseña",
"Loading…": "Cargando…",
"Decrypting paste…": "Descifrando texto…",
"Preparing new paste…": "Preparando texto nuevo…",
"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>.":
"En caso de que este mensaje nunca desaparezca por favor revise <a href=\"https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away\">este FAQ para obtener información para solucionar problemas</a>.",
"+++ no paste text +++": "+++ sin texto +++",
"Decrypting paste…": "Descifrando \"paste\"…",
"Preparing new paste…": "Preparando \"paste\" nuevo…",
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.":
"En caso de que este mensaje nunca desaparezca por favor revise <a href=\"%s\">este FAQ para obtener información para solucionar problemas</a>.",
"+++ no paste text +++": "+++ \"paste\" sin texto +++",
"Could not get paste data: %s":
"Could not get paste data: %s"
}
"No se pudieron obtener los datos: %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.",
"For more information <a href=\"%s\">see this FAQ entry</a>.":
"For more information <a href=\"%s\">see this FAQ entry</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>.",
"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,12 +31,10 @@
"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.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Encore sur Internet Explorer ? Faites-vous une faveur, passez à un navigateur moderne :",
"New":
"Nouveau",
"Send":
@@ -87,7 +85,7 @@
"FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.":
"POUR VOS YEUX UNIQUEMENT. Ne fermez pas cette fenêtre, ce paste ne pourra plus être affiché.",
"Could not decrypt comment; Wrong key?":
"Impossible de déchiffrer le commentaire ; mauvaise clé ?",
"Impossible de déchiffrer le commentaire; mauvaise clé ?",
"Reply":
"Répondre",
"Anonymous":
@@ -112,8 +110,6 @@
"Le serveur ne répond pas ou a rencontré une erreur",
"Could not post comment: %s":
"Impossible de poster le commentaire : %s",
"Please move your mouse for more entropy…":
"Merci de bouger votre souris pour plus d'entropie…",
"Sending paste…":
"Envoi du paste…",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>":
@@ -141,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": "alternatively drag & drop a file or paste an image from the clipboard",
"File too large, to display a preview. Please download the attachment.": "File too large, to display a preview. Please download the attachment.",
"Remove attachment": "Enlever l'attachement",
"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 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",
@@ -160,9 +156,42 @@
"Loading…": "Chargement…",
"Decrypting paste…": "Déchiffrement du paste…",
"Preparing new paste…": "Préparation du paste…",
"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>.":
"Si ce message ne disparaîssait pas, jetez un oeil à <a href=\"https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away\">cette FAQ pour des idées de résolution</a> (en Anglais).",
"+++ no paste text +++": "+++ pas de paste-text +++",
"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 texte copié +++",
"Could not get paste data: %s":
"Could not get paste data: %s"
}
"Impossible d'obtenir les données du paste: %s",
"QR code": "QR code",
"This website is using an insecure HTTP connection! Please use it only for testing.":
"Ce site web utilise une connexion HTTP non sécurisée ! Veuillez lutiliser uniquement pour des tests.",
"For more information <a href=\"%s\">see this FAQ entry</a>.":
"Pour plus d'informations <a href=\"%s\">consultez cette rubrique de la FAQ</a>.",
"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.":
"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,12 +31,10 @@
"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.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Még mindig Internet Explorert használsz? Ideje váltani:",
"New":
"Új",
"Send":
@@ -112,8 +110,6 @@
"A szerveren hiba lépett fel vagy nem válaszol.",
"Could not post comment: %s":
"Nem tudtuk beküldeni a hozzászólást: %s",
"Please move your mouse for more entropy…":
"Nincs elég véletlenszerűség a rendszerben. Mozgasd az egered, hogy növeld az entrópiát.",
"Sending paste…":
"Bejegyzés elküldése...",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>":
@@ -151,9 +147,42 @@
"Loading…": "Folyamatban...",
"Decrypting paste…": "Bejegyzés dekódolása...",
"Preparing new paste…": "Új bejegyzés előkészítése...",
"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>.":
"Abban az esetben, ha ez az üzenet mindig látható lenne, látogass el a <a href=\"https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away\">Gyakran Ismételt Kérdések szekcióba a megoldásához</a>.",
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.":
"Abban az esetben, ha ez az üzenet mindig látható lenne, látogass el a <a href=\"%s\">Gyakran Ismételt Kérdések szekcióba a megoldásához</a>.",
"+++ no paste text +++": "+++ nincs beillesztett szöveg +++",
"Could not get paste data: %s":
"Could not get paste data: %s"
}
"Could not get paste data: %s",
"QR code": "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.",
"For more information <a href=\"%s\">see this FAQ entry</a>.":
"For more information <a href=\"%s\">see this FAQ entry</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>.",
"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,12 +31,10 @@
"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.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Usi ancora Internet Explorer? Ti consigliamo di passare ad un browser più sicuro:",
"New":
"Nuovo",
"Send":
@@ -112,8 +110,6 @@
"errore o mancata risposta dal server",
"Could not post comment: %s":
"Impossibile inviare il commento: %s",
"Please move your mouse for more entropy…":
"Muovi il mouse in modo casuale, per generare maggior entropia…",
"Sending paste…":
"Messaggio in fase di invio…",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>":
@@ -151,9 +147,42 @@
"Loading…": "Carico…",
"Decrypting paste…": "Decifro il messaggio…",
"Preparing new paste…": "Preparo il nuovo messaggio…",
"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>.":
"Nel caso questo messaggio non scompaia, controlla questa <a href=\"https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away\">FAQ</a> per trovare informazioni su come risolvere il problema (in Inglese).",
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.":
"Nel caso questo messaggio non scompaia, controlla questa <a href=\"%s\">FAQ</a> per trovare informazioni su come risolvere il problema (in Inglese).",
"+++ no paste text +++": "+++ nessun testo nel messaggio +++",
"Could not get paste data: %s":
"Could not get paste data: %s"
}
"Could not get paste data: %s",
"QR code": "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.",
"For more information <a href=\"%s\">see this FAQ entry</a>.":
"For more information <a href=\"%s\">see this FAQ entry</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>.",
"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,12 +31,10 @@
"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 ",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Gebruik je nog steeds Internet explorer? Doe jezelf een plezier en maak gebruik van een moderne browser:",
"New":
"Nieuw",
"Send":
@@ -112,8 +110,6 @@
"Serverfout of server reageert niet",
"Could not post comment: %s":
"Kon het commentaar niet plaatsen: %s",
"Please move your mouse for more entropy…":
"Aub uw muis bewegen voor meer entropie…",
"Sending paste…":
"Geplakte tekst verzenden…",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>":
@@ -151,9 +147,42 @@
"Loading…": "Laden…",
"Decrypting paste…": "Geplakte tekst decoderen…",
"Preparing new paste…": "Nieuwe geplakte tekst voorbereiden…",
"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>.":
"In het geval dat dit bericht nooit verdwijnt, kijkt u dan eens naar <a href=\"https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away\"> veelgestelde vragen voor informatie over het oplossen van problemen </a>.",
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.":
"In het geval dat dit bericht nooit verdwijnt, kijkt u dan eens naar <a href=\"%s\"> veelgestelde vragen voor informatie over het oplossen van problemen </a>.",
"+++ no paste text +++": "+++ geen geplakte tekst +++",
"Could not get paste data: %s":
"Could not get paste data: %s"
}
"Could not get paste data: %s",
"QR code": "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.",
"For more information <a href=\"%s\">see this FAQ entry</a>.":
"For more information <a href=\"%s\">see this FAQ entry</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>.",
"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,12 +31,10 @@
"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.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Fortsatt bruker av Internet Explorer? Gjør deg selv en tjeneste og bytt til en moderne nettleser:",
"New":
"Ny",
"Send":
@@ -112,8 +110,6 @@
"tjener feilet eller svarer ikke",
"Could not post comment: %s":
"Kunne ikke sende kommentar: %s",
"Please move your mouse for more entropy…":
"Flytt musen for mer entropi…",
"Sending paste…":
"Sender innlegg…",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>":
@@ -151,9 +147,42 @@
"Loading…": "Laster…",
"Decrypting paste…": "Dekrypterer innlegg…",
"Preparing new paste…": "Klargjør nytt innlegg…",
"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>.":
"Hvis denne meldingen ikke forsvinner kan du ta en titt på siden med <a href=\"https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away\">ofte stilte spørsmål</a> for informasjon om feilsøking.",
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.":
"Hvis denne meldingen ikke forsvinner kan du ta en titt på siden med <a href=\"%s\">ofte stilte spørsmål</a> for informasjon om feilsøking.",
"+++ no paste text +++": "+++ ingen innleggstekst +++",
"Could not get paste data: %s":
"Could not get paste data: %s"
}
"Kunne ikke hente utklippsdata: %s",
"QR code": "QR kode",
"This website is using an insecure HTTP connection! Please use it only for testing.":
"Denne websiden bruker usikker HTTP tilkobling! Bruk den kun for testing.",
"For more information <a href=\"%s\">see this FAQ entry</a>.":
"For mer informasjon <a href=\"%s\">se ofte stilte spørsmål</a>.",
"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.",
"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

@@ -30,13 +30,11 @@
"Wrong deletion token. Paste was not deleted.":
"Geton de supression incorrècte. Lo tèxte es pas estat suprimit.",
"Paste was properly deleted.":
"Lo tèxte es estat correctament 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.",
"Lo tèxte es estat corrèctament suprimit.",
"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.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Encora sus Internet Explorer?Fasètz-vos una favor, passatz a un navigator modèrn:",
"New":
"Nòu",
"Send":
@@ -109,11 +107,9 @@
"unknown status":
"Estatut desconegut",
"server error or not responding":
"Lo servidor respond pas o a rencontrat una error",
"Lo servidor respond pas o a rescontrat una error",
"Could not post comment: %s":
"Impossible de mandar lo comentari:%s",
"Please move your mouse for more entropy…":
"Mercés de bolegar vòstra mirga per mai entropia…",
"Sending paste…":
"Mandadís del tèxte…",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>":
@@ -160,9 +156,42 @@
"Loading…": "Cargament…",
"Decrypting paste…": "Deschirament del tèxte…",
"Preparing new paste…": "Preparacion…",
"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>.":
"Se per cas aqueste messatge quita pas de safichar mercés de gaitar <a href=\"https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away\">aquesta FAQ per las solucions</a> (en anglés).",
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.":
"Se per cas aqueste messatge quite pas de safichar mercés de gaitar <a href=\"%s\">aquesta FAQ per las solucions</a> (en anglés).",
"+++ no paste text +++": "+++ cap de tèxte pegat +++",
"Could not get paste data: %s":
"Could not get paste data: %s"
}
"Recuperacion impossibla de las donadas copiadas: %s",
"QR code": "Còdi QR",
"This website is using an insecure HTTP connection! Please use it only for testing.":
"Aqueste site utiliza una connexion HTTP pas segura ! Mercés de lutilizar pas que per densages.",
"For more information <a href=\"%s\">see this FAQ entry</a>.":
"Per mai dinformacions <a href=\"%s\">vejatz aqueste article de FAQ</a>.",
"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.":
"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

@@ -8,7 +8,7 @@
"Paste does not exist, has expired or has been deleted.":
"Wklejka nie istnieje, wygasła albo została usunięta.",
"%s requires php %s or above to work. Sorry.":
"%s wymaga PHP w wersji %s lub nowszej, sorry.",
"%s wymaga PHP w wersji %s lub nowszej. Przykro mi.",
"%s requires configuration section [%s] to be present in configuration file.":
"%s wymaga obecności sekcji [%s] w pliku konfiguracyjnym.",
"Please wait %d seconds between each post.":
@@ -31,12 +31,10 @@
"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.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Cały czas używasz Internet Explorera? Zrób sobie przysługę, przesiądź się na nowoczesną przeglądarkę:",
"New":
"Nowa",
"Send":
@@ -109,11 +107,9 @@
"unknown status":
"nieznany status",
"server error or not responding":
"bląd serwera lub brak odpowiedzi",
"błąd serwera lub brak odpowiedzi",
"Could not post comment: %s":
"Nie udało się wysłać komentarza: %s",
"Please move your mouse for more entropy…":
"Proszę poruszać myszą aby uzyskać większą entropię…",
"Sending paste…":
"Wysyłanie wklejki…",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>":
@@ -130,10 +126,10 @@
"Markdown": "Markdown",
"Download attachment": "Pobierz załącznik",
"Cloned: '%s'": "Sklonowano: '%s'",
"The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.",
"The cloned file '%s' was attached to this paste.": "Sklonowany plik '%s' był dołączony do tej wklejki.",
"Attach a file": "Załącz plik",
"alternatively drag & drop a file or paste an image from the clipboard": "alternatively drag & drop a file or paste an image from the clipboard",
"File too large, to display a preview. Please download the attachment.": "File too large, to display a preview. Please download the attachment.",
"alternatively drag & drop a file or paste an image from the clipboard": "Alternatywnie przeciągnij i upuść plik albo wklej obraz ze schowka",
"File too large, to display a preview. Please download the attachment.": "Plik zbyt duży aby wyświetlić podgląd. Proszę pobrać załącznik.",
"Remove attachment": "Usuń załącznik",
"Your browser does not support uploading encrypted files. Please use a newer browser.":
"Twoja przeglądarka nie wspiera wysyłania zaszyfrowanych plików. Użyj nowszej przeglądarki.",
@@ -141,19 +137,52 @@
"Options": "Opcje",
"Shorten URL": "Skróć adres URL",
"Editor": "Edytować",
"Preview": "Zapowiedź",
"Preview": "Podgląd",
"%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.":
"%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.",
"Decrypt":
"Decrypt",
"Odszyfruj",
"Enter password":
"Wpisz hasło",
"Loading…": "Loading…",
"Decrypting paste…": "Decrypting paste…",
"Preparing new paste…": "Preparing new paste…",
"In case this message never disappears please have a look at <a href=\"https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away\">this FAQ for information to troubleshoot</a>.":
"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> (in English).",
"+++ no paste text +++": "+++ no paste text +++",
"Loading…": "Wczytywanie…",
"Decrypting paste…": "Odszyfrowywanie wklejki…",
"Preparing new paste…": "Przygotowywanie nowej wklejki…",
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.":
"W przypadku gdy ten komunikat nigdy nie znika, proszę spójrz na <a href=\"%s\">to FAQ aby rozwiązać problem</a> (po angielsku).",
"+++ no paste text +++": "+++ brak wklejonego tekstu +++",
"Could not get paste data: %s":
"Could not get paste data: %s"
}
"Nie można było pobrać danych wklejki: %s",
"QR code": "Kod 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.",
"For more information <a href=\"%s\">see this FAQ entry</a>.":
"For more information <a href=\"%s\">see this FAQ entry</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>.",
"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,12 +31,10 @@
"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.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Ainda usando Internet Explorer? Faça-se um favor, mude para um navegador moderno:",
"New":
"Novo",
"Send":
@@ -112,8 +110,6 @@
"Servidor em erro ou não responsivo",
"Could not post comment: %s":
"Não foi possível publicar o comentário: %s",
"Please move your mouse for more entropy…":
"Por favor, mova o mouse para maior entropia…",
"Sending paste…":
"Enviando cópia…",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>":
@@ -151,9 +147,42 @@
"Loading…": "Carregando…",
"Decrypting paste…": "Decifrando cópia…",
"Preparing new paste…": "Preparando nova cópia…",
"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>.":
"Caso essa mensagem nunca desapareça, por favor veja <a href=\"https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away\">este FAQ para saber como resolver os problemas</a>.",
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.":
"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"
}
"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.":
"Esse site usa uma conexão HTTP insegura! Use-o apenas para testes.",
"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>.":
"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.":
"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

@@ -12,7 +12,7 @@
"%s requires configuration section [%s] to be present in configuration file.":
"%s необходимо наличие секции [%s] в конфигурационном файле.",
"Please wait %d seconds between each post.":
["Пожалуйста ожидайте %d секунду между каждыми записями.", "Пожалуйста ожидайте %d секунды между каждыми записями.", "Пожалуйста ожидайте %d секунд между каждыми записями."],
["Пожалуйста, ожидайте %d секунду между каждыми записями.", "Пожалуйста, ожидайте %d секунды между каждыми записями.", "Пожалуйста, ожидайте %d секунд между каждыми записями."],
"Paste is limited to %s of encrypted data.":
"Размер записи ограничен %s зашифрованных данных.",
"Invalid data.":
@@ -28,15 +28,13 @@
"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.<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 требуется более современный браузер.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"До сих пор используете Internet Explorer? Пожалейте себя, перейдите на более современный браузер:",
"New":
"Новая запись",
"Send":
@@ -79,11 +77,11 @@
"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?":
@@ -112,18 +110,16 @@
"ошибка сервера или нет ответа",
"Could not post comment: %s":
"Не удалось опубликовать комментарий: %s",
"Please move your mouse for more entropy…":
"Пожалуйста двигайте мышкой для большей энтропии…",
"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>",
"Ссылка на запись <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": "Мбайт",
@@ -143,7 +139,7 @@
"Дубликат файла '%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.": "Файл слишком большой для отображения предпросмотра. Пожалуйста скачайте прикрепленный файл.",
"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.":
"Ваш браузер не поддерживает отправку зашифрованных файлов. Используйте более новый браузер.",
@@ -153,7 +149,7 @@
"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.",
"Переменная PATH необходима %s в конце \"%s\". Пожалуйста, обновите переменную PATH в вашем index.php.",
"Decrypt":
"Расшифровать",
"Enter password":
@@ -161,9 +157,42 @@
"Loading…": "Загрузка…",
"Decrypting paste…": "Расшифровка записи…",
"Preparing new paste…": "Подготовка новой записи…",
"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>.":
"Если данное сообщение не исчезает длительное время, посмотрите <a href=\"https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away\">этот FAQ с информацией о возможном решении проблемы (на английском)</a>.",
"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"
"Не удалось получить данные записи: %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.":
"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,12 +31,10 @@
"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.",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"Še vedno uporabljaš Internet Explorer? Naredi si uslugo, preklopi na moderen brskalnik:",
"New":
"Nov prilepek",
"Send":
@@ -112,8 +110,6 @@
"napaka na strežniku, ali pa se strežnik ne odziva",
"Could not post comment: %s":
"Komentarja ni bilo mogoče objaviti : %s",
"Please move your mouse for more entropy…":
"Prosim premakni svojo miško za več entropije…",
"Sending paste…":
"Pošiljam prilepek…",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>":
@@ -160,9 +156,42 @@
"Loading…": "Loading…",
"Decrypting paste…": "Decrypting paste…",
"Preparing new paste…": "Preparing new paste…",
"In case this message never disappears please have a look at <a href=\"https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away\">this FAQ for information to troubleshoot</a>.":
"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> (in English).",
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.":
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a> (in English).",
"+++ no paste text +++": "+++ no paste text +++",
"Could not get paste data: %s":
"Could not get paste data: %s"
"Could not get paste data: %s",
"QR code": "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.",
"For more information <a href=\"%s\">see this FAQ entry</a>.":
"For more information <a href=\"%s\">see this FAQ entry</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>.",
"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

@@ -1,16 +1,16 @@
{
"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是一个极简开源对粘贴内容毫不知情的在线粘贴板,数据<i>在浏览器内</i>进行AES-256加密。更多信息请查看<a href=\"https://privatebin.info/\">项目主页</a>。",
"%s是一个极简开源对粘贴内容毫不知情的在线粘贴板,数据<i>在浏览器内</i>进行AES-256加密。更多信息请查看<a href=\"https://privatebin.info/\">项目主页</a>。",
"Because ignorance is bliss":
"因为无知是福",
"en": "zh",
"Paste does not exist, has expired or has been deleted.":
"粘贴不存在,已过期或已被删除。",
"粘贴内容不存在,已过期或已被删除。",
"%s requires php %s or above to work. Sorry.":
"%s需要工作于PHP %s及以上版本抱歉。",
"%s需要PHP %s及以上版本来工作,抱歉。",
"%s requires configuration section [%s] to be present in configuration file.":
"%s需要设置配置文件中 [%s] 部分。",
"%s需要设置配置文件中 [%s] 部分。",
"Please wait %d seconds between each post.":
"每 %d 秒只能粘贴一次。",
"Paste is limited to %s of encrypted data.":
@@ -20,29 +20,27 @@
"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.":
"错误的删除token粘贴没有被删除。",
"错误的删除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需要工作于现代化的浏览器。",
"Still using Internet Explorer? Do yourself a favor, switch to a modern browser:":
"还在使用Internet Explorer帮自己个忙换上一个现代化的浏览器",
"%s需要在现代浏览器上工作。",
"New":
"新建",
"Send":
"送出",
"Clone":
"克隆",
"复制",
"Raw text":
"纯文本",
"Expires":
@@ -52,7 +50,7 @@
"Open discussion":
"开放讨论",
"Password (recommended)":
"密码 (推荐)",
"密码推荐",
"Discussion":
"讨论",
"Toggle navigation":
@@ -79,13 +77,13 @@
"This document will expire in %d months.":
["这份文档将在一个月后过期。", "这份文档将在 %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":
@@ -105,35 +103,33 @@
"Comment posted.":
"评论已发送。",
"Could not refresh display: %s":
"无法刷新显示: %s",
"无法刷新显示:%s",
"unknown status":
"未知状态",
"server error or not responding":
"服务器错误或无回应",
"Could not post comment: %s":
"无法发送评论: %s",
"Please move your mouse for more entropy…":
"请移动鼠标增加随机性…",
"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>",
"您粘贴内容的链接是<a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(按下 [Ctrl]+[c] 以复制)</span>",
"Delete data":
"删除数据",
"Could not create paste: %s":
"无法创建粘贴: %s",
"无法创建粘贴:%s",
"Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)":
"无法解密粘贴: URL中缺失解密密钥 (是否使用了重定向或者短链接导致密钥丢失?)",
"无法解密粘贴URL中缺失解密密钥是否使用了重定向或者短链接导致密钥丢失?",
"Format": "格式",
"Plain Text": "纯文本",
"Source Code": "源代码",
"Markdown": "Markdown",
"Download attachment": "下载附件",
"Cloned: '%s'": "克隆: '%s'",
"The cloned file '%s' was attached to this paste.": "克隆文件 '%s' 已附加到此粘贴。",
"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": "alternatively drag & drop a file or paste an image from the clipboard",
"File too large, to display a preview. Please download the attachment.": "File too large, to display a preview. Please download the attachment.",
"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.":
"您的浏览器不支持上传加密的文件,请使用更新的浏览器。",
@@ -150,10 +146,43 @@
"输入密码",
"Loading…": "载入中…",
"Decrypting paste…": "正在解密",
"Preparing new paste…": "正在准备新的粘贴",
"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>.":
"如果这个消息一直不消失,请参考 <a href=\"https://github.com/PrivateBin/PrivateBin/wiki/FAQ#why-does-not-the-loading-message-go-away\">这里的 FAQ 进行故障排除</a> (英文版)。",
"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":
"Could not get paste data: %s"
"无法获取粘贴数据:%s",
"QR code": "二维码",
"This website is using an insecure HTTP connection! Please use it only for testing.":
"该网站使用了不安全的HTTP连接 请仅将其用于测试。",
"For more information <a href=\"%s\">see this FAQ entry</a>.":
"有关更多信息,<a href=\"%s\">请参阅此常见问题解答</a>。",
"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.":
"您的浏览器不支持用于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":
"关闭"
}

90
img/browserstack.svg Normal file
View File

@@ -0,0 +1,90 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 490.1 105.6" style="enable-background:new 0 0 490.1 105.6;" xml:space="preserve">
<style type="text/css">
.st0{fill:#F4B960;}
.st1{fill:#E66F32;}
.st2{fill:#E43C41;}
.st3{fill:#BDD041;}
.st4{fill:#6DB54C;}
.st5{fill:#AEDAE6;}
.st6{fill:#56B8DE;}
.st7{fill:#00B1D5;}
.st8{fill:url(#SVGID_1_);}
.st9{fill:#221F1F;}
.st10{fill:#FFFFFF;}
.st11{fill:#000111;}
</style>
<title>Browserstack-logo-white</title>
<circle class="st0" cx="52.8" cy="52.8" r="52.8"/>
<circle class="st1" cx="47.5" cy="47.5" r="47.5"/>
<circle class="st2" cx="53.8" cy="41.1" r="41.1"/>
<circle class="st3" cx="57.1" cy="44.4" r="37.8"/>
<circle class="st4" cx="54.3" cy="47.2" r="35.1"/>
<circle class="st5" cx="48.8" cy="41.7" r="29.5"/>
<circle class="st6" cx="53.6" cy="36.8" r="24.7"/>
<circle class="st7" cx="56.6" cy="39.9" r="21.7"/>
<radialGradient id="SVGID_1_" cx="53.45" cy="63.02" r="18.57" gradientTransform="matrix(1 0 0 -1 0 106)" gradientUnits="userSpaceOnUse">
<stop offset="0" style="stop-color:#797979"/>
<stop offset="1" style="stop-color:#4C4C4C"/>
</radialGradient>
<circle class="st8" cx="53.5" cy="43" r="18.6"/>
<circle class="st9" cx="53.5" cy="43" r="18.6"/>
<ellipse transform="matrix(0.4094 -0.9123 0.9123 0.4094 2.8913 76.9251)" class="st10" cx="60.9" cy="36.2" rx="5.7" ry="3.7"/>
<path class="st11" d="M122.5,32.6c0-0.3,0.3-0.6,0.6-0.6c0,0,0,0,0.1,0h16.6c9.5,0,13.9,4.4,13.9,11c0.2,3.7-1.8,7.2-5.2,8.8v0.1
c3.7,1.5,6.1,5.2,6,9.3c0,8.2-5.6,12.2-15.4,12.2h-16c-0.3,0-0.6-0.2-0.7-0.5c0,0,0,0,0-0.1L122.5,32.6L122.5,32.6z M139.6,49.1
c3.9,0,6.4-2.2,6.4-5.4s-2.4-5.5-6.4-5.5h-8.9c-0.2,0-0.4,0.1-0.4,0.3c0,0,0,0,0,0.1v10.2c0,0.2,0.1,0.3,0.3,0.4c0,0,0,0,0.1,0
H139.6L139.6,49.1z M130.6,66.9h9.3c4.3,0,6.8-2.3,6.8-5.8s-2.4-5.7-6.7-5.7h-9.3c-0.2,0-0.4,0.1-0.4,0.3c0,0,0,0,0,0.1v10.7
C130.3,66.8,130.4,66.9,130.6,66.9C130.6,66.9,130.6,66.9,130.6,66.9L130.6,66.9z"/>
<path class="st11" d="M159.9,73.3c-0.3,0-0.6-0.2-0.7-0.5c0,0,0,0,0-0.1V44.6c0-0.3,0.3-0.6,0.6-0.6c0,0,0,0,0.1,0h6
c0.3,0,0.6,0.2,0.7,0.5c0,0,0,0,0,0.1v2.5h0.1c1.5-2.2,4.2-3.8,8.2-3.8c2.4,0,4.8,0.8,6.6,2.4c0.3,0.3,0.4,0.5,0.1,0.8l-3.5,4.1
c-0.2,0.3-0.6,0.4-0.9,0.2c0,0,0,0-0.1,0c-1.4-0.9-3-1.4-4.7-1.4c-4.1,0-6,2.7-6,7.4v15.9c0,0.3-0.3,0.6-0.6,0.6c0,0,0,0-0.1,0
H159.9L159.9,73.3z"/>
<path class="st11" d="M182.9,65.8c-0.8-2.3-1.1-4.8-1.1-7.2c-0.1-2.5,0.3-4.9,1.1-7.2c1.8-5.1,6.6-8.1,13.1-8.1s11.2,3,13,8.1
c0.8,2.3,1.1,4.8,1.1,7.2c0.1,2.5-0.3,4.9-1.1,7.2c-1.8,5.1-6.6,8.1-13,8.1S184.7,71,182.9,65.8z M201.9,64c0.5-1.7,0.8-3.6,0.7-5.4
c0.1-1.8-0.1-3.7-0.7-5.4c-0.9-2.5-3.3-4-5.9-3.8c-2.6-0.2-5.1,1.4-6,3.8c-0.5,1.8-0.8,3.6-0.7,5.4c-0.1,1.8,0.1,3.7,0.7,5.4
c0.9,2.5,3.4,4,6,3.8C198.6,68,201,66.5,201.9,64L201.9,64z"/>
<path class="st11" d="M241.9,73.3c-0.4,0-0.7-0.3-0.8-0.6L235,53.9h-0.1l-6.2,18.7c-0.1,0.4-0.4,0.6-0.8,0.6h-5.4
c-0.4,0-0.7-0.3-0.8-0.6l-10-28.1c-0.1-0.2,0-0.5,0.2-0.6c0.1,0,0.2-0.1,0.3,0h6.3c0.4,0,0.8,0.2,0.9,0.6l6.1,19.3h0.1l6-19.3
c0.1-0.4,0.5-0.6,0.9-0.6h4.7c0.4,0,0.7,0.2,0.9,0.6l6.4,19.3h0.1l5.8-19.3c0.1-0.4,0.5-0.7,0.9-0.6h6.3c0.2-0.1,0.5,0.1,0.5,0.3
c0,0.1,0,0.2,0,0.3l-10,28.1c-0.1,0.4-0.4,0.6-0.8,0.6L241.9,73.3L241.9,73.3z"/>
<path class="st11" d="M259.3,69.3c-0.2-0.2-0.3-0.6-0.1-0.8c0,0,0,0,0.1-0.1l3.7-3.6c0.3-0.2,0.7-0.2,0.9,0c2.6,2.1,5.9,3.3,9.3,3.3
c3.9,0,5.9-1.5,5.9-3.5c0-1.8-1.1-2.9-5.2-3.2l-3.4-0.3c-6.4-0.6-9.7-3.6-9.7-8.6c0-5.7,4.4-9.2,12.3-9.2c4.2-0.1,8.4,1.2,11.9,3.6
c0.3,0.2,0.3,0.5,0.2,0.8c0,0,0,0,0,0.1l-3.2,3.6c-0.2,0.3-0.6,0.3-0.9,0.1c-2.5-1.5-5.4-2.4-8.3-2.4c-3.1,0-4.8,1.3-4.8,3
s1.1,2.7,5.2,3.1l3.4,0.3c6.6,0.6,9.8,3.8,9.8,8.6c0,5.8-4.6,9.9-13.3,9.9C268,74,263.2,72.4,259.3,69.3z"/>
<path class="st11" d="M291.2,65.8c-0.8-2.3-1.2-4.7-1.1-7.2c-0.1-2.5,0.3-4.9,1-7.2c1.8-5.1,6.6-8.1,12.9-8.1c6.5,0,11.2,3.1,13,8.1
c0.7,2.1,1,4.1,1,8.8c0,0.3-0.3,0.6-0.6,0.6c0,0-0.1,0-0.1,0h-19.5c-0.2,0-0.4,0.1-0.4,0.3c0,0,0,0,0,0.1c0,0.8,0.2,1.5,0.5,2.2
c1,2.9,3.5,4.4,7.1,4.4c2.7,0.1,5.4-0.9,7.4-2.8c0.2-0.3,0.7-0.4,1-0.1c0,0,0,0,0,0l3.9,3.2c0.2,0.1,0.3,0.5,0.2,0.7
c0,0.1-0.1,0.1-0.1,0.1c-2.7,2.9-7.2,5-13,5C297.8,73.9,293,70.9,291.2,65.8z M310.4,52.8c-0.9-2.4-3.2-3.8-6.2-3.8
s-5.4,1.4-6.2,3.8c-0.3,0.8-0.4,1.6-0.4,2.5c0,0.2,0.1,0.3,0.3,0.4c0,0,0,0,0.1,0h12.4c0.2,0,0.4-0.1,0.4-0.3c0,0,0,0,0-0.1
C310.8,54.5,310.6,53.6,310.4,52.8L310.4,52.8z"/>
<path class="st11" d="M323.6,73.3c-0.3,0-0.6-0.2-0.7-0.5c0,0,0,0,0-0.1V44.6c0-0.3,0.3-0.6,0.6-0.6c0,0,0,0,0.1,0h6
c0.3,0,0.6,0.2,0.7,0.5c0,0,0,0,0,0.1v2.5h0.1c1.5-2.2,4.2-3.8,8.2-3.8c2.4,0,4.8,0.8,6.6,2.4c0.3,0.3,0.4,0.5,0.1,0.8l-3.5,4.1
c-0.2,0.3-0.6,0.4-0.9,0.2c0,0,0,0-0.1,0c-1.4-0.9-3-1.4-4.7-1.4c-4.1,0-6,2.7-6,7.4v15.9c0,0.3-0.3,0.6-0.6,0.6c0,0,0,0-0.1,0
H323.6L323.6,73.3z"/>
<path class="st11" d="M346.5,68.5c-0.3-0.2-0.4-0.6-0.2-0.9c0,0,0,0,0,0l4.1-4.4c0.2-0.3,0.6-0.3,0.9-0.1c0,0,0,0,0,0
c3.5,2.7,7.7,4.2,12.1,4.4c5.3,0,8.4-2.5,8.4-6c0-3-2-4.9-8.1-5.7l-2.4-0.3c-8.6-1.1-13.5-4.9-13.5-11.8c0-7.5,5.9-12.4,15.1-12.4
c5.1-0.1,10.1,1.4,14.5,4.2c0.3,0.1,0.4,0.4,0.2,0.7c0,0.1-0.1,0.1-0.1,0.2l-3.1,4.5c-0.2,0.3-0.6,0.4-0.9,0.2
c-3.2-2.1-6.9-3.2-10.7-3.2c-4.5,0-7,2.3-7,5.5c0,2.9,2.2,4.8,8.2,5.6l2.4,0.3c8.6,1.1,13.3,4.9,13.3,12c0,7.3-5.7,12.8-16.8,12.8
C356.3,73.9,350,71.5,346.5,68.5z"/>
<path class="st11" d="M393.3,73.8c-6.4,0-8.8-2.9-8.8-8.6V49.8c0-0.2-0.1-0.3-0.3-0.4c0,0,0,0-0.1,0H382c-0.3,0-0.6-0.2-0.7-0.5
c0,0,0,0,0-0.1v-4.1c0-0.3,0.3-0.6,0.6-0.6c0,0,0,0,0.1,0h2.1c0.2,0,0.4-0.1,0.4-0.3c0,0,0,0,0-0.1v-8c0-0.3,0.3-0.6,0.6-0.6
c0,0,0,0,0.1,0h6c0.3,0,0.6,0.2,0.7,0.5c0,0,0,0,0,0.1v8c0,0.2,0.1,0.3,0.3,0.4c0,0,0,0,0.1,0h4.2c0.3,0,0.6,0.2,0.7,0.5
c0,0,0,0,0,0.1v4.1c0,0.3-0.3,0.6-0.6,0.6c0,0,0,0-0.1,0h-4.2c-0.2,0-0.4,0.1-0.4,0.3c0,0,0,0,0,0.1V65c0,2.1,0.9,2.7,3,2.7h1.6
c0.3,0,0.6,0.2,0.7,0.5c0,0,0,0,0,0.1v4.9c0,0.3-0.3,0.6-0.6,0.6c0,0,0,0-0.1,0L393.3,73.8L393.3,73.8z"/>
<path class="st11" d="M421.2,73.3c-0.3,0-0.6-0.2-0.7-0.5c0,0,0,0,0-0.1v-2.1h0c-1.5,2-4.5,3.4-8.9,3.4c-5.8,0-10.6-2.8-10.6-8.9
c0-6.4,4.9-9.3,12.7-9.3h6.4c0.2,0,0.4-0.1,0.4-0.3c0,0,0,0,0-0.1v-1.4c0-3.3-1.7-4.9-7-4.9c-2.6-0.1-5.1,0.6-7.2,2
c-0.3,0.2-0.7,0.2-0.9-0.1c0,0,0,0,0-0.1l-2.4-4c-0.2-0.2-0.1-0.6,0.1-0.8c0,0,0,0,0,0c2.6-1.7,6-2.9,11.2-2.9
c9.6,0,13.2,3,13.2,10.2v19.1c0,0.3-0.3,0.6-0.6,0.6c0,0,0,0-0.1,0H421.2L421.2,73.3z M420.4,63.4v-2.2c0-0.2-0.1-0.3-0.3-0.4
c0,0,0,0-0.1,0h-5.2c-4.7,0-6.8,1.2-6.8,3.9c0,2.4,1.9,3.6,5.5,3.6C417.9,68.4,420.4,66.8,420.4,63.4L420.4,63.4z"/>
<path class="st11" d="M433.1,65.8c-0.7-2.3-1.1-4.8-1-7.2c-0.1-2.4,0.3-4.9,1-7.2c1.8-5.2,6.7-8.1,13.1-8.1c4.2-0.2,8.2,1.5,11,4.6
c0.2,0.2,0.2,0.6,0,0.8c0,0,0,0-0.1,0.1l-4.1,3.3c-0.3,0.2-0.7,0.2-0.9-0.1c0,0,0,0,0-0.1c-1.5-1.7-3.6-2.6-5.9-2.5
c-2.8,0-5,1.3-5.9,3.8c-0.5,1.8-0.8,3.6-0.7,5.4c-0.1,1.8,0.1,3.7,0.7,5.5c0.9,2.5,3.1,3.8,5.9,3.8c2.2,0.1,4.4-0.9,5.9-2.6
c0.2-0.3,0.6-0.3,0.9-0.1c0,0,0,0,0,0l4.1,3.3c0.3,0.2,0.3,0.5,0.1,0.8c0,0,0,0-0.1,0.1c-2.9,3-6.9,4.6-11,4.5
C439.8,73.9,435,71.1,433.1,65.8z"/>
<path class="st11" d="M482.8,73.3c-0.4,0-0.8-0.2-1-0.6l-8-12.3l-4.3,4.6v7.7c0,0.3-0.3,0.6-0.6,0.6c0,0,0,0-0.1,0h-6
c-0.3,0-0.6-0.2-0.7-0.5c0,0,0,0,0-0.1V32.6c0-0.3,0.3-0.6,0.6-0.6c0,0,0,0,0.1,0h6c0.3,0,0.6,0.2,0.7,0.5c0,0,0,0,0,0.1v23.8
l10.8-11.8c0.3-0.4,0.8-0.6,1.2-0.6h6.7c0.2,0,0.4,0.1,0.4,0.3c0,0.1,0,0.3-0.1,0.3l-10.1,10.7L490,72.7c0.1,0.2,0.1,0.4,0,0.5
c-0.1,0.1-0.2,0.1-0.3,0.1H482.8L482.8,73.3z"/>
</svg>

After

Width:  |  Height:  |  Size: 7.4 KiB

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

9
js/.nycrc.yml Normal file
View File

@@ -0,0 +1,9 @@
---
include:
- legacy.js
- privatebin.js
reporter:
- text
- html
report-dir: ../tst/log/js-coverage-report
temp-dir: /tmp/nyc-output

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

@@ -1 +0,0 @@
(function(global,factory){typeof exports==="object"&&typeof module!=="undefined"?module.exports=factory(global):typeof define==="function"&&define.amd?define(factory):factory(global)})(typeof self!=="undefined"?self:typeof window!=="undefined"?window:typeof global!=="undefined"?global:this,function(global){"use strict";var _Base64=global.Base64;var version="2.4.5";var buffer;if(typeof module!=="undefined"&&module.exports){try{buffer=require("buffer").Buffer}catch(err){}}var b64chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var b64tab=function(bin){var t={};for(var i=0,l=bin.length;i<l;i++)t[bin.charAt(i)]=i;return t}(b64chars);var fromCharCode=String.fromCharCode;var cb_utob=function(c){if(c.length<2){var cc=c.charCodeAt(0);return cc<128?c:cc<2048?fromCharCode(192|cc>>>6)+fromCharCode(128|cc&63):fromCharCode(224|cc>>>12&15)+fromCharCode(128|cc>>>6&63)+fromCharCode(128|cc&63)}else{var cc=65536+(c.charCodeAt(0)-55296)*1024+(c.charCodeAt(1)-56320);return fromCharCode(240|cc>>>18&7)+fromCharCode(128|cc>>>12&63)+fromCharCode(128|cc>>>6&63)+fromCharCode(128|cc&63)}};var re_utob=/[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;var utob=function(u){return u.replace(re_utob,cb_utob)};var cb_encode=function(ccc){var padlen=[0,2,1][ccc.length%3],ord=ccc.charCodeAt(0)<<16|(ccc.length>1?ccc.charCodeAt(1):0)<<8|(ccc.length>2?ccc.charCodeAt(2):0),chars=[b64chars.charAt(ord>>>18),b64chars.charAt(ord>>>12&63),padlen>=2?"=":b64chars.charAt(ord>>>6&63),padlen>=1?"=":b64chars.charAt(ord&63)];return chars.join("")};var btoa=global.btoa?function(b){return global.btoa(b)}:function(b){return b.replace(/[\s\S]{1,3}/g,cb_encode)};var _encode=buffer?buffer.from&&Uint8Array&&buffer.from!==Uint8Array.from?function(u){return(u.constructor===buffer.constructor?u:buffer.from(u)).toString("base64")}:function(u){return(u.constructor===buffer.constructor?u:new buffer(u)).toString("base64")}:function(u){return btoa(utob(u))};var encode=function(u,urisafe){return!urisafe?_encode(String(u)):_encode(String(u)).replace(/[+\/]/g,function(m0){return m0=="+"?"-":"_"}).replace(/=/g,"")};var encodeURI=function(u){return encode(u,true)};var re_btou=new RegExp(["[À-ß][€-¿]","[à-ï][€-¿]{2}","[ð-÷][€-¿]{3}"].join("|"),"g");var cb_btou=function(cccc){switch(cccc.length){case 4:var cp=(7&cccc.charCodeAt(0))<<18|(63&cccc.charCodeAt(1))<<12|(63&cccc.charCodeAt(2))<<6|63&cccc.charCodeAt(3),offset=cp-65536;return fromCharCode((offset>>>10)+55296)+fromCharCode((offset&1023)+56320);case 3:return fromCharCode((15&cccc.charCodeAt(0))<<12|(63&cccc.charCodeAt(1))<<6|63&cccc.charCodeAt(2));default:return fromCharCode((31&cccc.charCodeAt(0))<<6|63&cccc.charCodeAt(1))}};var btou=function(b){return b.replace(re_btou,cb_btou)};var cb_decode=function(cccc){var len=cccc.length,padlen=len%4,n=(len>0?b64tab[cccc.charAt(0)]<<18:0)|(len>1?b64tab[cccc.charAt(1)]<<12:0)|(len>2?b64tab[cccc.charAt(2)]<<6:0)|(len>3?b64tab[cccc.charAt(3)]:0),chars=[fromCharCode(n>>>16),fromCharCode(n>>>8&255),fromCharCode(n&255)];chars.length-=[0,0,2,1][padlen];return chars.join("")};var atob=global.atob?function(a){return global.atob(a)}:function(a){return a.replace(/[\s\S]{1,4}/g,cb_decode)};var _decode=buffer?buffer.from&&Uint8Array&&buffer.from!==Uint8Array.from?function(a){return(a.constructor===buffer.constructor?a:buffer.from(a,"base64")).toString()}:function(a){return(a.constructor===buffer.constructor?a:new buffer(a,"base64")).toString()}:function(a){return btou(atob(a))};var decode=function(a){return _decode(String(a).replace(/[-_]/g,function(m0){return m0=="-"?"+":"/"}).replace(/[^A-Za-z0-9\+\/]/g,""))};var noConflict=function(){var Base64=global.Base64;global.Base64=_Base64;return Base64};global.Base64={VERSION:version,atob:atob,btoa:btoa,fromBase64:decode,toBase64:encode,utob:utob,encode:encode,encodeURI:encodeURI,btou:btou,decode:decode,noConflict:noConflict};if(typeof Object.defineProperty==="function"){var noEnum=function(v){return{value:v,enumerable:false,writable:true,configurable:true}};global.Base64.extendString=function(){Object.defineProperty(String.prototype,"fromBase64",noEnum(function(){return decode(this)}));Object.defineProperty(String.prototype,"toBase64",noEnum(function(urisafe){return encode(this,urisafe)}));Object.defineProperty(String.prototype,"toBase64URI",noEnum(function(){return encode(this,true)}))}}if(global["Meteor"]){Base64=global.Base64}if(typeof module!=="undefined"&&module.exports){module.exports.Base64=global.Base64}else if(typeof define==="function"&&define.amd){define([],function(){return global.Base64})}return{Base64:global.Base64}});

View File

@@ -1,16 +1,35 @@
{
"@context": {
"so": "https://schema.org/",
"status": "so:Integer",
"id": "so:name",
"parentid": "so:name",
"url: {
"@id": "so:url",
"@type": "@id"
"pb": "?jsonld=types#",
"cm": "?jsonld=commentmeta#",
"status": {
"@type": "so:Integer"
},
"id": {
"@type": "so:name"
},
"pasteid": {
"@type": "so:name"
},
"parentid": {
"@type": "so:name"
},
"url": {
"@type": "so:url"
},
"v": {
"@type": "so:Integer",
"@value": 2
},
"ct": {
"@type": "pb:CipherText"
},
"adata": {
"@type": "pb:CipherParameters"
},
"data": "so:Text",
"meta": {
"@id": "?jsonld=commentmeta"
"@type": "cm:MetaData"
}
}
}

View File

@@ -1,8 +1,14 @@
{
"@context": {
"so": "https://schema.org/",
"postdate": "so:Integer",
"nickname": "so:Text",
"vizhash": "so:Text"
"pb": "?jsonld=types#"
},
"MetaData": {
"created": {
"@type": "CreationTime"
},
"icon": {
"@type": "so:url"
}
}
}

View File

@@ -5,61 +5,44 @@ global.assert = require('assert');
global.jsc = require('jsverify');
global.jsdom = require('jsdom-global');
global.cleanup = global.jsdom();
global.URL = require('jsdom-url').URL;
global.fs = require('fs');
global.WebCrypto = require('node-webcrypto-ossl');
// application libraries to test
global.$ = global.jQuery = require('./jquery-3.3.1');
global.sjcl = require('./sjcl-1.0.7');
global.Base64 = require('./base64-2.4.5').Base64;
global.RawDeflate = require('./rawdeflate-0.5').RawDeflate;
global.RawDeflate.inflate = require('./rawinflate-0.3').RawDeflate.inflate;
global.$ = global.jQuery = require('./jquery-3.4.1');
global.RawDeflate = require('./rawinflate-0.3').RawDeflate;
global.zlib = require('./zlib-1.2.11').zlib;
require('./prettify');
global.prettyPrint = window.PR.prettyPrint;
global.prettyPrintOne = window.PR.prettyPrintOne;
global.showdown = require('./showdown-1.8.6');
global.DOMPurify = require('./purify-1.0.7');
global.showdown = require('./showdown-1.9.1');
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');
// internal variables
var a2zString = ['a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z'],
alnumString = a2zString.concat(['0','1','2','3','4','5','6','7','8','9']),
queryString = alnumString.concat(['+','%','&','.','*','-','_']),
hashString = queryString.concat(['!']),
var a2zString = ['a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z'],
digitString = ['0','1','2','3','4','5','6','7','8','9'],
alnumString = a2zString.concat(digitString),
hexString = digitString.concat(['a','b','c','d','e','f']),
queryString = alnumString.concat(['+','%','&','.','*','-','_']),
hashString = queryString.concat(['!']),
base64String = alnumString.concat(['+','/','=']).concat(
a2zString.map(function(c) {
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;'
},
logFile = fs.createWriteStream('test.log'),
mimeFile = fs.createReadStream('/etc/mime.types'),
mimeLine = '';
// redirect console messages to log file
console.info = console.warn = console.error = function () {
logFile.write(Array.prototype.slice.call(arguments).join('') + '\n');
};
// populate mime types from environment
mimeFile.on('data', function(data) {
mimeLine += data;
@@ -96,22 +79,8 @@ function parseMime(line) {
}
// common testing helper functions
/**
* 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];
});
};
exports.atob = atob;
exports.btoa = btoa;
// provides random lowercase characters from a to z
exports.jscA2zString = function() {
@@ -123,6 +92,11 @@ exports.jscAlnumString = function() {
return jsc.elements(alnumString);
};
//provides random characters allowed in hexadecimal notation
exports.jscHexString = function() {
return jsc.elements(hexString);
};
// provides random characters allowed in GET queries
exports.jscQueryString = function() {
return jsc.elements(queryString);

2
js/jquery-3.3.1.js vendored

File diff suppressed because one or more lines are too long

2
js/jquery-3.4.1.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

2
js/kjua-0.6.0.js Normal file

File diff suppressed because one or more lines are too long

311
js/legacy.js Normal file
View File

@@ -0,0 +1,311 @@
/**
* PrivateBin
*
* a zero-knowledge paste bin
*
* @see {@link https://github.com/PrivateBin/PrivateBin}
* @copyright 2012 Sébastien SAUVAGE ({@link http://sebsauvage.net})
* @license {@link https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License}
* @version 1.3.1
* @name Legacy
* @namespace
*/
/**
* IMPORTANT NOTICE FOR DEVELOPERS:
* The logic in this file is intended to run in legacy browsers. Avoid any use of:
* - jQuery (doesn't work in older browsers)
* - ES5 or newer in general
* - const/let, use the traditional var declarations instead
* - async/await or Promises, use traditional callbacks
* - shorthand function notation "() => output", use the full "function() {return output;}" style
* - IE doesn't support:
* - URL(), use the traditional window.location object
* - endsWith(), use indexof()
* - yes, this logic needs to support IE 6, to at least display the error message
*/
'use strict';
(function() {
/**
* compatibility check
*
* @name Check
* @class
*/
var Check = (function () {
var me = {};
/**
* Status of the initial check, true means it passed
*
* @private
* @prop {bool}
*/
var status = false;
/**
* Initialization check did run
*
* @private
* @prop {bool}
*/
var init = false;
/**
* blacklist of UserAgents (parts) known to belong to a bot
*
* @private
* @enum {Array}
* @readonly
*/
var badBotUA = [
'Bot',
'bot'
];
/**
* whitelist of top level domains to consider a secure context,
* regardless of protocol
*
* @private
* @enum {Array}
* @readonly
*/
var tld = [
'.onion',
'.i2p'
];
/**
* whitelist of hostnames to consider a secure context,
* regardless of protocol
*
* @private
* @enum {Array}
* @readonly
*/
// whitelists of TLDs & local hostnames
var hostname = [
'localhost',
'127.0.0.1',
'[::1]'
];
/**
* check if the context is secure
*
* @private
* @name Check.isSecureContext
* @function
* @return {bool}
*/
function isSecureContext()
{
// use .isSecureContext if available
if (window.isSecureContext === true || window.isSecureContext === false) {
return window.isSecureContext;
}
// HTTP is obviously insecure
if (window.location.protocol !== 'http:') {
return true;
}
// filter out actually secure connections over HTTP
for (var i = 0; i < tld.length; i++) {
if (
window.location.hostname.indexOf(
tld[i],
window.location.hostname.length - tld[i].length
) !== -1
) {
return true;
}
}
// whitelist localhost for development
for (var j = 0; j < hostname.length; j++) {
if (window.location.hostname === hostname[j]) {
return true;
}
}
// totally INSECURE http protocol!
return false;
}
/**
* checks whether this is a bot we dislike
*
* @private
* @name Check.isBadBot
* @function
* @return {bool}
*/
function isBadBot() {
// check whether a bot user agent part can be found in the current
// user agent
for (var i = 0; i < badBotUA.length; i++) {
if (navigator.userAgent.indexOf(badBotUA[i]) !== -1) {
return true;
}
}
return false;
}
/**
* checks whether this is an unsupported browser, via feature detection
*
* @private
* @name Check.isOldBrowser
* @function
* @return {bool}
*/
function isOldBrowser() {
// webcrypto support
if (!(
'crypto' in window &&
'getRandomValues' in window.crypto &&
'subtle' in window.crypto &&
'encrypt' in window.crypto.subtle &&
'decrypt' in window.crypto.subtle &&
'Uint8Array' in window &&
'Uint32Array' in window
)) {
return true;
}
// async & ES6 support
try {
eval('async () => {}');
} catch (e) {
if (e instanceof SyntaxError) {
return true;
} else {
throw e; // throws CSP error
}
}
return false;
}
/**
* shows an error message
*
* @private
* @name Check.showError
* @param {string} message
* @function
*/
function showError(message)
{
var element = document.getElementById('errormessage');
if (message.indexOf('<a') === -1) {
element.appendChild(
document.createTextNode(message)
);
} else {
element.innerHTML = message;
}
removeHiddenFromId('errormessage');
}
/**
* removes "hidden" CSS class from element with given ID
*
* @private
* @name Check.removeHiddenFromId
* @param {string} id
* @function
*/
function removeHiddenFromId(id)
{
var element = document.getElementById(id);
if (element) {
element.className = element.className.replace(/\bhidden\b/g, '');
}
}
/**
* returns if the check has concluded
*
* @name Check.getInit
* @function
* @return {bool}
*/
me.getInit = function()
{
return init;
};
/**
* returns the current status of the check
*
* @name Check.getStatus
* @function
* @return {bool}
*/
me.getStatus = function()
{
return status;
};
/**
* init on application start, returns an all-clear signal
*
* @name Check.init
* @function
*/
me.init = function()
{
// prevent bots from viewing a paste and potentially deleting data
// when burn-after-reading is set
if (isBadBot()) {
showError('I love you too, bot…');
init = true;
return;
}
if (isOldBrowser()) {
// some browsers (Chrome based ones) would have webcrypto support if using HTTPS
if (!isSecureContext()) {
removeHiddenFromId('insecurecontextnotice');
}
removeHiddenFromId('oldnotice');
init = true;
return;
}
if (!isSecureContext()) {
removeHiddenFromId('httpnotice');
}
init = true;
// only if everything passed, we set the status to true
status = true;
};
return me;
})();
// main application start, called when DOM is fully loaded
if (document.readyState === 'complete' || (!document.attachEvent && document.readyState === 'interactive')) {
Check.init();
} else {
if (document.addEventListener) {
// first choice is DOMContentLoaded event
document.addEventListener('DOMContentLoaded', Check.init, false);
// backup is window load event
window.addEventListener('load', Check.init, false);
} else {
// must be IE
document.attachEvent('onreadystatechange', Check.init);
window.attachEvent('onload', Check.init);
}
}
this.Legacy = {
Check: Check
};
}).call(this);

43
js/package.json Normal file
View File

@@ -0,0 +1,43 @@
{
"name": "privatebin",
"version": "1.3.0",
"description": "PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted in the browser using 256 bit AES in Galois Counter mode (GCM).",
"main": "privatebin.js",
"directories": {
"test": "test"
},
"dependencies": {},
"devDependencies": {
"jsdom": "^9.12.0",
"jsdom-global": "^2.1.1",
"jsdom-url": "^2.2.1",
"jsverify": "^0.8.3",
"node-webcrypto-ossl": "^1.0.37"
},
"scripts": {
"test": "mocha"
},
"repository": {
"type": "git",
"url": "git+https://github.com/PrivateBin/PrivateBin.git"
},
"keywords": [
"private",
"secure",
"end-to-end-encrypted",
"e2e",
"paste",
"pastebin",
"zero",
"zero-knowledge",
"encryption",
"encrypted",
"AES"
],
"author": "",
"license": "zlib-acknowledgement",
"bugs": {
"url": "https://github.com/PrivateBin/PrivateBin/issues"
},
"homepage": "https://privatebin.info/"
}

View File

@@ -1,24 +1,42 @@
{
"@context": {
"so": "https://schema.org/",
"status": {"@id": "so:Integer"},
"id": {"@id": "so:name"},
"deletetoken": {"@id": "so:Text"},
"url": {
"@type": "@id",
"@id": "so:url"
"pb": "?jsonld=types#",
"pm": "?jsonld=pastemeta#",
"status": {
"@type": "so:Integer"
},
"id": {
"@type": "so:name"
},
"deletetoken": {
"@type": "so:Text"
},
"url": {
"@type": "so:url"
},
"v": {
"@type": "so:Integer",
"@value": 2
},
"ct": {
"@type": "pb:CipherText"
},
"adata": {
"@type": "pm:AuthenticatedData"
},
"data": {"@id": "so:Text"},
"attachment": {"@id": "so:Text"},
"attachmentname": {"@id": "so:Text"},
"meta": {
"@id": "?jsonld=pastemeta"
"@type": "pm:MetaData"
},
"comments": {
"@id": "?jsonld=comment",
"@type": "?jsonld=comment",
"@container": "@list"
},
"comment_count": {"@id": "so:Integer"},
"comment_offset": {"@id": "so:Integer"}
"comment_count": {
"@type": "so:Integer"
},
"comment_offset": {
"@type": "so:Integer"
}
}
}

View File

@@ -1,11 +1,31 @@
{
"@context": {
"so": "https://schema.org/",
"formatter": {"@id": "so:Text"},
"postdate": {"@id": "so:Integer"},
"opendiscussion": {"@id": "so:True"},
"burnafterreading": {"@id": "so:True"},
"expire_date": {"@id": "so:Integer"},
"remaining_time": {"@id": "so:Integer"}
"pb": "?jsonld=types#"
},
"AuthenticatedData": {
"@container": "@list",
"@value": [
{
"@type": "pb:CipherParameters"
},
{
"@type": "pb:Formatter"
},
{
"@type": "pb:OpenDiscussion"
},
{
"@type": "pb:BurnAfterReading"
}
]
},
"MetaData": {
"expire": {
"@type": "pb:Expiration"
},
"time_to_live": {
"@type": "pb:RemainingSeconds"
}
}
}

File diff suppressed because it is too large Load Diff

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 it is too large Load Diff

File diff suppressed because one or more lines are too long

2
js/showdown-1.9.1.js Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,60 +0,0 @@
"use strict";var sjcl={cipher:{},hash:{},keyexchange:{},mode:{},misc:{},codec:{},exception:{corrupt:function(a){this.toString=function(){return"CORRUPT: "+this.message};this.message=a},invalid:function(a){this.toString=function(){return"INVALID: "+this.message};this.message=a},bug:function(a){this.toString=function(){return"BUG: "+this.message};this.message=a},notReady:function(a){this.toString=function(){return"NOT READY: "+this.message};this.message=a}}};
sjcl.cipher.aes=function(a){this.s[0][0][0]||this.O();var b,c,d,e,f=this.s[0][4],g=this.s[1];b=a.length;var h=1;if(4!==b&&6!==b&&8!==b)throw new sjcl.exception.invalid("invalid aes key size");this.b=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(0===a%b||8===b&&4===a%b)c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255],0===a%b&&(c=c<<8^c>>>24^h<<24,h=h<<1^283*(h>>7));d[a]=d[a-b]^c}for(b=0;a;b++,a--)c=d[b&3?a:a-4],e[b]=4>=a||4>b?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^g[3][f[c&
255]]};
sjcl.cipher.aes.prototype={encrypt:function(a){return t(this,a,0)},decrypt:function(a){return t(this,a,1)},s:[[[],[],[],[],[]],[[],[],[],[],[]]],O:function(){var a=this.s[0],b=this.s[1],c=a[4],d=b[4],e,f,g,h=[],k=[],l,n,m,p;for(e=0;0x100>e;e++)k[(h[e]=e<<1^283*(e>>7))^e]=e;for(f=g=0;!c[f];f^=l||1,g=k[g]||1)for(m=g^g<<1^g<<2^g<<3^g<<4,m=m>>8^m&255^99,c[f]=m,d[m]=f,n=h[e=h[l=h[f]]],p=0x1010101*n^0x10001*e^0x101*l^0x1010100*f,n=0x101*h[m]^0x1010100*m,e=0;4>e;e++)a[e][f]=n=n<<24^n>>>8,b[e][m]=p=p<<24^p>>>8;for(e=
0;5>e;e++)a[e]=a[e].slice(0),b[e]=b[e].slice(0)}};
function t(a,b,c){if(4!==b.length)throw new sjcl.exception.invalid("invalid aes block size");var d=a.b[c],e=b[0]^d[0],f=b[c?3:1]^d[1],g=b[2]^d[2];b=b[c?1:3]^d[3];var h,k,l,n=d.length/4-2,m,p=4,r=[0,0,0,0];h=a.s[c];a=h[0];var q=h[1],v=h[2],w=h[3],x=h[4];for(m=0;m<n;m++)h=a[e>>>24]^q[f>>16&255]^v[g>>8&255]^w[b&255]^d[p],k=a[f>>>24]^q[g>>16&255]^v[b>>8&255]^w[e&255]^d[p+1],l=a[g>>>24]^q[b>>16&255]^v[e>>8&255]^w[f&255]^d[p+2],b=a[b>>>24]^q[e>>16&255]^v[f>>8&255]^w[g&255]^d[p+3],p+=4,e=h,f=k,g=l;for(m=
0;4>m;m++)r[c?3&-m:m]=x[e>>>24]<<24^x[f>>16&255]<<16^x[g>>8&255]<<8^x[b&255]^d[p++],h=e,e=f,f=g,g=b,b=h;return r}
sjcl.bitArray={bitSlice:function(a,b,c){a=sjcl.bitArray.$(a.slice(b/32),32-(b&31)).slice(1);return void 0===c?a:sjcl.bitArray.clamp(a,c-b)},extract:function(a,b,c){var d=Math.floor(-b-c&31);return((b+c-1^b)&-32?a[b/32|0]<<32-d^a[b/32+1|0]>>>d:a[b/32|0]>>>d)&(1<<c)-1},concat:function(a,b){if(0===a.length||0===b.length)return a.concat(b);var c=a[a.length-1],d=sjcl.bitArray.getPartial(c);return 32===d?a.concat(b):sjcl.bitArray.$(b,d,c|0,a.slice(0,a.length-1))},bitLength:function(a){var b=a.length;return 0===
b?0:32*(b-1)+sjcl.bitArray.getPartial(a[b-1])},clamp:function(a,b){if(32*a.length<b)return a;a=a.slice(0,Math.ceil(b/32));var c=a.length;b=b&31;0<c&&b&&(a[c-1]=sjcl.bitArray.partial(b,a[c-1]&2147483648>>b-1,1));return a},partial:function(a,b,c){return 32===a?b:(c?b|0:b<<32-a)+0x10000000000*a},getPartial:function(a){return Math.round(a/0x10000000000)||32},equal:function(a,b){if(sjcl.bitArray.bitLength(a)!==sjcl.bitArray.bitLength(b))return!1;var c=0,d;for(d=0;d<a.length;d++)c|=a[d]^b[d];return 0===
c},$:function(a,b,c,d){var e;e=0;for(void 0===d&&(d=[]);32<=b;b-=32)d.push(c),c=0;if(0===b)return d.concat(a);for(e=0;e<a.length;e++)d.push(c|a[e]>>>b),c=a[e]<<32-b;e=a.length?a[a.length-1]:0;a=sjcl.bitArray.getPartial(e);d.push(sjcl.bitArray.partial(b+a&31,32<b+a?c:d.pop(),1));return d},i:function(a,b){return[a[0]^b[0],a[1]^b[1],a[2]^b[2],a[3]^b[3]]},byteswapM:function(a){var b,c;for(b=0;b<a.length;++b)c=a[b],a[b]=c>>>24|c>>>8&0xff00|(c&0xff00)<<8|c<<24;return a}};
sjcl.codec.utf8String={fromBits:function(a){var b="",c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d<c/8;d++)0===(d&3)&&(e=a[d/4]),b+=String.fromCharCode(e>>>8>>>8>>>8),e<<=8;return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],c,d=0;for(c=0;c<a.length;c++)d=d<<8|a.charCodeAt(c),3===(c&3)&&(b.push(d),d=0);c&3&&b.push(sjcl.bitArray.partial(8*(c&3),d));return b}};
sjcl.codec.hex={fromBits:function(a){var b="",c;for(c=0;c<a.length;c++)b+=((a[c]|0)+0xf00000000000).toString(16).substr(4);return b.substr(0,sjcl.bitArray.bitLength(a)/4)},toBits:function(a){var b,c=[],d;a=a.replace(/\s|0x/g,"");d=a.length;a=a+"00000000";for(b=0;b<a.length;b+=8)c.push(parseInt(a.substr(b,8),16)^0);return sjcl.bitArray.clamp(c,4*d)}};
sjcl.codec.base32={B:"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",X:"0123456789ABCDEFGHIJKLMNOPQRSTUV",BITS:32,BASE:5,REMAINING:27,fromBits:function(a,b,c){var d=sjcl.codec.base32.BASE,e=sjcl.codec.base32.REMAINING,f="",g=0,h=sjcl.codec.base32.B,k=0,l=sjcl.bitArray.bitLength(a);c&&(h=sjcl.codec.base32.X);for(c=0;f.length*d<l;)f+=h.charAt((k^a[c]>>>g)>>>e),g<d?(k=a[c]<<d-g,g+=e,c++):(k<<=d,g-=d);for(;f.length&7&&!b;)f+="=";return f},toBits:function(a,b){a=a.replace(/\s|=/g,"").toUpperCase();var c=sjcl.codec.base32.BITS,
d=sjcl.codec.base32.BASE,e=sjcl.codec.base32.REMAINING,f=[],g,h=0,k=sjcl.codec.base32.B,l=0,n,m="base32";b&&(k=sjcl.codec.base32.X,m="base32hex");for(g=0;g<a.length;g++){n=k.indexOf(a.charAt(g));if(0>n){if(!b)try{return sjcl.codec.base32hex.toBits(a)}catch(p){}throw new sjcl.exception.invalid("this isn't "+m+"!");}h>e?(h-=e,f.push(l^n>>>h),l=n<<c-h):(h+=d,l^=n<<c-h)}h&56&&f.push(sjcl.bitArray.partial(h&56,l,1));return f}};
sjcl.codec.base32hex={fromBits:function(a,b){return sjcl.codec.base32.fromBits(a,b,1)},toBits:function(a){return sjcl.codec.base32.toBits(a,1)}};
sjcl.codec.base64={B:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",fromBits:function(a,b,c){var d="",e=0,f=sjcl.codec.base64.B,g=0,h=sjcl.bitArray.bitLength(a);c&&(f=f.substr(0,62)+"-_");for(c=0;6*d.length<h;)d+=f.charAt((g^a[c]>>>e)>>>26),6>e?(g=a[c]<<6-e,e+=26,c++):(g<<=6,e-=6);for(;d.length&3&&!b;)d+="=";return d},toBits:function(a,b){a=a.replace(/\s|=/g,"");var c=[],d,e=0,f=sjcl.codec.base64.B,g=0,h;b&&(f=f.substr(0,62)+"-_");for(d=0;d<a.length;d++){h=f.indexOf(a.charAt(d));
if(0>h)throw new sjcl.exception.invalid("this isn't base64!");26<e?(e-=26,c.push(g^h>>>e),g=h<<32-e):(e+=6,g^=h<<32-e)}e&56&&c.push(sjcl.bitArray.partial(e&56,g,1));return c}};sjcl.codec.base64url={fromBits:function(a){return sjcl.codec.base64.fromBits(a,1,1)},toBits:function(a){return sjcl.codec.base64.toBits(a,1)}};sjcl.hash.sha256=function(a){this.b[0]||this.O();a?(this.F=a.F.slice(0),this.A=a.A.slice(0),this.l=a.l):this.reset()};sjcl.hash.sha256.hash=function(a){return(new sjcl.hash.sha256).update(a).finalize()};
sjcl.hash.sha256.prototype={blockSize:512,reset:function(){this.F=this.Y.slice(0);this.A=[];this.l=0;return this},update:function(a){"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));var b,c=this.A=sjcl.bitArray.concat(this.A,a);b=this.l;a=this.l=b+sjcl.bitArray.bitLength(a);if(0x1fffffffffffff<a)throw new sjcl.exception.invalid("Cannot hash more than 2^53 - 1 bits");if("undefined"!==typeof Uint32Array){var d=new Uint32Array(c),e=0;for(b=512+b-(512+b&0x1ff);b<=a;b+=512)u(this,d.subarray(16*e,
16*(e+1))),e+=1;c.splice(0,16*e)}else for(b=512+b-(512+b&0x1ff);b<=a;b+=512)u(this,c.splice(0,16));return this},finalize:function(){var a,b=this.A,c=this.F,b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);b.push(Math.floor(this.l/0x100000000));for(b.push(this.l|0);b.length;)u(this,b.splice(0,16));this.reset();return c},Y:[],b:[],O:function(){function a(a){return 0x100000000*(a-Math.floor(a))|0}for(var b=0,c=2,d,e;64>b;c++){e=!0;for(d=2;d*d<=c;d++)if(0===c%d){e=
!1;break}e&&(8>b&&(this.Y[b]=a(Math.pow(c,.5))),this.b[b]=a(Math.pow(c,1/3)),b++)}}};
function u(a,b){var c,d,e,f=a.F,g=a.b,h=f[0],k=f[1],l=f[2],n=f[3],m=f[4],p=f[5],r=f[6],q=f[7];for(c=0;64>c;c++)16>c?d=b[c]:(d=b[c+1&15],e=b[c+14&15],d=b[c&15]=(d>>>7^d>>>18^d>>>3^d<<25^d<<14)+(e>>>17^e>>>19^e>>>10^e<<15^e<<13)+b[c&15]+b[c+9&15]|0),d=d+q+(m>>>6^m>>>11^m>>>25^m<<26^m<<21^m<<7)+(r^m&(p^r))+g[c],q=r,r=p,p=m,m=n+d|0,n=l,l=k,k=h,h=d+(k&l^n&(k^l))+(k>>>2^k>>>13^k>>>22^k<<30^k<<19^k<<10)|0;f[0]=f[0]+h|0;f[1]=f[1]+k|0;f[2]=f[2]+l|0;f[3]=f[3]+n|0;f[4]=f[4]+m|0;f[5]=f[5]+p|0;f[6]=f[6]+r|0;f[7]=
f[7]+q|0}
sjcl.mode.ccm={name:"ccm",G:[],listenProgress:function(a){sjcl.mode.ccm.G.push(a)},unListenProgress:function(a){a=sjcl.mode.ccm.G.indexOf(a);-1<a&&sjcl.mode.ccm.G.splice(a,1)},fa:function(a){var b=sjcl.mode.ccm.G.slice(),c;for(c=0;c<b.length;c+=1)b[c](a)},encrypt:function(a,b,c,d,e){var f,g=b.slice(0),h=sjcl.bitArray,k=h.bitLength(c)/8,l=h.bitLength(g)/8;e=e||64;d=d||[];if(7>k)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(f=2;4>f&&l>>>8*f;f++);f<15-k&&(f=15-k);c=h.clamp(c,
8*(15-f));b=sjcl.mode.ccm.V(a,b,c,d,e,f);g=sjcl.mode.ccm.C(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),k=f.clamp(b,h-e),l=f.bitSlice(b,h-e),h=(h-e)/8;if(7>g)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(b=2;4>b&&h>>>8*b;b++);b<15-g&&(b=15-g);c=f.clamp(c,8*(15-b));k=sjcl.mode.ccm.C(a,k,c,l,e,b);a=sjcl.mode.ccm.V(a,k.data,c,d,e,b);if(!f.equal(k.tag,a))throw new sjcl.exception.corrupt("ccm: tag doesn't match");
return k.data},na:function(a,b,c,d,e,f){var g=[],h=sjcl.bitArray,k=h.i;d=[h.partial(8,(b.length?64:0)|d-2<<2|f-1)];d=h.concat(d,c);d[3]|=e;d=a.encrypt(d);if(b.length)for(c=h.bitLength(b)/8,65279>=c?g=[h.partial(16,c)]:0xffffffff>=c&&(g=h.concat([h.partial(16,65534)],[c])),g=h.concat(g,b),b=0;b<g.length;b+=4)d=a.encrypt(k(d,g.slice(b,b+4).concat([0,0,0])));return d},V:function(a,b,c,d,e,f){var g=sjcl.bitArray,h=g.i;e/=8;if(e%2||4>e||16<e)throw new sjcl.exception.invalid("ccm: invalid tag length");
if(0xffffffff<d.length||0xffffffff<b.length)throw new sjcl.exception.bug("ccm: can't deal with 4GiB or more data");c=sjcl.mode.ccm.na(a,d,c,e,g.bitLength(b)/8,f);for(d=0;d<b.length;d+=4)c=a.encrypt(h(c,b.slice(d,d+4).concat([0,0,0])));return g.clamp(c,8*e)},C:function(a,b,c,d,e,f){var g,h=sjcl.bitArray;g=h.i;var k=b.length,l=h.bitLength(b),n=k/50,m=n;c=h.concat([h.partial(8,f-1)],c).concat([0,0,0]).slice(0,4);d=h.bitSlice(g(d,a.encrypt(c)),0,e);if(!k)return{tag:d,data:[]};for(g=0;g<k;g+=4)g>n&&(sjcl.mode.ccm.fa(g/
k),n+=m),c[3]++,e=a.encrypt(c),b[g]^=e[0],b[g+1]^=e[1],b[g+2]^=e[2],b[g+3]^=e[3];return{tag:d,data:h.clamp(b,l)}}};
sjcl.mode.ocb2={name:"ocb2",encrypt:function(a,b,c,d,e,f){if(128!==sjcl.bitArray.bitLength(c))throw new sjcl.exception.invalid("ocb iv must be 128 bits");var g,h=sjcl.mode.ocb2.S,k=sjcl.bitArray,l=k.i,n=[0,0,0,0];c=h(a.encrypt(c));var m,p=[];d=d||[];e=e||64;for(g=0;g+4<b.length;g+=4)m=b.slice(g,g+4),n=l(n,m),p=p.concat(l(c,a.encrypt(l(c,m)))),c=h(c);m=b.slice(g);b=k.bitLength(m);g=a.encrypt(l(c,[0,0,0,b]));m=k.clamp(l(m.concat([0,0,0]),g),b);n=l(n,l(m.concat([0,0,0]),g));n=a.encrypt(l(n,l(c,h(c))));
d.length&&(n=l(n,f?d:sjcl.mode.ocb2.pmac(a,d)));return p.concat(k.concat(m,k.clamp(n,e)))},decrypt:function(a,b,c,d,e,f){if(128!==sjcl.bitArray.bitLength(c))throw new sjcl.exception.invalid("ocb iv must be 128 bits");e=e||64;var g=sjcl.mode.ocb2.S,h=sjcl.bitArray,k=h.i,l=[0,0,0,0],n=g(a.encrypt(c)),m,p,r=sjcl.bitArray.bitLength(b)-e,q=[];d=d||[];for(c=0;c+4<r/32;c+=4)m=k(n,a.decrypt(k(n,b.slice(c,c+4)))),l=k(l,m),q=q.concat(m),n=g(n);p=r-32*c;m=a.encrypt(k(n,[0,0,0,p]));m=k(m,h.clamp(b.slice(c),p).concat([0,
0,0]));l=k(l,m);l=a.encrypt(k(l,k(n,g(n))));d.length&&(l=k(l,f?d:sjcl.mode.ocb2.pmac(a,d)));if(!h.equal(h.clamp(l,e),h.bitSlice(b,r)))throw new sjcl.exception.corrupt("ocb: tag doesn't match");return q.concat(h.clamp(m,p))},pmac:function(a,b){var c,d=sjcl.mode.ocb2.S,e=sjcl.bitArray,f=e.i,g=[0,0,0,0],h=a.encrypt([0,0,0,0]),h=f(h,d(d(h)));for(c=0;c+4<b.length;c+=4)h=d(h),g=f(g,a.encrypt(f(h,b.slice(c,c+4))));c=b.slice(c);128>e.bitLength(c)&&(h=f(h,d(h)),c=e.concat(c,[-2147483648,0,0,0]));g=f(g,c);
return a.encrypt(f(d(f(h,d(h))),g))},S:function(a){return[a[0]<<1^a[1]>>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^135*(a[0]>>>31)]}};
sjcl.mode.gcm={name:"gcm",encrypt:function(a,b,c,d,e){var f=b.slice(0);b=sjcl.bitArray;d=d||[];a=sjcl.mode.gcm.C(!0,a,f,d,c,e||128);return b.concat(a.data,a.tag)},decrypt:function(a,b,c,d,e){var f=b.slice(0),g=sjcl.bitArray,h=g.bitLength(f);e=e||128;d=d||[];e<=h?(b=g.bitSlice(f,h-e),f=g.bitSlice(f,0,h-e)):(b=f,f=[]);a=sjcl.mode.gcm.C(!1,a,f,d,c,e);if(!g.equal(a.tag,b))throw new sjcl.exception.corrupt("gcm: tag doesn't match");return a.data},ka:function(a,b){var c,d,e,f,g,h=sjcl.bitArray.i;e=[0,0,
0,0];f=b.slice(0);for(c=0;128>c;c++){(d=0!==(a[Math.floor(c/32)]&1<<31-c%32))&&(e=h(e,f));g=0!==(f[3]&1);for(d=3;0<d;d--)f[d]=f[d]>>>1|(f[d-1]&1)<<31;f[0]>>>=1;g&&(f[0]^=-0x1f000000)}return e},j:function(a,b,c){var d,e=c.length;b=b.slice(0);for(d=0;d<e;d+=4)b[0]^=0xffffffff&c[d],b[1]^=0xffffffff&c[d+1],b[2]^=0xffffffff&c[d+2],b[3]^=0xffffffff&c[d+3],b=sjcl.mode.gcm.ka(b,a);return b},C:function(a,b,c,d,e,f){var g,h,k,l,n,m,p,r,q=sjcl.bitArray;m=c.length;p=q.bitLength(c);r=q.bitLength(d);h=q.bitLength(e);
g=b.encrypt([0,0,0,0]);96===h?(e=e.slice(0),e=q.concat(e,[1])):(e=sjcl.mode.gcm.j(g,[0,0,0,0],e),e=sjcl.mode.gcm.j(g,e,[0,0,Math.floor(h/0x100000000),h&0xffffffff]));h=sjcl.mode.gcm.j(g,[0,0,0,0],d);n=e.slice(0);d=h.slice(0);a||(d=sjcl.mode.gcm.j(g,h,c));for(l=0;l<m;l+=4)n[3]++,k=b.encrypt(n),c[l]^=k[0],c[l+1]^=k[1],c[l+2]^=k[2],c[l+3]^=k[3];c=q.clamp(c,p);a&&(d=sjcl.mode.gcm.j(g,h,c));a=[Math.floor(r/0x100000000),r&0xffffffff,Math.floor(p/0x100000000),p&0xffffffff];d=sjcl.mode.gcm.j(g,d,a);k=b.encrypt(e);
d[0]^=k[0];d[1]^=k[1];d[2]^=k[2];d[3]^=k[3];return{tag:q.bitSlice(d,0,f),data:c}}};sjcl.misc.hmac=function(a,b){this.W=b=b||sjcl.hash.sha256;var c=[[],[]],d,e=b.prototype.blockSize/32;this.w=[new b,new b];a.length>e&&(a=b.hash(a));for(d=0;d<e;d++)c[0][d]=a[d]^909522486,c[1][d]=a[d]^1549556828;this.w[0].update(c[0]);this.w[1].update(c[1]);this.R=new b(this.w[0])};
sjcl.misc.hmac.prototype.encrypt=sjcl.misc.hmac.prototype.mac=function(a){if(this.aa)throw new sjcl.exception.invalid("encrypt on already updated hmac called!");this.update(a);return this.digest(a)};sjcl.misc.hmac.prototype.reset=function(){this.R=new this.W(this.w[0]);this.aa=!1};sjcl.misc.hmac.prototype.update=function(a){this.aa=!0;this.R.update(a)};sjcl.misc.hmac.prototype.digest=function(){var a=this.R.finalize(),a=(new this.W(this.w[1])).update(a).finalize();this.reset();return a};
sjcl.misc.pbkdf2=function(a,b,c,d,e){c=c||1E4;if(0>d||0>c)throw new sjcl.exception.invalid("invalid params to pbkdf2");"string"===typeof a&&(a=sjcl.codec.utf8String.toBits(a));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));e=e||sjcl.misc.hmac;a=new e(a);var f,g,h,k,l=[],n=sjcl.bitArray;for(k=1;32*l.length<(d||1);k++){e=f=a.encrypt(n.concat(b,[k]));for(g=1;g<c;g++)for(f=a.encrypt(f),h=0;h<f.length;h++)e[h]^=f[h];l=l.concat(e)}d&&(l=n.clamp(l,d));return l};
sjcl.prng=function(a){this.c=[new sjcl.hash.sha256];this.m=[0];this.P=0;this.H={};this.N=0;this.U={};this.Z=this.f=this.o=this.ha=0;this.b=[0,0,0,0,0,0,0,0];this.h=[0,0,0,0];this.L=void 0;this.M=a;this.D=!1;this.K={progress:{},seeded:{}};this.u=this.ga=0;this.I=1;this.J=2;this.ca=0x10000;this.T=[0,48,64,96,128,192,0x100,384,512,768,1024];this.da=3E4;this.ba=80};
sjcl.prng.prototype={randomWords:function(a,b){var c=[],d;d=this.isReady(b);var e;if(d===this.u)throw new sjcl.exception.notReady("generator isn't seeded");if(d&this.J){d=!(d&this.I);e=[];var f=0,g;this.Z=e[0]=(new Date).valueOf()+this.da;for(g=0;16>g;g++)e.push(0x100000000*Math.random()|0);for(g=0;g<this.c.length&&(e=e.concat(this.c[g].finalize()),f+=this.m[g],this.m[g]=0,d||!(this.P&1<<g));g++);this.P>=1<<this.c.length&&(this.c.push(new sjcl.hash.sha256),this.m.push(0));this.f-=f;f>this.o&&(this.o=
f);this.P++;this.b=sjcl.hash.sha256.hash(this.b.concat(e));this.L=new sjcl.cipher.aes(this.b);for(d=0;4>d&&(this.h[d]=this.h[d]+1|0,!this.h[d]);d++);}for(d=0;d<a;d+=4)0===(d+1)%this.ca&&y(this),e=z(this),c.push(e[0],e[1],e[2],e[3]);y(this);return c.slice(0,a)},setDefaultParanoia:function(a,b){if(0===a&&"Setting paranoia=0 will ruin your security; use it only for testing"!==b)throw new sjcl.exception.invalid("Setting paranoia=0 will ruin your security; use it only for testing");this.M=a},addEntropy:function(a,
b,c){c=c||"user";var d,e,f=(new Date).valueOf(),g=this.H[c],h=this.isReady(),k=0;d=this.U[c];void 0===d&&(d=this.U[c]=this.ha++);void 0===g&&(g=this.H[c]=0);this.H[c]=(this.H[c]+1)%this.c.length;switch(typeof a){case "number":void 0===b&&(b=1);this.c[g].update([d,this.N++,1,b,f,1,a|0]);break;case "object":c=Object.prototype.toString.call(a);if("[object Uint32Array]"===c){e=[];for(c=0;c<a.length;c++)e.push(a[c]);a=e}else for("[object Array]"!==c&&(k=1),c=0;c<a.length&&!k;c++)"number"!==typeof a[c]&&
(k=1);if(!k){if(void 0===b)for(c=b=0;c<a.length;c++)for(e=a[c];0<e;)b++,e=e>>>1;this.c[g].update([d,this.N++,2,b,f,a.length].concat(a))}break;case "string":void 0===b&&(b=a.length);this.c[g].update([d,this.N++,3,b,f,a.length]);this.c[g].update(a);break;default:k=1}if(k)throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string");this.m[g]+=b;this.f+=b;h===this.u&&(this.isReady()!==this.u&&A("seeded",Math.max(this.o,this.f)),A("progress",this.getProgress()))},
isReady:function(a){a=this.T[void 0!==a?a:this.M];return this.o&&this.o>=a?this.m[0]>this.ba&&(new Date).valueOf()>this.Z?this.J|this.I:this.I:this.f>=a?this.J|this.u:this.u},getProgress:function(a){a=this.T[a?a:this.M];return this.o>=a?1:this.f>a?1:this.f/a},startCollectors:function(){if(!this.D){this.a={loadTimeCollector:B(this,this.ma),mouseCollector:B(this,this.oa),keyboardCollector:B(this,this.la),accelerometerCollector:B(this,this.ea),touchCollector:B(this,this.qa)};if(window.addEventListener)window.addEventListener("load",
this.a.loadTimeCollector,!1),window.addEventListener("mousemove",this.a.mouseCollector,!1),window.addEventListener("keypress",this.a.keyboardCollector,!1),window.addEventListener("devicemotion",this.a.accelerometerCollector,!1),window.addEventListener("touchmove",this.a.touchCollector,!1);else if(document.attachEvent)document.attachEvent("onload",this.a.loadTimeCollector),document.attachEvent("onmousemove",this.a.mouseCollector),document.attachEvent("keypress",this.a.keyboardCollector);else throw new sjcl.exception.bug("can't attach event");
this.D=!0}},stopCollectors:function(){this.D&&(window.removeEventListener?(window.removeEventListener("load",this.a.loadTimeCollector,!1),window.removeEventListener("mousemove",this.a.mouseCollector,!1),window.removeEventListener("keypress",this.a.keyboardCollector,!1),window.removeEventListener("devicemotion",this.a.accelerometerCollector,!1),window.removeEventListener("touchmove",this.a.touchCollector,!1)):document.detachEvent&&(document.detachEvent("onload",this.a.loadTimeCollector),document.detachEvent("onmousemove",
this.a.mouseCollector),document.detachEvent("keypress",this.a.keyboardCollector)),this.D=!1)},addEventListener:function(a,b){this.K[a][this.ga++]=b},removeEventListener:function(a,b){var c,d,e=this.K[a],f=[];for(d in e)e.hasOwnProperty(d)&&e[d]===b&&f.push(d);for(c=0;c<f.length;c++)d=f[c],delete e[d]},la:function(){C(this,1)},oa:function(a){var b,c;try{b=a.x||a.clientX||a.offsetX||0,c=a.y||a.clientY||a.offsetY||0}catch(d){c=b=0}0!=b&&0!=c&&this.addEntropy([b,c],2,"mouse");C(this,0)},qa:function(a){a=
a.touches[0]||a.changedTouches[0];this.addEntropy([a.pageX||a.clientX,a.pageY||a.clientY],1,"touch");C(this,0)},ma:function(){C(this,2)},ea:function(a){a=a.accelerationIncludingGravity.x||a.accelerationIncludingGravity.y||a.accelerationIncludingGravity.z;if(window.orientation){var b=window.orientation;"number"===typeof b&&this.addEntropy(b,1,"accelerometer")}a&&this.addEntropy(a,2,"accelerometer");C(this,0)}};
function A(a,b){var c,d=sjcl.random.K[a],e=[];for(c in d)d.hasOwnProperty(c)&&e.push(d[c]);for(c=0;c<e.length;c++)e[c](b)}function C(a,b){"undefined"!==typeof window&&window.performance&&"function"===typeof window.performance.now?a.addEntropy(window.performance.now(),b,"loadtime"):a.addEntropy((new Date).valueOf(),b,"loadtime")}function y(a){a.b=z(a).concat(z(a));a.L=new sjcl.cipher.aes(a.b)}function z(a){for(var b=0;4>b&&(a.h[b]=a.h[b]+1|0,!a.h[b]);b++);return a.L.encrypt(a.h)}
function B(a,b){return function(){b.apply(a,arguments)}}sjcl.random=new sjcl.prng(6);
a:try{var D,E,F,G;if(G="undefined"!==typeof module&&module.exports){var H;try{H=require("crypto")}catch(a){H=null}G=E=H}if(G&&E.randomBytes)D=E.randomBytes(128),D=new Uint32Array((new Uint8Array(D)).buffer),sjcl.random.addEntropy(D,1024,"crypto['randomBytes']");else if("undefined"!==typeof window&&"undefined"!==typeof Uint32Array){F=new Uint32Array(32);if(window.crypto&&window.crypto.getRandomValues)window.crypto.getRandomValues(F);else if(window.msCrypto&&window.msCrypto.getRandomValues)window.msCrypto.getRandomValues(F);
else break a;sjcl.random.addEntropy(F,1024,"crypto['getRandomValues']")}}catch(a){"undefined"!==typeof window&&window.console&&(console.log("There was an error collecting entropy from the browser:"),console.log(a))}
sjcl.json={defaults:{v:1,iter:1E4,ks:128,ts:64,mode:"ccm",adata:"",cipher:"aes"},ja:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json,f=e.g({iv:sjcl.random.randomWords(4,0)},e.defaults),g;e.g(f,c);c=f.adata;"string"===typeof f.salt&&(f.salt=sjcl.codec.base64.toBits(f.salt));"string"===typeof f.iv&&(f.iv=sjcl.codec.base64.toBits(f.iv));if(!sjcl.mode[f.mode]||!sjcl.cipher[f.cipher]||"string"===typeof a&&100>=f.iter||64!==f.ts&&96!==f.ts&&128!==f.ts||128!==f.ks&&192!==f.ks&&0x100!==f.ks||2>f.iv.length||
4<f.iv.length)throw new sjcl.exception.invalid("json encrypt: invalid parameters");"string"===typeof a?(g=sjcl.misc.cachedPbkdf2(a,f),a=g.key.slice(0,f.ks/32),f.salt=g.salt):sjcl.ecc&&a instanceof sjcl.ecc.elGamal.publicKey&&(g=a.kem(),f.kemtag=g.tag,a=g.key.slice(0,f.ks/32));"string"===typeof b&&(b=sjcl.codec.utf8String.toBits(b));"string"===typeof c&&(f.adata=c=sjcl.codec.utf8String.toBits(c));g=new sjcl.cipher[f.cipher](a);e.g(d,f);d.key=a;f.ct="ccm"===f.mode&&sjcl.arrayBuffer&&sjcl.arrayBuffer.ccm&&
b instanceof ArrayBuffer?sjcl.arrayBuffer.ccm.encrypt(g,b,f.iv,c,f.ts):sjcl.mode[f.mode].encrypt(g,b,f.iv,c,f.ts);return f},encrypt:function(a,b,c,d){var e=sjcl.json,f=e.ja.apply(e,arguments);return e.encode(f)},ia:function(a,b,c,d){c=c||{};d=d||{};var e=sjcl.json;b=e.g(e.g(e.g({},e.defaults),b),c,!0);var f,g;f=b.adata;"string"===typeof b.salt&&(b.salt=sjcl.codec.base64.toBits(b.salt));"string"===typeof b.iv&&(b.iv=sjcl.codec.base64.toBits(b.iv));if(!sjcl.mode[b.mode]||!sjcl.cipher[b.cipher]||"string"===
typeof a&&100>=b.iter||64!==b.ts&&96!==b.ts&&128!==b.ts||128!==b.ks&&192!==b.ks&&0x100!==b.ks||!b.iv||2>b.iv.length||4<b.iv.length)throw new sjcl.exception.invalid("json decrypt: invalid parameters");"string"===typeof a?(g=sjcl.misc.cachedPbkdf2(a,b),a=g.key.slice(0,b.ks/32),b.salt=g.salt):sjcl.ecc&&a instanceof sjcl.ecc.elGamal.secretKey&&(a=a.unkem(sjcl.codec.base64.toBits(b.kemtag)).slice(0,b.ks/32));"string"===typeof f&&(f=sjcl.codec.utf8String.toBits(f));g=new sjcl.cipher[b.cipher](a);f="ccm"===
b.mode&&sjcl.arrayBuffer&&sjcl.arrayBuffer.ccm&&b.ct instanceof ArrayBuffer?sjcl.arrayBuffer.ccm.decrypt(g,b.ct,b.iv,b.tag,f,b.ts):sjcl.mode[b.mode].decrypt(g,b.ct,b.iv,f,b.ts);e.g(d,b);d.key=a;return 1===c.raw?f:sjcl.codec.utf8String.fromBits(f)},decrypt:function(a,b,c,d){var e=sjcl.json;return e.ia(a,e.decode(b),c,d)},encode:function(a){var b,c="{",d="";for(b in a)if(a.hasOwnProperty(b)){if(!b.match(/^[a-z0-9]+$/i))throw new sjcl.exception.invalid("json encode: invalid property name");c+=d+'"'+
b+'":';d=",";switch(typeof a[b]){case "number":case "boolean":c+=a[b];break;case "string":c+='"'+escape(a[b])+'"';break;case "object":c+='"'+sjcl.codec.base64.fromBits(a[b],0)+'"';break;default:throw new sjcl.exception.bug("json encode: unsupported type");}}return c+"}"},decode:function(a){a=a.replace(/\s/g,"");if(!a.match(/^\{.*\}$/))throw new sjcl.exception.invalid("json decode: this isn't json!");a=a.replace(/^\{|\}$/g,"").split(/,/);var b={},c,d;for(c=0;c<a.length;c++){if(!(d=a[c].match(/^\s*(?:(["']?)([a-z][a-z0-9]*)\1)\s*:\s*(?:(-?\d+)|"([a-z0-9+\/%*_.@=\-]*)"|(true|false))$/i)))throw new sjcl.exception.invalid("json decode: this isn't json!");
null!=d[3]?b[d[2]]=parseInt(d[3],10):null!=d[4]?b[d[2]]=d[2].match(/^(ct|adata|salt|iv)$/)?sjcl.codec.base64.toBits(d[4]):unescape(d[4]):null!=d[5]&&(b[d[2]]="true"===d[5])}return b},g:function(a,b,c){void 0===a&&(a={});if(void 0===b)return a;for(var d in b)if(b.hasOwnProperty(d)){if(c&&void 0!==a[d]&&a[d]!==b[d])throw new sjcl.exception.invalid("required parameter overridden");a[d]=b[d]}return a},sa:function(a,b){var c={},d;for(d in a)a.hasOwnProperty(d)&&a[d]!==b[d]&&(c[d]=a[d]);return c},ra:function(a,
b){var c={},d;for(d=0;d<b.length;d++)void 0!==a[b[d]]&&(c[b[d]]=a[b[d]]);return c}};sjcl.encrypt=sjcl.json.encrypt;sjcl.decrypt=sjcl.json.decrypt;sjcl.misc.pa={};sjcl.misc.cachedPbkdf2=function(a,b){var c=sjcl.misc.pa,d;b=b||{};d=b.iter||1E3;c=c[a]=c[a]||{};d=c[d]=c[d]||{firstSalt:b.salt&&b.salt.length?b.salt.slice(0):sjcl.random.randomWords(2,0)};c=void 0===b.salt?d.firstSalt:b.salt;d[c]=d[c]||sjcl.misc.pbkdf2(a,c,b.iter);return{key:d[c].slice(0),salt:c.slice(0)}};
"undefined"!==typeof module&&module.exports&&(module.exports=sjcl);"function"===typeof define&&define([],function(){return sjcl});

View File

@@ -3,21 +3,56 @@ var common = require('../common');
describe('Alert', function () {
describe('showStatus', function () {
before(function () {
cleanup();
});
jsc.property(
'shows a status message',
'shows a status message (basic)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (icon, message) {
icon = icon.join('');
message = message.join('');
var expected = '<div id="status" role="alert" ' +
const expected = '<div id="status">' + message + '</div>';
$('body').html(
'<div id="status"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showStatus(message, icon);
const result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows a status message (bootstrap)',
jsc.array(common.jscAlnumString()),
function (message) {
message = message.join('');
const expected = '<div id="status" role="alert" ' +
'class="statusmessage alert alert-info"><span ' +
'class="glyphicon glyphicon-info-sign" ' +
'aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
'<div id="status" role="alert" class="statusmessage ' +
'alert alert-info hidden"><span class="glyphicon ' +
'glyphicon-info-sign" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showStatus(message);
const result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows a status message (bootstrap, custom icon)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (icon, message) {
icon = icon.join('');
message = message.join('');
const expected = '<div id="status" role="alert" ' +
'class="statusmessage alert alert-info"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> ' + message + '</div>';
'" aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
'<div id="status" role="alert" class="statusmessage ' +
'alert alert-info hidden"><span class="glyphicon ' +
@@ -25,28 +60,129 @@ describe('Alert', function () {
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showStatus(message, icon);
var result = $('body').html();
const result = $('body').html();
return expected === result;
}
);
});
describe('showWarning', function () {
jsc.property(
'shows a warning message (basic)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (icon, message) {
icon = icon.join('');
message = message.join('');
const expected = '<div id="errormessage">' + message + '</div>';
$('body').html(
'<div id="errormessage"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showWarning(message, icon);
const result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows a warning message (bootstrap)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (message) {
message = message.join('');
const expected = '<div id="errormessage" role="alert" ' +
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-warning-sign" ' +
'aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger hidden"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showWarning(message);
const result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows a warning message (bootstrap, custom icon)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (icon, message) {
icon = icon.join('');
message = message.join('');
const expected = '<div id="errormessage" role="alert" ' +
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger hidden"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showWarning(message, icon);
const result = $('body').html();
return expected === result;
}
);
});
describe('showError', function () {
before(function () {
cleanup();
});
jsc.property(
'shows an error message',
'shows an error message (basic)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (icon, message) {
icon = icon.join('');
message = message.join('');
var expected = '<div id="errormessage" role="alert" ' +
const expected = '<div id="errormessage">' + message + '</div>';
$('body').html(
'<div id="errormessage"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showError(message, icon);
const result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows an error message (bootstrap)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (icon, message) {
message = message.join('');
const expected = '<div id="errormessage" role="alert" ' +
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-alert" ' +
'aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger hidden"><span class="glyphicon ' +
'glyphicon-alert" aria-hidden="true"></span> </div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showError(message);
const result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows an error message (bootstrap, custom icon)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (icon, message) {
icon = icon.join('');
message = message.join('');
const expected = '<div id="errormessage" role="alert" ' +
'class="statusmessage alert alert-danger"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> ' + message + '</div>';
'" aria-hidden="true"></span> <span>' + message + '</span></div>';
$('body').html(
'<div id="errormessage" role="alert" class="statusmessage ' +
'alert alert-danger hidden"><span class="glyphicon ' +
@@ -54,29 +190,44 @@ describe('Alert', function () {
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showError(message, icon);
var result = $('body').html();
const result = $('body').html();
return expected === result;
}
);
});
describe('showRemaining', function () {
before(function () {
cleanup();
});
jsc.property(
'shows remaining time',
'shows remaining time (basic)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
'integer',
function (message, string, number) {
message = message.join('');
string = string.join('');
var expected = '<div id="remainingtime" role="alert" ' +
const expected = '<div id="remainingtime" class="">' + string + message + number + '</div>';
$('body').html(
'<div id="remainingtime" class="hidden"></div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]);
const result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows remaining time (bootstrap)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
'integer',
function (message, string, number) {
message = message.join('');
string = string.join('');
const expected = '<div id="remainingtime" role="alert" ' +
'class="alert alert-info"><span ' +
'class="glyphicon glyphicon-fire" aria-hidden="true">' +
'</span> ' + string + message + number + '</div>';
'</span> <span>' + string + message + number + '</span></div>';
$('body').html(
'<div id="remainingtime" role="alert" class="hidden ' +
'alert alert-info"><span class="glyphicon ' +
@@ -84,32 +235,50 @@ describe('Alert', function () {
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showRemaining(['%s' + message + '%d', string, number]);
var result = $('body').html();
const result = $('body').html();
return expected === result;
}
);
});
describe('showLoading', function () {
before(function () {
cleanup();
});
jsc.property(
'shows a loading message',
'shows a loading message (basic)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (message, icon) {
message = message.join('');
icon = icon.join('');
var defaultMessage = 'Loading…';
const defaultMessage = 'Loading…';
if (message.length === 0) {
message = defaultMessage;
}
var expected = '<ul class="nav navbar-nav"><li ' +
const expected = '<div id="loadingindicator" class="">' + message + '</div>';
$('body').html(
'<div id="loadingindicator" class="hidden">' + defaultMessage + '</div>'
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showLoading(message, icon);
const result = $('body').html();
return expected === result;
}
);
jsc.property(
'shows a loading message (bootstrap)',
jsc.array(common.jscAlnumString()),
jsc.array(common.jscAlnumString()),
function (message, icon) {
message = message.join('');
icon = icon.join('');
const defaultMessage = 'Loading…';
if (message.length === 0) {
message = defaultMessage;
}
const expected = '<ul class="nav navbar-nav"><li ' +
'id="loadingindicator" class="navbar-text"><span ' +
'class="glyphicon glyphicon-' + icon +
'" aria-hidden="true"></span> ' + message + '</li></ul>';
'" aria-hidden="true"></span> <span>' + message + '</span></li></ul>';
$('body').html(
'<ul class="nav navbar-nav"><li id="loadingindicator" ' +
'class="navbar-text hidden"><span class="glyphicon ' +
@@ -118,17 +287,13 @@ describe('Alert', function () {
);
$.PrivateBin.Alert.init();
$.PrivateBin.Alert.showLoading(message, icon);
var result = $('body').html();
const result = $('body').html();
return expected === result;
}
);
});
describe('hideLoading', function () {
before(function () {
cleanup();
});
it(
'hides the loading message',
function() {
@@ -150,10 +315,6 @@ describe('Alert', function () {
});
describe('hideMessages', function () {
before(function () {
cleanup();
});
it(
'hides all messages',
function() {
@@ -176,17 +337,13 @@ describe('Alert', function () {
});
describe('setCustomHandler', function () {
before(function () {
cleanup();
});
jsc.property(
'calls a given handler function',
'nat 3',
jsc.array(common.jscAlnumString()),
function (trigger, message) {
message = message.join('');
var handlerCalled = false,
let handlerCalled = false,
defaultMessage = 'Loading…',
functions = [
$.PrivateBin.Alert.showStatus,
@@ -218,6 +375,7 @@ describe('Alert', function () {
return jsc.random(0, 1) ? true : $element;
});
functions[trigger](message);
$.PrivateBin.Alert.setCustomHandler(null);
return handlerCalled;
}
);

View File

@@ -4,28 +4,26 @@ 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',
common.jscMimeTypes(),
jsc.nearray(common.jscBase64String()),
'string',
'string',
'string',
function (mimeType, base64, filename, prefix, postfix) {
var clean = jsdom(),
data = 'data:' + mimeType + ';base64,' + base64.join(''),
'string',
function (mimeType, rawdata, filename, prefix, postfix) {
let clean = jsdom(),
data = 'data:' + mimeType + ';base64,' + btoa(rawdata),
previewSupported = (
mimeType.substring(0, 6) === 'image/' ||
mimeType.substring(0, 6) === 'audio/' ||
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 ' +
@@ -34,6 +32,16 @@ describe('AttachmentViewer', function () {
'Download attachment</a></div><div id="attachmentPrevie' +
'w" class="hidden"></div>'
);
// mock createObjectURL for jsDOM
if (typeof window.URL.createObjectURL === 'undefined') {
Object.defineProperty(
window.URL,
'createObjectURL',
{value: function(blob) {
return 'blob:' + location.origin + '/1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed';
}}
)
}
$.PrivateBin.AttachmentViewer.init();
results.push(
!$.PrivateBin.AttachmentViewer.hasAttachment() &&
@@ -45,7 +53,9 @@ describe('AttachmentViewer', function () {
} else {
$.PrivateBin.AttachmentViewer.setAttachment(data);
}
var attachment = $.PrivateBin.AttachmentViewer.getAttachment();
// beyond this point we will get the blob URL instead of the data
data = window.URL.createObjectURL(data);
const attachment = $.PrivateBin.AttachmentViewer.getAttachment();
results.push(
$.PrivateBin.AttachmentViewer.hasAttachment() &&
$('#attachment').hasClass('hidden') &&
@@ -72,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);

80
js/test/Check.js Normal file
View File

@@ -0,0 +1,80 @@
'use strict';
var common = require('../common');
/* global Legacy, WebCrypto */
describe('Check', function () {
describe('init', function () {
this.timeout(30000);
it('returns false and shows error, if a bot UA is detected', function () {
jsc.assert(jsc.forall(
'string',
jsc.elements(['Bot', 'bot']),
'string',
function (prefix, botBit, suffix) {
const clean = jsdom(
'<html><body><div id="errormessage" class="hidden"></div>' +
'</body></html>', {
'userAgent': prefix + botBit + suffix
}
);
Legacy.Check.init();
const result1 = Legacy.Check.getInit() && !Legacy.Check.getStatus(),
result2 = (document.getElementById('errormessage').className !== 'hidden');
clean();
return result1 && result2;
}
),
{tests: 10});
});
jsc.property(
'shows error, if no webcrypto is detected',
'bool',
jsc.elements(['localhost', '127.0.0.1', '[::1]', '']),
jsc.nearray(common.jscA2zString()),
jsc.elements(['.onion', '.i2p', '']),
function (secureProtocol, localhost, domain, tld) {
const isDomain = localhost === '',
isSecureContext = secureProtocol || !isDomain || tld.length > 0,
clean = jsdom(
'<html><body><div id="errormessage" class="hidden"></div>' +
'<div id="oldnotice" class="hidden"></div>' +
'<div id="insecurecontextnotice" class="hidden"></div></body></html>',
{
'url': (secureProtocol ? 'https' : 'http' ) + '://' +
(isDomain ? domain.join('') + tld : localhost) + '/'
}
);
Legacy.Check.init();
const result1 = Legacy.Check.getInit() && !Legacy.Check.getStatus(),
result2 = isSecureContext === (document.getElementById('insecurecontextnotice').className === 'hidden'),
result3 = (document.getElementById('oldnotice').className !== 'hidden');
clean();
return result1 && result2 && result3;
}
);
jsc.property(
'shows error, if HTTP only site is detected',
'bool',
jsc.nearray(common.jscA2zString()),
function (secureProtocol, domain) {
const clean = jsdom(
'<html><body><div id="httpnotice" class="hidden"></div>' +
'</body></html>',
{
'url': (secureProtocol ? 'https' : 'http' ) + '://' + domain.join('') + '/'
}
);
window.crypto = new WebCrypto();
Legacy.Check.init();
const result1 = Legacy.Check.getInit() && Legacy.Check.getStatus(),
result2 = secureProtocol === (document.getElementById('httpnotice').className === 'hidden');
clean();
return result1 && result2;
}
);
});
});

View File

@@ -3,35 +3,53 @@ require('../common');
describe('CryptTool', function () {
describe('cipher & decipher', function () {
afterEach(async function () {
// pause to let async functions conclude
await new Promise(resolve => setTimeout(resolve, 1900));
});
this.timeout(30000);
it('can en- and decrypt any message', function () {
jsc.check(jsc.forall(
jsc.assert(jsc.forall(
'string',
'string',
'string',
function (key, password, message) {
return message === $.PrivateBin.CryptTool.decipher(
key,
password,
$.PrivateBin.CryptTool.cipher(key, password, message)
);
async function (key, password, message) {
// pause to let async functions conclude
await new Promise(resolve => setTimeout(resolve, 300));
let clean = jsdom();
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
window.crypto = new WebCrypto();
message = message.trim();
let cipherMessage = await $.PrivateBin.CryptTool.cipher(
key, password, message, []
),
plaintext = await $.PrivateBin.CryptTool.decipher(
key, password, cipherMessage
);
clean();
return message === plaintext;
}
),
// reducing amount of checks as running 100 takes about 5 minutes
{tests: 5, quiet: true});
{tests: 3});
});
// The below static unit tests are included to ensure deciphering of "classic"
// SJCL based pastes still works
it(
'supports PrivateBin v1 ciphertext (SJCL & Base64)',
'supports PrivateBin v1 ciphertext (SJCL & browser atob)',
function () {
delete global.Base64;
let clean = jsdom();
window.crypto = new WebCrypto();
// Of course you can easily decipher the following texts, if you like.
// Bonus points for finding their sources and hidden meanings.
var paste1 = $.PrivateBin.CryptTool.decipher(
return $.PrivateBin.CryptTool.decipher(
'6t2qsmLyfXIokNCL+3/yl15rfTUBQvm5SOnFPvNE7Q8=',
// -- "That's amazing. I've got the same combination on my luggage."
Array.apply(0, Array(6)).map(function(_,b) { return b + 1; }).join(''),
Array.apply(0, Array(6)).map((_,b) => b + 1).join(''),
'{"iv":"4HNFIl7eYbCh6HuShctTIA==","v":1,"iter":10000,"ks"' +
':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' +
'lt":"u0lQvePq6L0=","ct":"fGPUVrDyaVr1ZDGb+kqQ3CPEW8x4YKG' +
@@ -59,56 +77,56 @@ describe('CryptTool', function () {
'QUxMXI5htsn2rf0HxCFu7Po8DNYLxTS+67hYjDIYWYaEIc8LXWMLyDm9' +
'C5fARPJ4F2BIWgzgzkNj+dVjusft2XnziamWdbS5u3kuRlVuz5LQj+R5' +
'imnqQAincdZTkTT1nYx+DatlOLllCYIHffpI="}'
),
paste2 = $.PrivateBin.CryptTool.decipher(
's9pmKZKOBN7EVvHpTA8jjLFH3Xlz/0l8lB4+ONPACrM=',
'', // no password
'{"iv":"WA42mdxIVXUwBqZu7JYNiw==","v":1,"iter":10000,"ks"' +
':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' +
'lt":"jN6CjbQMJCM=","ct":"kYYMo5DFG1+w0UHiYXT5pdV0IUuXxzO' +
'lslkW/c3DRCbGFROCVkAskHce7HoRczee1N9c5MhHjVMJUIZE02qIS8U' +
'yHdJ/GqcPVidTUcj9rnDNWsTXkjVv8jCwHS/cwmAjDTWpwp5ThECN+ov' +
'/wNp/NdtTj8Qj7f/T3rfZIOCWfwLH9s4Des35UNcUidfPTNQ1l0Gm0X+' +
'r98CCUSYZjQxkZc6hRZBLPQ8EaNVooUwd5eP4GiYlmSDNA0wOSA+5isP' +
'YxomVCt+kFf58VBlNhpfNi7BLYAUTPpXT4SfH5drR9+C7NTeZ+tTCYjb' +
'U94PzYItOpu8vgnB1/a6BAM5h3m9w+giUb0df4hgTWeZnZxLjo5BN8WV' +
'+kdTXMj3/Vv0gw0DQrDcCuX/cBAjpy3lQGwlAN1vXoOIyZJUjMpQRrOL' +
'dKvLB+zcmVNtGDbgnfP2IYBzk9NtodpUa27ne0T0ZpwOPlVwevsIVZO2' +
'24WLa+iQmmHOWDFFpVDlS0t0fLfOk7Hcb2xFsTxiCIiyKMho/IME1Du3' +
'X4e6BVa3hobSSZv0rRtNgY1KcyYPrUPW2fxZ+oik3y9SgGvb7XpjVIta' +
'8DWlDWRfZ9kzoweWEYqz9IA8Xd373RefpyuWI25zlHoX3nwljzsZU6dC' +
'//h/Dt2DNr+IAvKO3+u23cWoB9kgcZJ2FJuqjLvVfCF+OWcig7zs2pTY' +
'JW6Rg6lqbBCxiUUlae6xJrjfv0pzD2VYCLY7v1bVTagppwKzNI3WaluC' +
'OrdDYUCxUSe56yd1oAoLPRVbYvomRboUO6cjQhEknERyvt45og2kORJO' +
'EJayHW+jZgR0Y0jM3Nk17ubpij2gHxNx9kiLDOiCGSV5mn9mV7qd3HHc' +
'OMSykiBgbyzjobi96LT2dIGLeDXTIdPOog8wyobO4jWq0GGs0vBB8oSY' +
'XhHvixZLcSjX2KQuHmEoWzmJcr3DavdoXZmAurGWLKjzEdJc5dSD/eNr' +
'99gjHX7wphJ6umKMM+fn6PcbYJkhDh2GlJL5COXjXfm/5aj/vuyaRRWZ' +
'MZtmnYpGAtAPg7AUG"}'
);
assert.ok(
paste1.includes('securely packed in iron') &&
paste2.includes('Sol is right')
);
).then(function (paste1) {
$.PrivateBin.CryptTool.decipher(
's9pmKZKOBN7EVvHpTA8jjLFH3Xlz/0l8lB4+ONPACrM=',
'', // no password
'{"iv":"WA42mdxIVXUwBqZu7JYNiw==","v":1,"iter":10000,"ks"' +
':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' +
'lt":"jN6CjbQMJCM=","ct":"kYYMo5DFG1+w0UHiYXT5pdV0IUuXxzO' +
'lslkW/c3DRCbGFROCVkAskHce7HoRczee1N9c5MhHjVMJUIZE02qIS8U' +
'yHdJ/GqcPVidTUcj9rnDNWsTXkjVv8jCwHS/cwmAjDTWpwp5ThECN+ov' +
'/wNp/NdtTj8Qj7f/T3rfZIOCWfwLH9s4Des35UNcUidfPTNQ1l0Gm0X+' +
'r98CCUSYZjQxkZc6hRZBLPQ8EaNVooUwd5eP4GiYlmSDNA0wOSA+5isP' +
'YxomVCt+kFf58VBlNhpfNi7BLYAUTPpXT4SfH5drR9+C7NTeZ+tTCYjb' +
'U94PzYItOpu8vgnB1/a6BAM5h3m9w+giUb0df4hgTWeZnZxLjo5BN8WV' +
'+kdTXMj3/Vv0gw0DQrDcCuX/cBAjpy3lQGwlAN1vXoOIyZJUjMpQRrOL' +
'dKvLB+zcmVNtGDbgnfP2IYBzk9NtodpUa27ne0T0ZpwOPlVwevsIVZO2' +
'24WLa+iQmmHOWDFFpVDlS0t0fLfOk7Hcb2xFsTxiCIiyKMho/IME1Du3' +
'X4e6BVa3hobSSZv0rRtNgY1KcyYPrUPW2fxZ+oik3y9SgGvb7XpjVIta' +
'8DWlDWRfZ9kzoweWEYqz9IA8Xd373RefpyuWI25zlHoX3nwljzsZU6dC' +
'//h/Dt2DNr+IAvKO3+u23cWoB9kgcZJ2FJuqjLvVfCF+OWcig7zs2pTY' +
'JW6Rg6lqbBCxiUUlae6xJrjfv0pzD2VYCLY7v1bVTagppwKzNI3WaluC' +
'OrdDYUCxUSe56yd1oAoLPRVbYvomRboUO6cjQhEknERyvt45og2kORJO' +
'EJayHW+jZgR0Y0jM3Nk17ubpij2gHxNx9kiLDOiCGSV5mn9mV7qd3HHc' +
'OMSykiBgbyzjobi96LT2dIGLeDXTIdPOog8wyobO4jWq0GGs0vBB8oSY' +
'XhHvixZLcSjX2KQuHmEoWzmJcr3DavdoXZmAurGWLKjzEdJc5dSD/eNr' +
'99gjHX7wphJ6umKMM+fn6PcbYJkhDh2GlJL5COXjXfm/5aj/vuyaRRWZ' +
'MZtmnYpGAtAPg7AUG"}'
).then(function (paste2) {
clean();
assert.ok(
paste1.includes('securely packed in iron') &&
paste2.includes('Sol is right')
);
});
});
}
);
it(
'supports ZeroBin ciphertext (SJCL & Base64 1.7)',
function () {
var newBase64 = global.Base64;
global.Base64 = require('../base64-1.7').Base64;
jsdom();
delete require.cache[require.resolve('../privatebin')];
require('../privatebin');
var clean = jsdom();
window.crypto = new WebCrypto();
// Of course you can easily decipher the following texts, if you like.
// Bonus points for finding their sources and hidden meanings.
var paste1 = $.PrivateBin.CryptTool.decipher(
return $.PrivateBin.CryptTool.decipher(
'6t2qsmLyfXIokNCL+3/yl15rfTUBQvm5SOnFPvNE7Q8=',
// -- "That's amazing. I've got the same combination on my luggage."
Array.apply(0, Array(6)).map(function(_,b) { return b + 1; }).join(''),
Array.apply(0, Array(6)).map((_,b) => b + 1).join(''),
'{"iv":"aTnR2qBL1CAmLX8FdWe3VA==","v":1,"iter":10000,"ks"' +
':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' +
'lt":"u0lQvePq6L0=","ct":"A3nBTvICZtYy6xqbIJE0c8Veored5lM' +
@@ -128,80 +146,121 @@ describe('CryptTool', function () {
'7mNNo7xba/YT9KoPDaniqnYqb+q2pX1WNWE7dLS2wfroMAS3kh8P22DA' +
'V37AeiNoD2PcI6ZcHbRdPa+XRrRcJhSPPW7UQ0z4OvBfjdu/w390QxAx' +
'SxvZewoh49fKKB6hTsRnZb4tpHkjlww=="}'
),
paste2 = $.PrivateBin.CryptTool.decipher(
's9pmKZKOBN7EVvHpTA8jjLFH3Xlz/0l8lB4+ONPACrM=',
'', // no password
'{"iv":"Z7lAZQbkrqGMvruxoSm6Pw==","v":1,"iter":10000,"ks"' +
':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' +
'lt":"jN6CjbQMJCM=","ct":"PuOPWB3i2FPcreSrLYeQf84LdE8RHjs' +
'c+MGtiOr4b7doNyWKYtkNorbRadxaPnEee2/Utrp1MIIfY5juJSy8RGw' +
'EPX5ciWcYe6EzsXWznsnvhmpKNj9B7eIIrfSbxfy8E2e/g7xav1nive+' +
'ljToka3WT1DZ8ILQd/NbnJeHWaoSEOfvz8+d8QJPb1tNZvs7zEY95Dum' +
'QwbyOsIMKAvcZHJ9OJNpujXzdMyt6DpcFcqlldWBZ/8q5rAUTw0HNx/r' +
'CgbhAxRYfNoTLIcMM4L0cXbPSgCjwf5FuO3EdE13mgEDhcClW79m0Qvc' +
'nIh8xgzYoxLbp0+AwvC/MbZM8savN/0ieWr2EKkZ04ggiOIEyvfCUuNp' +
'rQBYO+y8kKduNEN6by0Yf4LRCPfmwN+GezDLuzTnZIMhPbGqUAdgV6Ex' +
'qK2ULEEIrQEMoOuQIxfoMhqLlzG79vXGt2O+BY+4IiYfvmuRLks4UXfy' +
'HqxPXTJg48IYbGs0j4TtJPUgp3523EyYLwEGyVTAuWhYAmVIwd/hoV7d' +
'7tmfcF73w9dufDFI3LNca2KxzBnWNPYvIZKBwWbq8ncxkb191dP6mjEi' +
'7NnhqVk5A6vIBbu4AC5PZf76l6yep4xsoy/QtdDxCMocCXeAML9MQ9uP' +
'QbuspOKrBvMfN5igA1kBqasnxI472KBNXsdZnaDddSVUuvhTcETM="}'
);
global.Base64 = newBase64;
jsdom();
delete require.cache[require.resolve('../privatebin')];
require('../privatebin');
assert.ok(
paste1.includes('securely packed in iron') &&
paste2.includes('Sol is right')
);
}
);
});
describe('isEntropyReady & addEntropySeedListener', function () {
it(
'lets us know that enough entropy is collected or make us wait for it',
function(done) {
if ($.PrivateBin.CryptTool.isEntropyReady()) {
done();
} else {
$.PrivateBin.CryptTool.addEntropySeedListener(function() {
done();
).then(function (paste1) {
$.PrivateBin.CryptTool.decipher(
's9pmKZKOBN7EVvHpTA8jjLFH3Xlz/0l8lB4+ONPACrM=',
'', // no password
'{"iv":"Z7lAZQbkrqGMvruxoSm6Pw==","v":1,"iter":10000,"ks"' +
':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' +
'lt":"jN6CjbQMJCM=","ct":"PuOPWB3i2FPcreSrLYeQf84LdE8RHjs' +
'c+MGtiOr4b7doNyWKYtkNorbRadxaPnEee2/Utrp1MIIfY5juJSy8RGw' +
'EPX5ciWcYe6EzsXWznsnvhmpKNj9B7eIIrfSbxfy8E2e/g7xav1nive+' +
'ljToka3WT1DZ8ILQd/NbnJeHWaoSEOfvz8+d8QJPb1tNZvs7zEY95Dum' +
'QwbyOsIMKAvcZHJ9OJNpujXzdMyt6DpcFcqlldWBZ/8q5rAUTw0HNx/r' +
'CgbhAxRYfNoTLIcMM4L0cXbPSgCjwf5FuO3EdE13mgEDhcClW79m0Qvc' +
'nIh8xgzYoxLbp0+AwvC/MbZM8savN/0ieWr2EKkZ04ggiOIEyvfCUuNp' +
'rQBYO+y8kKduNEN6by0Yf4LRCPfmwN+GezDLuzTnZIMhPbGqUAdgV6Ex' +
'qK2ULEEIrQEMoOuQIxfoMhqLlzG79vXGt2O+BY+4IiYfvmuRLks4UXfy' +
'HqxPXTJg48IYbGs0j4TtJPUgp3523EyYLwEGyVTAuWhYAmVIwd/hoV7d' +
'7tmfcF73w9dufDFI3LNca2KxzBnWNPYvIZKBwWbq8ncxkb191dP6mjEi' +
'7NnhqVk5A6vIBbu4AC5PZf76l6yep4xsoy/QtdDxCMocCXeAML9MQ9uP' +
'QbuspOKrBvMfN5igA1kBqasnxI472KBNXsdZnaDddSVUuvhTcETM="}'
).then(function (paste2) {
clean();
delete global.Base64;
assert.ok(
paste1.includes('securely packed in iron') &&
paste2.includes('Sol is right')
);
});
}
});
}
);
it('does not truncate messages', async function () {
let message = fs.readFileSync('test/compression-sample.txt', 'utf8'),
clean = jsdom();
window.crypto = new WebCrypto();
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
let cipherMessage = await $.PrivateBin.CryptTool.cipher(
'foo', 'bar', message, []
),
plaintext = await $.PrivateBin.CryptTool.decipher(
'foo', 'bar', cipherMessage
);
clean();
assert.strictEqual(
message,
plaintext
);
});
it('can en- and decrypt a particular message (#260)', function () {
jsc.assert(jsc.forall(
'string',
'string',
async function (key, password) {
// pause to let async functions conclude
await new Promise(resolve => setTimeout(resolve, 300));
const message = `
1 subgoal
inv : Assert
expr : Expr
sBody : Instr
deduction : (|- [|inv /\ assertOfExpr expr|] sBody [|inv|])%assert
IHdeduction : (|= [|inv /\ assertOfExpr expr |] sBody [|inv|])%assert
mem : Mem
preInMem : inv mem
m : Mem
n : nat
interpRel : interp (nth_iterate sBody n) (MemElem mem) = CpoElem Mem m
lastIter : interp (nth_iterate sBody n) (MemElem mem) |=e expr_neg expr
notLastIter : forall p : nat,
p < n -> interp (nth_iterate sBody p) (MemElem mem) |=e expr
isWhile : interp (while expr sBody) (MemElem mem) =
interp (nth_iterate sBody n) (MemElem mem)
======================== ( 1 / 1 )
conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem))
`;
let clean = jsdom();
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
window.crypto = new WebCrypto();
let cipherMessage = await $.PrivateBin.CryptTool.cipher(
key, password, message, []
),
plaintext = await $.PrivateBin.CryptTool.decipher(
key, password, cipherMessage
);
clean();
return message === plaintext;
}
),
{tests: 3});
});
});
describe('getSymmetricKey', function () {
this.timeout(30000);
var keys = [];
// the parameter is used to ensure the test is run more then one time
jsc.property(
'returns random, non-empty keys',
function() {
'integer',
function(counter) {
var clean = jsdom();
window.crypto = new WebCrypto();
var key = $.PrivateBin.CryptTool.getSymmetricKey(),
result = (key !== '' && keys.indexOf(key) === -1);
keys.push(key);
clean();
return result;
}
);
});
describe('Base64.js vs SJCL.js vs abab.js', function () {
jsc.property(
'these all return the same base64 string',
'string',
function(string) {
var base64 = Base64.toBase64(string),
sjcl = global.sjcl.codec.base64.fromBits(global.sjcl.codec.utf8String.toBits(string)),
abab = window.btoa(Base64.utob(string));
return base64 === sjcl && sjcl === abab;
}
);
});
});

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',
@@ -63,7 +60,7 @@ describe('DiscussionViewer', function () {
comments.forEach(function (comment) {
comment.id = comment.idArray.join('');
comment.parentid = comment.parentidArray.join('');
$.PrivateBin.DiscussionViewer.addComment(comment, comment.data, comment.meta.nickname);
$.PrivateBin.DiscussionViewer.addComment($.PrivateBin.Helper.CommentFactory(comment), comment.data, comment.meta.nickname);
});
results.push(
$('#discussion').hasClass('hidden')

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',
@@ -183,9 +175,9 @@ describe('Helper', function () {
'string',
'string',
function (prefix, uint, middle, string, postfix) {
prefix = prefix.replace(/%(s|d)/g, '%%');
middle = middle.replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%');
prefix = prefix.replace(/%(s|d)/g, '');
middle = middle.replace(/%(s|d)/g, '');
postfix = postfix.replace(/%(s|d)/g, '');
var params = [prefix + '%d' + middle + '%s' + postfix, uint, string],
result = prefix + uint + middle + string + postfix;
return result === $.PrivateBin.Helper.sprintf.apply(this, params);
@@ -199,9 +191,9 @@ describe('Helper', function () {
'string',
'string',
function (prefix, uint, middle, string, postfix) {
prefix = prefix.replace(/%(s|d)/g, '%%');
middle = middle.replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%');
prefix = prefix.replace(/%(s|d)/g, '');
middle = middle.replace(/%(s|d)/g, '');
postfix = postfix.replace(/%(s|d)/g, '');
var params = [prefix + '%s' + middle + '%d' + postfix, string, uint],
result = prefix + string + middle + uint + postfix;
return result === $.PrivateBin.Helper.sprintf.apply(this, params);
@@ -211,17 +203,20 @@ describe('Helper', function () {
describe('getCookie', function () {
this.timeout(30000);
before(function () {
cleanup();
});
jsc.property(
'returns the requested cookie',
'nearray asciinestring',
'nearray asciistring',
jsc.nearray(jsc.nearray(common.jscAlnumString())),
jsc.nearray(jsc.nearray(common.jscAlnumString())),
function (labels, values) {
var selectedKey = '', selectedValue = '',
cookieArray = [];
labels.forEach(function(item, i) {
// deliberatly using a non-ascii key for replacing invalid characters
var key = item.replace(/[\s;,=]/g, Array(i+2).join('£')),
value = (values[i] || values[0]).replace(/[\s;,=]/g, '');
var key = item.join(''),
value = (values[i] || values[0]).join('');
cookieArray.push(key + '=' + value);
if (Math.random() < 1 / i || selectedKey === key)
{
@@ -231,6 +226,7 @@ describe('Helper', function () {
});
var clean = jsdom('', {cookie: cookieArray}),
result = $.PrivateBin.Helper.getCookie(selectedKey);
$.PrivateBin.Helper.reset();
clean();
return result === selectedValue;
}
@@ -239,21 +235,19 @@ describe('Helper', function () {
describe('baseUri', function () {
this.timeout(30000);
before(function () {
$.PrivateBin.Helper.reset();
});
jsc.property(
'returns the URL without query & fragment',
common.jscSchemas(),
jsc.elements(['http', 'https']),
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscA2zString()),
jsc.array(common.jscQueryString()),
'string',
function (schema, address, query, fragment) {
var expected = schema + '://' + address.join('') + '/',
function (schema, address, path, query, fragment) {
$.PrivateBin.Helper.reset();
var path = path.join('') + (path.length > 0 ? '/' : ''),
expected = schema + '://' + address.join('') + '/' + path,
clean = jsdom('', {url: expected + '?' + query.join('') + '#' + fragment}),
result = $.PrivateBin.Helper.baseUri();
$.PrivateBin.Helper.reset();
clean();
return expected === result;
}
@@ -261,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 () {
@@ -87,14 +184,17 @@ describe('I18n', function () {
'downloads and handles any supported language',
common.jscSupportedLanguages(),
function(language) {
var clean = jsdom('', {url: 'https://privatebin.net/', cookie: ['lang=' + language]});
// cleanup
var clean = jsdom('', {cookie: ['lang=en']});
$.PrivateBin.I18n.reset('en');
$.PrivateBin.I18n.loadTranslations();
clean();
// mock
clean = jsdom('', {cookie: ['lang=' + language]});
$.PrivateBin.I18n.reset(language, require('../../i18n/' + language + '.json'));
var result = $.PrivateBin.I18n.translate('en'),
alias = $.PrivateBin.I18n._('en');
clean();
return language === result && language === alias;
}

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();
@@ -72,27 +74,32 @@ describe('Model', function () {
describe('getPasteId', function () {
this.timeout(30000);
before(function () {
beforeEach(function () {
$.PrivateBin.Model.reset();
cleanup();
});
jsc.property(
'returns the query string without separator, if any',
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscHashString()),
jsc.tuple(new Array(16).fill(common.jscHexString)),
jsc.array(common.jscQueryString()),
jsc.array(common.jscQueryString()),
'string',
function (schema, address, query, fragment) {
var queryString = query.join(''),
clean = jsdom('', {
function (schema, address, pasteId, queryStart, queryEnd, fragment) {
var pasteIdString = pasteId.join(''),
queryStartString = queryStart.join('') + (queryStart.length > 0 ? '&' : ''),
queryEndString = (queryEnd.length > 0 ? '&' : '') + queryEnd.join(''),
queryString = queryStartString + pasteIdString + queryEndString,
clean = jsdom('', {
url: schema.join('') + '://' + address.join('') +
'/?' + queryString + '#' + fragment
}),
result = $.PrivateBin.Model.getPasteId();
});
global.URL = require('jsdom-url').URL;
var result = $.PrivateBin.Model.getPasteId();
$.PrivateBin.Model.reset();
clean();
return queryString === result;
return pasteIdString === result;
}
);
jsc.property(
@@ -106,6 +113,7 @@ describe('Model', function () {
'/#' + fragment
}),
result = false;
global.URL = require('jsdom-url').URL;
try {
$.PrivateBin.Model.getPasteId();
}
@@ -121,15 +129,19 @@ describe('Model', function () {
describe('getPasteKey', function () {
this.timeout(30000);
beforeEach(function () {
$.PrivateBin.Model.reset();
});
jsc.property(
'returns the fragment of the URL',
'returns the fragment of a v1 URL',
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscQueryString()),
jsc.nearray(common.jscBase64String()),
'nestring',
function (schema, address, query, fragment) {
var fragmentString = fragment.join(''),
clean = jsdom('', {
const fragmentString = common.btoa(fragment.padStart(32, '\u0000'));
let clean = jsdom('', {
url: schema.join('') + '://' + address.join('') +
'/?' + query.join('') + '#' + fragmentString
}),
@@ -140,15 +152,15 @@ describe('Model', function () {
}
);
jsc.property(
'returns the fragment stripped of trailing query parts',
'returns the v1 fragment stripped of trailing query parts',
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscQueryString()),
jsc.nearray(common.jscBase64String()),
'nestring',
jsc.array(common.jscHashString()),
function (schema, address, query, fragment, trail) {
var fragmentString = fragment.join(''),
clean = jsdom('', {
const fragmentString = common.btoa(fragment.padStart(32, '\u0000'));
let clean = jsdom('', {
url: schema.join('') + '://' + address.join('') + '/?' +
query.join('') + '#' + fragmentString + '&' + trail.join('')
}),
@@ -158,6 +170,47 @@ describe('Model', function () {
return fragmentString === result;
}
);
jsc.property(
'returns the fragment of a v2 URL',
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscQueryString()),
'nestring',
function (schema, address, query, fragment) {
// base58 strips leading NULL bytes, so the string is padded with these if not found
fragment = fragment.padStart(32, '\u0000');
let fragmentString = $.PrivateBin.CryptTool.base58encode(fragment),
clean = jsdom('', {
url: schema.join('') + '://' + address.join('') +
'/?' + query.join('') + '#' + fragmentString
}),
result = $.PrivateBin.Model.getPasteKey();
$.PrivateBin.Model.reset();
clean();
return fragment === result;
}
);
jsc.property(
'returns the v2 fragment stripped of trailing query parts',
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscQueryString()),
'nestring',
jsc.array(common.jscHashString()),
function (schema, address, query, fragment, trail) {
// base58 strips leading NULL bytes, so the string is padded with these if not found
fragment = fragment.padStart(32, '\u0000');
let fragmentString = $.PrivateBin.CryptTool.base58encode(fragment),
clean = jsdom('', {
url: schema.join('') + '://' + address.join('') + '/?' +
query.join('') + '#' + fragmentString + '&' + trail.join('')
}),
result = $.PrivateBin.Model.getPasteKey();
$.PrivateBin.Model.reset();
clean();
return fragment === result;
}
);
jsc.property(
'throws exception on empty fragment of the URL',
jsc.nearray(common.jscA2zString()),
@@ -183,9 +236,8 @@ describe('Model', function () {
});
describe('getTemplate', function () {
before(function () {
beforeEach(function () {
$.PrivateBin.Model.reset();
cleanup();
});
jsc.property(

View File

@@ -4,9 +4,6 @@ var common = require('../common');
describe('PasteStatus', function () {
describe('createPasteNotification', function () {
this.timeout(30000);
before(function () {
cleanup();
});
jsc.property(
'creates a notification after a successfull paste upload',
@@ -24,7 +21,7 @@ describe('PasteStatus', function () {
var expected1 = schema1 + '://' + address1.join('') + '/?' +
encodeURI(query1.join('').replace(/^&+|&+$/gm,'') + '#' + fragment1),
expected2 = schema2 + '://' + address2.join('') + '/?' +
encodeURI(query2.join('')),
encodeURI(query2.join('').replace(/^&+|&+$/gm,'')),
clean = jsdom();
$('body').html('<div><div id="deletelink"></div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
@@ -39,12 +36,9 @@ describe('PasteStatus', function () {
describe('showRemainingTime', function () {
this.timeout(30000);
before(function () {
cleanup();
});
jsc.property(
'shows burn after reading message or remaining time',
'shows burn after reading message or remaining time v1',
'bool',
'nat',
jsc.nearray(common.jscA2zString()),
@@ -62,11 +56,51 @@ describe('PasteStatus', function () {
result;
$('body').html('<div id="remainingtime" class="hidden"></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.showRemainingTime({
$.PrivateBin.PasteStatus.showRemainingTime($.PrivateBin.Helper.PasteFactory({'meta': {
'burnafterreading': burnafterreading,
'remaining_time': remainingTime,
'expire_date': remainingTime ? ((new Date()).getTime() / 1000) + remainingTime : 0
});
'remaining_time': remainingTime
}}));
if (burnafterreading) {
result = $('#remainingtime').hasClass('foryoureyesonly') &&
!$('#remainingtime').hasClass('hidden');
} else if (remainingTime) {
result =!$('#remainingtime').hasClass('foryoureyesonly') &&
!$('#remainingtime').hasClass('hidden');
} else {
result = $('#remainingtime').hasClass('hidden') &&
!$('#remainingtime').hasClass('foryoureyesonly');
}
clean();
return result;
}
);
jsc.property(
'shows burn after reading message or remaining time v2',
'bool',
'nat',
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscQueryString()),
'string',
function (
burnafterreading, remainingTime,
schema, address, query, fragment
) {
var clean = jsdom('', {
url: schema.join('') + '://' + address.join('') +
'/?' + query.join('') + '#' + fragment
}),
result;
$('body').html('<div id="remainingtime" class="hidden"></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.showRemainingTime($.PrivateBin.Helper.PasteFactory({
'adata': [null, null, null, burnafterreading],
'v': 2,
'meta': {
'time_to_live': remainingTime
}
}));
if (burnafterreading) {
result = $('#remainingtime').hasClass('foryoureyesonly') &&
!$('#remainingtime').hasClass('hidden');
@@ -84,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,17 +6,13 @@ 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',
'string',
function (password) {
password = password.replace(/\r+/g, '');
var clean = jsdom('', {url: 'ftp://example.com/?0'});
var clean = jsdom('', {url: 'ftp://example.com/?0000000000000000'});
$('body').html(
'<div id="passwordmodal" class="modal fade" role="dialog">' +
'<div class="modal-dialog"><div class="modal-content">' +
@@ -26,12 +22,15 @@ 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();
$('#passworddecrypt').val(password);
$('#passwordform').submit();
var result = $.PrivateBin.Prompt.getPassword();
// TODO triggers error messages in current jsDOM version, find better solution
//$('#passwordform').submit();
//var result = $.PrivateBin.Prompt.getPassword();
var result = $('#passworddecrypt').val();
$.PrivateBin.Model.reset();
clean();
return result === password;

View File

@@ -0,0 +1,40 @@
'use strict';
require('../common');
describe('ServerInteraction', function () {
describe('prepare', function () {
afterEach(async function () {
// pause to let async functions conclude
await new Promise(resolve => setTimeout(resolve, 1900));
});
this.timeout(30000);
it('can prepare an encrypted paste', function () {
jsc.assert(jsc.forall(
'string',
'string',
'string',
async function (key, password, message) {
// pause to let async functions conclude
await new Promise(resolve => setTimeout(resolve, 300));
let clean = jsdom();
window.crypto = new WebCrypto();
message = message.trim();
$.PrivateBin.ServerInteraction.prepare();
$.PrivateBin.ServerInteraction.setCryptParameters(password, key);
$.PrivateBin.ServerInteraction.setUnencryptedData('adata', [
// encryption parameters defined by CryptTool, format, discussion, burn after reading
null, 'plaintext', 0, 0
]);
$.PrivateBin.ServerInteraction.setUnencryptedData('meta', {'expire': '5min'});
await $.PrivateBin.ServerInteraction.setCipherMessage({'paste': message});
//console.log($.PrivateBin.ServerInteraction.getData());
clean();
// TODO currently not testing anything and just used to generate v2 pastes for starting development of server side v2 implementation
return true;
}
),
{tests: 3});
});
});
});

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

@@ -6,7 +6,7 @@ describe('UiHelper', function () {
// for now we use a mock function to trigger the event
describe('historyChange', function () {
this.timeout(30000);
before(function () {
beforeEach(function () {
$.PrivateBin.Helper.reset();
cleanup();
});

File diff suppressed because it is too large Load Diff

124
js/types.jsonld Normal file
View File

@@ -0,0 +1,124 @@
{
"@context": {
"so": "https://schema.org/",
"dp": "http://dbpedia.org/resource/",
"pb": "?jsonld=types#"
},
"Base64": {
"@type": "so:Text"
},
"CipherText": {
"@type": "pb:Base64"
},
"PasteCipherMessage": {
"paste": {
"@type": "so:Text"
},
"attachment": {
"@type": "so:MediaObject"
},
"attachment_name": {
"@type": "so:Text"
}
},
"CommentCipherMessage": {
"comment": {
"@type": "so:Text"
},
"nickname": {
"@type": "so:Text"
}
},
"InitializationVector": {
"@type": "pb:Base64"
},
"Salt": {
"@type": "pb:Base64"
},
"Iterations": {
"@type": "so:Integer",
"@minimum": 1
},
"KeySize": {
"@type": "so:Integer",
"@value": 256,
"@minimum": 128,
"@maximum": 256,
"@enum": [128, 196, 256]
},
"TagSize": {
"@type": "so:Integer",
"@value": 128,
"@minimum": 32,
"@maximum": 128,
"@enum": [32, 64, 96, 104, 112, 120, 128]
},
"Algorithm": {
"@type": "so:Text",
"@value": "aes"
},
"Mode": {
"@type": "so:Text",
"@value": "gcm",
"@enum": ["ctr", "cbc", "gcm"]
},
"Compression": {
"@type": "so:Text",
"@value": "zlib",
"@enum": ["zlib", "none"]
},
"Formatter": {
"@type": "so:Text",
"@value": "plaintext",
"@enum": ["plaintext", "syntaxhighlighting", "markdown"]
},
"Expiration": {
"@type": "so:Text",
"@value": "1week",
"@enum": ["5min", "10min", "1hour", "1day", "1week", "1month", "1year", "never"]
},
"OpenDiscussion": {
"@type": "so:Boolean",
"@enum": [false, true]
},
"BurnAfterReading": {
"@type": "so:Boolean",
"@enum": [false, true]
},
"CreationTime": {
"@type": "dp:Unix_time"
},
"RemainingSeconds": {
"@type": "dp:Second",
"@minimum": 1
},
"CipherParameters": {
"@container": "@list",
"@value": [
{
"@type": "pb:InitializationVector"
},
{
"@type": "pb:Salt"
},
{
"@type": "pb:Iterations"
},
{
"@type": "pb:KeySize"
},
{
"@type": "pb:TagSize"
},
{
"@type": "pb:Algorithm"
},
{
"@type": "pb:Mode"
},
{
"@type": "pb:Compression"
}
]
}
}

146
js/zlib-1.2.11.js Normal file
View File

@@ -0,0 +1,146 @@
'use strict';
(function() {
let ret;
async function initialize() {
if (ret) return ret;
const COMPRESSION_LEVEL = 7;
const NO_ZLIB_HEADER = -1;
const CHUNK_SIZE = 32 * 1024;
const map = {};
const memory = new WebAssembly.Memory({
initial: 1,
maximum: 1024, // 64MB
});
const env = {
memory,
writeToJs(ptr, size) {
const o = map[ptr];
o.onData(new Uint8Array(memory.buffer, dstPtr, size));
},
_abort: errno => { console.error(`Error: ${errno}`) },
_grow: () => { },
};
let buff;
if (typeof fetch === 'undefined') {
buff = fs.readFileSync('zlib-1.2.11.wasm');
} else {
const resp = await fetch('js/zlib-1.2.11.wasm');
buff = await resp.arrayBuffer();
}
const module = await WebAssembly.compile(buff);
const ins = await WebAssembly.instantiate(module, { env });
const srcPtr = ins.exports._malloc(CHUNK_SIZE);
const dstPtr = ins.exports._malloc(CHUNK_SIZE);
class RawDef {
constructor() {
this.zstreamPtr = ins.exports._createDeflateContext(COMPRESSION_LEVEL, NO_ZLIB_HEADER);
map[this.zstreamPtr] = this;
this.offset = 0;
this.buff = new Uint8Array(CHUNK_SIZE);
}
deflate(chunk, flush) {
const src = new Uint8Array(memory.buffer, srcPtr, chunk.length);
src.set(chunk);
ins.exports._deflate(this.zstreamPtr, srcPtr, dstPtr, chunk.length, CHUNK_SIZE, flush);
}
onData(chunk) {
if (this.buff.length < this.offset + chunk.length) {
const buff = this.buff;
this.buff = new Uint8Array(this.buff.length * 2);
this.buff.set(buff);
}
this.buff.set(chunk, this.offset);
this.offset += chunk.length;
}
destroy() {
ins.exports._freeDeflateContext(this.zstreamPtr);
delete map[this.zstreamPtr];
this.buff = null;
}
getBuffer() {
const res = new Uint8Array(this.offset);
for (let i = 0; i < this.offset; ++i) {
res[i] = this.buff[i];
}
return res;
}
}
class RawInf {
constructor() {
this.zstreamPtr = ins.exports._createInflateContext(NO_ZLIB_HEADER);
map[this.zstreamPtr] = this;
this.offset = 0;
this.buff = new Uint8Array(CHUNK_SIZE);
}
inflate(chunk) {
const src = new Uint8Array(memory.buffer, srcPtr, chunk.length);
src.set(chunk);
ins.exports._inflate(this.zstreamPtr, srcPtr, dstPtr, chunk.length, CHUNK_SIZE);
}
onData(chunk) {
if (this.buff.length < this.offset + chunk.length) {
const buff = this.buff;
this.buff = new Uint8Array(this.buff.length * 2);
this.buff.set(buff);
}
this.buff.set(chunk, this.offset);
this.offset += chunk.length;
}
destroy() {
ins.exports._freeInflateContext(this.zstreamPtr);
delete map[this.zstreamPtr];
this.buff = null;
}
getBuffer() {
const res = new Uint8Array(this.offset);
for (let i = 0; i < this.offset; ++i) {
res[i] = this.buff[i];
}
return res;
}
}
ret = {
inflate(rawDeflateBuffer) {
const rawInf = new RawInf();
for (let offset = 0; offset < rawDeflateBuffer.length; offset += CHUNK_SIZE) {
const end = Math.min(offset + CHUNK_SIZE, rawDeflateBuffer.length);
const chunk = rawDeflateBuffer.subarray(offset, end);
rawInf.inflate(chunk);
}
const ret = rawInf.getBuffer();
rawInf.destroy();
return ret;
},
deflate(rawInflateBuffer) {
const rawDef = new RawDef();
for (let offset = 0; offset < rawInflateBuffer.length; offset += CHUNK_SIZE) {
const end = Math.min(offset + CHUNK_SIZE, rawInflateBuffer.length);
const chunk = rawInflateBuffer.subarray(offset, end);
rawDef.deflate(chunk, rawInflateBuffer.length <= offset + CHUNK_SIZE);
}
const ret = rawDef.getBuffer();
rawDef.destroy();
return ret;
},
}
return ret;
}
this.zlib = initialize();
}).call(this);

BIN
js/zlib-1.2.11.wasm Normal file

Binary file not shown.

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.2.1
* @version 1.3.3
*/
namespace PrivateBin;
@@ -45,7 +45,7 @@ class Configuration
'burnafterreadingselected' => false,
'defaultformatter' => 'plaintext',
'syntaxhighlightingtheme' => null,
'sizelimit' => 2097152,
'sizelimit' => 10485760,
'template' => 'bootstrap',
'notice' => '',
'languageselection' => false,
@@ -53,8 +53,10 @@ class Configuration
'urlshortener' => '',
'qrcode' => true,
'icon' => 'identicon',
'cspheader' => 'default-src \'none\'; manifest-src \'self\'; connect-src *; script-src \'self\'; style-src \'self\'; font-src \'self\'; img-src \'self\' data:; media-src data:; object-src data:; Referrer-Policy: \'no-referrer\'; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals',
'cspheader' => 'default-src \'none\'; manifest-src \'self\'; connect-src * blob:; script-src \'self\' \'unsafe-eval\'; style-src \'self\'; font-src \'self\'; img-src \'self\' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals',
'zerobincompatibility' => false,
'httpwarning' => true,
'compression' => 'zlib',
),
'expire' => array(
'default' => '1week',
@@ -100,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)) {
@@ -110,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.2.1
* @version 1.3.3
*/
namespace PrivateBin;
@@ -28,14 +28,14 @@ class Controller
*
* @const string
*/
const VERSION = '1.2.1';
const VERSION = '1.3.3';
/**
* minimal required PHP version
*
* @const string
*/
const MIN_PHP_VERSION = '5.4.0';
const MIN_PHP_VERSION = '5.6.0';
/**
* show the same error message if the paste expired or does not exist
@@ -154,6 +154,7 @@ class Controller
* initialize PrivateBin
*
* @access private
* @throws Exception
*/
private function _init()
{
@@ -177,16 +178,16 @@ class Controller
* Store new paste or comment
*
* POST contains one or both:
* data = json encoded SJCL encrypted text (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct)
* attachment = json encoded SJCL encrypted text (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct)
* data = json encoded FormatV2 encrypted text (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct)
* attachment = json encoded FormatV2 encrypted text (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct)
*
* All optional data will go to meta information:
* expire (optional) = expiration delay (never,5min,10min,1hour,1day,1week,1month,1year,burn) (default:never)
* formatter (optional) = format to display the paste as (plaintext,syntaxhighlighting,markdown) (default:syntaxhighlighting)
* burnafterreading (optional) = if this paste may only viewed once ? (0/1) (default:0)
* opendiscusssion (optional) = is the discussion allowed on this paste ? (0/1) (default:0)
* attachmentname = json encoded SJCL encrypted text (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct)
* nickname (optional) = in discussion, encoded SJCL encrypted text nickname of author of comment (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct)
* attachmentname = json encoded FormatV2 encrypted text (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct)
* nickname (optional) = in discussion, encoded FormatV2 encrypted text nickname of author of comment (containing keys: iv,v,iter,ks,ts,mode,adata,cipher,salt,ct)
* parentid (optional) = in discussion, which comment this comment replies to.
* pasteid (optional) = in discussion, which paste this comment belongs to.
*
@@ -198,59 +199,52 @@ class Controller
// Ensure last paste from visitors IP address was more than configured amount of seconds ago.
TrafficLimiter::setConfiguration($this->_conf);
if (!TrafficLimiter::canPass()) {
return $this->_return_message(
1, I18n::_(
'Please wait %d seconds between each post.',
$this->_conf->getKey('limit', 'traffic')
)
);
$this->_return_message(
1, I18n::_(
'Please wait %d seconds between each post.',
$this->_conf->getKey('limit', 'traffic')
)
);
return;
}
$data = $this->_request->getParam('data');
$attachment = $this->_request->getParam('attachment');
$attachmentname = $this->_request->getParam('attachmentname');
// Ensure content is not too big.
$data = $this->_request->getData();
$isComment = array_key_exists('pasteid', $data) &&
!empty($data['pasteid']) &&
array_key_exists('parentid', $data) &&
!empty($data['parentid']);
if (!FormatV2::isValid($data, $isComment)) {
$this->_return_message(1, I18n::_('Invalid data.'));
return;
}
$sizelimit = $this->_conf->getKey('sizelimit');
if (
strlen($data) + strlen($attachment) + strlen($attachmentname) > $sizelimit
) {
return $this->_return_message(
1,
I18n::_(
'Paste is limited to %s of encrypted data.',
Filter::formatHumanReadableSize($sizelimit)
)
);
}
// Ensure attachment did not get lost due to webserver limits or Suhosin
if (strlen($attachmentname) > 0 && strlen($attachment) == 0) {
return $this->_return_message(1, 'Attachment missing in data received by server. Please check your webserver or suhosin configuration for maximum POST parameter limitations.');
// Ensure content is not too big.
if (strlen($data['ct']) > $sizelimit) {
$this->_return_message(
1,
I18n::_(
'Paste is limited to %s of encrypted data.',
Filter::formatHumanReadableSize($sizelimit)
)
);
return;
}
// The user posts a comment.
$pasteid = $this->_request->getParam('pasteid');
$parentid = $this->_request->getParam('parentid');
if (!empty($pasteid) && !empty($parentid)) {
$paste = $this->_model->getPaste($pasteid);
if ($isComment) {
$paste = $this->_model->getPaste($data['pasteid']);
if ($paste->exists()) {
try {
$comment = $paste->getComment($parentid);
$nickname = $this->_request->getParam('nickname');
if (!empty($nickname)) {
$comment->setNickname($nickname);
}
$comment = $paste->getComment($data['parentid']);
$comment->setData($data);
$comment->store();
} catch (Exception $e) {
return $this->_return_message(1, $e->getMessage());
$this->_return_message(1, $e->getMessage());
return;
}
$this->_return_message(0, $comment->getId());
} else {
$this->_return_message(1, 'Invalid data.');
$this->_return_message(1, I18n::_('Invalid data.'));
}
}
// The user posts a standard paste.
@@ -259,34 +253,6 @@ class Controller
$paste = $this->_model->getPaste();
try {
$paste->setData($data);
if (!empty($attachment)) {
$paste->setAttachment($attachment);
if (!empty($attachmentname)) {
$paste->setAttachmentName($attachmentname);
}
}
$expire = $this->_request->getParam('expire');
if (!empty($expire)) {
$paste->setExpiration($expire);
}
$burnafterreading = $this->_request->getParam('burnafterreading');
if (!empty($burnafterreading)) {
$paste->setBurnafterreading($burnafterreading);
}
$opendiscussion = $this->_request->getParam('opendiscussion');
if (!empty($opendiscussion)) {
$paste->setOpendiscussion($opendiscussion);
}
$formatter = $this->_request->getParam('formatter');
if (!empty($formatter)) {
$paste->setFormatter($formatter);
}
$paste->store();
} catch (Exception $e) {
return $this->_return_message(1, $e->getMessage());
@@ -307,22 +273,15 @@ class Controller
try {
$paste = $this->_model->getPaste($dataid);
if ($paste->exists()) {
// accessing this property ensures that the paste would be
// accessing this method ensures that the paste would be
// deleted if it has already expired
$burnafterreading = $paste->isBurnafterreading();
if (
($burnafterreading && $deletetoken == 'burnafterreading') || // either we burn-after it has been read //@TODO: not needed anymore now?
Filter::slowEquals($deletetoken, $paste->getDeleteToken()) // or we manually delete it with this secret token
) {
// Paste exists and deletion token (if required) is valid: Delete the paste.
$paste->get();
if (hash_equals($paste->getDeleteToken(), $deletetoken)) {
// Paste exists and deletion token is valid: Delete the paste.
$paste->delete();
$this->_status = 'Paste was properly deleted.';
} else {
if (!$burnafterreading && $deletetoken == 'burnafterreading') {
$this->_error = 'Paste is not of burn-after-reading type.';
} else {
$this->_error = 'Wrong deletion token. Paste was not deleted.';
}
$this->_error = 'Wrong deletion token. Paste was not deleted.';
}
} else {
$this->_error = self::GENERIC_ERROR;
@@ -355,8 +314,8 @@ class Controller
$paste = $this->_model->getPaste($dataid);
if ($paste->exists()) {
$data = $paste->get();
if (property_exists($data->meta, 'salt')) {
unset($data->meta->salt);
if (array_key_exists('salt', $data['meta'])) {
unset($data['meta']['salt']);
}
$this->_return_message(0, $dataid, (array) $data);
} else {
@@ -382,6 +341,7 @@ class Controller
header('Last-Modified: ' . $time);
header('Vary: Accept');
header('Content-Security-Policy: ' . $this->_conf->getKey('cspheader'));
header('Referrer-Policy: no-referrer');
header('X-Xss-Protection: 1; mode=block');
header('X-Frame-Options: DENY');
header('X-Content-Type-Options: nosniff');
@@ -425,6 +385,9 @@ class Controller
$page->assign('EXPIREDEFAULT', $this->_conf->getKey('default', 'expire'));
$page->assign('URLSHORTENER', $this->_conf->getKey('urlshortener'));
$page->assign('QRCODE', $this->_conf->getKey('qrcode'));
$page->assign('HTTPWARNING', $this->_conf->getKey('httpwarning'));
$page->assign('HTTPSLINK', 'https://' . $this->_request->getHost() . $this->_request->getRequestUri());
$page->assign('COMPRESSION', $this->_conf->getKey('compression'));
$page->draw($this->_conf->getKey('template'));
}
@@ -476,6 +439,6 @@ class Controller
$result['url'] = $this->_urlBase . '?' . $message;
}
$result += $other;
$this->_json = json_encode($result);
$this->_json = Json::encode($result);
}
}

View File

@@ -7,13 +7,11 @@
* @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.2.1
* @version 1.3.3
*/
namespace PrivateBin\Data;
use stdClass;
/**
* AbstractData
*
@@ -60,7 +58,7 @@ abstract class AbstractData
* @param array $options
* @return AbstractData
*/
public static function getInstance($options)
public static function getInstance(array $options)
{
}
@@ -72,14 +70,14 @@ abstract class AbstractData
* @param array $paste
* @return bool
*/
abstract public function create($pasteid, $paste);
abstract public function create($pasteid, array $paste);
/**
* Read a paste.
*
* @access public
* @param string $pasteid
* @return stdClass|false
* @return array|false
*/
abstract public function read($pasteid);
@@ -110,7 +108,7 @@ abstract class AbstractData
* @param array $comment
* @return bool
*/
abstract public function createComment($pasteid, $parentid, $commentid, $comment);
abstract public function createComment($pasteid, $parentid, $commentid, array $comment);
/**
* Read all comments of paste.
@@ -163,12 +161,12 @@ abstract class AbstractData
/**
* Get next free slot for comment from postdate.
*
* @access public
* @access protected
* @param array $comments
* @param int|string $postdate
* @return int|string
*/
protected function getOpenSlot(&$comments, $postdate)
protected function getOpenSlot(array &$comments, $postdate)
{
if (array_key_exists($postdate, $comments)) {
$parts = explode('.', $postdate, 2);
@@ -180,4 +178,25 @@ abstract class AbstractData
}
return $postdate;
}
/**
* Upgrade pre-version 1 pastes with attachment to version 1 format.
*
* @access protected
* @static
* @param array $paste
* @return array
*/
protected static function upgradePreV1Format(array $paste)
{
if (array_key_exists('attachment', $paste['meta'])) {
$paste['attachment'] = $paste['meta']['attachment'];
unset($paste['meta']['attachment']);
if (array_key_exists('attachmentname', $paste['meta'])) {
$paste['attachmentname'] = $paste['meta']['attachmentname'];
unset($paste['meta']['attachmentname']);
}
}
return $paste;
}
}

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.2.1
* @version 1.3.3
*/
namespace PrivateBin\Data;
@@ -16,7 +16,7 @@ use Exception;
use PDO;
use PDOException;
use PrivateBin\Controller;
use stdClass;
use PrivateBin\Json;
/**
* Database
@@ -68,80 +68,78 @@ class Database extends AbstractData
* @throws Exception
* @return Database
*/
public static function getInstance($options = null)
public static function getInstance(array $options)
{
// if needed initialize the singleton
if (!(self::$_instance instanceof self)) {
self::$_instance = new self;
}
if (is_array($options)) {
// set table prefix if given
if (array_key_exists('tbl', $options)) {
self::$_prefix = $options['tbl'];
// set table prefix if given
if (array_key_exists('tbl', $options)) {
self::$_prefix = $options['tbl'];
}
// initialize the db connection with new options
if (
array_key_exists('dsn', $options) &&
array_key_exists('usr', $options) &&
array_key_exists('pwd', $options) &&
array_key_exists('opt', $options)
) {
// set default options
$options['opt'][PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
$options['opt'][PDO::ATTR_EMULATE_PREPARES] = false;
$options['opt'][PDO::ATTR_PERSISTENT] = true;
$db_tables_exist = true;
// setup type and dabase connection
self::$_type = strtolower(
substr($options['dsn'], 0, strpos($options['dsn'], ':'))
);
$tableQuery = self::_getTableQuery(self::$_type);
self::$_db = new PDO(
$options['dsn'],
$options['usr'],
$options['pwd'],
$options['opt']
);
// check if the database contains the required tables
$tables = self::$_db->query($tableQuery)->fetchAll(PDO::FETCH_COLUMN, 0);
// create paste table if necessary
if (!in_array(self::_sanitizeIdentifier('paste'), $tables)) {
self::_createPasteTable();
$db_tables_exist = false;
}
// initialize the db connection with new options
if (
array_key_exists('dsn', $options) &&
array_key_exists('usr', $options) &&
array_key_exists('pwd', $options) &&
array_key_exists('opt', $options)
) {
// set default options
$options['opt'][PDO::ATTR_ERRMODE] = PDO::ERRMODE_EXCEPTION;
$options['opt'][PDO::ATTR_EMULATE_PREPARES] = false;
$options['opt'][PDO::ATTR_PERSISTENT] = true;
$db_tables_exist = true;
// create comment table if necessary
if (!in_array(self::_sanitizeIdentifier('comment'), $tables)) {
self::_createCommentTable();
$db_tables_exist = false;
}
// setup type and dabase connection
self::$_type = strtolower(
substr($options['dsn'], 0, strpos($options['dsn'], ':'))
);
$tableQuery = self::_getTableQuery(self::$_type);
self::$_db = new PDO(
$options['dsn'],
$options['usr'],
$options['pwd'],
$options['opt']
);
// check if the database contains the required tables
$tables = self::$_db->query($tableQuery)->fetchAll(PDO::FETCH_COLUMN, 0);
// create paste table if necessary
if (!in_array(self::_sanitizeIdentifier('paste'), $tables)) {
self::_createPasteTable();
$db_tables_exist = false;
}
// create comment table if necessary
if (!in_array(self::_sanitizeIdentifier('comment'), $tables)) {
self::_createCommentTable();
$db_tables_exist = false;
}
// create config table if necessary
$db_version = Controller::VERSION;
if (!in_array(self::_sanitizeIdentifier('config'), $tables)) {
self::_createConfigTable();
// if we only needed to create the config table, the DB is older then 0.22
if ($db_tables_exist) {
$db_version = '0.21';
}
} else {
$db_version = self::_getConfig('VERSION');
}
// update database structure if necessary
if (version_compare($db_version, Controller::VERSION, '<')) {
self::_upgradeDatabase($db_version);
// create config table if necessary
$db_version = Controller::VERSION;
if (!in_array(self::_sanitizeIdentifier('config'), $tables)) {
self::_createConfigTable();
// if we only needed to create the config table, the DB is older then 0.22
if ($db_tables_exist) {
$db_version = '0.21';
}
} else {
throw new Exception(
'Missing configuration for key dsn, usr, pwd or opt in the section model_options, please check your configuration file', 6
);
$db_version = self::_getConfig('VERSION');
}
// update database structure if necessary
if (version_compare($db_version, Controller::VERSION, '<')) {
self::_upgradeDatabase($db_version);
}
} else {
throw new Exception(
'Missing configuration for key dsn, usr, pwd or opt in the section model_options, please check your configuration file', 6
);
}
return self::$_instance;
@@ -155,7 +153,7 @@ class Database extends AbstractData
* @param array $paste
* @return bool
*/
public function create($pasteid, $paste)
public function create($pasteid, array $paste)
{
if (
array_key_exists($pasteid, self::$_cache)
@@ -167,42 +165,50 @@ class Database extends AbstractData
}
}
$opendiscussion = $burnafterreading = false;
$attachment = $attachmentname = '';
$meta = $paste['meta'];
unset($meta['postdate']);
$expire_date = 0;
if (array_key_exists('expire_date', $paste['meta'])) {
$expire_date = (int) $paste['meta']['expire_date'];
$expire_date = 0;
$opendiscussion = $burnafterreading = false;
$attachment = $attachmentname = null;
$meta = $paste['meta'];
$isVersion1 = array_key_exists('data', $paste);
list($createdKey) = self::_getVersionedKeys($isVersion1 ? 1 : 2);
$created = (int) $meta[$createdKey];
unset($meta[$createdKey], $paste['meta']);
if (array_key_exists('expire_date', $meta)) {
$expire_date = (int) $meta['expire_date'];
unset($meta['expire_date']);
}
if (array_key_exists('opendiscussion', $paste['meta'])) {
$opendiscussion = (bool) $paste['meta']['opendiscussion'];
if (array_key_exists('opendiscussion', $meta)) {
$opendiscussion = $meta['opendiscussion'];
unset($meta['opendiscussion']);
}
if (array_key_exists('burnafterreading', $paste['meta'])) {
$burnafterreading = (bool) $paste['meta']['burnafterreading'];
if (array_key_exists('burnafterreading', $meta)) {
$burnafterreading = $meta['burnafterreading'];
unset($meta['burnafterreading']);
}
if (array_key_exists('attachment', $paste['meta'])) {
$attachment = $paste['meta']['attachment'];
unset($meta['attachment']);
}
if (array_key_exists('attachmentname', $paste['meta'])) {
$attachmentname = $paste['meta']['attachmentname'];
unset($meta['attachmentname']);
if ($isVersion1) {
if (array_key_exists('attachment', $meta)) {
$attachment = $meta['attachment'];
unset($meta['attachment']);
}
if (array_key_exists('attachmentname', $meta)) {
$attachmentname = $meta['attachmentname'];
unset($meta['attachmentname']);
}
} else {
$opendiscussion = $paste['adata'][2];
$burnafterreading = $paste['adata'][3];
}
return self::_exec(
'INSERT INTO ' . self::_sanitizeIdentifier('paste') .
' VALUES(?,?,?,?,?,?,?,?,?)',
array(
$pasteid,
$paste['data'],
$paste['meta']['postdate'],
$isVersion1 ? $paste['data'] : Json::encode($paste),
$created,
$expire_date,
(int) $opendiscussion,
(int) $burnafterreading,
json_encode($meta),
Json::encode($meta),
$attachment,
$attachmentname,
)
@@ -214,65 +220,63 @@ class Database extends AbstractData
*
* @access public
* @param string $pasteid
* @return stdClass|false
* @return array|false
*/
public function read($pasteid)
{
if (
!array_key_exists($pasteid, self::$_cache)
) {
self::$_cache[$pasteid] = false;
$paste = self::_select(
'SELECT * FROM ' . self::_sanitizeIdentifier('paste') .
' WHERE dataid = ?', array($pasteid), true
);
if (array_key_exists($pasteid, self::$_cache)) {
return self::$_cache[$pasteid];
}
if (false !== $paste) {
// create object
self::$_cache[$pasteid] = new stdClass;
self::$_cache[$pasteid]->data = $paste['data'];
self::$_cache[$pasteid] = false;
$paste = self::_select(
'SELECT * FROM ' . self::_sanitizeIdentifier('paste') .
' WHERE dataid = ?', array($pasteid), true
);
$meta = json_decode($paste['meta']);
if (!is_object($meta)) {
$meta = new stdClass;
}
if ($paste === false) {
return false;
}
// create array
$data = Json::decode($paste['data']);
$isVersion2 = array_key_exists('v', $data) && $data['v'] >= 2;
if ($isVersion2) {
self::$_cache[$pasteid] = $data;
list($createdKey) = self::_getVersionedKeys(2);
} else {
self::$_cache[$pasteid] = array('data' => $paste['data']);
list($createdKey) = self::_getVersionedKeys(1);
}
// support older attachments
if (property_exists($meta, 'attachment')) {
self::$_cache[$pasteid]->attachment = $meta->attachment;
unset($meta->attachment);
if (property_exists($meta, 'attachmentname')) {
self::$_cache[$pasteid]->attachmentname = $meta->attachmentname;
unset($meta->attachmentname);
}
}
// support current attachments
elseif (array_key_exists('attachment', $paste) && strlen($paste['attachment'])) {
self::$_cache[$pasteid]->attachment = $paste['attachment'];
if (array_key_exists('attachmentname', $paste) && strlen($paste['attachmentname'])) {
self::$_cache[$pasteid]->attachmentname = $paste['attachmentname'];
}
}
self::$_cache[$pasteid]->meta = $meta;
self::$_cache[$pasteid]->meta->postdate = (int) $paste['postdate'];
$expire_date = (int) $paste['expiredate'];
if (
$expire_date > 0
) {
self::$_cache[$pasteid]->meta->expire_date = $expire_date;
}
if (
$paste['opendiscussion']
) {
self::$_cache[$pasteid]->meta->opendiscussion = true;
}
if (
$paste['burnafterreading']
) {
self::$_cache[$pasteid]->meta->burnafterreading = true;
}
try {
$paste['meta'] = Json::decode($paste['meta']);
} catch (Exception $e) {
$paste['meta'] = array();
}
$paste = self::upgradePreV1Format($paste);
self::$_cache[$pasteid]['meta'] = $paste['meta'];
self::$_cache[$pasteid]['meta'][$createdKey] = (int) $paste['postdate'];
$expire_date = (int) $paste['expiredate'];
if ($expire_date > 0) {
self::$_cache[$pasteid]['meta']['expire_date'] = $expire_date;
}
if ($isVersion2) {
return self::$_cache[$pasteid];
}
// support v1 attachments
if (array_key_exists('attachment', $paste) && strlen($paste['attachment'])) {
self::$_cache[$pasteid]['attachment'] = $paste['attachment'];
if (array_key_exists('attachmentname', $paste) && strlen($paste['attachmentname'])) {
self::$_cache[$pasteid]['attachmentname'] = $paste['attachmentname'];
}
}
if ($paste['opendiscussion']) {
self::$_cache[$pasteid]['meta']['opendiscussion'] = true;
}
if ($paste['burnafterreading']) {
self::$_cache[$pasteid]['meta']['burnafterreading'] = true;
}
return self::$_cache[$pasteid];
}
@@ -327,11 +331,21 @@ class Database extends AbstractData
* @param array $comment
* @return bool
*/
public function createComment($pasteid, $parentid, $commentid, $comment)
public function createComment($pasteid, $parentid, $commentid, array $comment)
{
foreach (array('nickname', 'vizhash') as $key) {
if (!array_key_exists($key, $comment['meta'])) {
$comment['meta'][$key] = null;
if (array_key_exists('data', $comment)) {
$version = 1;
$data = $comment['data'];
} else {
$version = 2;
$data = Json::encode($comment);
}
list($createdKey, $iconKey) = self::_getVersionedKeys($version);
$meta = $comment['meta'];
unset($comment['meta']);
foreach (array('nickname', $iconKey) as $key) {
if (!array_key_exists($key, $meta)) {
$meta[$key] = null;
}
}
return self::_exec(
@@ -341,10 +355,10 @@ class Database extends AbstractData
$commentid,
$pasteid,
$parentid,
$comment['data'],
$comment['meta']['nickname'],
$comment['meta']['vizhash'],
$comment['meta']['postdate'],
$data,
$meta['nickname'],
$meta[$iconKey],
$meta[$createdKey],
)
);
}
@@ -367,16 +381,22 @@ class Database extends AbstractData
$comments = array();
if (count($rows)) {
foreach ($rows as $row) {
$i = $this->getOpenSlot($comments, (int) $row['postdate']);
$comments[$i] = new stdClass;
$comments[$i]->id = $row['dataid'];
$comments[$i]->parentid = $row['parentid'];
$comments[$i]->data = $row['data'];
$comments[$i]->meta = new stdClass;
$comments[$i]->meta->postdate = (int) $row['postdate'];
foreach (array('nickname', 'vizhash') as $key) {
if (array_key_exists($key, $row) && !empty($row[$key])) {
$comments[$i]->meta->$key = $row[$key];
$i = $this->getOpenSlot($comments, (int) $row['postdate']);
$data = Json::decode($row['data']);
if (array_key_exists('v', $data) && $data['v'] >= 2) {
$version = 2;
$comments[$i] = $data;
} else {
$version = 1;
$comments[$i] = array('data' => $row['data']);
}
list($createdKey, $iconKey) = self::_getVersionedKeys($version);
$comments[$i]['id'] = $row['dataid'];
$comments[$i]['parentid'] = $row['parentid'];
$comments[$i]['meta'] = array($createdKey => (int) $row['postdate']);
foreach (array('nickname' => 'nickname', 'vizhash' => $iconKey) as $rowKey => $commentKey) {
if (array_key_exists($rowKey, $row) && !empty($row[$rowKey])) {
$comments[$i]['meta'][$commentKey] = $row[$rowKey];
}
}
}
@@ -415,7 +435,8 @@ class Database extends AbstractData
$pastes = array();
$rows = self::_select(
'SELECT dataid FROM ' . self::_sanitizeIdentifier('paste') .
' WHERE expiredate < ? AND expiredate != ? LIMIT ?', array(time(), 0, $batchsize)
' WHERE expiredate < ? AND expiredate != ? LIMIT ?',
array(time(), 0, $batchsize)
);
if (count($rows)) {
foreach ($rows as $row) {
@@ -452,7 +473,7 @@ class Database extends AbstractData
* @param array $params
* @param bool $firstOnly if only the first row should be returned
* @throws PDOException
* @return array
* @return array|false
*/
private static function _select($sql, array $params, $firstOnly = false)
{
@@ -465,6 +486,22 @@ class Database extends AbstractData
return $result;
}
/**
* get version dependent key names
*
* @access private
* @static
* @param int $version
* @return array
*/
private static function _getVersionedKeys($version)
{
if ($version === 1) {
return array('postdate', 'vizhash');
}
return array('created', 'icon');
}
/**
* get table list query, depending on the database type
*
@@ -543,7 +580,7 @@ class Database extends AbstractData
*
* @access private
* @static
* @param string $key
* @param string $key
* @return array
*/
private static function _getPrimaryKeyClauses($key = 'dataid')
@@ -557,6 +594,34 @@ class Database extends AbstractData
return array($main_key, $after_key);
}
/**
* get the data type, depending on the database driver
*
* PostgreSQL uses a different API for BLOBs then SQL, hence we use TEXT
*
* @access private
* @static
* @return string
*/
private static function _getDataType()
{
return self::$_type === 'pgsql' ? 'TEXT' : 'BLOB';
}
/**
* get the attachment type, depending on the database driver
*
* PostgreSQL uses a different API for BLOBs then SQL, hence we use TEXT
*
* @access private
* @static
* @return string
*/
private static function _getAttachmentType()
{
return self::$_type === 'pgsql' ? 'TEXT' : 'MEDIUMBLOB';
}
/**
* create the paste table
*
@@ -566,17 +631,18 @@ class Database extends AbstractData
private static function _createPasteTable()
{
list($main_key, $after_key) = self::_getPrimaryKeyClauses();
$dataType = self::$_type === 'pgsql' ? 'TEXT' : 'BLOB';
$dataType = self::_getDataType();
$attachmentType = self::_getAttachmentType();
self::$_db->exec(
'CREATE TABLE ' . self::_sanitizeIdentifier('paste') . ' ( ' .
"dataid CHAR(16) NOT NULL$main_key, " .
"data $dataType, " .
"data $attachmentType, " .
'postdate INT, ' .
'expiredate INT, ' .
'opendiscussion INT, ' .
'burnafterreading INT, ' .
'meta TEXT, ' .
'attachment ' . (self::$_type === 'pgsql' ? 'TEXT' : 'MEDIUMBLOB') . ', ' .
"attachment $attachmentType, " .
"attachmentname $dataType$after_key );"
);
}
@@ -590,7 +656,7 @@ class Database extends AbstractData
private static function _createCommentTable()
{
list($main_key, $after_key) = self::_getPrimaryKeyClauses();
$dataType = self::$_type === 'pgsql' ? 'text' : 'BLOB';
$dataType = self::_getDataType();
self::$_db->exec(
'CREATE TABLE ' . self::_sanitizeIdentifier('comment') . ' ( ' .
"dataid CHAR(16) NOT NULL$main_key, " .
@@ -649,7 +715,8 @@ class Database extends AbstractData
*/
private static function _upgradeDatabase($oldversion)
{
$dataType = self::$_type === 'pgsql' ? 'TEXT' : 'BLOB';
$dataType = self::_getDataType();
$attachmentType = self::_getAttachmentType();
switch ($oldversion) {
case '0.21':
// create the meta column if necessary (pre 0.21 change)
@@ -661,8 +728,7 @@ class Database extends AbstractData
// SQLite only allows one ALTER statement at a time...
self::$_db->exec(
'ALTER TABLE ' . self::_sanitizeIdentifier('paste') .
' ADD COLUMN attachment ' .
(self::$_type === 'pgsql' ? 'TEXT' : 'MEDIUMBLOB') . ';'
" ADD COLUMN attachment $attachmentType;"
);
self::$_db->exec(
'ALTER TABLE ' . self::_sanitizeIdentifier('paste') . " ADD COLUMN attachmentname $dataType;"
@@ -672,7 +738,7 @@ class Database extends AbstractData
if (self::$_type !== 'sqlite') {
self::$_db->exec(
'ALTER TABLE ' . self::_sanitizeIdentifier('paste') .
' ADD PRIMARY KEY (dataid), MODIFY COLUMN data $dataType;'
" ADD PRIMARY KEY (dataid), MODIFY COLUMN data $dataType;"
);
self::$_db->exec(
'ALTER TABLE ' . self::_sanitizeIdentifier('comment') .
@@ -694,6 +760,17 @@ class Database extends AbstractData
self::_sanitizeIdentifier('comment') . '(pasteid);'
);
// no break, continue with updates for 0.22 and later
case '1.3':
// SQLite doesn't support MODIFY, but it allows TEXT of similar
// size as BLOB and PostgreSQL uses TEXT, so there is no need
// to change it there
if (self::$_type !== 'sqlite' && self::$_type !== 'pgsql') {
self::$_db->exec(
'ALTER TABLE ' . self::_sanitizeIdentifier('paste') .
" MODIFY COLUMN data $attachmentType;"
);
}
// no break, continue with updates for all newer versions
default:
self::_exec(
'UPDATE ' . self::_sanitizeIdentifier('config') .

View File

@@ -7,12 +7,11 @@
* @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.2.1
* @version 1.3.3
*/
namespace PrivateBin\Data;
use PrivateBin\Model\Paste;
use PrivateBin\Persistence\DataStore;
/**
@@ -30,7 +29,7 @@ class Filesystem extends AbstractData
* @param array $options
* @return Filesystem
*/
public static function getInstance($options = null)
public static function getInstance(array $options)
{
// if needed initialize the singleton
if (!(self::$_instance instanceof self)) {
@@ -54,7 +53,7 @@ class Filesystem extends AbstractData
* @param array $paste
* @return bool
*/
public function create($pasteid, $paste)
public function create($pasteid, array $paste)
{
$storagedir = self::_dataid2path($pasteid);
$file = $storagedir . $pasteid . '.php';
@@ -72,23 +71,16 @@ class Filesystem extends AbstractData
*
* @access public
* @param string $pasteid
* @return stdClass|false
* @return array|false
*/
public function read($pasteid)
{
if (!$this->exists($pasteid)) {
return false;
}
$paste = DataStore::get(self::_dataid2path($pasteid) . $pasteid . '.php');
if (property_exists($paste->meta, 'attachment')) {
$paste->attachment = $paste->meta->attachment;
unset($paste->meta->attachment);
if (property_exists($paste->meta, 'attachmentname')) {
$paste->attachmentname = $paste->meta->attachmentname;
unset($paste->meta->attachmentname);
}
}
return $paste;
return self::upgradePreV1Format(
DataStore::get(self::_dataid2path($pasteid) . $pasteid . '.php')
);
}
/**
@@ -163,7 +155,7 @@ class Filesystem extends AbstractData
* @param array $comment
* @return bool
*/
public function createComment($pasteid, $parentid, $commentid, $comment)
public function createComment($pasteid, $parentid, $commentid, array $comment)
{
$storagedir = self::_dataid2discussionpath($pasteid);
$file = $storagedir . $pasteid . '.' . $commentid . '.' . $parentid . '.php';
@@ -198,11 +190,11 @@ class Filesystem extends AbstractData
$comment = DataStore::get($discdir . $filename);
$items = explode('.', $filename);
// Add some meta information not contained in file.
$comment->id = $items[1];
$comment->parentid = $items[2];
$comment['id'] = $items[1];
$comment['parentid'] = $items[2];
// Store in array
$key = $this->getOpenSlot($comments, (int) $comment->meta->postdate);
$key = $this->getOpenSlot($comments, (int) $comment['meta']['created']);
$comments[$key] = $comment;
}
}
@@ -291,8 +283,8 @@ class Filesystem extends AbstractData
if ($this->exists($pasteid)) {
$data = $this->read($pasteid);
if (
property_exists($data->meta, 'expire_date') &&
$data->meta->expire_date < time()
array_key_exists('expire_date', $data['meta']) &&
$data['meta']['expire_date'] < time()
) {
$pastes[] = $pasteid;
if (count($pastes) >= $batchsize) {

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.2.1
* @version 1.3.3
*/
namespace PrivateBin;
@@ -68,23 +68,4 @@ class Filter
}
return number_format($size, ($i ? 2 : 0), '.', ' ') . ' ' . I18n::_($iec[$i]);
}
/**
* fixed time string comparison operation to prevent timing attacks
* https://crackstation.net/hashing-security.htm?=rd#slowequals
*
* @access public
* @static
* @param string $a
* @param string $b
* @return bool
*/
public static function slowEquals($a, $b)
{
$diff = strlen($a) ^ strlen($b);
for ($i = 0; $i < strlen($a) && $i < strlen($b); ++$i) {
$diff |= ord($a[$i]) ^ ord($b[$i]);
}
return $diff === 0;
}
}

127
lib/FormatV2.php Normal file
View File

@@ -0,0 +1,127 @@
<?php
/**
* PrivateBin
*
* a zero-knowledge paste bin
*
* @link https://github.com/PrivateBin/PrivateBin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 1.3.3
*/
namespace PrivateBin;
/**
* FormatV2
*
* Provides validation function for version 2 format of pastes & comments.
*/
class FormatV2
{
/**
* version 2 format validator
*
* Checks if the given array is a proper version 2 formatted, encrypted message.
*
* @access public
* @static
* @param array $message
* @param bool $isComment
* @return bool
*/
public static function isValid($message, $isComment = false)
{
$required_keys = array('adata', 'v', 'ct');
if ($isComment) {
$required_keys[] = 'pasteid';
$required_keys[] = 'parentid';
} else {
$required_keys[] = 'meta';
}
// Make sure no additionnal keys were added.
if (count(array_keys($message)) != count($required_keys)) {
return false;
}
// Make sure required fields are present.
foreach ($required_keys as $k) {
if (!array_key_exists($k, $message)) {
return false;
}
}
$cipherParams = $isComment ? $message['adata'] : $message['adata'][0];
// Make sure some fields are base64 data:
// - initialization vector
if (!base64_decode($cipherParams[0], true)) {
return false;
}
// - salt
if (!base64_decode($cipherParams[1], true)) {
return false;
}
// - cipher text
if (!($ct = base64_decode($message['ct'], true))) {
return false;
}
// Make sure some fields have a reasonable size:
// - initialization vector
if (strlen($cipherParams[0]) > 24) {
return false;
}
// - salt
if (strlen($cipherParams[1]) > 14) {
return false;
}
// Make sure some fields contain no unsupported values:
// - version
if (!(is_int($message['v']) || is_float($message['v'])) || (float) $message['v'] < 2) {
return false;
}
// - iterations, refuse less then 10000 iterations (minimum NIST recommendation)
if (!is_int($cipherParams[2]) || $cipherParams[2] <= 10000) {
return false;
}
// - key size
if (!in_array($cipherParams[3], array(128, 192, 256), true)) {
return false;
}
// - tag size
if (!in_array($cipherParams[4], array(64, 96, 128), true)) {
return false;
}
// - algorithm, must be AES
if ($cipherParams[5] !== 'aes') {
return false;
}
// - mode
if (!in_array($cipherParams[6], array('ctr', 'cbc', 'gcm'), true)) {
return false;
}
// - compression
if (!in_array($cipherParams[7], array('zlib', 'none'), true)) {
return false;
}
// Reject data if entropy is too low
if (strlen($ct) > strlen(gzdeflate($ct))) {
return false;
}
// require only the key 'expire' in the metadata of pastes
if (!$isComment && (
count($message['meta']) === 0 ||
!array_key_exists('expire', $message['meta']) ||
count($message['meta']) > 1
)) {
return false;
}
return true;
}
}

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.2.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
*
@@ -156,9 +178,8 @@ class I18n
// load translations
self::$_language = $match;
self::$_translations = ($match == 'en') ? array() : json_decode(
file_get_contents(self::_getPath($match . '.json')),
true
self::$_translations = ($match == 'en') ? array() : Json::decode(
file_get_contents(self::_getPath($match . '.json'))
);
}
@@ -244,7 +265,7 @@ class I18n
{
$file = self::_getPath('languages.json');
if (count(self::$_languageLabels) == 0 && is_readable($file)) {
self::$_languageLabels = json_decode(file_get_contents($file), true);
self::$_languageLabels = Json::decode(file_get_contents($file));
}
if (count($languages) == 0) {
return self::$_languageLabels;
@@ -295,6 +316,8 @@ class I18n
protected static function _getPluralForm($n)
{
switch (self::$_language) {
case 'cs':
return $n == 1 ? 0 : ($n >= 2 && $n <= 4 ? 1 : 2);
case 'fr':
case 'oc':
case 'zh':
@@ -302,10 +325,11 @@ 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));
// de, en, es, hu, it, nl, no, pt
// bg, de, en, es, hu, it, nl, no, pt
default:
return $n != 1 ? 1 : 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.2.1
* @version 1.3.3
*/
namespace PrivateBin;
@@ -33,9 +33,39 @@ class Json
public static function encode($input)
{
$jsonString = json_encode($input);
$errorCode = json_last_error();
self::_detectError();
return $jsonString;
}
/**
* Returns an array with the contents as described in the given JSON input
*
* @access public
* @static
* @param string $input
* @throws Exception
* @return array
*/
public static function decode($input)
{
$array = json_decode($input, true);
self::_detectError();
return $array;
}
/**
* Detects JSON errors and raises an exception if one is found
*
* @access private
* @static
* @throws Exception
* @return void
*/
private static function _detectError()
{
$errorCode = json_last_error();
if ($errorCode === JSON_ERROR_NONE) {
return $jsonString;
return;
}
$message = 'A JSON error occurred';

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.2.1
* @version 1.3.3
*/
namespace PrivateBin;
@@ -32,7 +32,7 @@ class Model
/**
* Data storage.
*
* @var AbstractData
* @var Data\AbstractData
*/
private $_store = null;
@@ -75,7 +75,7 @@ class Model
/**
* Gets, and creates if neccessary, a store object
*
* @return AbstractData
* @return Data\AbstractData
*/
private function _getStore()
{

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