Compare commits

...

251 Commits

Author SHA1 Message Date
El RIDO 74ac3350a3
Merge pull request #1268 from PrivateBin/crowdin-translation
New Crowdin updates
2024-03-18 19:24:44 +01:00
PrivateBin Translator Bot 5a52f71bb7 New translations en.json (French) 2024-03-18 18:14:41 +01:00
El RIDO f0794e3c0b document & attribute changes from #1267 2024-03-18 07:48:20 +01:00
El RIDO db287a10fe
Merge pull request #1267 from asherber/shorten-yourls
Allow for shortenviayourls in query params
2024-03-18 07:42:59 +01:00
Aaron Sherber 7a4c6c010f
Update conf.sample.php 2024-03-16 19:46:57 -04:00
Aaron Sherber 7c9cc7754f
Allow for shortenviayourls in query params 2024-03-16 16:55:49 -04:00
El RIDO 6eb5fdcc06
Merge pull request #1264 from PrivateBin/email-shortend-url
shortened paste URL does not appear in email
2024-03-14 06:59:07 +01:00
El RIDO e1e0e8399c
phpdoc improvements 2024-03-10 18:01:46 +01:00
El RIDO 89a5d07b94
shortened paste URL does not appear in email
fixes #606
2024-03-10 17:26:30 +01:00
El RIDO 5f00587d71
phpdoc improvements, fixes #1036 2024-03-10 17:07:10 +01:00
El RIDO 53d2d3334d
document & attribute changes 2024-03-10 16:12:40 +01:00
Aaron Sherber fd7d9f4715
Fix styleci issues 2024-03-09 16:55:44 -05:00
Aaron Sherber 8abf6ae9cb
Always add cache control headers 2024-03-09 16:49:42 -05:00
El RIDO a62f4babbf
Merge pull request #1258 from PrivateBin/dependabot/composer/phpunit/phpunit-9.6.17
Bump phpunit/phpunit from 9.6.16 to 9.6.17
2024-02-26 12:37:38 +01:00
El RIDO d52b8af0f5
Merge pull request #1257 from PrivateBin/crowdin-translation
New Crowdin updates
2024-02-26 12:35:33 +01:00
dependabot[bot] 6474c374e2
Bump phpunit/phpunit from 9.6.16 to 9.6.17
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.6.16 to 9.6.17.
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/9.6.17/ChangeLog-9.6.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.6.16...9.6.17)

---
updated-dependencies:
- dependency-name: phpunit/phpunit
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-26 11:13:45 +00:00
PrivateBin Translator Bot b15571ae4a New translations en.json (German) 2024-02-26 10:05:41 +01:00
El RIDO c162f04384
Merge pull request #1256 from LMS235/patch-1
Update de.json
2024-02-22 08:46:08 +01:00
Florian 6999ed3f4b
Update de.json
Text verständlicher gemacht
2024-02-21 11:34:33 +01:00
El RIDO 03e7f6a9a7
Merge pull request #1250 from PrivateBin/crowdin-translation
New Crowdin updates
2024-02-17 20:25:15 +01:00
PrivateBin Translator Bot a1095d0d21 New translations en.json (Arabic) 2024-02-17 17:15:15 +01:00
El RIDO 7576459135
Merge pull request #1249 from PrivateBin/doc-slsa
doc: Fix (direct) link to SLSA verifier
2024-02-17 09:03:14 +01:00
rugk cb117d6797
doc: Fix (direct) link to SLSA verifier
Apparently the headline changed, this is the direct link for GitHub.
2024-02-16 17:19:17 +01:00
El RIDO 244703babb
Merge pull request #1248 from PrivateBin/crowdin-translation
New Crowdin updates
2024-02-15 07:53:06 +01:00
PrivateBin Translator Bot b00085f30f New translations en.json (Romanian) 2024-02-15 07:09:13 +01:00
PrivateBin Translator Bot fc1b1ae0ca New translations en.json (Russian) 2024-02-15 07:09:12 +01:00
PrivateBin Translator Bot 45e335eca6 New translations en.json (German) 2024-02-15 07:09:11 +01:00
PrivateBin Translator Bot f03bccd31e New translations en.json (Bulgarian) 2024-02-15 07:09:10 +01:00
PrivateBin Translator Bot 04da6db079 New translations en.json (Arabic) 2024-02-15 07:09:09 +01:00
PrivateBin Translator Bot 580a034189 New translations en.json (French) 2024-02-15 07:09:08 +01:00
PrivateBin Translator Bot 6c5a500fcd New translations en.json (Corsican) 2024-02-15 00:50:42 +01:00
PrivateBin Translator Bot da4ad06758 New translations en.json (Occitan) 2024-02-14 21:17:17 +01:00
PrivateBin Translator Bot 2f394a4714 New translations en.json (Lojban) 2024-02-14 21:17:16 +01:00
PrivateBin Translator Bot 39949cea34 New translations en.json (Estonian) 2024-02-14 21:17:15 +01:00
PrivateBin Translator Bot a9d287874b New translations en.json (Thai) 2024-02-14 21:17:14 +01:00
PrivateBin Translator Bot 2381e30dc4 New translations en.json (Indonesian) 2024-02-14 21:17:13 +01:00
PrivateBin Translator Bot 0255f72ae0 New translations en.json (Chinese Simplified) 2024-02-14 21:17:12 +01:00
PrivateBin Translator Bot 900200c35f New translations en.json (Ukrainian) 2024-02-14 21:17:11 +01:00
PrivateBin Translator Bot 860b4b183e New translations en.json (Turkish) 2024-02-14 21:17:10 +01:00
PrivateBin Translator Bot e585aeacda New translations en.json (Swedish) 2024-02-14 21:17:09 +01:00
PrivateBin Translator Bot a4820618dd New translations en.json (Slovenian) 2024-02-14 21:17:08 +01:00
PrivateBin Translator Bot d957d344d1 New translations en.json (Slovak) 2024-02-14 21:17:07 +01:00
PrivateBin Translator Bot c9c99f7535 New translations en.json (Portuguese) 2024-02-14 21:17:06 +01:00
PrivateBin Translator Bot 516a4c7d13 New translations en.json (Polish) 2024-02-14 21:17:05 +01:00
PrivateBin Translator Bot 2ccc90798f New translations en.json (Norwegian) 2024-02-14 21:17:04 +01:00
PrivateBin Translator Bot 647ddebb5c New translations en.json (Dutch) 2024-02-14 21:17:03 +01:00
PrivateBin Translator Bot f40f3dd3a5 New translations en.json (Lithuanian) 2024-02-14 21:17:02 +01:00
PrivateBin Translator Bot ce4f3a1b09 New translations en.json (Japanese) 2024-02-14 21:17:01 +01:00
PrivateBin Translator Bot 888b3cb49c New translations en.json (Italian) 2024-02-14 21:17:00 +01:00
PrivateBin Translator Bot 6e0bc8bceb New translations en.json (Hungarian) 2024-02-14 21:16:59 +01:00
PrivateBin Translator Bot 43d396efd9 New translations en.json (Hebrew) 2024-02-14 21:16:58 +01:00
PrivateBin Translator Bot 3b6ebfdf02 New translations en.json (Finnish) 2024-02-14 21:16:57 +01:00
PrivateBin Translator Bot f3df151a8c New translations en.json (Greek) 2024-02-14 21:16:56 +01:00
PrivateBin Translator Bot e4329b623d New translations en.json (Czech) 2024-02-14 21:16:55 +01:00
PrivateBin Translator Bot e18ec99aa9 New translations en.json (Catalan) 2024-02-14 21:16:54 +01:00
PrivateBin Translator Bot 6d2d19c38c New translations en.json (Spanish) 2024-02-14 21:16:53 +01:00
PrivateBin Translator Bot 532f85c6b7 New translations en.json (Romanian) 2024-02-14 19:53:04 +01:00
PrivateBin Translator Bot 0dc7b1f6fc New translations en.json (Corsican) 2024-02-14 19:53:03 +01:00
PrivateBin Translator Bot f0cc0e878a New translations en.json (Occitan) 2024-02-14 19:53:02 +01:00
PrivateBin Translator Bot 2f775c218c New translations en.json (Latin) 2024-02-14 19:53:01 +01:00
PrivateBin Translator Bot 98b3d0e2ae New translations en.json (Lojban) 2024-02-14 19:53:00 +01:00
PrivateBin Translator Bot 7ba642c0ad New translations en.json (Hindi) 2024-02-14 19:52:59 +01:00
PrivateBin Translator Bot 63b63354d7 New translations en.json (Estonian) 2024-02-14 19:52:58 +01:00
PrivateBin Translator Bot 569b47ee62 New translations en.json (Thai) 2024-02-14 19:52:57 +01:00
PrivateBin Translator Bot 050917f035 New translations en.json (Indonesian) 2024-02-14 19:52:56 +01:00
PrivateBin Translator Bot eff7eb5e23 New translations en.json (Chinese Simplified) 2024-02-14 19:52:55 +01:00
PrivateBin Translator Bot 326feb1808 New translations en.json (Ukrainian) 2024-02-14 19:52:54 +01:00
PrivateBin Translator Bot 3ed954fef4 New translations en.json (Turkish) 2024-02-14 19:52:53 +01:00
PrivateBin Translator Bot ebe997bd02 New translations en.json (Swedish) 2024-02-14 19:52:52 +01:00
PrivateBin Translator Bot a90a874d82 New translations en.json (Slovenian) 2024-02-14 19:52:51 +01:00
PrivateBin Translator Bot dd49b8e694 New translations en.json (Slovak) 2024-02-14 19:52:50 +01:00
PrivateBin Translator Bot fec82754bb New translations en.json (Russian) 2024-02-14 19:52:50 +01:00
PrivateBin Translator Bot 24bd804d38 New translations en.json (Portuguese) 2024-02-14 19:52:49 +01:00
PrivateBin Translator Bot d0d77325de New translations en.json (Polish) 2024-02-14 19:52:48 +01:00
PrivateBin Translator Bot a8b4bf84c4 New translations en.json (Norwegian) 2024-02-14 19:52:47 +01:00
PrivateBin Translator Bot a398b1ff59 New translations en.json (Dutch) 2024-02-14 19:52:46 +01:00
PrivateBin Translator Bot 3e2fc24e11 New translations en.json (Lithuanian) 2024-02-14 19:52:45 +01:00
PrivateBin Translator Bot e6acab38d8 New translations en.json (Kurdish) 2024-02-14 19:52:44 +01:00
PrivateBin Translator Bot bcd899b3c4 New translations en.json (Japanese) 2024-02-14 19:52:43 +01:00
PrivateBin Translator Bot 196e5046ac New translations en.json (Italian) 2024-02-14 19:52:42 +01:00
PrivateBin Translator Bot 64a209483a New translations en.json (Hungarian) 2024-02-14 19:52:41 +01:00
PrivateBin Translator Bot a5725d503e New translations en.json (Hebrew) 2024-02-14 19:52:40 +01:00
PrivateBin Translator Bot 14a73ddc61 New translations en.json (Finnish) 2024-02-14 19:52:39 +01:00
PrivateBin Translator Bot 1503fb8aa7 New translations en.json (Greek) 2024-02-14 19:52:38 +01:00
PrivateBin Translator Bot 5291e381c8 New translations en.json (German) 2024-02-14 19:52:37 +01:00
PrivateBin Translator Bot a412a85ad0 New translations en.json (Czech) 2024-02-14 19:52:37 +01:00
PrivateBin Translator Bot 64e533ba8c New translations en.json (Catalan) 2024-02-14 19:52:36 +01:00
PrivateBin Translator Bot 57a03839fa New translations en.json (Bulgarian) 2024-02-14 19:52:35 +01:00
PrivateBin Translator Bot 7d8f57ffe8 New translations en.json (Arabic) 2024-02-14 19:52:34 +01:00
PrivateBin Translator Bot a14151b85c New translations en.json (Spanish) 2024-02-14 19:52:33 +01:00
PrivateBin Translator Bot 76affbc63b New translations en.json (French) 2024-02-14 19:52:32 +01:00
El RIDO 253e078263 fix base translation 2024-02-14 19:49:52 +01:00
PrivateBin Translator Bot 8b66612622 New translations en.json (Corsican) 2024-02-14 17:50:16 +01:00
PrivateBin Translator Bot bfddc388b9 New translations en.json (Russian) 2024-02-14 17:50:15 +01:00
PrivateBin Translator Bot a68d81b10b New translations en.json (Russian) 2024-02-14 16:14:15 +01:00
PrivateBin Translator Bot c37ca3f495 New translations en.json (Corsican) 2024-02-14 01:19:05 +01:00
PrivateBin Translator Bot 4048e2f45d New translations en.json (Occitan) 2024-02-14 01:19:04 +01:00
PrivateBin Translator Bot 024bbc246e New translations en.json (Latin) 2024-02-14 01:19:03 +01:00
PrivateBin Translator Bot 25318facd7 New translations en.json (Lojban) 2024-02-14 01:19:02 +01:00
PrivateBin Translator Bot 1e9c5cb812 New translations en.json (Hindi) 2024-02-14 01:19:01 +01:00
PrivateBin Translator Bot cab26c619b New translations en.json (Estonian) 2024-02-14 01:19:00 +01:00
PrivateBin Translator Bot cabfa18a35 New translations en.json (Thai) 2024-02-14 01:18:59 +01:00
PrivateBin Translator Bot 629faeea8d New translations en.json (Indonesian) 2024-02-14 01:18:58 +01:00
PrivateBin Translator Bot 0a9770ae51 New translations en.json (Chinese Simplified) 2024-02-14 01:18:57 +01:00
PrivateBin Translator Bot 5c76cc9203 New translations en.json (Ukrainian) 2024-02-14 01:18:56 +01:00
PrivateBin Translator Bot 7710a6066c New translations en.json (Turkish) 2024-02-14 01:18:55 +01:00
PrivateBin Translator Bot 94f0808996 New translations en.json (Swedish) 2024-02-14 01:18:55 +01:00
PrivateBin Translator Bot 494623eec7 New translations en.json (Slovenian) 2024-02-14 01:18:54 +01:00
PrivateBin Translator Bot 7174be4dfb New translations en.json (Slovak) 2024-02-14 01:18:53 +01:00
PrivateBin Translator Bot af72f0694d New translations en.json (Russian) 2024-02-14 01:18:52 +01:00
PrivateBin Translator Bot 126d08933a New translations en.json (Portuguese) 2024-02-14 01:18:51 +01:00
PrivateBin Translator Bot 5ec102a75c New translations en.json (Polish) 2024-02-14 01:18:50 +01:00
PrivateBin Translator Bot cd33a4824b New translations en.json (Norwegian) 2024-02-14 01:18:49 +01:00
PrivateBin Translator Bot 966d0f5d64 New translations en.json (Dutch) 2024-02-14 01:18:48 +01:00
PrivateBin Translator Bot 37c57e5815 New translations en.json (Lithuanian) 2024-02-14 01:18:47 +01:00
PrivateBin Translator Bot 5854770286 New translations en.json (Kurdish) 2024-02-14 01:18:46 +01:00
PrivateBin Translator Bot 40df875334 New translations en.json (Japanese) 2024-02-14 01:18:45 +01:00
PrivateBin Translator Bot 120fe77e1e New translations en.json (Italian) 2024-02-14 01:18:45 +01:00
PrivateBin Translator Bot 5bf7c04e04 New translations en.json (Hungarian) 2024-02-14 01:18:44 +01:00
PrivateBin Translator Bot 9f623b4130 New translations en.json (Hebrew) 2024-02-14 01:18:43 +01:00
PrivateBin Translator Bot 41b20da78b New translations en.json (Finnish) 2024-02-14 01:18:42 +01:00
PrivateBin Translator Bot 3547e67cc6 New translations en.json (Greek) 2024-02-14 01:18:41 +01:00
PrivateBin Translator Bot 4eb55be55e New translations en.json (Czech) 2024-02-14 01:18:39 +01:00
PrivateBin Translator Bot c3d143f9ba New translations en.json (Catalan) 2024-02-14 01:18:39 +01:00
PrivateBin Translator Bot 7467c7998c New translations en.json (Bulgarian) 2024-02-14 01:18:38 +01:00
PrivateBin Translator Bot 979dc58575 New translations en.json (Arabic) 2024-02-14 01:18:37 +01:00
PrivateBin Translator Bot 41a3748656 New translations en.json (Spanish) 2024-02-14 01:18:36 +01:00
El RIDO c5704b445a
Merge pull request #1246 from PrivateBin/crowdin-translation
New Crowdin updates
2024-02-14 00:02:04 +01:00
El RIDO c172cde994
Merge pull request #1245 from PrivateBin/send-create-button
Rename "Send" button to "Create"
2024-02-14 00:00:29 +01:00
El RIDO 7d070fe3a4
Merge pull request #1244 from PrivateBin/composer
composer fixes for #1222
2024-02-13 23:58:53 +01:00
PrivateBin Translator Bot 28a05abfc5 New translations en.json (Arabic) 2024-02-13 13:56:04 +01:00
PrivateBin Translator Bot 456e62f29b New translations en.json (Romanian) 2024-02-12 23:51:38 +01:00
El RIDO 63b2526ee7
"Send" button now labeled "Create", fixes #946 2024-02-12 21:50:11 +01:00
El RIDO dd8aa4f8fb
Merge branch 'master' into send-create-button 2024-02-12 21:42:15 +01:00
El RIDO 6dddf808c6
composer fixes #1222
- clarify installation
- ensure composer files get released in exported archive
- fix lock checksum
2024-02-12 21:18:58 +01:00
El RIDO eb59f3a4f3
post-release cleanup 2024-02-11 15:36:59 +01:00
El RIDO aad975a721
incrementing version 2024-02-11 15:31:11 +01:00
El RIDO 5c29619fee
post-release cleanup
- prep changelog for future changes
- composer changes from re-running composer on the repo, testing deps
- change to phpunit coverage make target, required with newer releases
2024-02-11 15:10:01 +01:00
El RIDO a3ee624d3a
incrementing version 2024-02-11 14:17:27 +01:00
El RIDO 1eee8032c7
Merge pull request #1240 from PrivateBin/crowdin-translation
New Crowdin updates
2024-02-09 07:19:21 +01:00
PrivateBin Translator Bot f3fba1c0f5 New translations en.json (Corsican) 2024-02-09 00:48:48 +01:00
PrivateBin Translator Bot a54a55a9a1 New translations en.json (Italian) 2024-02-08 07:21:52 +01:00
PrivateBin Translator Bot 56f0ec7d52 New translations en.json (German) 2024-02-08 07:21:51 +01:00
PrivateBin Translator Bot 208c922e04 New translations en.json (French) 2024-02-08 07:21:50 +01:00
El RIDO 4db0db320b Merge branch 'master' into crowdin-translation 2024-02-08 05:29:53 +01:00
PrivateBin Translator Bot 772ab96364 New translations en.json (Corsican) 2024-02-07 20:47:56 +01:00
PrivateBin Translator Bot dc2db9e622 New translations en.json (Occitan) 2024-02-07 20:47:55 +01:00
PrivateBin Translator Bot 6d559c3043 New translations en.json (Latin) 2024-02-07 20:47:54 +01:00
PrivateBin Translator Bot 096a5118d1 New translations en.json (Lojban) 2024-02-07 20:47:54 +01:00
PrivateBin Translator Bot 5084ab7a07 New translations en.json (Hindi) 2024-02-07 20:47:53 +01:00
PrivateBin Translator Bot fbe4ac5a6c New translations en.json (Estonian) 2024-02-07 20:47:52 +01:00
PrivateBin Translator Bot 4e21e980de New translations en.json (Thai) 2024-02-07 20:47:51 +01:00
PrivateBin Translator Bot a3243b3165 New translations en.json (Indonesian) 2024-02-07 20:47:50 +01:00
PrivateBin Translator Bot 223ef02a43 New translations en.json (Chinese Simplified) 2024-02-07 20:47:49 +01:00
PrivateBin Translator Bot c7da424ef9 New translations en.json (Ukrainian) 2024-02-07 20:47:48 +01:00
PrivateBin Translator Bot e1c74457e5 New translations en.json (Turkish) 2024-02-07 20:47:47 +01:00
PrivateBin Translator Bot 1a6c3dd8d8 New translations en.json (Swedish) 2024-02-07 20:47:46 +01:00
PrivateBin Translator Bot 146b2513c1 New translations en.json (Slovenian) 2024-02-07 20:47:45 +01:00
PrivateBin Translator Bot 5ec8a57c60 New translations en.json (Slovak) 2024-02-07 20:47:44 +01:00
PrivateBin Translator Bot cd67d81ae3 New translations en.json (Russian) 2024-02-07 20:47:43 +01:00
PrivateBin Translator Bot 218e68a604 New translations en.json (Portuguese) 2024-02-07 20:47:42 +01:00
PrivateBin Translator Bot 9611991748 New translations en.json (Polish) 2024-02-07 20:47:41 +01:00
PrivateBin Translator Bot b613d9558c New translations en.json (Norwegian) 2024-02-07 20:47:40 +01:00
PrivateBin Translator Bot 5523ba9a45 New translations en.json (Dutch) 2024-02-07 20:47:39 +01:00
PrivateBin Translator Bot 421342396f New translations en.json (Lithuanian) 2024-02-07 20:47:38 +01:00
PrivateBin Translator Bot 4e3b469c08 New translations en.json (Kurdish) 2024-02-07 20:47:37 +01:00
PrivateBin Translator Bot cb0edf4f2b New translations en.json (Japanese) 2024-02-07 20:47:37 +01:00
PrivateBin Translator Bot a0f8e0a566 New translations en.json (Italian) 2024-02-07 20:47:36 +01:00
PrivateBin Translator Bot 089652382a New translations en.json (Hungarian) 2024-02-07 20:47:35 +01:00
PrivateBin Translator Bot a1408601d9 New translations en.json (Hebrew) 2024-02-07 20:47:34 +01:00
PrivateBin Translator Bot 3d4887e5f0 New translations en.json (Finnish) 2024-02-07 20:47:33 +01:00
PrivateBin Translator Bot 5c876df2ea New translations en.json (Greek) 2024-02-07 20:47:32 +01:00
PrivateBin Translator Bot fe4a64529a New translations en.json (German) 2024-02-07 20:47:31 +01:00
PrivateBin Translator Bot a25bfd4cce New translations en.json (Czech) 2024-02-07 20:47:30 +01:00
PrivateBin Translator Bot 53639b913e New translations en.json (Catalan) 2024-02-07 20:47:29 +01:00
PrivateBin Translator Bot 9379a73632 New translations en.json (Bulgarian) 2024-02-07 20:47:28 +01:00
PrivateBin Translator Bot efd6c3f8c4 New translations en.json (Arabic) 2024-02-07 20:47:27 +01:00
PrivateBin Translator Bot 51f68f0c78 New translations en.json (Spanish) 2024-02-07 20:47:26 +01:00
PrivateBin Translator Bot ad2de3a135 New translations en.json (French) 2024-02-07 20:47:25 +01:00
PrivateBin Translator Bot ea7f1fca6e New translations en.json (Romanian) 2024-02-07 20:47:25 +01:00
El RIDO 57b1890815 Merge branch 'master' into ask-before-burn 2024-02-07 19:45:54 +01:00
El RIDO 7bb913acdf
Merge pull request #1236 from PrivateBin/bump-libs
bump libraries to DOMpurify 3.0.8 & zlib 1.3.1, increase compression level
2024-02-07 19:30:25 +01:00
El RIDO 25de89c954
change loading confirm prefix, fix password modal focus, again 2024-02-06 20:22:47 +01:00
El RIDO 950c0b56b4
revert changing compression level
as per discussion with @rugk, see:
https://github.com/PrivateBin/PrivateBin/pull/1236#discussion_r1473639960
2024-02-06 19:21:14 +01:00
El RIDO 070ae2e5ec
Merge pull request #1228 from PrivateBin/crowdin-translation
New Crowdin updates
2024-01-27 19:23:34 +01:00
El RIDO 239f6da73c
Merge branch 'master' into crowdin-translation 2024-01-27 19:19:08 +01:00
El RIDO 257fc5d2b6
enable Romanian translation and credit it 2024-01-27 19:15:40 +01:00
El RIDO 03d2291ec7
Merge branch 'master' into ask-before-burn 2024-01-27 18:56:52 +01:00
El RIDO 56f5b2386c
document changes 2024-01-27 18:51:12 +01:00
El RIDO d0e03e5167
change logic into asking for loading confirmation
also:
- fixes #1039 - email buttons overlapping in some languages
- fixes #1191 - language change URL mangling
- adds focus to password input in modal
- prevents needless reload on visiting default URL
2024-01-27 18:26:19 +01:00
El RIDO 0d2376cd88
bump libraries to DOMpurify 3.0.8 & zlib 1.3.1, increase compression level to 9 2024-01-27 11:33:54 +01:00
El RIDO df703dfe4b
Merge pull request #1234 from PrivateBin/dependabot/composer/phpunit/phpunit-9.6.16
Bump phpunit/phpunit from 9.6.15 to 9.6.16
2024-01-20 08:50:57 +01:00
dependabot[bot] 3ff3db72a1
Bump phpunit/phpunit from 9.6.15 to 9.6.16
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.6.15 to 9.6.16.
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/9.6.16/ChangeLog-9.6.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.6.15...9.6.16)

---
updated-dependencies:
- dependency-name: phpunit/phpunit
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-19 11:44:19 +00:00
El RIDO a27cb0cffc
Merge pull request #1233 from PrivateBin/dependabot/github_actions/actions/cache-4
Bump actions/cache from 3 to 4
2024-01-18 18:23:52 +01:00
dependabot[bot] ba25ab8fa9
Bump actions/cache from 3 to 4
Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-18 11:21:35 +00:00
El RIDO d091382313
Merge pull request #1229 from PrivateBin/shortener-sort
add YOURLS API samples for extractUrl validation
2024-01-09 06:36:32 +01:00
Tobias Gurtzick 2a508cb7bf
burn after reading only
Signed-off-by: Tobias Gurtzick <magic@wizardtales.com>
2024-01-08 12:38:48 +01:00
Tobias Gurtzick 8516a3f4a4
Merge branch '162' into encrypt-browser 2024-01-08 12:29:06 +01:00
Tobias Gurtzick 2cc2cf0de7
working browser password
Signed-off-by: Tobias Gurtzick <magic@wizardtales.com>
2024-01-08 12:28:41 +01:00
Tobias Gurtzick e1e8618015
Merge branch 'change' into 162 2024-01-08 11:10:11 +01:00
Tobias Gurtzick 7fddefeb05
password
Signed-off-by: Tobias Gurtzick <magic@wizardtales.com>
2024-01-08 10:36:59 +01:00
El RIDO 4e62e1f6ef address jsverify rngState 87ab3f64de258190c7, fixes #1139 2024-01-08 08:09:29 +01:00
El RIDO 405479642f add YOURLS API samples for extractUrl validation 2024-01-07 17:45:01 +01:00
El RIDO fd82b937a9 refactor URL generators 2024-01-07 16:06:24 +01:00
El RIDO d493ba7337 refactor URL generators 2024-01-07 15:47:29 +01:00
El RIDO 37ee3b1c7c refactor URL generators 2024-01-07 14:10:43 +01:00
PrivateBin Translator Bot 7ab20c23e9 New translations en.json (Romanian) 2024-01-06 23:17:48 +01:00
PrivateBin Translator Bot cc5c81afbc New translations en.json (Romanian) 2024-01-06 22:12:59 +01:00
El RIDO 9fb7aee589
Merge pull request #1227 from PrivateBin/shortener-idn
Shortener URL validation improvement
2024-01-06 17:35:09 +01:00
El RIDO ba17e94c5e use the newer function, if possible 2024-01-05 06:40:12 +01:00
El RIDO c3331070cb codestyle, let's use readable variable names
Co-authored-by: rugk <rugk+git@posteo.de>
2024-01-05 06:30:21 +01:00
El RIDO cc0b6e387a avoid use of bleeding edge function
only supported in Firefox & Chrome >= 120 & node >= 19.9.0 & 18.17.0
2024-01-04 23:23:47 +01:00
El RIDO a80bd4e4ea fix url filter, IDN URL unit test 2024-01-04 23:08:17 +01:00
PrivateBin Translator Bot b3b97b69c6 New translations en.json (Romanian) 2024-01-04 20:47:08 +01:00
El RIDO 8427c1136c document change 2024-01-04 06:52:27 +01:00
El RIDO 7cb1f8ca67 relax URL regex to support finding IDN domains, filter using built in function, removing non-URLs 2024-01-04 06:48:34 +01:00
El RIDO 9a707e288a
Merge pull request #1225 from PrivateBin/crowdin-translation
New Crowdin updates
2024-01-02 07:50:28 +01:00
El RIDO 83a1de271a
Merge pull request #1223 from PrivateBin/install-cloud-libs
improve SDK install docs
2024-01-02 07:49:26 +01:00
PrivateBin Translator Bot c264904f77 New translations en.json (Chinese Simplified) 2024-01-01 12:29:13 +01:00
El RIDO 712715caba improve SDK install docs
fixes #1222
2023-12-27 18:58:39 +01:00
El RIDO 2985305dbb
Merge pull request #1220 from PrivateBin/en-default-test
prevent regression around presence or absence of en.json
2023-12-23 13:06:05 +01:00
El RIDO 0581522414
Merge pull request #1221 from PrivateBin/zlib-1.3
updating zlib to 1.3
2023-12-19 21:39:13 +01:00
El RIDO dc8cb66adc
updating zlib to 1.3 2023-12-19 06:22:30 +01:00
El RIDO 54585549e0
Merge pull request #1218 from PrivateBin/detect-broken-pastes
detect and report on damaged pastes
2023-12-19 05:39:39 +01:00
El RIDO d49be80ffb
prevent regression around presence or absence of en.json
it gets excluded in the release archive, it's absence should not make
any difference
2023-12-18 21:49:21 +01:00
El RIDO a17529c7e1
document change 2023-12-18 21:02:27 +01:00
El RIDO 0a7a341fda
Merge pull request #1217 from PrivateBin/releasedoc
Created doc for “how to verify and how to do release” (release doc)
2023-12-18 20:57:11 +01:00
El RIDO d88945663e detect and report on damaged pastes
May occur during statistics or purge, when existing pastes get parsed, addresses #1214
2023-12-16 07:38:09 +01:00
El RIDO 255fd4b12b updated release document
- removed duplicate content
- clarified what is signed and since which release
- updated verification sample output (also in wiki) using the output of https://github.com/PrivateBin/docker-nginx-fpm-alpine/actions/runs/7228527399/job/19698112056#step:7:156
- Corrected release process - we trigger the release on the push of the tag, not a branch (fixed point in time instead of a moving target)
2023-12-16 07:02:21 +01:00
rugk 43d162f452
Created doc for “how to verify and how to do release” (release doc) (WIP)
This documents/should document:
* what the signatures are and what they proof
* how to verify them
* how to build releases (I know more of a maintainer doc, but yeah, I found it a good place here, if you want a separate one feel free)

This should also make it easier for other maintainers to create releases or so.

@elrido feel free to adjust/push to the branch if you want to have some details fixed. I have left some TODOs of stuff where I am unsure.
2023-12-15 14:17:51 +01:00
El RIDO 9b07e3ff62
Merge pull request #1215 from PrivateBin/dependabot/github_actions/github/codeql-action-3
Bump github/codeql-action from 2 to 3
2023-12-15 08:13:08 +01:00
El RIDO d0420fb418
1.6.2 release 2023-12-15 07:20:20 +01:00
El RIDO 3b17dfc6ef
Merge pull request #1213 from PrivateBin/en-lang-selection
ensure English is always added to available languages, fixes #1208
2023-12-15 07:03:06 +01:00
dependabot[bot] 03e3e4fa06
Bump github/codeql-action from 2 to 3
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 2 to 3.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-14 11:52:46 +00:00
El RIDO 879c7400bf
Merge pull request #1212 from joeskeen/conf-view-as-ini
add workspace settings with config files treated as INI
2023-12-09 12:17:51 +01:00
El RIDO 46d8d7d781
Merge pull request #1210 from joeskeen/devcontainer-postcreate
move postCreateCommands to a separate file
2023-12-09 12:16:21 +01:00
El RIDO 684924e9e5
apply StyleCI patch 2023-12-09 12:00:57 +01:00
El RIDO a7f720d825
ensure English is always added to available languages, fixes #1208
bug got introduced in 3668f1e3f4 and
started affecting release after 896a49c8cf
2023-12-09 11:58:29 +01:00
El RIDO 826444bef7
fix shasum in release pipeline, hope this fixes #1169 2023-12-09 10:50:49 +01:00
Joe Skeen 10c6841f8a
Update .devcontainer/postCreateCommand.sh
Co-authored-by: rugk <rugk+git@posteo.de>
2023-12-08 15:31:45 -07:00
Joe Skeen 49a87c6038 add workspace settings with config files treated as INI 2023-12-08 16:30:45 +00:00
Joe Skeen 7a5036d957 move postCreateCommands to a separate file 2023-12-08 15:34:00 +00:00
El RIDO f8c2f58604
typo 2023-12-04 21:24:12 +01:00
El RIDO edec91de1c
Merge branch 'master' of github.com:PrivateBin/PrivateBin 2023-12-04 21:17:32 +01:00
El RIDO 8131518ba1
Merge pull request #1204 from PrivateBin/crowdin-translation
New Crowdin updates
2023-12-04 19:10:18 +01:00
PrivateBin Translator Bot bb89eb7fba New translations en.json (Finnish) 2023-12-04 18:46:19 +01:00
El RIDO 94d1908777
Merge pull request #1203 from PrivateBin/dependabot/composer/phpunit/phpunit-9.6.15
Bump phpunit/phpunit from 9.6.14 to 9.6.15
2023-12-04 17:39:48 +01:00
PrivateBin Translator Bot 5b2f788e48 New translations en.json (Finnish) 2023-12-04 16:43:03 +01:00
PrivateBin Translator Bot 33e9025d09 New translations en.json (Finnish) 2023-12-04 15:14:57 +01:00
dependabot[bot] 6133f6c35c
Bump phpunit/phpunit from 9.6.14 to 9.6.15
Bumps [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) from 9.6.14 to 9.6.15.
- [Changelog](https://github.com/sebastianbergmann/phpunit/blob/9.6.15/ChangeLog-9.6.md)
- [Commits](https://github.com/sebastianbergmann/phpunit/compare/9.6.14...9.6.15)

---
updated-dependencies:
- dependency-name: phpunit/phpunit
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-04 11:37:40 +00:00
J. Fernando LAGRANGE f797311650 Change "Send" button label to "Save"
Includes french translation.
2022-06-28 10:34:40 +02:00
99 changed files with 1138 additions and 474 deletions

View File

@ -40,11 +40,7 @@
"forwardPorts": [
8080
],
"postCreateCommand": [
"composer install --no-dev --optimize-autoloader",
"sudo chmod a+x \"$(pwd)\" && sudo rm -rf /var/www/html && sudo ln -s \"$(pwd)\" /var/www/html",
"npm install --global nyc"
],
"postCreateCommand": ".devcontainer/postCreateCommand.sh",
// alternatiuve: apache2ctl start (but requires root)
"postAttachCommand": "php -S 0.0.0.0:8080"
}

View File

@ -0,0 +1,5 @@
#!/bin/sh
composer install --no-dev --optimize-autoloader
sudo chmod a+x "$(pwd)" && sudo rm -rf /var/www/html && sudo ln -s "$(pwd)" /var/www/html
npm install --global nyc

2
.gitattributes vendored
View File

@ -26,8 +26,6 @@ js/test/ export-ignore
.vscode export-ignore
codacy-analysis.yml export-ignore
crowdin.yml export-ignore
composer.json export-ignore
composer.lock export-ignore
BADGES.md export-ignore
CODE_OF_CONDUCT.md export-ignore
Makefile export-ignore

View File

@ -37,7 +37,7 @@ jobs:
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
@ -46,4 +46,4 @@ jobs:
# queries: ./path/to/local/query, your-org/your-repo/queries@main
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3

View File

@ -34,7 +34,7 @@ jobs:
- name: Generate hashes
shell: bash
id: hash
run: echo "hashes=$(sha256sum ${GITHUB_REF_NAME} | base64 -w0)" >> "$GITHUB_OUTPUT"
run: echo "hashes=$(sha256sum ${GITHUB_REF_NAME}.* | base64 -w0)" >> "$GITHUB_OUTPUT"
provenance:
needs:

View File

@ -24,6 +24,6 @@ jobs:
with:
args: --sarif-file-output=snyk.sarif
- name: Upload result to GitHub Code Scanning
uses: github/codeql-action/upload-sarif@v2
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: snyk.sarif

View File

@ -41,7 +41,7 @@ jobs:
key: ${{ runner.os }}-${{ env.extensions-cache-key }}
- name: Cache extensions
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ${{ steps.extcache.outputs.dir }}
key: ${{ steps.extcache.outputs.key }}
@ -76,7 +76,7 @@ jobs:
shell: bash
- name: Cache dependencies
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-composer-${{ steps.get-date.outputs.date }}-${{ hashFiles('**/composer.json') }}

5
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,5 @@
{
"files.associations": {
"**/cfg/conf*.php": "ini"
}
}

View File

@ -1,12 +1,36 @@
# PrivateBin version history
## 1.7.2 (not yet released)
* ADDED: Allow use of `shortenviayourls` in query parameters (#1267)
* CHANGED: "Send" button now labeled "Create" (#946)
* FIXED: Add cache control headers also to API calls (#1263)
* FIXED: Shortened paste URL does not appear in email (#606)
## 1.7.1 (2024-02-11)
* FIXED: zlib 1.3.1 wasm file reference
## 1.7.0 (2024-02-11)
* ADDED: Translations for Romanian
* ADDED: Detect and report on damaged pastes (#1218)
* CHANGED: Ask for confirmation, before loading burn after reading pastes (#1237)
* CHANGED: Focus on password input in modal dialog
* CHANGED: Upgrading libraries to: DOMpurify 3.0.8 & zlib 1.3.1
* FIXED: Support more types of valid URLs for shorteners, incl. IDN ones (#1224)
* FIXED: Email timezone buttons overlapping in some languages (#1039)
* FIXED: Changing language mangles URL (#1191)
* FIXED: Needless reload when visiting default URL
## 1.6.2 (2023-12-15)
* FIXED: English not selectable when `languageselection` enabled (#1208)
* FIXED: SRI mismatch due to cached file having changed (#1207)
## 1.6.1 (2023-12-04)
* ADDED: Right-To-Left (RTL) support for Arabic & Hebrew (#1174)
* CHANGED: Upgrading libraries to: DOMpurify 3.0.6
## 1.6.0 (2023-09-11)
* ADDED: Translations for Japanese & Arabic
* ADDED: Configuration option to disable Email button (#1164)
* ADDED: Configuration option to disable email button (#1164)
* CHANGED: Minimum required PHP version is 7.3, due to upgrading PHPunit (#707)
* CHANGED: Removed PHP 5 polyfill for random_bytes()

View File

@ -32,6 +32,7 @@
* Felix J. Ogris - S3 Storage backend, script for data backend migrations, dropped singleton behaviour of data backends
* Mounir Idrassi & J. Mozdzen - secure YOURLS integration
* Felipe Nakandakari - enabled AWS SDK to use default credential provider chain in the S3 Storage backend
* Aaron Sherber - cache control headers for API calls & use of `shortenviayourls` in query parameters
## Translations
* Hexalyse - French
@ -65,3 +66,4 @@
* jaideejung007 - Thai
* Nicolas Le Gall - Japanese
* lazerns - Arabic
* Edward205 - Romanian

View File

@ -1,7 +1,7 @@
.PHONY: all coverage coverage-js coverage-php doc doc-js doc-php increment sign test test-js test-php help
CURRENT_VERSION = 1.6.1
VERSION ?= 1.6.2
CURRENT_VERSION = 1.7.1
VERSION ?= 1.7.2
VERSION_FILES = index.php bin/ cfg/ *.md doc/Installation.md css/ i18n/ img/ js/package.json js/privatebin.js lib/ Makefile tpl/ tst/
REGEX_CURRENT_VERSION := $(shell echo $(CURRENT_VERSION) | sed "s/\./\\\./g")
REGEX_VERSION := $(shell echo $(VERSION) | sed "s/\./\\\./g")
@ -17,7 +17,7 @@ coverage-js: ## Run JS unit tests and generate code coverage reports.
cd js && nyc mocha
coverage-php: ## Run PHP unit tests and generate code coverage reports.
cd tst && phpunit 2> /dev/null
cd tst && XDEBUG_MODE=coverage phpunit 2> /dev/null
cd tst/log/php-coverage-report && sed -i "s#$(CURDIR)/##g" *.html */*.html
doc: doc-js doc-php ## Generate all code documentation.

View File

@ -1,6 +1,6 @@
# [![PrivateBin](https://cdn.rawgit.com/PrivateBin/assets/master/images/preview/logoSmall.png)](https://privatebin.info/)
*Current version: 1.6.1*
*Current version: 1.7.1*
**PrivateBin** is a minimalist, open source online
[pastebin](https://en.wikipedia.org/wiki/Pastebin)
@ -55,7 +55,7 @@ without losing any data.
paste (first) might still be disclosed via access logs.
- In case of a server breach your data is secure as it is only stored encrypted
on the server. However, the server could be absused or the server admin could
on the server. However, the server could be abused or the server admin could
be legally forced into sending malicious code to their users, which logs
the decryption key and sends it to a server when a user accesses a paste.
Therefore, do not access any PrivateBin instance if you think it has been

View File

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

View File

@ -9,11 +9,12 @@
* @link https://github.com/PrivateBin/PrivateBin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 1.6.1
* @version 1.7.1
*/
namespace PrivateBin;
use Exception;
use PrivateBin\Configuration;
use PrivateBin\Data\AbstractData;
use PrivateBin\Model\Paste;
@ -195,6 +196,7 @@ EOT, PHP_EOL;
{
$counters = array(
'burn' => 0,
'damaged' => 0,
'discussion' => 0,
'expired' => 0,
'md' => 0,
@ -217,7 +219,12 @@ EOT, PHP_EOL;
echo "Total:\t\t\t{$counters['total']}", PHP_EOL;
foreach ($ids as $pasteid) {
$paste = $this->_store->read($pasteid);
try {
$paste = $this->_store->read($pasteid);
} catch (Exception $e) {
echo "Error reading paste {$pasteid}: ", $e->getMessage(), PHP_EOL;
++$counters['damaged'];
}
++$counters['progress'];
if (
@ -271,6 +278,9 @@ Plain Text:\t\t{$counters['plain']}
Source Code:\t\t{$counters['syntax']}
Markdown:\t\t{$counters['md']}
EOT, PHP_EOL;
if ($counters['damaged'] > 0) {
echo "Damaged:\t\t{$counters['damaged']}", PHP_EOL;
}
if ($counters['unknown'] > 0) {
echo "Unknown format:\t\t{$counters['unknown']}", PHP_EOL;
}
@ -305,7 +315,12 @@ EOT, PHP_EOL;
}
if ($this->_option('p', 'purge') !== null) {
$this->_store->purge(PHP_INT_MAX);
try {
$this->_store->purge(PHP_INT_MAX);
} catch (Exception $e) {
echo 'Error purging pastes: ', $e->getMessage(), PHP_EOL,
'Run the statistics to find damaged paste IDs and either delete them or restore them from backup.', PHP_EOL;
}
exit('purging of expired pastes concluded' . PHP_EOL);
}

View File

@ -254,8 +254,8 @@ dir = PATH "data"
; Only use this if you allow short URL creation without credentials.
; - Alternatively, using the parameters in this section ("signature" and
; "apiurl"), "urlshortener" needs to point to the base URL of your PrivateBin
; instance with "shortenviayourls?link=" appended. For example:
; urlshortener = "${basepath}shortenviayourls?link="
; instance with "?shortenviayourls&link=" appended. For example:
; urlshortener = "${basepath}?shortenviayourls&link="
; This URL will in turn call YOURLS on the server side, using the URL from
; "apiurl" and the "access signature" from the "signature" parameters below.

View File

@ -24,10 +24,10 @@
"docs" : "https://privatebin.info/codedoc/"
},
"require" : {
"php" : "^7.3 || ^8.0",
"yzalis/identicon" : "2.0.0",
"mlocati/ip-lib" : "1.18.0",
"jdenticon/jdenticon": "1.0.2"
"php": "^7.3 || ^8.0",
"jdenticon/jdenticon": "1.0.2",
"mlocati/ip-lib": "1.18.0",
"yzalis/identicon": "2.0.0"
},
"suggest" : {
"google/cloud-storage" : "1.32.0",

68
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "96f9b3968855bf9f45813d12568f1cac",
"content-hash": "b76c0c25f93dc79c4525cb3c86e5af99",
"packages": [
{
"name": "jdenticon/jdenticon",
@ -316,16 +316,16 @@
},
{
"name": "nikic/php-parser",
"version": "v4.17.1",
"version": "v4.18.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d"
"reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"reference": "a6303e50c90c355c7eeee2c4a8b27fe8dc8fef1d",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/1bcbb2179f97633e98bbbc87044ee2611c7d7999",
"reference": "1bcbb2179f97633e98bbbc87044ee2611c7d7999",
"shasum": ""
},
"require": {
@ -366,9 +366,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.17.1"
"source": "https://github.com/nikic/PHP-Parser/tree/v4.18.0"
},
"time": "2023-08-13T19:53:39+00:00"
"time": "2023-12-10T21:03:43+00:00"
},
{
"name": "phar-io/manifest",
@ -483,23 +483,23 @@
},
{
"name": "phpunit/php-code-coverage",
"version": "9.2.29",
"version": "9.2.30",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/php-code-coverage.git",
"reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76"
"reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/6a3a87ac2bbe33b25042753df8195ba4aa534c76",
"reference": "6a3a87ac2bbe33b25042753df8195ba4aa534c76",
"url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/ca2bd87d2f9215904682a9cb9bb37dda98e76089",
"reference": "ca2bd87d2f9215904682a9cb9bb37dda98e76089",
"shasum": ""
},
"require": {
"ext-dom": "*",
"ext-libxml": "*",
"ext-xmlwriter": "*",
"nikic/php-parser": "^4.15",
"nikic/php-parser": "^4.18 || ^5.0",
"php": ">=7.3",
"phpunit/php-file-iterator": "^3.0.3",
"phpunit/php-text-template": "^2.0.2",
@ -549,7 +549,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.29"
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/9.2.30"
},
"funding": [
{
@ -557,7 +557,7 @@
"type": "github"
}
],
"time": "2023-09-19T04:57:46+00:00"
"time": "2023-12-22T06:47:57+00:00"
},
{
"name": "phpunit/php-file-iterator",
@ -802,16 +802,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.6.14",
"version": "9.6.17",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "43653e6ad7adc22e7b667dd561bf8fcb74c10cf0"
"reference": "1a156980d78a6666721b7e8e8502fe210b587fcd"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43653e6ad7adc22e7b667dd561bf8fcb74c10cf0",
"reference": "43653e6ad7adc22e7b667dd561bf8fcb74c10cf0",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/1a156980d78a6666721b7e8e8502fe210b587fcd",
"reference": "1a156980d78a6666721b7e8e8502fe210b587fcd",
"shasum": ""
},
"require": {
@ -885,7 +885,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.14"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.17"
},
"funding": [
{
@ -901,7 +901,7 @@
"type": "tidelift"
}
],
"time": "2023-12-01T06:10:48+00:00"
"time": "2024-02-23T13:14:51+00:00"
},
{
"name": "sebastian/cli-parser",
@ -1146,20 +1146,20 @@
},
{
"name": "sebastian/complexity",
"version": "2.0.2",
"version": "2.0.3",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/complexity.git",
"reference": "739b35e53379900cc9ac327b2147867b8b6efd88"
"reference": "25f207c40d62b8b7aa32f5ab026c53561964053a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/739b35e53379900cc9ac327b2147867b8b6efd88",
"reference": "739b35e53379900cc9ac327b2147867b8b6efd88",
"url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/25f207c40d62b8b7aa32f5ab026c53561964053a",
"reference": "25f207c40d62b8b7aa32f5ab026c53561964053a",
"shasum": ""
},
"require": {
"nikic/php-parser": "^4.7",
"nikic/php-parser": "^4.18 || ^5.0",
"php": ">=7.3"
},
"require-dev": {
@ -1191,7 +1191,7 @@
"homepage": "https://github.com/sebastianbergmann/complexity",
"support": {
"issues": "https://github.com/sebastianbergmann/complexity/issues",
"source": "https://github.com/sebastianbergmann/complexity/tree/2.0.2"
"source": "https://github.com/sebastianbergmann/complexity/tree/2.0.3"
},
"funding": [
{
@ -1199,7 +1199,7 @@
"type": "github"
}
],
"time": "2020-10-26T15:52:27+00:00"
"time": "2023-12-22T06:19:30+00:00"
},
{
"name": "sebastian/diff",
@ -1473,20 +1473,20 @@
},
{
"name": "sebastian/lines-of-code",
"version": "1.0.3",
"version": "1.0.4",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/lines-of-code.git",
"reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc"
"reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/c1c2e997aa3146983ed888ad08b15470a2e22ecc",
"reference": "c1c2e997aa3146983ed888ad08b15470a2e22ecc",
"url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/e1e4a170560925c26d424b6a03aed157e7dcc5c5",
"reference": "e1e4a170560925c26d424b6a03aed157e7dcc5c5",
"shasum": ""
},
"require": {
"nikic/php-parser": "^4.6",
"nikic/php-parser": "^4.18 || ^5.0",
"php": ">=7.3"
},
"require-dev": {
@ -1518,7 +1518,7 @@
"homepage": "https://github.com/sebastianbergmann/lines-of-code",
"support": {
"issues": "https://github.com/sebastianbergmann/lines-of-code/issues",
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.3"
"source": "https://github.com/sebastianbergmann/lines-of-code/tree/1.0.4"
},
"funding": [
{
@ -1526,7 +1526,7 @@
"type": "github"
}
],
"time": "2020-11-28T06:42:11+00:00"
"time": "2023-12-22T06:20:34+00:00"
},
{
"name": "sebastian/object-enumerator",

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.6.1
* @version 1.7.1
*/
body {

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

View File

@ -201,7 +201,7 @@ CREATE INDEX parent ON prefix_comment(pasteid);
CREATE TABLE prefix_config (
id CHAR(16) NOT NULL, value TEXT, PRIMARY KEY (id)
);
INSERT INTO prefix_config VALUES('VERSION', '1.6.1');
INSERT INTO prefix_config VALUES('VERSION', '1.7.1');
```
In **PostgreSQL**, the `data`, `attachment`, `nickname` and `vizhash` columns
@ -213,11 +213,30 @@ to be `CLOB` and not `BLOB` or `MEDIUMBLOB`, the `id` column in the `config`
table needs to be `VARCHAR2(16)` and the `meta` column in the `paste` table
and the `value` column in the `config` table need to be `VARCHAR2(4000)`.
### Cloud Storage Backends
Due to the large size of the respective cloud SDKs required for these, we didn't
include these in the `vendor` directory shipped in our release archives. To use
these in your manual installation, you will need [composer installed](https://getcomposer.org/)
and require the used library (see instructions below).
This is not required if using the dedicated container images that have these SDKs
preinstalled.
#### Using Google Cloud Storage
If you want to deploy PrivateBin in a serverless manner in the Google Cloud, you
can choose the `GoogleCloudStorage` as backend. To use this backend, you create
a GCS bucket and specify the name as the model option `bucket`. Alternatively,
you can set the name through the environment variable `PRIVATEBIN_GCS_BUCKET`.
can choose the `GoogleCloudStorage` as backend.
To use this backend, you first have to install the SDK from the installation
directory of PrivateBin:
```console
composer require --no-update google/cloud-storage
composer update --no-dev --optimize-autoloader
```
You have to create a GCS bucket and specify the name as the model option `bucket`.
Alternatively, you can set the name through the environment variable `PRIVATEBIN_GCS_BUCKET`.
The default prefix for pastes stored in the bucket is `pastes`. To change the
prefix, specify the option `prefix`.
@ -226,15 +245,20 @@ Google Cloud Storage buckets may be significantly slower than a `FileSystem` or
`Database` backend. The big advantage is that the deployment on Google Cloud
Platform using Google Cloud Run is easy and cheap.
To use the Google Cloud Storage backend you have to install the suggested
library using the command `composer require google/cloud-storage`.
#### Using S3 Storage
Similar to Google Cloud Storage, you can choose S3 as storage backend. It uses
the AWS SDK for PHP, but can also talk to a Rados gateway as part of a CEPH
cluster. To use this backend, you first have to install the SDK in the
document root of PrivateBin: `composer require aws/aws-sdk-php`. You have to
create the S3 bucket on the CEPH cluster before using the S3 backend.
the AWS SDK for PHP, but can also talk to a Rados gateway as part of a Ceph
cluster.
To use this backend, you first have to install the SDK from the installation
directory of PrivateBin:
```console
composer require --no-update aws/aws-sdk-php
composer update --no-dev --optimize-autoloader
```
You have to create an S3 bucket on the Ceph cluster before using the S3 backend.
In the `[model]` section of cfg/conf.php, set `class` to `S3Storage`.
@ -256,7 +280,7 @@ data beneath this prefix.
For AWS, you have to provide at least `region`, `bucket`, `accesskey`, and
`secretkey`.
For CEPH, follow this example:
For Ceph, follow this example:
```
region = ""

44
doc/Release.md Normal file
View File

@ -0,0 +1,44 @@
# Release
## Overview of Supply-Chain Security
As of the PrivateBin 1.0 release we [cryptographically sign](https://git-scm.com/book/uz/v2/Git-Tools-Signing-Your-Work) our git commits and tags, so that you can verify we actually developed the software. Later, we also [started signing the release archives on GitHub](https://github.com/PrivateBin/PrivateBin/issues/219) and retroactively signed all releases from 1.0 forward.
Since [release 1.6.2](https://github.com/PrivateBin/PrivateBin/releases/tag/1.6.2) our release assets additionally also are [verified with the SLSA (Supply-chain Levels for Software Artifacts) framework](https://slsa.dev/), providing an in-toto manifest of the release archive.
This achieves the following:
1. It ensures no maintainer has gone rogue and has modified/tampered with the source code before “building” the release.
2. It ensures the release is build exactly according to the source as defined by the branch that was used for the release.
This includes the workflow file defining how the release is done itself.
3. Our release should achieve [SLSA build level 3](https://slsa.dev/spec/v1.0/levels#build-l3) as it [runs on GitHub](https://slsa.dev/spec/v1.0/threats). Some more properties [are thus achieved](https://slsa.dev/spec/v1.0/threats).
For more information [see the corresponding issue](https://github.com/PrivateBin/PrivateBin/issues/1169) and [the GitHub workflow file](/.github/workflows/release.yml).
## Reproducible builds
All releases `.tar.gz` and `.zip` archives since 1.0 come with corresponding `.asc` signatures that can be used to confirm the authenticity of the fact that the release has been issued by a PrivateBin maintainer.
This uses traditional [PGP](https://en.wikipedia.org/wiki/Pretty_Good_Privacy) signatures.
## Verification
You can use the gpg signatures for verifying the reproducibility and that a maintainer in posession with that PGP private key created the release with that content:
```
$ gpg2 --verify 1.6.2.tar.gz.asc
gpg: assuming signed data in '1.6.2.tar.gz'
gpg: Signature made Fri Dec 15 06:21:08 2023 UTC
gpg: using RSA key 28CA7C964938EA5C1481D42AE11B7950E9E183DB
gpg: Good signature from "PrivateBin release (solely used for signing releases)" [unknown]
gpg: WARNING: This key is not certified with a trusted signature!
gpg: There is no indication that the signature belongs to the owner.
Primary key fingerprint: 28CA 7C96 4938 EA5C 1481 D42A E11B 7950 E9E1 83DB
```
For a more step-by-step guide in detail [see this FAQ](https://github.com/PrivateBin/PrivateBin/wiki/FAQ#how-can-i-securely-clonedownload-your-project).
SLSA verification can be performed using the [SLSA verifier](https://github.com/slsa-framework/slsa-verifier?tab=readme-ov-file#verification-for-github-builders).
## Release process
The release process is outlined in the [release checklist](https://github.com/PrivateBin/PrivateBin/wiki/Release-Checklist). The key manual steps are performed using a [Makefile](https://github.com/PrivateBin/PrivateBin/blob/master/Makefile#L31-L43) and using a [shell script](https://github.com/rugk/gittools/blob/master/signrelease.sh).

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "جافاسكرِبت (JavaScript) مطلوب %s للعمل. نأسف للإزعاج.",
"%s requires a modern browser to work.": "%s يتطلب متصفحًا حديثًا للعمل.",
"New": "جديد",
"Send": "إرسال",
"Create": "أنشِئ",
"Clone": "استنساخ",
"Raw text": "نص خام",
"Expires": "تنتهي",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "عنوان IP الخاص بك غير مصرح له بإنشاء لصُق.",
"Trying to shorten a URL that isn't pointing at our instance.": "محاولة تقصير عنوان URL لا يشير إلى خادمنا.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "خطأ في الاتصال بـ YOURLS. ربما تكون هناك مشكلة في التضبيط، مثل \"apiurl\" أو \"التوقيع\" الخاطئ أو المفقود.",
"Error parsing YOURLS response.": "خطأ في تحليل استجابة YOURLS."
"Error parsing YOURLS response.": "خطأ في تحليل استجابة YOURLS.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "لا يمكن عرض اللصق احرقه بعد قراءته إلا مرة واحدة عند تحميله. هل تريد فتحه الآن؟",
"Yes, load it": "نعم، حمله"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Услугата %s се нуждае от JavaScript, за да работи. Съжаляваме за неудобството.",
"%s requires a modern browser to work.": "%s се нуждае от съвременен браузър за да работи.",
"New": "Създаване",
"Send": "Изпрати",
"Create": "Създай",
"Clone": "Дублирай",
"Raw text": "Чист текст",
"Expires": "Изтича",
@ -199,10 +199,10 @@
"Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.",
"Retry": "Нов опит",
"Showing raw text…": "Showing raw text…",
"Notice:": "Notice:",
"Notice:": "Известие:",
"This link will expire after %s.": "This link will expire after %s.",
"This link can only be accessed once, do not use back or refresh button in your browser.": "This link can only be accessed once, do not use back or refresh button in your browser.",
"Link:": "Link:",
"Link:": "Връзка:",
"Recipient may become aware of your timezone, convert time to UTC?": "Recipient may become aware of your timezone, convert time to UTC?",
"Use Current Timezone": "Use Current Timezone",
"Convert To UTC": "Convert To UTC",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Cal JavaScript perquè %s funcioni. Em sap greu les molèsties.",
"%s requires a modern browser to work.": "%s requereix un navegador modern per funcionar.",
"New": "Nou",
"Send": "Enviar",
"Create": "Crear",
"Clone": "Clona",
"Raw text": "Text sense processar",
"Expires": "Caducitat",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript hè richiestu per fà funziunà %s. Scusate per stu penseru.",
"%s requires a modern browser to work.": "%s richiede un navigatore mudernu per funziunà.",
"New": "Novu",
"Send": "Mandà",
"Create": "Creà",
"Clone": "Duppione",
"Raw text": "Testu grossu",
"Expires": "Scadenza",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "U vostru indirizzu IP ùn hè micca auturizatu à creà lappiccichi.",
"Trying to shorten a URL that isn't pointing at our instance.": "Pruvate dammuzzà un indirizzu web chì ùn punta micca versu a vostra instanza.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Sbagliu à a chjama di YOURLS. Seria forse una cunfigurazione gattiva, tale una \"apiurl\" o \"signature\" falsa o assente.",
"Error parsing YOURLS response.": "Sbagliu durante lanalisa di a risposta di YOURLS."
"Error parsing YOURLS response.": "Sbagliu durante lanalisa di a risposta di YOURLS.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Si pò affissà lappiccichi « Squassà dopu a lettura » solu dopu u so caricamentu. Vulete aprelu subitu ?",
"Yes, load it": "Iè, caricatelu"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Pro fungování %s je vyžadován JavaScript. Omlouváme se za nepříjemnosti.",
"%s requires a modern browser to work.": "%%s requires a modern browser to work.",
"New": "Nový",
"Send": "Odeslat",
"Create": "Vytvořit",
"Clone": "Klonovat",
"Raw text": "Pouze Text",
"Expires": "Expirace",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Vaše IP adresa nemá oprávnění k vytvoření vložení.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript ist eine Voraussetzung, um %s zu nutzen. Bitte entschuldige die Unannehmlichkeiten.",
"%s requires a modern browser to work.": "%s setzt einen modernen Browser voraus, um funktionieren zu können.",
"New": "Neu",
"Send": "Senden",
"Create": "Erstellen",
"Clone": "Klonen",
"Raw text": "Reiner Text",
"Expires": "Ablaufzeit",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Deine IP ist nicht berechtigt, Texte zu erstellen.",
"Trying to shorten a URL that isn't pointing at our instance.": "Versuch eine URL zu verkürzen, die nicht auf unsere Instanz zeigt.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Fehler beim Aufruf von YOURLS. Wahrscheinlich ein Konfigurationsproblem, wie eine falsche oder fehlende \"apiurl\" oder \"signature\".",
"Error parsing YOURLS response.": "Fehler beim Verarbeiten der YOURLS-Antwort."
"Error parsing YOURLS response.": "Fehler beim Verarbeiten der YOURLS-Antwort.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Texte des \"Einmal\"-Typs können nach dem Öffnen nur einmal angezeigt werden. Möchtest Du ihn jetzt öffnen?",
"Yes, load it": "Ja, jetzt öffnen"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Η JavaScript είναι απαραίτητη για να λειτουργήσει το %s. Συγγνώμη για την ταλαιπωρία.",
"%s requires a modern browser to work.": "%s απαιτεί σύγχρονο φυλλομετρητή (browser) για να λειτουργήσει.",
"New": "Νέο",
"Send": "Αποστολή",
"Create": "Δημιουργία",
"Clone": "Κλωνοποίηση",
"Raw text": "Κείμενο",
"Expires": "Λήγει",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Η IP σας δεν επιτρέπεται να δημιουργεί επικολλήσεις.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.",
"New": "New",
"Send": "Send",
"Create": "Create",
"Clone": "Clone",
"Raw text": "Raw text",
"Expires": "Expires",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript es necesario para que %s funcione. Sentimos los inconvenientes ocasionados.",
"%s requires a modern browser to work.": "%s requiere un navegador moderno para funcionar.",
"New": "Nuevo",
"Send": "Enviar",
"Create": "Crear",
"Clone": "Clonar",
"Raw text": "Texto sin formato",
"Expires": "Caducar en",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Tu IP no está autorizada para crear contenido.",
"Trying to shorten a URL that isn't pointing at our instance.": "Intentando acortar una URL que no apunta a nuestra instancia.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript on vajalik %s'i töötamiseks. Vabandame ebamugavuste pärast.",
"%s requires a modern browser to work.": "%s vajab töötamiseks kaasaegset brauserit.",
"New": "Uus",
"Send": "Saada",
"Create": "Loo",
"Clone": "Klooni",
"Raw text": "Lähtetekst",
"Expires": "Aegub",
@ -211,8 +211,10 @@
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Kirja nägemiseks külasta seda linki. Teistele URL-i andmine lubab ka neil ligi pääseda kirjale.",
"URL shortener may expose your decrypt key in URL.": "URL-i lühendaja võib paljastada sinu dekrüpteerimisvõtme URL-is.",
"Save paste": "Salvesta kleebe",
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Your IP is not authorized to create pastes.": "Su IP-l ei ole lubatud kleepeid luua.",
"Trying to shorten a URL that isn't pointing at our instance.": "Püüame lühendada URL-i, mis ei viita meie instantsile.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Viga YOURLS-i kutsumisel. Tõenäoliselt konfiguratsiooniprobleem, näiteks vale või puuduv \"apiurl\" või \"signature\".",
"Error parsing YOURLS response.": "Viga YOURLS vastuse parsimisel.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "%s vaatii JavaScriptiä toimiakseen. Anteeksi haitasta.",
"%s requires a modern browser to work.": "%s vaatii modernin selaimen toimiakseen.",
"New": "Uusi",
"Send": "Lähetä",
"Create": "Luo",
"Clone": "Kloonaa",
"Raw text": "Raaka teksti",
"Expires": "Vanhenee",
@ -208,11 +208,13 @@
"Convert To UTC": "Muuta UTC:ksi",
"Close": "Sulje",
"Encrypted note on %s": "Salattu viesti %sissä",
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Käy tässä linkissä nähdäksesi viestin. URL:n antaminen kenellekään antaa heidänkin päästä katsomeen viestiä. ",
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Vieraile tässä linkissä nähdäksesi viestin. URL:n antaminen kenellekään antaa heidänkin päästä katsomaan viestiä.",
"URL shortener may expose your decrypt key in URL.": "URL-lyhentäjä voi paljastaa purkuavaimesi URL:ssä.",
"Save paste": "Tallenna paste",
"Your IP is not authorized to create pastes.": "IP:llesi ei ole annettu oikeutta luoda pasteja.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Trying to shorten a URL that isn't pointing at our instance.": "Yritetään lyhentää URL-osoite, joka ei osoita meidän instanssiiin.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Virhe kutsuttaessa YOURLS. Luultavasti asetusongelma kuten väärä tai puuttuuva \"apiurl\" tai \"signature\".",
"Error parsing YOURLS response.": "Virhe jäsennettäessä YOURLS-vastausta.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript est requis pour faire fonctionner %s. Désolé pour cet inconvénient.",
"%s requires a modern browser to work.": "%s nécessite un navigateur moderne pour fonctionner.",
"New": "Nouveau",
"Send": "Envoyer",
"Create": "Créer",
"Clone": "Cloner",
"Raw text": "Texte brut",
"Expires": "Expire",
@ -212,7 +212,9 @@
"URL shortener may expose your decrypt key in URL.": "Raccourcir l'URL peut exposer votre clé de déchiffrement dans l'URL.",
"Save paste": "Sauver le paste",
"Your IP is not authorized to create pastes.": "Votre adresse IP n'est pas autorisée à créer des pastes.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Trying to shorten a URL that isn't pointing at our instance.": "Essayer de raccourcir une URL qui ne pointe pas vers notre instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Erreur lors de l'appel de YOURLS. Peut-être un problème de configuration, comme \"apiurl\" ou \"signature\" manquant.",
"Error parsing YOURLS response.": "Erreur d'analyse de la réponse YOURLS.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Les pastes de type \"Effacer après la lecture\" ne peuvent être affichés qu'une seule fois. Voulez-vous l'ouvrir maintenant ?",
"Yes, load it": "Oui, chargez-le"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "צריך JavaScript כדי לאפשר ל־%s לפעול. סליחה על חוסר הנוחות.",
"%s requires a modern browser to work.": "%s דורש דפדפן מודרני כדי לפעול.",
"New": "חדש",
"Send": "שליחה",
"Create": "צור",
"Clone": "שכפול",
"Raw text": "טקסט גולמי",
"Expires": "Expires",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.",
"New": "New",
"Send": "Send",
"Create": "Create",
"Clone": "Clone",
"Raw text": "Raw text",
"Expires": "Expires",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript szükséges a %s működéséhez. Elnézést a fennakadásért.",
"%s requires a modern browser to work.": "A %s működéséhez a jelenleginél újabb böngészőre van szükség.",
"New": "Új",
"Send": "Beküldöm!",
"Create": "Létrehozás",
"Clone": "Másol",
"Raw text": "A nyers szöveg",
"Expires": "Lejárati idő",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript diperlukan agar %s bekerja. Maaf untuk ketidaknyamanannya.",
"%s requires a modern browser to work.": "%s memerlukan sebuah browser modern untuk bekerja.",
"New": "Baru",
"Send": "Kirim",
"Create": "Buat baru",
"Clone": "Klon",
"Raw text": "Teks mentah",
"Expires": "Kadaluarsa",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "%s funziona solo con JavaScript attivo. Ci dispiace per l'inconveniente.",
"%s requires a modern browser to work.": "%s richiede un browser moderno e aggiornato per funzionare.",
"New": "Nuovo",
"Send": "Invia",
"Create": "Crea",
"Clone": "Clona",
"Raw text": "Testo Raw",
"Expires": "Scade",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Il tuo IP non è autorizzato a creare dei messaggi.",
"Trying to shorten a URL that isn't pointing at our instance.": "Tantativo in corso di accorciare un URL che non punta alla nostra istanza.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Errore nella chiamata a YOURLS. Probabilmente un problema di configurazione, come un \"apiurl\" o una \"signature\" sbagliati o mancanti.",
"Error parsing YOURLS response.": "Errore nell'analizzare la risposta YOURLS."
"Error parsing YOURLS response.": "Errore nell'analizzare la risposta YOURLS.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Messaggi di tipo Distruggi-dopo-lettura piovono essere visualizzata solo una volta al caricamento. Vuoi aprirle ora?",
"Yes, load it": "Sì, caricalo"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "%s の動作にはJavaScriptが必要です。ご迷惑をおかけして申し訳ありません。",
"%s requires a modern browser to work.": "%s の動作には最近のブラウザが必要です。",
"New": "新規",
"Send": "送信",
"Create": "作成",
"Clone": "複製",
"Raw text": "未加工テキスト",
"Expires": "有効期限",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "あなたのIPアドレスにはペーストを作成する権限がありません。",
"Trying to shorten a URL that isn't pointing at our instance.": "このインスタンスを指していないURLを短縮しようとしています。",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "YOURLSの呼び出し中にエラーが発生しました。\"apiurl\"または\"signature\"等の設定に問題がある可能性があります。",
"Error parsing YOURLS response.": "YOURLSレスポンスの解析中にエラーが発生しました。"
"Error parsing YOURLS response.": "YOURLSレスポンスの解析中にエラーが発生しました。",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.",
"New": "cnino",
"Send": "benji",
"Create": "benji",
"Clone": "fukpi",
"Raw text": "vlapoi nalselrucyzu'e",
"Expires": "vimcu",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.",
"New": "New",
"Send": "Send",
"Create": "Create",
"Clone": "Clone",
"Raw text": "Raw text",
"Expires": "Expires",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.",
"New": "New",
"Send": "Send",
"Create": "Create",
"Clone": "Clone",
"Raw text": "Raw text",
"Expires": "Expires",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "%s darbui reikalinga JavaScript. Atsiprašome už nepatogumus.",
"%s requires a modern browser to work.": "%s savo darbui reikalauja šiuolaikinės naršyklės.",
"New": "Naujas",
"Send": "Siųsti",
"Create": "Kurti",
"Clone": "Dubliuoti",
"Raw text": "Neapdorotas tekstas",
"Expires": "Baigs galioti po",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Jūsų IP adresas neturi įgaliojimų kurti įdėjimų.",
"Trying to shorten a URL that isn't pointing at our instance.": "Bandoma sutrumpinti URL adresą, kuris nenurodo į mūsų egzempliorių.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Klaida iškviečiant YOURLS. Tikriausiai, konfigūracijos klaida, pavyzdžiui, neteisingi „apiurl“ ar „signature“, arba jų nėra.",
"Error parsing YOURLS response.": "Klaida nagrinėjant YOURLS atsaką."
"Error parsing YOURLS response.": "Klaida nagrinėjant YOURLS atsaką.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript vereist om %s te laten werken. Sorry voor het ongemak.",
"%s requires a modern browser to work.": "%s vereist een moderne browser om te kunnen werken.",
"New": "Nieuw",
"Send": "Verzenden",
"Create": "Maak",
"Clone": "Klonen",
"Raw text": "Onbewerkte tekst",
"Expires": "Verloopt",
@ -180,7 +180,7 @@
"Options": "Opties",
"Shorten URL": "URL verkorten",
"Editor": "Editor",
"Preview": "Preview",
"Preview": "Voorbeeld",
"%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s vereist dat PATH eindigt in een '%s'. a.u.b. PATH updaten in je index.php.",
"Decrypt": "Decoderen",
"Enter password": "Voer het wachtwoord in",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Je IP-adres is niet gemachtigd om pastes te maken.",
"Trying to shorten a URL that isn't pointing at our instance.": "Proberen om een URL te verkorten dat niet naar ons systeem wijst.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Foutmelding ophalen YOURLS. Waarschijnlijk een configuratiefout, zoals een verkeerde of missende \"apiurl\" of \"signature\".",
"Error parsing YOURLS response.": "Foutmelding bij parsen van YOURLS respons."
"Error parsing YOURLS response.": "Foutmelding bij parsen van YOURLS respons.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Brand na het lezen van de plagen kan slechts eenmaal worden weergegeven wanneer deze worden geladen. Wilt u het nu openen?",
"Yes, load it": "Ja, laad het"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Javascript kreves for at %s skal fungere. Beklager.",
"%s requires a modern browser to work.": "%s krever en moderne nettleser for å fungere.",
"New": "Ny",
"Send": "Send",
"Create": "Opprette",
"Clone": "Kopier",
"Raw text": "Ren tekst",
"Expires": "Utgår",
@ -211,8 +211,10 @@
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Besøk denne lenken for å se notatet. Hvis lenken deles med andre, vil de også kunne se notatet.",
"URL shortener may expose your decrypt key in URL.": "URL forkorter kan avsløre dekrypteringsnøkkelen.",
"Save paste": "Lagre utklipp",
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Your IP is not authorized to create pastes.": "Din IP er ikke autorisert til å opprette advarsler.",
"Trying to shorten a URL that isn't pointing at our instance.": "Prøver å forkorte en URL som ikke peker i vår instans.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Feil ved å ringe YOURLS. Sannsynligvis et konfigurasjonsproblem, som feil eller mangler, \"apiurl\" eller \"signatur\".",
"Error parsing YOURLS response.": "Feil ved analyse av YOURLS svar.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Brenne etter lesing av pasta kan kun vises når den lastes inn. Vil du åpne den nå?",
"Yes, load it": "Ja, last den"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript es requesit per far foncionar %s. O planhèm per linconvenient.",
"%s requires a modern browser to work.": "%s requerís un navigator modèrn per foncionar.",
"New": "Nòu",
"Send": "Mandar",
"Create": "Mandar",
"Clone": "Clonar",
"Raw text": "Tèxte brut",
"Expires": "Expira",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Vòstra adreça IP a pas lautorizacion de crear de tèxtes.",
"Trying to shorten a URL that isn't pointing at our instance.": "Ensag dabracar una URL que mena pas a nòstra instància.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error en cridant YOURLS. Es probablament un problèma de configuracion, quicòm coma « apirul » o « signature » marrit o absent.",
"Error parsing YOURLS response.": "Error d'analisi de la responsa YOURLS."
"Error parsing YOURLS response.": "Error d'analisi de la responsa YOURLS.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Do działania %sa jest wymagany JavaScript. Przepraszamy za tę niedogodność.",
"%s requires a modern browser to work.": "%s wymaga do działania nowoczesnej przeglądarki.",
"New": "Nowa",
"Send": "Wyślij",
"Create": "Stwórz",
"Clone": "Sklonuj",
"Raw text": "Czysty tekst",
"Expires": "Wygasa za",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript é necessário para que %s funcione. Pedimos desculpas pela inconveniência.",
"%s requires a modern browser to work.": "%s requer um navegador moderno para funcionar.",
"New": "Novo",
"Send": "Enviar",
"Create": "Criar",
"Clone": "Clonar",
"Raw text": "Texto sem formato",
"Expires": "Expirar em",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Seu IP não está autorizado a criar cópias.",
"Trying to shorten a URL that isn't pointing at our instance.": "Tentando encurtar uma URL que não aponta para a nossa instância.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

220
i18n/ro.json Normal file
View File

@ -0,0 +1,220 @@
{
"PrivateBin": "PrivateBin",
"%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s este un pastebin online, minimalist și cu sursă deschisă unde serverul are zero acces la datele introduse. Datele sunt criptate/decriptate %sîn browser%s folosind AES cu 256 de biți.",
"More information on the <a href=\"https://privatebin.info/\">project page</a>.": "Mai multe informații pe <a href=\"https://privatebin.info/\">pagina proiectului</a>.",
"Because ignorance is bliss": "Ignoranța este o binecuvântare",
"Paste does not exist, has expired or has been deleted.": "Paste-ul nu există, a expirat sau a fost șters.",
"%s requires php %s or above to work. Sorry.": "%s necesită php %s sau mai nou pentru a funcționa. Scuze.",
"%s requires configuration section [%s] to be present in configuration file.": "%s necesită ca secțiunea de configurare [%s] să fie prezentă în fișierul de configurare.",
"Please wait %d seconds between each post.": [
"Vă rugăm să așteptați %d secundă între fiecare postare",
"Vă rugăm să așteptați %d secunde între fiecare postare",
"Vă rugăm să așteptați %d de secunde între fiecare postare",
"Vă rugăm să așteptați %d de secunde între fiecare postare",
"Vă rugăm să așteptați %d de secunde între fiecare postare",
"Vă rugăm să așteptați %d de secunde între fiecare postare"
],
"Paste is limited to %s of encrypted data.": "Paste-ul este limitat la %s de date criptate.",
"Invalid data.": "Date invalide.",
"You are unlucky. Try again.": "Ați avut ghinion. Încercați din nou.",
"Error saving comment. Sorry.": "Eroare la salvarea comentariului. Ne pare rău.",
"Error saving paste. Sorry.": "Eroare la salvarea paste-ului. Ne pare rău.",
"Invalid paste ID.": "ID paste invalid.",
"Paste is not of burn-after-reading type.": "Paste-ul nu se șterge după citire.",
"Wrong deletion token. Paste was not deleted.": "Token de ștergere incorect. Paste-ul nu a fost șters.",
"Paste was properly deleted.": "Paste-ul a fost șters cu succes.",
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript este necesar pentru ca %s să funcționeze. Ne cerem scuze pentru neplăceri.",
"%s requires a modern browser to work.": "%s necesită un browser modern pentru a funcționa.",
"New": "Nou",
"Create": "Creează",
"Clone": "Clonați",
"Raw text": "Text brut",
"Expires": "Expiră",
"Burn after reading": "Ștergere după citire",
"Open discussion": "Deschideți discuția",
"Password (recommended)": "Parolă (recomandată)",
"Discussion": "Discuție",
"Toggle navigation": "Comutați navigarea",
"%d seconds": [
"%d secundă",
"%d secunde",
"%d de secunde",
"%d de secunde",
"%d de secunde",
"%d de secunde"
],
"%d minutes": [
"%d minut",
"%d minute",
"%d de minute",
"%d de secunde",
"%d de secunde",
"%d de secunde"
],
"%d hours": [
"%d oră",
"%d ore",
"%d de ore",
"%d de ore",
"%d de ore",
"%d de ore"
],
"%d days": [
"%d zi",
"%d zile",
"%d de zile",
"%d de zile",
"%d de zile",
"%d de zile"
],
"%d weeks": [
"%d săptămână",
"%d săptămână",
"%d săptămâni",
"%d de săptămâni",
"%d de săptămâni",
"%d de săptămâni"
],
"%d months": [
"%d lună",
"%d luni",
"%d de luni",
"%d de luni",
"%d de luni",
"%d de luni"
],
"%d years": [
"%d an",
"%d ani",
"%d de ani",
"%d de ani",
"%d de ani",
"%d de ani"
],
"Never": "Niciodată",
"Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "Notă: Acesta este un serviciu de test: Datele ar putea fi șterse oricând. Vor muri niște pisicuțe dacă abuzați acest serviciu.",
"This document will expire in %d seconds.": [
"Acest document va expira în %d secundă.",
"Acest document va expira în %d secunde.",
"Acest document va expira în %d de secunde.",
"Acest document va expira în %d de secunde.",
"Acest document va expira în %d de secunde.",
"Acest document va expira în %d de secunde."
],
"This document will expire in %d minutes.": [
"Acest document va expira în %d minut.",
"Acest document va expira în %d minute.",
"Acest document va expira în %d de minute.",
"Acest document va expira în %d de minute.",
"Acest document va expira în %d de minute.",
"Acest document va expira în %d de minute."
],
"This document will expire in %d hours.": [
"Acest document va expira în %d oră.",
"Acest document va expira în %d ore.",
"Acest document va expira în %d de ore.",
"Acest document va expira în %d de ore.",
"Acest document va expira în %d de ore.",
"Acest document va expira în %d de ore."
],
"This document will expire in %d days.": [
"Acest document va expira în %d zi.",
"Acest document va expira în %d zile.",
"Acest document va expira în %d de zile.",
"Acest document va expira în %d de zile.",
"Acest document va expira în %d de zile.",
"Acest document va expira în %d de zile."
],
"This document will expire in %d months.": [
"Acest document va expira în %d lună.",
"Acest document va expira în %d luni.",
"Acest document va expira în %d de luni.",
"Acest document va expira în %d de luni.",
"Acest document va expira în %d de luni.",
"Acest document va expira în %d de luni."
],
"Please enter the password for this paste:": "Va rugăm să introduceți parola pentru acest paste:",
"Could not decrypt data (Wrong key?)": "Nu s-au putut decripta datele (Cheie gresită?)",
"Could not delete the paste, it was not stored in burn after reading mode.": "Nu s-a putut șterge paste-ul, nu a fost stocat în modul de ștergere după citire.",
"FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "NUMAI PENTRU OCHII DVS. Nu închideți această fereastră, acest mesaj nu poate fi afișat din nou.",
"Could not decrypt comment; Wrong key?": "Nu s-a putut decripta comentariul; Cheie greșită?",
"Reply": "Răspundeți",
"Anonymous": "Anonim",
"Avatar generated from IP address": "Avatar generat din adresa IP",
"Add comment": "Adăugați un comentariu",
"Optional nickname…": "Poreclă opțională…",
"Post comment": "Postați comentariul",
"Sending comment…": "Se trimite comentariul…",
"Comment posted.": "Comentariul a fost postat.",
"Could not refresh display: %s": "Nu s-a putut actualiza afișarea: %s",
"unknown status": "stare necunoscută",
"server error or not responding": "eroare de server sau nu răspunde",
"Could not post comment: %s": "Nu s-a putut posta comentariul: %s",
"Sending paste…": "Se trimite paste-ul…",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit [Ctrl]+[c] to copy)</span>": "Paste-ul dvs. este <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Apăsați [Ctrl]+[c] pentru a copia)</span>",
"Delete data": "Ștergeți datele",
"Could not create paste: %s": "Nu s-a putut crea paste-ul: %s",
"Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Nu s-a putut decripta paste-ul: Cheia de decriptare lipsește din URL (Ați folosit un redirector sau un scurtător de URL care a tăiat o parte din URL?)",
"B": "B",
"KiB": "KiB",
"MiB": "MiB",
"GiB": "GiB",
"TiB": "TiB",
"PiB": "PiB",
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"Format": "Formatare",
"Plain Text": "Text neformatat",
"Source Code": "Cod sursă",
"Markdown": "Markdown",
"Download attachment": "Descărcați fișierul atașat",
"Cloned: '%s'": "S-a clonat: '%s'",
"The cloned file '%s' was attached to this paste.": "Fișierul clonat '%s' a fost atașat la acest paste.",
"Attach a file": "Atașați un fișier",
"alternatively drag & drop a file or paste an image from the clipboard": "alternativ, trageți și plasați un fișier sau lipiți o imagine din clipboard",
"File too large, to display a preview. Please download the attachment.": "Fișierul este prea mare pentru a afișa o previzualizare. Vă rugăm să descărcaţi fișierul.",
"Remove attachment": "Eliminați fișierul atașat",
"Your browser does not support uploading encrypted files. Please use a newer browser.": "Browserul dvs. nu acceptă încărcarea fișierelor criptate. Vă rugăm să folosiți un browser mai nou.",
"Invalid attachment.": "Fișier invalid.",
"Options": "Opţiuni",
"Shorten URL": "Scurtați URL-ul",
"Editor": "Editor",
"Preview": "Previzualizare",
"%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s necesită ca PATH să se termine cu \"%s\". Vă rugăm să actualizați PATH în index.php.",
"Decrypt": "Decriptare",
"Enter password": "Introduceţi parola",
"Loading…": "Se încarcă…",
"Decrypting paste…": "Se decriptează paste-ul…",
"Preparing new paste…": "Se pregătește un paste nou…",
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.": "În cazul în care acest mesaj nu dispare niciodată, vă rugăm să aruncaţi o privire la <a href=\"%s\">acest FAQ pentru informații de depanare</a>.",
"+++ no paste text +++": "+++ fără text +++",
"Could not get paste data: %s": "Nu s-a putut obține datele paste-ului: %s",
"QR code": "Cod QR",
"This website is using an insecure HTTP connection! Please use it only for testing.": "Acest website folosește o conexiune HTTP nesigură! Vă rugăm să îl folosiți doar pentru teste.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "Pentru mai multe informații <a href=\"%s\">a se vedea secțiunea FAQ</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Este posibil ca browserul dvs. să necesite o conexiune HTTPS pentru a suporta API-ul WebCrypto. Încercați să <a href=\"%s\">comutați la HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Browserul dvs. nu acceptă WebAssembly folosit pentru compresia zlib. Puteți crea documente necompresate, dar nu le puteți citi pe cele compresate.",
"waiting on user to provide a password": "se așteaptă ca utilizatorul să furnizeze o parolă",
"Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Nu s-au putut decripta datele. Ați introdus parola greșită? Reîncercați folosind butonul de sus.",
"Retry": "Reîncercați",
"Showing raw text…": "Se afișează textul brut…",
"Notice:": "Observaţie:",
"This link will expire after %s.": "Acest link va expira după %s.",
"This link can only be accessed once, do not use back or refresh button in your browser.": "Acest link poate fi accesat o singură dată, nu folosiți butonul înapoi sau reîmprospătare din browserul dvs.",
"Link:": "Link:",
"Recipient may become aware of your timezone, convert time to UTC?": "Destinatarul vă poate afla fusul dvs. orar, convertiți timpul în UTC?",
"Use Current Timezone": "Se folosește fusul orar actual",
"Convert To UTC": "Convertire la UTC",
"Close": "Închideți",
"Encrypted note on %s": "Notă criptată pe %s",
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "Accesați acest link pentru a vedea nota. Nota poate fi accesată de către oricine care are acest URL.",
"URL shortener may expose your decrypt key in URL.": "Scurtătorul de URL ar putea să vă expună cheia de decriptare din URL.",
"Save paste": "Salvați paste-ul",
"Your IP is not authorized to create pastes.": "Adresa dvs. IP nu este autorizată să creeze paste-uri.",
"Trying to shorten a URL that isn't pointing at our instance.": "Încercarea de a scurta un URL care nu direcționează spre instanța noastră.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Eroare la apelarea YOURLS. Probabil o problemă de configurare, cum ar fi \"apiurl\" sau \"signature\" greșite sau lipsă.",
"Error parsing YOURLS response.": "Eroare la analizarea răspunsului YOURLS.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Paste-urile care se șterg după citire pot fi afișate numai o dată după încărcare. Doriți să o deschideți acum?",
"Yes, load it": "Da, deschide-o"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Для работы %s требуется включенный JavaScript. Приносим извинения за неудобства.",
"%s requires a modern browser to work.": "Для работы %s требуется более современный браузер.",
"New": "Новая запись",
"Send": "Отправить",
"Create": "Создать",
"Clone": "Дублировать",
"Raw text": "Исходный текст",
"Expires": "Удалить через",
@ -212,7 +212,9 @@
"URL shortener may expose your decrypt key in URL.": "Сервис сокращения ссылок может получить ваш ключ расшифровки из ссылки.",
"Save paste": "Сохранить запись",
"Your IP is not authorized to create pastes.": "Вашему IP адресу не разрешено создавать записи.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Trying to shorten a URL that isn't pointing at our instance.": "Попытка сократить URL, который указывает не на наш сервер.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Ошибка обращения к YOURLS. Возможно в конфигурации допущена ошибка, например неверный или отсутствующий параметр \"apiurl\" или \"signature\".",
"Error parsing YOURLS response.": "Ошибка разбора ответа от YOURLS.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Записи, удаляемые после прочтения, могут быть отображены после загрузки только один раз. Вы хотите открыть её сейчас?",
"Yes, load it": "Да, загрузить"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Na fungovanie %s je potrebný JavaScript. Ospravedlňujeme sa za nepríjemnosti.",
"%s requires a modern browser to work.": "%s vyžaduje na fungovanie moderný prehliadač.",
"New": "Nový",
"Send": "Odoslať",
"Create": "Vytvoriť",
"Clone": "Klonovať",
"Raw text": "Surový text",
"Expires": "Expirácia",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Vaša IP adresa nie je oprávnená vytvárať príspevky.",
"Trying to shorten a URL that isn't pointing at our instance.": "Pokúšate sa skrátiť adresu URL, ktorá neukazuje na túto inštanciu.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Da %s deluje, moraš vklopiti JavaScript. Oprosti za povročene nevšečnosti.",
"%s requires a modern browser to work.": "%s za svoje delovanje potrebuje moderen brskalnik.",
"New": "Nov prilepek",
"Send": "Pošlji",
"Create": "Ustvari",
"Clone": "Kloniraj",
"Raw text": "Surov tekst",
"Expires": "Poteče",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.",
"%s requires a modern browser to work.": "%s requires a modern browser to work.",
"New": "New",
"Send": "Send",
"Create": "Skapa",
"Clone": "Clone",
"Raw text": "Raw text",
"Expires": "Expires",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "จำเป็นต้องใช้ JavaScript เพื่อให้ %s สามารถทำงานได้ ขออภัยในความไม่สะดวก",
"%s requires a modern browser to work.": "%s ต้องใช้เบราว์เซอร์สมัยใหม่ถึงจะสามารถใช้งานได้",
"New": "ใหม่",
"Send": "ส่ง",
"Create": "สร้าง",
"Clone": "โคลน",
"Raw text": "ข้อความล้วน",
"Expires": "หมดอายุ",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "IP ของคุณไม่ได้รับอนุญาตให้สร้างการฝากโค้ด",
"Trying to shorten a URL that isn't pointing at our instance.": "กำลังพยายามใช้เครื่องมือสร้างลิงก์ย่อ ที่ไม่ได้ชี้ไปที่อินสแตนซ์ของเรา",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "เกิดข้อผิดพลาดในการเรียก YOURLS อาจเป็นปัญหามาจากการกำหนดค่า เช่น \"apiurl\" หรือ \"signature\" ไม่ถูกต้องหรือขาดหายไป",
"Error parsing YOURLS response.": "เกิดข้อผิดพลาดในการแยกวิเคราะห์การตอบสนองของ YOURLS"
"Error parsing YOURLS response.": "เกิดข้อผิดพลาดในการแยกวิเคราะห์การตอบสนองของ YOURLS",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript %s 'in çalışması için gereklidir. Rahatsızlıktan dolayı özür dileriz.",
"%s requires a modern browser to work.": "%s çalışmak için çağdaş bir tarayıcı gerektirir.",
"New": "Yeni",
"Send": "Gönder",
"Create": "Oluştur",
"Clone": "Kopyala",
"Raw text": "Açık yazı",
"Expires": "Süre Sonu",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "IP adresinizin yazı oluşturmaya yetkisi yoktur.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?",
"Yes, load it": "Yes, load it"
}

View File

@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "Для роботи %s потрібен увімкнутий JavaScript. Вибачте.",
"%s requires a modern browser to work.": "Для роботи %s потрібен більш сучасний переглядач.",
"New": "Новий допис",
"Send": "Відправити",
"Create": "Створити",
"Clone": "Дублювати",
"Raw text": "Початковий текст",
"Expires": "Вилучити через",
@ -212,7 +212,9 @@
"URL shortener may expose your decrypt key in URL.": "Сервіс скорочення посилань може викрити ваш ключ дешифрування з URL.",
"Save paste": "Зберегти вставку",
"Your IP is not authorized to create pastes.": "Вашому IP не дозволено створювати вставки.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response."
"Trying to shorten a URL that isn't pointing at our instance.": "Спроба скоротити URL, який не вказує на наш екземпляр.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Помилка виклику YOURLS. Ймовірно проблема з конфігурацією, наприклад \"apiurl\" чи \"signature\".",
"Error parsing YOURLS response.": "Помилка розбору відповіді YOURLS.",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "Спалити після вставки читання можна вивести лише один раз під час завантаження. Відкрити його зараз?",
"Yes, load it": "Так, завантажити"
}

View File

@ -2,7 +2,7 @@
"PrivateBin": "PrivateBin",
"%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s 是一个极简、开源、对粘贴内容毫不知情的在线粘贴板,数据%s在浏览器内%s进行 AES-256 加密和解密。",
"More information on the <a href=\"https://privatebin.info/\">project page</a>.": "更多信息请查看<a href=\"https://privatebin.info/\">项目主页</a>。",
"Because ignorance is bliss": "因为无知是福",
"Because ignorance is bliss": "以不知为幸",
"Paste does not exist, has expired or has been deleted.": "粘贴内容不存在、已过期或已被删除。",
"%s requires php %s or above to work. Sorry.": "抱歉,%s 需要 PHP %s 及以上版本才能运行。",
"%s requires configuration section [%s] to be present in configuration file.": "%s 需要设置配置文件中的 [%s] 部分。",
@ -26,7 +26,7 @@
"JavaScript is required for %s to work. Sorry for the inconvenience.": "%s 需要 JavaScript 来进行加解密。 给你带来的不便敬请谅解。",
"%s requires a modern browser to work.": "%s 需要在现代浏览器上工作。",
"New": "新建",
"Send": "送出",
"Create": "创建",
"Clone": "复制",
"Raw text": "纯文本",
"Expires": "有效期",
@ -214,5 +214,7 @@
"Your IP is not authorized to create pastes.": "您的 IP 无权创建粘贴。",
"Trying to shorten a URL that isn't pointing at our instance.": "尝试缩短一个不指向我们实例的URL。",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "调用 YOURLS 时出错。可能是配置问题例如“apiurl”或“signature”错误或缺失。",
"Error parsing YOURLS response.": "解析 YOURLS 响应时出错。"
"Error parsing YOURLS response.": "解析 YOURLS 响应时出错。",
"Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?": "读取粘贴后只能在加载时显示一次。您想现在打开吗?",
"Yes, load it": "是的,加载它"
}

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

View File

@ -12,12 +12,12 @@ global.WebCrypto = require('@peculiar/webcrypto').Crypto;
// application libraries to test
global.$ = global.jQuery = require('./jquery-3.7.0');
global.RawDeflate = require('./rawinflate-0.3').RawDeflate;
global.zlib = require('./zlib-1.2.13').zlib;
global.zlib = require('./zlib-1.3.1').zlib;
require('./prettify');
global.prettyPrint = window.PR.prettyPrint;
global.prettyPrintOne = window.PR.prettyPrintOne;
global.showdown = require('./showdown-2.1.0');
global.DOMPurify = require('./purify-3.0.6');
global.DOMPurify = require('./purify-3.0.8');
global.baseX = require('./base-x-4.0.0').baseX;
global.Legacy = require('./legacy').Legacy;
require('./bootstrap-3.4.1');
@ -37,7 +37,7 @@ var a2zString = ['a','b','c','d','e','f','g','h','i','j','k','l','m',
})
),
schemas = ['ftp','http','https'],
supportedLanguages = ['de', 'es', 'fr', 'it', 'no', 'pl', 'pt', 'oc', 'ru', 'sl', 'zh'],
supportedLanguages = ['ar', 'bg', 'ca', 'co', 'cs', 'de', 'el', 'es', 'et', 'fi', 'fr', 'he', 'hu', 'id', 'it', 'ja', 'jbo', 'lt', 'no', 'nl', 'pl', 'pt', 'oc', 'ru', 'sk', 'sl', 'th', 'tr', 'uk', 'zh'],
mimeTypes = ['image/png', 'application/octet-stream'],
formats = ['plaintext', 'markdown', 'syntaxhighlighting'],
mimeFile = fs.createReadStream('/etc/mime.types'),
@ -113,8 +113,8 @@ exports.jscBase64String = function() {
};
// provides a random URL schema supported by the whatwg-url library
exports.jscSchemas = function() {
return jsc.elements(schemas);
exports.jscSchemas = function(withFtp = true) {
return jsc.elements(withFtp ? schemas : schemas.slice(1));
};
// provides a random supported language string
@ -131,3 +131,24 @@ exports.jscMimeTypes = function() {
exports.jscFormats = function() {
return jsc.elements(formats);
};
// provides random URLs
exports.jscUrl = function(withFragment = true, withQuery = true) {
let url = {
schema: exports.jscSchemas(),
address: jsc.nearray(exports.jscA2zString()),
};
if (withFragment) {
url.fragment = jsc.string;
}
if(withQuery) {
url.query = jsc.array(exports.jscQueryString());
}
return jsc.record(url);
};
exports.urlToString = function (url) {
return url.schema + '://' + url.address.join('') + '/' + (url.query ? '?' +
encodeURI(url.query.join('').replace(/^&+|&+$/gm,'')) : '') +
(url.fragment ? '#' + encodeURI(url.fragment) : '');
};

4
js/package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "privatebin",
"version": "1.5.2",
"version": "1.6.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "privatebin",
"version": "1.5.2",
"version": "1.6.2",
"license": "zlib-acknowledgement",
"devDependencies": {
"@peculiar/webcrypto": "^1.1.1",

View File

@ -1,6 +1,6 @@
{
"name": "privatebin",
"version": "1.6.1",
"version": "1.7.1",
"description": "PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted in the browser using 256 bit AES in Galois Counter mode (GCM).",
"main": "privatebin.js",
"directories": {

View File

@ -6,7 +6,7 @@
* @see {@link https://github.com/PrivateBin/PrivateBin}
* @copyright 2012 Sébastien SAUVAGE ({@link http://sebsauvage.net})
* @license {@link https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License}
* @version 1.6.1
* @version 1.7.1
* @name PrivateBin
* @namespace
*/
@ -77,6 +77,13 @@ jQuery.PrivateBin = (function($, RawDeflate) {
}
};
/**
* URL fragment prefix requiring load confirmation
*
* @private
*/
const loadConfirmPrefix = '#-';
/**
* CryptoData class
*
@ -228,7 +235,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;',
'\'': '&#39;',
'/': '&#x2F;',
'`': '&#x60;',
'=': '&#x3D;'
@ -627,7 +634,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
* @prop {string[]}
* @readonly
*/
const supportedLanguages = ['ar', 'bg', 'ca', 'co', 'cs', 'de', 'el', 'es', 'et', 'fi', 'fr', 'he', 'hu', 'id', 'it', 'ja', 'jbo', 'lt', 'no', 'nl', 'pl', 'pt', 'oc', 'ru', 'sk', 'sl', 'th', 'tr', 'uk', 'zh'];
const supportedLanguages = ['ar', 'bg', 'ca', 'co', 'cs', 'de', 'el', 'es', 'et', 'fi', 'fr', 'he', 'hu', 'id', 'it', 'ja', 'jbo', 'lt', 'no', 'nl', 'pl', 'pt', 'oc', 'ro', 'ru', 'sk', 'sl', 'th', 'tr', 'uk', 'zh'];
/**
* built in language
@ -836,6 +843,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
return n % 10 === 1 && n % 100 !== 11 ? 0 : ((n % 10 >= 2 && n % 100 < 10 || n % 100 >= 20) ? 1 : 2);
case 'pl':
return n === 1 ? 0 : (n % 10 >= 2 && n %10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2);
case 'ro':
return n === 1 ? 0 : ((n === 0 || (n % 100 > 0 && n % 100 < 20)) ? 1 : 2);
case 'ru':
case 'uk':
return n % 10 === 1 && n % 100 !== 11 ? 0 : (n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 10 || n % 100 >= 20) ? 1 : 2);
@ -1512,10 +1521,11 @@ jQuery.PrivateBin = (function($, RawDeflate) {
me.getPasteKey = function()
{
if (symmetricKey === null) {
let newKey = window.location.hash.substring(1);
if (newKey === '') {
throw 'no encryption key given';
let startPos = 1;
if(window.location.hash.startsWith(loadConfirmPrefix)) {
startPos = loadConfirmPrefix.length;
}
let newKey = window.location.hash.substring(startPos);
// Some web 2.0 services and redirectors add data AFTER the anchor
// (such as &utm_source=...). We will strip any additional data.
@ -1524,6 +1534,9 @@ jQuery.PrivateBin = (function($, RawDeflate) {
{
newKey = newKey.substring(0, ampersandPos);
}
if (newKey === '') {
throw 'no encryption key given';
}
// version 2 uses base58, version 1 uses base64 without decoding
try {
@ -2035,29 +2048,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
xhrFields: {
withCredentials: false
},
success: function(response) {
let responseString = response;
if (typeof responseString === 'object') {
responseString = JSON.stringify(responseString);
}
if (typeof responseString === 'string' && responseString.length > 0) {
const shortUrlMatcher = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/g;
const shortUrl = (responseString.match(shortUrlMatcher) || []).sort(function(a, b) {
return a.length - b.length;
})[0];
if (typeof shortUrl === 'string' && shortUrl.length > 0) {
// we disable the button to avoid calling shortener again
$shortenButton.addClass('buttondisabled');
// update link
$pasteUrl.text(shortUrl);
$pasteUrl.prop('href', shortUrl);
// we pre-select the link so that the user only has to [Ctrl]+[c] the link
Helper.selectText($pasteUrl[0]);
return;
}
}
Alert.showError('Cannot parse response from URL shortener.');
}
success: PasteStatus.extractUrl
})
.fail(function(data, textStatus, errorThrown) {
console.error(textStatus, errorThrown);
@ -2123,6 +2114,50 @@ jQuery.PrivateBin = (function($, RawDeflate) {
Helper.selectText($pasteUrl[0]);
};
/**
* extracts URLs from given string
*
* if at least one is found, it disables the shortener button and
* replaces the paste URL
*
* @name PasteStatus.extractUrl
* @function
* @param {string} response
*/
me.extractUrl = function(response)
{
if (typeof response === 'object') {
response = JSON.stringify(response);
}
if (typeof response === 'string' && response.length > 0) {
const shortUrlMatcher = /https?:\/\/[^\s"<]+/g; // JSON API will have URL in quotes, XML in tags
const shortUrl = (response.match(shortUrlMatcher) || []).filter(function(urlRegExMatch) {
if (typeof URL.canParse === 'function') {
return URL.canParse(urlRegExMatch);
}
// polyfill for older browsers (< 120) & node (< 19.9 & < 18.17)
try {
return !!new URL(urlRegExMatch);
} catch (error) {
return false;
}
}).sort(function(a, b) {
return a.length - b.length; // shortest first
})[0];
if (typeof shortUrl === 'string' && shortUrl.length > 0) {
// we disable the button to avoid calling shortener again
$shortenButton.addClass('buttondisabled');
// update link
$pasteUrl.text(shortUrl);
$pasteUrl.prop('href', shortUrl);
// we pre-select the link so that the user only has to [Ctrl]+[c] the link
Helper.selectText($pasteUrl[0]);
return;
}
}
Alert.showError('Cannot parse response from URL shortener.');
};
/**
* shows the remaining time
*
@ -2228,6 +2263,34 @@ jQuery.PrivateBin = (function($, RawDeflate) {
PasteDecrypter.run();
}
/**
* Request users confirmation to load possibly burn after reading paste
*
* @name Prompt.requestLoadConfirmation
* @function
*/
me.requestLoadConfirmation = function()
{
const $loadconfirmmodal = $('#loadconfirmmodal');
if ($loadconfirmmodal.length > 0) {
const $loadconfirmOpenNow = $loadconfirmmodal.find('#loadconfirm-open-now');
$loadconfirmOpenNow.off('click.loadPaste');
$loadconfirmOpenNow.on('click.loadPaste', PasteDecrypter.run);
const $loadconfirmClose = $loadconfirmmodal.find('.close');
$loadconfirmClose.off('click.close');
$loadconfirmClose.on('click.close', Controller.newPaste);
$loadconfirmmodal.modal('show');
} else {
if (window.confirm(
I18n._('Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?')
)) {
PasteDecrypter.run();
} else {
Controller.newPaste();
}
}
}
/**
* ask the user for the password and set it
*
@ -2242,6 +2305,12 @@ jQuery.PrivateBin = (function($, RawDeflate) {
backdrop: 'static',
keyboard: false
});
// focus password input
$passwordDecrypt.focus();
// then re-focus it, when modal causes it to loose focus again
setTimeout(function () {
$passwordDecrypt.focus();
}, 500);
return;
}
@ -2301,13 +2370,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
$passwordForm = $('#passwordform');
$passwordModal = $('#passwordmodal');
// bind events
// focus password input when it is shown
$passwordModal.on('shown.bs.Model', function () {
$passwordDecrypt.focus();
});
// handle Model password submission
// bind events - handle Model password submission
$passwordForm.submit(submitPasswordModal);
};
@ -3541,7 +3604,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
if (fadeOut === true) {
setTimeout(function () {
$comment.removeClass('highlight');
}, 300);
}
};
@ -3789,6 +3851,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
{
document.cookie = 'lang=' + $(event.target).data('lang') + ';secure';
UiHelper.reloadHome();
event.preventDefault();
}
/**
@ -3902,7 +3965,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
}
emailBody += I18n._('Link:');
emailBody += EOL;
emailBody += `${window.location.href}`;
emailBody += $('#pasteurl').attr('href'); // might have been shortened
return emailBody;
}
@ -3944,10 +4007,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
const $emailconfirmmodal = $('#emailconfirmmodal');
if ($emailconfirmmodal.length > 0) {
if (expirationDate !== null) {
I18n._(
$emailconfirmmodal.find('#emailconfirm-display'),
'Recipient may become aware of your timezone, convert time to UTC?'
);
const $emailconfirmTimezoneCurrent = $emailconfirmmodal.find('#emailconfirm-timezone-current');
const $emailconfirmTimezoneUtc = $emailconfirmmodal.find('#emailconfirm-timezone-utc');
$emailconfirmTimezoneCurrent.off('click.sendEmailCurrentTimezone');
@ -4802,7 +4861,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
// show notification
const baseUri = Helper.baseUri() + '?',
url = baseUri + data.id + '#' + CryptTool.base58encode(data.encryptionKey),
url = baseUri + data.id + (TopNav.getBurnAfterReading() ? loadConfirmPrefix : '#') + CryptTool.base58encode(data.encryptionKey),
deleteUrl = baseUri + 'pasteid=' + data.id + '&deletetoken=' + data.deletetoken;
PasteStatus.createPasteNotification(url, deleteUrl);
@ -5221,7 +5280,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
Alert.hideMessages();
Alert.showLoading('Decrypting paste…', 'cloud-download');
if (typeof paste === 'undefined') {
if (typeof paste === 'undefined' || paste.type === 'click') {
// get cipher data and wait until it is available
Model.getPasteData(me.run);
return;
@ -5328,7 +5387,10 @@ jQuery.PrivateBin = (function($, RawDeflate) {
AttachmentViewer.removeAttachmentData();
Alert.hideLoading();
history.pushState({type: 'create'}, document.title, Helper.baseUri());
// only push new state if we are coming from a different one
if (Helper.baseUri() != window.location) {
history.pushState({type: 'create'}, document.title, Helper.baseUri());
}
// clear discussion
DiscussionViewer.prepareNewDiscussion();
@ -5354,6 +5416,12 @@ jQuery.PrivateBin = (function($, RawDeflate) {
}
}
// check if we should request loading confirmation
if(window.location.hash.startsWith(loadConfirmPrefix)) {
Prompt.requestLoadConfirmation();
return;
}
// show proper elements on screen
PasteDecrypter.run();
};

File diff suppressed because one or more lines are too long

2
js/purify-3.0.8.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -96,36 +96,34 @@ describe('Helper', function () {
jsc.property(
'replaces URLs with anchors',
'string',
jsc.elements(['http', 'https', 'ftp']),
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscQueryString()),
common.jscUrl(),
jsc.array(common.jscHashString()),
'string',
function (prefix, schema, address, query, fragment, postfix) {
query = query.join('');
fragment = fragment.join('');
function (prefix, url, fragment, postfix) {
prefix = prefix.replace(/\r|\f/g, '\n').replace(/\u0000/g, '').replace(/\u000b/g, '');
postfix = ' ' + postfix.replace(/\r/g, '\n').replace(/\u0000/g, '');
let url = schema + '://' + address.join('') + '/?' + query + '#' + fragment,
url.fragment = fragment.join('');
let urlString = common.urlToString(url),
clean = jsdom();
$('body').html('<div id="foo"></div>');
let e = $('#foo');
// special cases: When the query string and fragment imply the beginning of an HTML entity, eg. &#0 or &#x
if (
query.slice(-1) === '&' &&
(parseInt(fragment.substring(0, 1), 10) >= 0 || fragment.charAt(0) === 'x' )
)
{
url = schema + '://' + address.join('') + '/?' + query.substring(0, query.length - 1);
url.query[-1] === '&' &&
(parseInt(url.fragment.charAt(0), 10) >= 0 || url.fragment.charAt(0) === 'x')
) {
url.query.pop();
urlString = common.urlToString(url);
postfix = '';
}
e.text(prefix + url + postfix);
e.text(prefix + urlString + postfix);
$.PrivateBin.Helper.urls2links(e);
let result = e.html();
clean();
url = $('<div />').text(url).html();
return $('<div />').text(prefix).html() + '<a href="' + url + '" target="_blank" rel="nofollow noopener noreferrer">' + url + '</a>' + $('<div />').text(postfix).html() === result;
urlString = $('<div />').text(urlString).html();
const expected = $('<div />').text(prefix).html() + '<a href="' + urlString + '" target="_blank" rel="nofollow noopener noreferrer">' + urlString + '</a>' + $('<div />').text(postfix).html();
return $('<div />').text(prefix).html() + '<a href="' + urlString + '" target="_blank" rel="nofollow noopener noreferrer">' + urlString + '</a>' + $('<div />').text(postfix).html() === result;
}
);
jsc.property(
@ -261,16 +259,16 @@ describe('Helper', function () {
this.timeout(30000);
jsc.property(
'returns the URL without query & fragment',
jsc.elements(['http', 'https']),
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscA2zString()),
jsc.array(common.jscQueryString()),
'string',
function (schema, address, path, query, fragment) {
common.jscSchemas(false),
common.jscUrl(),
function (schema, url) {
url.schema = schema;
const fullUrl = common.urlToString(url);
delete(url.query);
delete(url.fragment);
$.PrivateBin.Helper.reset();
var path = path.join('') + (path.length > 0 ? '/' : ''),
expected = schema + '://' + address.join('') + '/' + path,
clean = jsdom('', {url: expected + '?' + query.join('') + '#' + fragment}),
const expected = common.urlToString(url),
clean = jsdom('', {url: fullUrl}),
result = $.PrivateBin.Helper.baseUri();
clean();
return expected === result;

View File

@ -80,23 +80,22 @@ describe('Model', function () {
jsc.property(
'returns the query string without separator, if any',
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscA2zString()),
common.jscUrl(true, false),
jsc.tuple(new Array(16).fill(common.jscHexString)),
jsc.array(common.jscQueryString()),
jsc.array(common.jscQueryString()),
'string',
function (schema, address, pasteId, queryStart, queryEnd, fragment) {
var pasteIdString = pasteId.join(''),
queryStartString = queryStart.join('') + (queryStart.length > 0 ? '&' : ''),
queryEndString = (queryEnd.length > 0 ? '&' : '') + queryEnd.join(''),
queryString = queryStartString + pasteIdString + queryEndString,
clean = jsdom('', {
url: schema.join('') + '://' + address.join('') +
'/?' + queryString + '#' + fragment
});
global.URL = require('jsdom-url').URL;
var result = $.PrivateBin.Model.getPasteId();
function (url, pasteId, queryStart, queryEnd) {
if (queryStart.length > 0) {
queryStart.push('&');
}
if (queryEnd.length > 0) {
queryEnd.unshift('&');
}
url.query = queryStart.concat(pasteId, queryEnd);
const pasteIdString = pasteId.join(''),
clean = jsdom('', {url: common.urlToString(url)});
global.URL = require('jsdom-url').URL;
const result = $.PrivateBin.Model.getPasteId();
$.PrivateBin.Model.reset();
clean();
return pasteIdString === result;
@ -104,14 +103,9 @@ describe('Model', function () {
);
jsc.property(
'throws exception on empty query string',
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscA2zString()),
'string',
function (schema, address, fragment) {
var clean = jsdom('', {
url: schema.join('') + '://' + address.join('') +
'/#' + fragment
}),
common.jscUrl(true, false),
function (url) {
let clean = jsdom('', {url: common.urlToString(url)}),
result = false;
global.URL = require('jsdom-url').URL;
try {
@ -135,35 +129,24 @@ describe('Model', function () {
jsc.property(
'returns the fragment of a v1 URL',
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscQueryString()),
'nestring',
function (schema, address, query, fragment) {
const fragmentString = common.btoa(fragment.padStart(32, '\u0000'));
let clean = jsdom('', {
url: schema.join('') + '://' + address.join('') +
'/?' + query.join('') + '#' + fragmentString
}),
common.jscUrl(),
function (url) {
url.fragment = common.btoa(url.fragment.padStart(32, '\u0000'));
const clean = jsdom('', {url: common.urlToString(url)}),
result = $.PrivateBin.Model.getPasteKey();
$.PrivateBin.Model.reset();
clean();
return fragmentString === result;
return url.fragment === result;
}
);
jsc.property(
'returns the v1 fragment stripped of trailing query parts',
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscQueryString()),
'nestring',
common.jscUrl(),
jsc.array(common.jscHashString()),
function (schema, address, query, fragment, trail) {
const fragmentString = common.btoa(fragment.padStart(32, '\u0000'));
let clean = jsdom('', {
url: schema.join('') + '://' + address.join('') + '/?' +
query.join('') + '#' + fragmentString + '&' + trail.join('')
}),
function (url, trail) {
const fragmentString = common.btoa(url.fragment.padStart(32, '\u0000'));
url.fragment = fragmentString + '&' + trail.join('');
const clean = jsdom('', {url: common.urlToString(url)}),
result = $.PrivateBin.Model.getPasteKey();
$.PrivateBin.Model.reset();
clean();
@ -172,18 +155,12 @@ describe('Model', function () {
);
jsc.property(
'returns the fragment of a v2 URL',
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscQueryString()),
'nestring',
function (schema, address, query, fragment) {
common.jscUrl(),
function (url) {
// base58 strips leading NULL bytes, so the string is padded with these if not found
fragment = fragment.padStart(32, '\u0000');
let fragmentString = $.PrivateBin.CryptTool.base58encode(fragment),
clean = jsdom('', {
url: schema.join('') + '://' + address.join('') +
'/?' + query.join('') + '#' + fragmentString
}),
const fragment = url.fragment.padStart(32, '\u0000');
url.fragment = $.PrivateBin.CryptTool.base58encode(fragment);
const clean = jsdom('', {url: common.urlToString(url)}),
result = $.PrivateBin.Model.getPasteKey();
$.PrivateBin.Model.reset();
clean();
@ -192,19 +169,13 @@ describe('Model', function () {
);
jsc.property(
'returns the v2 fragment stripped of trailing query parts',
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscQueryString()),
'nestring',
common.jscUrl(),
jsc.array(common.jscHashString()),
function (schema, address, query, fragment, trail) {
function (url, trail) {
// base58 strips leading NULL bytes, so the string is padded with these if not found
fragment = fragment.padStart(32, '\u0000');
let fragmentString = $.PrivateBin.CryptTool.base58encode(fragment),
clean = jsdom('', {
url: schema.join('') + '://' + address.join('') + '/?' +
query.join('') + '#' + fragmentString + '&' + trail.join('')
}),
const fragment = url.fragment.padStart(32, '\u0000');
url.fragment = $.PrivateBin.CryptTool.base58encode(fragment) + '&' + trail.join('');
const clean = jsdom('', {url: common.urlToString(url)}),
result = $.PrivateBin.Model.getPasteKey();
$.PrivateBin.Model.reset();
clean();
@ -213,14 +184,9 @@ describe('Model', function () {
);
jsc.property(
'throws exception on empty fragment of the URL',
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscQueryString()),
function (schema, address, query) {
var clean = jsdom('', {
url: schema.join('') + '://' + address.join('') +
'/?' + query.join('')
}),
common.jscUrl(false),
function (url) {
let clean = jsdom('', {url: common.urlToString(url)}),
result = false;
try {
$.PrivateBin.Model.getPasteKey();

View File

@ -1,32 +1,39 @@
'use strict';
var common = require('../common');
function urlStrings(schema, longUrl, shortUrl) {
longUrl.schema = schema;
shortUrl.schema = schema;
let longUrlString = common.urlToString(longUrl),
shortUrlString = common.urlToString(shortUrl);
// ensure the two random URLs actually are sorted as expected
if (longUrlString.length <= shortUrlString.length) {
if (longUrlString.length === shortUrlString.length) {
longUrl.address.unshift('a');
longUrlString = common.urlToString(longUrl);
} else {
[longUrlString, shortUrlString] = [shortUrlString, longUrlString];
}
}
return [longUrlString, shortUrlString];
}
describe('PasteStatus', function () {
describe('createPasteNotification', function () {
this.timeout(30000);
jsc.property(
'creates a notification after a successfull paste upload',
common.jscSchemas(),
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscQueryString()),
'string',
common.jscSchemas(),
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscQueryString()),
function (
schema1, address1, query1, fragment1,
schema2, address2, query2
) {
var expected1 = schema1 + '://' + address1.join('') + '/?' +
encodeURI(query1.join('').replace(/^&+|&+$/gm,'') + '#' + fragment1),
expected2 = schema2 + '://' + address2.join('') + '/?' +
encodeURI(query2.join('').replace(/^&+|&+$/gm,'')),
common.jscUrl(),
common.jscUrl(false),
function (url1, url2) {
const expected1 = common.urlToString(url1).replace(/&(gt|lt)$/, '&$1a'),
expected2 = common.urlToString(url2).replace(/&(gt|lt)$/, '&$1a'),
clean = jsdom();
$('body').html('<div><div id="deletelink"></div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification(expected1, expected2);
var result1 = $('#pasteurl')[0].href,
const result1 = $('#pasteurl')[0].href,
result2 = $('#deletelink a')[0].href;
clean();
return result1 === expected1 && result2 === expected2;
@ -34,6 +41,138 @@ describe('PasteStatus', function () {
);
});
describe('extractUrl', function () {
this.timeout(30000);
jsc.property(
'extracts and updates IDN URLs found in given response',
common.jscSchemas(false),
'nestring',
common.jscUrl(),
function (schema, domain, url) {
domain = domain.replace(/\P{Letter}|[\u00AA-\u00BA]/gu, '').toLowerCase();
if (domain.length === 0) {
domain = 'a';
}
url.schema = schema;
url.address.unshift('.');
url.address = domain.split('').concat(url.address);
const urlString = common.urlToString(url),
expected = urlString.substring((schema + '://' + domain).length),
clean = jsdom();
$('body').html('<div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification('', '');
$.PrivateBin.PasteStatus.extractUrl(urlString);
const result = $('#pasteurl')[0].href;
clean();
return result.endsWith(expected) && (
result.startsWith(schema + '://xn--') ||
result.startsWith(schema + '://' + domain)
);
}
);
// YOURLS API samples from: https://yourls.org/readme.html#API;apireturn
jsc.property(
'extracts and updates URLs found in YOURLS API JSON response',
common.jscSchemas(false),
common.jscUrl(),
common.jscUrl(false),
function (schema, longUrl, shortUrl) {
const [longUrlString, shortUrlString] = urlStrings(schema, longUrl, shortUrl),
yourlsResponse = {
url: {
keyword: longUrl.address.join(''),
url: longUrlString,
title: "example title",
date: "2014-10-24 16:01:39",
ip: "127.0.0.1"
},
status: "success",
message: longUrlString + " added to database",
title: "example title",
shorturl: shortUrlString,
statusCode: 200
},
clean = jsdom();
$('body').html('<div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification('', '');
$.PrivateBin.PasteStatus.extractUrl(JSON.stringify(yourlsResponse, undefined, 4));
const result = $('#pasteurl')[0].href;
clean();
return result === shortUrlString;
}
);
jsc.property(
'extracts and updates URLs found in YOURLS API XML response',
common.jscSchemas(false),
common.jscUrl(),
common.jscUrl(false),
function (schema, longUrl, shortUrl) {
const [longUrlString, shortUrlString] = urlStrings(schema, longUrl, shortUrl),
yourlsResponse = '<result>\n' +
' <keyword>' + longUrl.address.join('') + '</keyword>\n' +
' <shorturl>' + shortUrlString + '</shorturl>\n' +
' <longurl>' + longUrlString + '</longurl>\n' +
' <message>success</message>\n' +
' <statusCode>200</statusCode>\n' +
'</result>',
clean = jsdom();
$('body').html('<div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification('', '');
$.PrivateBin.PasteStatus.extractUrl(yourlsResponse);
const result = $('#pasteurl')[0].href;
clean();
return result === shortUrlString;
}
);
jsc.property(
'extracts and updates URLs found in YOURLS proxy HTML response',
common.jscSchemas(false),
common.jscUrl(),
common.jscUrl(false),
function (schema, longUrl, shortUrl) {
const [longUrlString, shortUrlString] = urlStrings(schema, longUrl, shortUrl),
yourlsResponse = '<!DOCTYPE html>\n' +
'<html lang="en">\n' +
'\t<head>\n' +
'\t\t<meta charset="utf-8" />\n' +
'\t\t<meta http-equiv="Content-Security-Policy" content="default-src \'none\'; base-uri \'self\'; form-action \'none\'; manifest-src \'self\'; connect-src * blob:; script-src \'self\' \'unsafe-eval\'; style-src \'self\'; font-src \'self\'; frame-ancestors \'none\'; img-src \'self\' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-downloads">\n' +
'\t\t<meta name="robots" content="noindex" />\n' +
'\t\t<meta name="google" content="notranslate">\n' +
'\t\t<title>PrivateBin</title>\n' +
'\t</head>\n' +
'\t<body>\n' +
'\t\t<p>Your paste is <a id="pasteurl" href="' + shortUrlString + '">' + shortUrlString + '</a> <span id="copyhint">(Hit [Ctrl]+[c] to copy)</span></p>\n' +
'\t</body>\n' +
'</html>',
clean = jsdom();
$('body').html('<div><div id="pastelink"></div></div>');
$.PrivateBin.PasteStatus.init();
$.PrivateBin.PasteStatus.createPasteNotification('', '');
$.PrivateBin.PasteStatus.extractUrl(yourlsResponse);
const result = $('#pasteurl')[0].href;
clean();
return result === shortUrlString;
}
);
});
describe('showRemainingTime', function () {
this.timeout(30000);
@ -41,18 +180,9 @@ describe('PasteStatus', function () {
'shows burn after reading message or remaining time v1',
'bool',
'nat',
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscQueryString()),
'string',
function (
burnafterreading, remainingTime,
schema, address, query, fragment
) {
var clean = jsdom('', {
url: schema.join('') + '://' + address.join('') +
'/?' + query.join('') + '#' + fragment
}),
common.jscUrl(),
function (burnafterreading, remainingTime, url) {
let clean = jsdom('', {url: common.urlToString(url)}),
result;
$('body').html('<div id="remainingtime" class="hidden"></div>');
$.PrivateBin.PasteStatus.init();
@ -79,18 +209,9 @@ describe('PasteStatus', function () {
'shows burn after reading message or remaining time v2',
'bool',
'nat',
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscA2zString()),
jsc.nearray(common.jscQueryString()),
'string',
function (
burnafterreading, remainingTime,
schema, address, query, fragment
) {
var clean = jsdom('', {
url: schema.join('') + '://' + address.join('') +
'/?' + query.join('') + '#' + fragment
}),
common.jscUrl(),
function (burnafterreading, remainingTime, url) {
let clean = jsdom('', {url: common.urlToString(url)}),
result;
$('body').html('<div id="remainingtime" class="hidden"></div>');
$.PrivateBin.PasteStatus.init();

View File

@ -77,7 +77,7 @@ describe('TopNav', function () {
'<li id="attach" class="hidden">Attach a file</li><li>' +
'<a id="formatter" href="#" class="hidden">Format</a>' +
'</li><li><button id="sendbutton" type="button" ' +
'class="hidden">Send</button></li></ul></div></nav>'
'class="hidden">Create</button></li></ul></div></nav>'
);
$.PrivateBin.TopNav.init();
results.push(

View File

@ -13,10 +13,9 @@ describe('UiHelper', function () {
jsc.property(
'redirects to home, when the state is null',
common.jscSchemas(),
jsc.nearray(common.jscA2zString()),
function (schema, address) {
var expected = schema + '://' + address.join('') + '/',
common.jscUrl(false, false),
function (url) {
const expected = common.urlToString(url),
clean = jsdom('', {url: expected});
// make window.location.href writable
@ -34,13 +33,11 @@ describe('UiHelper', function () {
jsc.property(
'does not redirect to home, when a new paste is created',
common.jscSchemas(),
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscQueryString()),
common.jscUrl(false),
jsc.nearray(common.jscBase64String()),
function (schema, address, query, fragment) {
var expected = schema + '://' + address.join('') + '/?' +
query.join('') + '#' + fragment.join(''),
function (url, fragment) {
url.fragment = fragment.join('');
const expected = common.urlToString(url),
clean = jsdom('', {url: expected});
// make window.location.href writable
@ -67,15 +64,12 @@ describe('UiHelper', function () {
jsc.property(
'redirects to home',
common.jscSchemas(),
jsc.nearray(common.jscA2zString()),
jsc.array(common.jscQueryString()),
jsc.nearray(common.jscBase64String()),
function (schema, address, query, fragment) {
var expected = schema + '://' + address.join('') + '/',
clean = jsdom('', {
url: expected + '?' + query.join('') + '#' + fragment.join('')
});
common.jscUrl(),
function (url) {
const clean = jsdom('', {url: common.urlToString(url)});
delete(url.query);
delete(url.fragment);
const expected = common.urlToString(url);
// make window.location.href writable
Object.defineProperty(window.location, 'href', {

View File

@ -26,9 +26,9 @@
let buff;
if (typeof fs === 'object') {
buff = fs.readFileSync('zlib-1.2.13.wasm');
buff = fs.readFileSync('zlib-1.3.1.wasm');
} else {
const resp = await fetch('js/zlib-1.2.13.wasm');
const resp = await fetch('js/zlib-1.3.1.wasm');
buff = await resp.arrayBuffer();
}
const module = await WebAssembly.compile(buff);

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

View File

@ -7,7 +7,7 @@
* @link https://github.com/PrivateBin/PrivateBin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 1.6.1
* @version 1.7.1
*/
namespace PrivateBin;
@ -28,7 +28,7 @@ class Controller
*
* @const string
*/
const VERSION = '1.6.1';
const VERSION = '1.7.1';
/**
* minimal required PHP version
@ -111,10 +111,12 @@ class Controller
public function __construct()
{
if (version_compare(PHP_VERSION, self::MIN_PHP_VERSION) < 0) {
throw new Exception(I18n::_('%s requires php %s or above to work. Sorry.', I18n::_('PrivateBin'), self::MIN_PHP_VERSION), 1);
error_log(I18n::_('%s requires php %s or above to work. Sorry.', I18n::_('PrivateBin'), self::MIN_PHP_VERSION));
return;
}
if (strlen(PATH) < 0 && substr(PATH, -1) !== DIRECTORY_SEPARATOR) {
throw new Exception(I18n::_('%s requires the PATH to end in a "%s". Please update the PATH in your index.php.', I18n::_('PrivateBin'), DIRECTORY_SEPARATOR), 5);
error_log(I18n::_('%s requires the PATH to end in a "%s". Please update the PATH in your index.php.', I18n::_('PrivateBin'), DIRECTORY_SEPARATOR));
return;
}
// load config from ini file, initialize required classes
@ -141,6 +143,8 @@ class Controller
break;
}
$this->_setCacheHeaders();
// output JSON or HTML
if ($this->_request->isJsonApiCall()) {
header('Content-type: ' . Request::MIME_JSON);
@ -176,6 +180,22 @@ class Controller
}
}
/**
* Turn off browser caching
*
* @access private
*/
private function _setCacheHeaders()
{
// set headers to disable caching
$time = gmdate('D, d M Y H:i:s \G\M\T');
header('Cache-Control: no-store, no-cache, no-transform, must-revalidate');
header('Pragma: no-cache');
header('Expires: ' . $time);
header('Last-Modified: ' . $time);
header('Vary: Accept');
}
/**
* Store new paste or comment
*
@ -250,7 +270,14 @@ class Controller
}
// The user posts a standard paste.
else {
$this->_model->purge();
try {
$this->_model->purge();
} catch (Exception $e) {
error_log('Error purging pastes: ' . $e->getMessage() . PHP_EOL .
'Use the administration scripts statistics to find ' .
'damaged paste IDs and either delete them or restore them ' .
'from backup.');
}
$paste = $this->_model->getPaste();
try {
$paste->setData($data);
@ -334,13 +361,6 @@ class Controller
*/
private function _view()
{
// set headers to disable caching
$time = gmdate('D, d M Y H:i:s \G\M\T');
header('Cache-Control: no-store, no-cache, no-transform, must-revalidate');
header('Pragma: no-cache');
header('Expires: ' . $time);
header('Last-Modified: ' . $time);
header('Vary: Accept');
header('Content-Security-Policy: ' . $this->_conf->getKey('cspheader'));
header('Cross-Origin-Resource-Policy: same-origin');
header('Cross-Origin-Embedder-Policy: require-corp');

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

View File

@ -7,7 +7,7 @@
* @link https://github.com/PrivateBin/PrivateBin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 1.6.1
* @version 1.7.1
*/
namespace PrivateBin\Data;
@ -55,7 +55,6 @@ class Database extends AbstractData
* @access public
* @param array $options
* @throws Exception
* @return
*/
public function __construct(array $options)
{

View File

@ -7,12 +7,13 @@
* @link https://github.com/PrivateBin/PrivateBin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 1.6.1
* @version 1.7.1
*/
namespace PrivateBin\Data;
use Exception;
use GlobIterator;
use PrivateBin\Json;
/**
@ -65,7 +66,6 @@ class Filesystem extends AbstractData
*
* @access public
* @param array $options
* @return
*/
public function __construct(array $options)
{
@ -394,7 +394,7 @@ class Filesystem extends AbstractData
public function getAllPastes()
{
$pastes = array();
foreach (new \GlobIterator($this->_path . self::PASTE_FILE_PATTERN) as $file) {
foreach (new GlobIterator($this->_path . self::PASTE_FILE_PATTERN) as $file) {
if ($file->isFile()) {
$pastes[] = $file->getBasename('.php');
}

View File

@ -47,7 +47,6 @@ class GoogleCloudStorage extends AbstractData
*
* @access public
* @param array $options
* @return
*/
public function __construct(array $options)
{

View File

@ -4,7 +4,7 @@
*
* an S3 compatible data backend for PrivateBin with CEPH/RadosGW in mind
* see https://docs.ceph.com/en/latest/radosgw/s3/php/
* based on lib/Data/GoogleCloudStorage.php from PrivateBin version 1.6.1
* based on lib/Data/GoogleCloudStorage.php from PrivateBin version 1.7.1
*
* @link https://github.com/PrivateBin/PrivateBin
* @copyright 2022 Felix J. Ogris (https://ogris.de/)
@ -78,7 +78,6 @@ class S3Storage extends AbstractData
*
* @access public
* @param array $options
* @return
*/
public function __construct(array $options)
{

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

View File

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

View File

@ -7,11 +7,14 @@
* @link https://github.com/PrivateBin/PrivateBin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 1.6.1
* @version 1.7.1
*/
namespace PrivateBin;
use AppendIterator;
use GlobIterator;
/**
* I18n
*
@ -78,11 +81,11 @@ class I18n
*
* @access public
* @static
* @param string $messageId
* @param string|array $messageId
* @param mixed $args one or multiple parameters injected into placeholders
* @return string
*/
public static function _($messageId)
public static function _($messageId, ...$args)
{
return forward_static_call_array('PrivateBin\I18n::translate', func_get_args());
}
@ -92,16 +95,16 @@ class I18n
*
* @access public
* @static
* @param string $messageId
* @param string|array $messageId
* @param mixed $args one or multiple parameters injected into placeholders
* @return string
*/
public static function translate($messageId)
public static function translate($messageId, ...$args)
{
if (empty($messageId)) {
return $messageId;
}
if (count(self::$_translations) === 0) {
if (empty(self::$_translations)) {
self::loadTranslations();
}
$messages = $messageId;
@ -111,7 +114,7 @@ class I18n
if (!array_key_exists($messageId, self::$_translations)) {
self::$_translations[$messageId] = $messages;
}
$args = func_get_args();
array_unshift($args, $messageId);
if (is_array(self::$_translations[$messageId])) {
$number = (int) $args[1];
$key = self::_getPluralForm($number);
@ -127,11 +130,9 @@ class I18n
}
// encode any non-integer arguments and the message ID, if it doesn't contain a link
$argsCount = count($args);
if ($argsCount > 1) {
for ($i = 0; $i < $argsCount; ++$i) {
if (($i > 0 && !is_int($args[$i])) || strpos($args[0], '<a') === false) {
$args[$i] = self::encode($args[$i]);
}
for ($i = 0; $i < $argsCount; ++$i) {
if ($i > 0 ? !is_int($args[$i]) : strpos($args[0], '<a') === false) {
$args[$i] = self::encode($args[$i]);
}
}
return call_user_func_array('sprintf', $args);
@ -193,10 +194,14 @@ class I18n
public static function getAvailableLanguages()
{
if (count(self::$_availableLanguages) == 0) {
$i18n = dir(self::_getPath());
while (false !== ($file = $i18n->read())) {
if (preg_match('/^([a-z]{2,3}).json$/', $file, $match) === 1) {
self::$_availableLanguages[] = $match[1];
self::$_availableLanguages[] = 'en'; // en.json is not part of the release archive
$languageIterator = new AppendIterator();
$languageIterator->append(new GlobIterator(self::_getPath('??.json')));
$languageIterator->append(new GlobIterator(self::_getPath('???.json'))); // for jbo
foreach ($languageIterator as $file) {
$language = $file->getBasename('.json');
if ($language != 'en') {
self::$_availableLanguages[] = $language;
}
}
}
@ -308,10 +313,10 @@ class I18n
*/
protected static function _getPath($file = '')
{
if (strlen(self::$_path) == 0) {
if (empty(self::$_path)) {
self::$_path = PUBLIC_PATH . DIRECTORY_SEPARATOR . 'i18n';
}
return self::$_path . (strlen($file) ? DIRECTORY_SEPARATOR . $file : '');
return self::$_path . (empty($file) ? '' : DIRECTORY_SEPARATOR . $file);
}
/**
@ -349,6 +354,8 @@ class I18n
return $n % 10 === 1 && $n % 100 !== 11 ? 0 : (($n % 10 >= 2 && $n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
case 'pl':
return $n === 1 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);
case 'ro':
return $n === 1 ? 0 : (($n === 0 || ($n % 100 > 0 && $n % 100 < 20)) ? 1 : 2);
case 'ru':
case 'uk':
return $n % 10 === 1 && $n % 100 != 11 ? 0 : ($n % 10 >= 2 && $n % 10 <= 4 && ($n % 100 < 10 || $n % 100 >= 20) ? 1 : 2);

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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.6.1
* @version 1.7.1
*/
namespace PrivateBin;
@ -143,7 +143,7 @@ class Request
} elseif (array_key_exists('jsonld', $this->_params) && !empty($this->_params['jsonld'])) {
$this->_operation = 'jsonld';
} elseif (array_key_exists('link', $this->_params) && !empty($this->_params['link'])) {
if (strpos($this->getRequestUri(), '/shortenviayourls') !== false) {
if (strpos($this->getRequestUri(), '/shortenviayourls') !== false || array_key_exists('shortenviayourls', $this->_params)) {
$this->_operation = 'yourlsproxy';
}
}

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

View File

@ -8,7 +8,7 @@
* @link https://sebsauvage.net/wiki/doku.php?id=php:vizhash_gd
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
* @version 0.0.5 beta PrivateBin 1.6.1
* @version 0.0.5 beta PrivateBin 1.7.1
*/
namespace PrivateBin;

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

View File

@ -55,7 +55,7 @@ if ($ZEROBINCOMPATIBILITY) :
<?php
endif;
?>
<script type="text/javascript" data-cfasync="false" src="js/zlib-1.2.13.js" integrity="sha512-Ltu/5qZMapdRIy4B3/iuLessSK6CvAui1C8txOX0z/uAFDJXXSwjvHsiFg9peQ2Gg/ga2tneKBfS0+00ndFsjQ==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/zlib-1.3.1.js" integrity="sha512-Z90oppVx/mn0DG2k9airjFVQuliELlXLeT3SRiO6MLiUSbhGlAq+UFwmYbG4i9mwW87dkG8fgJPapGwnUq7Osg==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/base-x-4.0.0.js" integrity="sha512-nNPg5IGCwwrveZ8cA/yMGr5HiRS5Ps2H+s0J/mKTPjCPWUgFGGw7M5nqdnPD3VsRwCVysUh3Y8OWjeSKGkEQJQ==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/rawinflate-0.3.js" integrity="sha512-g8uelGgJW9A/Z1tB6Izxab++oj5kdD7B4qC7DHwZkB6DGMXKyzx7v5mvap2HXueI2IIn08YlRYM56jwWdm2ucQ==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/bootstrap-3.4.1.js" integrity="sha512-oBTprMeNEKCnqfuqKd6sbvFzmFQtlXS3e0C/RGFV0hD6QzhHV+ODfaQbAlmY6/q0ubbwlAM/nCJjkrgA3waLzg==" crossorigin="anonymous"></script>
@ -71,9 +71,9 @@ if ($MARKDOWN) :
<?php
endif;
?>
<script type="text/javascript" data-cfasync="false" src="js/purify-3.0.6.js" integrity="sha512-N3y6/HOk3pbsw3lFh4O8CKKEVwu1B2CF8kinhjURf8Yqa5OfSUt+/arozxFW+TUPOPw3TsDCRT/0u7BGRTEVUw==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/purify-3.0.8.js" integrity="sha512-wWBDKh5wYGtJ1Df+PPZIn59jHVBnJ4/Yb2W/pVnzaXab8cmlZnHVx+FEBGu5JX39s3P2Qlt+aNQou0XnjW86hg==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LYos+qXHIRqFf5ZPNphvtTB0cgzHUizu2wwcOwcwz/VIpRv9lpcBgPYz4uq6jx0INwCAj6Fbnl5HoKiLufS2jg==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-Vhf93RhPJlAbV7jV1kizBzCDsx2xTrvneXe+9vdz6Ceg8wSfVZPzC6HWNdTWQLJIatlSVxd36rTra9M1uj5c+g==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-B5PWlo7wh39YRHm8rkP5KUyJkoBgL1/TY7ldx6d041+L20/0QLuCN3V2FUK0BpvOUl1CRb7IHbnS80HFMoGFrg==" crossorigin="anonymous"></script>
<!-- icon -->
<link rel="apple-touch-icon" href="<?php echo I18n::encode($BASEPATH); ?>img/apple-touch-icon.png" sizes="180x180" />
<link rel="icon" type="image/png" href="img/favicon-32x32.png" sizes="32x32" />
@ -123,22 +123,32 @@ if (count($class)) {
</div>
</div>
</div>
<div id="loadconfirmmodal" tabindex="-1" class="modal fade" role="dialog" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="<?php echo I18n::_('Close') ?>"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><?php echo I18n::_('Burn after reading pastes can only be displayed once upon loading it. Do you want to open it now?') ?></h4>
</div>
<div class="modal-body text-center">
<button id="loadconfirm-open-now" type="button" class="btn btn-success" data-dismiss="modal"><span class="glyphicon glyphicon-download"></span> <?php echo I18n::_('Yes, load it') ?></button>
</div>
</div>
</div>
</div>
<?php
if ($QRCODE) :
?>
<div id="qrcodemodal" tabindex="-1" class="modal fade" aria-labelledby="qrcodemodalTitle" role="dialog" aria-hidden="true">
<div id="qrcodemodal" tabindex="-1" class="modal fade" role="dialog" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="<?php echo I18n::_('Close') ?>"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><?php echo I18n::_('QR code') ?></h4>
</div>
<div class="modal-body">
<div class="mx-auto" id="qrcode-display"></div>
</div>
<div class="row">
<div class="btn-group col-xs-12">
<span class="col-xs-12">
<button type="button" class="btn btn-primary btn-block" data-dismiss="modal"><?php echo I18n::_('Close') ?></button>
</span>
</div>
</div>
</div>
</div>
</div>
@ -146,23 +156,19 @@ if ($QRCODE) :
endif;
if ($EMAIL) :
?>
<div id="emailconfirmmodal" tabindex="-1" class="modal fade" aria-labelledby="emailconfirmmodalTitle" role="dialog" aria-hidden="true">
<div id="emailconfirmmodal" tabindex="-1" class="modal fade" role="dialog" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-body">
<div id="emailconfirm-display"></div>
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="<?php echo I18n::_('Close') ?>"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><?php echo I18n::_('Recipient may become aware of your timezone, convert time to UTC?') ?></h4>
</div>
<div class="row">
<div class="btn-group col-xs-12" data-toggle="buttons">
<span class="col-xs-12 col-md-4">
<button id="emailconfirm-timezone-current" type="button" class="btn btn-danger btn-block" data-dismiss="modal"><?php echo I18n::_('Use Current Timezone') ?></button>
</span>
<span class="col-xs-12 col-md-4">
<button id="emailconfirm-timezone-utc" type="button" class="btn btn-default btn-block" data-dismiss="modal"><?php echo I18n::_('Convert To UTC') ?></button>
</span>
<span class="col-xs-12 col-md-4">
<button type="button" class="btn btn-primary btn-block" data-dismiss="modal"><?php echo I18n::_('Close') ?></button>
</span>
<div class="modal-body row">
<div class="col-xs-12 col-md-6">
<button id="emailconfirm-timezone-current" type="button" class="btn btn-danger"><span class="glyphicon glyphicon-time"></span> <?php echo I18n::_('Use Current Timezone') ?></button>
</div>
<div class="col-xs-12 col-md-6 text-right">
<button id="emailconfirm-timezone-utc" type="button" class="btn btn-success"><span class="glyphicon glyphicon-globe"></span> <?php echo I18n::_('Convert To UTC') ?></button>
</div>
</div>
</div>
@ -203,7 +209,7 @@ endif;
if ($isPage) :
?>
<button id="sendbutton" type="button" class="hidden btn btn-<?php echo $isDark ? 'warning' : 'primary'; ?> navbar-btn">
<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?php echo I18n::_('Send'), PHP_EOL;
<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?php echo I18n::_('Create'), PHP_EOL;
else :
?>
<button id="newbutton" type="button" class="hidden btn btn-<?php echo $isDark ? 'warning' : 'default'; ?> navbar-btn">
@ -555,7 +561,7 @@ if ($isPage) :
else :
?>
<button id="sendbutton" type="button" class="hidden btn btn-<?php echo $isDark ? 'warning' : 'primary'; ?>">
<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?php echo I18n::_('Send'), PHP_EOL;
<span class="glyphicon glyphicon-upload" aria-hidden="true"></span> <?php echo I18n::_('Create'), PHP_EOL;
endif;
?>
</button>

View File

@ -34,7 +34,7 @@ if ($ZEROBINCOMPATIBILITY):
<?php
endif;
?>
<script type="text/javascript" data-cfasync="false" src="js/zlib-1.2.13.js" integrity="sha512-Ltu/5qZMapdRIy4B3/iuLessSK6CvAui1C8txOX0z/uAFDJXXSwjvHsiFg9peQ2Gg/ga2tneKBfS0+00ndFsjQ==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/zlib-1.3.1.js" integrity="sha512-Z90oppVx/mn0DG2k9airjFVQuliELlXLeT3SRiO6MLiUSbhGlAq+UFwmYbG4i9mwW87dkG8fgJPapGwnUq7Osg==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/base-x-4.0.0.js" integrity="sha512-nNPg5IGCwwrveZ8cA/yMGr5HiRS5Ps2H+s0J/mKTPjCPWUgFGGw7M5nqdnPD3VsRwCVysUh3Y8OWjeSKGkEQJQ==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/rawinflate-0.3.js" integrity="sha512-g8uelGgJW9A/Z1tB6Izxab++oj5kdD7B4qC7DHwZkB6DGMXKyzx7v5mvap2HXueI2IIn08YlRYM56jwWdm2ucQ==" crossorigin="anonymous"></script>
<?php
@ -49,9 +49,9 @@ if ($MARKDOWN):
<?php
endif;
?>
<script type="text/javascript" data-cfasync="false" src="js/purify-3.0.6.js" integrity="sha512-N3y6/HOk3pbsw3lFh4O8CKKEVwu1B2CF8kinhjURf8Yqa5OfSUt+/arozxFW+TUPOPw3TsDCRT/0u7BGRTEVUw==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/purify-3.0.8.js" integrity="sha512-wWBDKh5wYGtJ1Df+PPZIn59jHVBnJ4/Yb2W/pVnzaXab8cmlZnHVx+FEBGu5JX39s3P2Qlt+aNQou0XnjW86hg==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/legacy.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-LYos+qXHIRqFf5ZPNphvtTB0cgzHUizu2wwcOwcwz/VIpRv9lpcBgPYz4uq6jx0INwCAj6Fbnl5HoKiLufS2jg==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-Vhf93RhPJlAbV7jV1kizBzCDsx2xTrvneXe+9vdz6Ceg8wSfVZPzC6HWNdTWQLJIatlSVxd36rTra9M1uj5c+g==" crossorigin="anonymous"></script>
<script type="text/javascript" data-cfasync="false" src="js/privatebin.js?<?php echo rawurlencode($VERSION); ?>" integrity="sha512-B5PWlo7wh39YRHm8rkP5KUyJkoBgL1/TY7ldx6d041+L20/0QLuCN3V2FUK0BpvOUl1CRb7IHbnS80HFMoGFrg==" crossorigin="anonymous"></script>
<!-- icon -->
<link rel="apple-touch-icon" href="img/apple-touch-icon.png?<?php echo rawurlencode($VERSION); ?>" sizes="180x180" />
<link rel="icon" type="image/png" href="img/favicon-32x32.png?<?php echo rawurlencode($VERSION); ?>" sizes="32x32" />
@ -125,7 +125,7 @@ endif;
<div id="toolbar">
<button id="newbutton" class="reloadlink hidden"><img src="img/icon_new.png" width="11" height="15" alt="" /><?php echo I18n::_('New'); ?></button>
<button id="retrybutton" class="reloadlink hidden"><?php echo I18n::_('Retry'), PHP_EOL; ?></button>
<button id="sendbutton" class="hidden"><img src="img/icon_send.png" width="18" height="15" alt="" /><?php echo I18n::_('Send'); ?></button>
<button id="sendbutton" class="hidden"><img src="img/icon_send.png" width="18" height="15" alt="" /><?php echo I18n::_('Create'); ?></button>
<button id="clonebutton" class="hidden"><img src="img/icon_clone.png" width="15" height="17" alt="" /><?php echo I18n::_('Clone'); ?></button>
<button id="rawtextbutton" class="hidden"><img src="img/icon_raw.png" width="15" height="15" alt="" /><?php echo I18n::_('Raw text'); ?></button>
<button id="downloadtextbutton" class="hidden"><?php echo I18n::_('Save paste'), PHP_EOL; ?></button>

View File

@ -3,6 +3,24 @@
use PHPUnit\Framework\TestCase;
use PrivateBin\I18n;
class I18nMock extends I18n
{
public static function resetAvailableLanguages()
{
self::$_availableLanguages = array();
}
public static function resetPath($path = '')
{
self::$_path = $path;
}
public static function getPath($file = '')
{
return self::_getPath($file);
}
}
class I18nTest extends TestCase
{
private $_translations = array();
@ -167,6 +185,38 @@ class I18nTest extends TestCase
$this->assertEquals($result . $result, I18n::_($input . '%s', $input), 'encodes message ID as well, when no link');
}
public function testFallbackAlwaysPresent()
{
$path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_i18n';
if (!is_dir($path)) {
mkdir($path);
}
$languageIterator = new AppendIterator();
$languageIterator->append(new GlobIterator(I18nMock::getPath('??.json')));
$languageIterator->append(new GlobIterator(I18nMock::getPath('???.json'))); // for jbo
$languageCount = 0;
foreach ($languageIterator as $file) {
++$languageCount;
$this->assertTrue(copy($file, $path . DIRECTORY_SEPARATOR . $file->getBasename()));
}
I18nMock::resetPath($path);
$languagesDevelopment = I18nMock::getAvailableLanguages();
$this->assertEquals($languageCount, count($languagesDevelopment), 'all copied languages detected');
$this->assertTrue(in_array('en', $languagesDevelopment), 'English fallback present');
unlink($path . DIRECTORY_SEPARATOR . 'en.json');
I18nMock::resetAvailableLanguages();
$languagesDeployed = I18nMock::getAvailableLanguages();
$this->assertEquals($languageCount, count($languagesDeployed), 'all copied languages detected, plus fallback');
$this->assertTrue(in_array('en', $languagesDeployed), 'English fallback still present');
I18nMock::resetAvailableLanguages();
I18nMock::resetPath();
Helper::rmDir($path);
}
public function testMessageIdsExistInAllLanguages()
{
$messageIds = array();

View File

@ -285,26 +285,39 @@ class JsonApiTest extends TestCase
/**
* @runInSeparateProcess
* @dataProvider baseUriProvider
*/
public function testShortenViaYourls()
public function testShortenViaYourls($baseUri)
{
$mock_yourls_service = $this->_path . DIRECTORY_SEPARATOR . 'yourls.json';
$options = parse_ini_file(CONF, true);
$options['main']['basepath'] = 'https://example.com/path'; // missing slash gets added by Configuration constructor
$options['main']['urlshortener'] = 'https://example.com/path/shortenviayourls?link=';
$options['main']['urlshortener'] = 'https://example.com' . $baseUri . 'link=';
$options['yourls']['apiurl'] = $mock_yourls_service;
Helper::createIniFile(CONF, $options);
// the real service answer is more complex, but we only look for the shorturl & statusCode
file_put_contents($mock_yourls_service, '{"shorturl":"https:\/\/example.com\/1","statusCode":200}');
$_SERVER['REQUEST_URI'] = '/path/shortenviayourls?link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar';
$_SERVER['REQUEST_URI'] = $baseUri . 'link=https%3A%2F%2Fexample.com%2Fpath%2F%3Ffoo%23bar';
$_GET['link'] = 'https://example.com/path/?foo#bar';
if (strpos($baseUri, '?shortenviayourls') !== false) {
$_GET['shortenviayourls'] = null;
}
ob_start();
new Controller;
$content = ob_get_contents();
ob_end_clean();
$this->assertStringContainsString('id="pasteurl" href="https://example.com/1"', $content, 'outputs shortened URL correctly');
$this->assertStringContainsString('id="pasteurl" href="https://example.com/1"', $content, "'{$baseUri}' outputs shortened URL correctly");
}
public function baseUriProvider()
{
return array(
array('/path/shortenviayourls?'),
array('/path/index.php/shortenviayourls?'),
array('/path?shortenviayourls&'),
);
}
/**