Compare commits

..

261 commits

Author SHA1 Message Date
El RIDO
c1050e08e8
Merge pull request #1596 from zertrin/1554-add-error-logging
Added some more error logging for database and filesystem store backends
2025-07-17 06:44:46 +02:00
zertrin
7e4d9eb535 Updated changelog 2025-07-17 04:28:55 +00:00
zertrin
330855f58d Added some more error logging for database and filesystem store backends
This is to address issue #1554
2025-07-16 15:50:41 +00:00
El RIDO
80d8c8d831
Merge pull request #1592 from PrivateBin/jdenticons-default
switch to Jdenticons as the default icon generator
2025-07-15 12:44:27 +02:00
El RIDO
13869e46be
updating jdenticon library to 2.0.0, minimum PHP version 7.4 2025-07-14 22:01:11 +02:00
El RIDO
3ba29ea29e
Merge branch 'master' into jdenticons-default 2025-07-14 21:42:23 +02:00
El RIDO
f8a1affcfa
Merge pull request #1595 from touchweb-vincent/master
ModSecurity2 – JSON Body Processor Compliance
2025-07-08 18:29:30 +02:00
TW - Vincent
778a7dec71
Mod_security2 BodyProcessor json compliance 2025-07-08 13:44:48 +02:00
TW - Vincent
ce025cf884
Mod_security2 BodyProcessor json compliance 2025-07-08 13:43:46 +02:00
El RIDO
55ed70eca6
Merge pull request #1594 from AnonymousWP/chore(translation)-update-Dutch-translation
chore(translation): fix Dutch translation for 'Theme'
2025-07-07 17:12:52 +02:00
Anonymoussaurus
5e78be8778
chore(translation): fix Dutch translation for 'Theme' 2025-07-07 17:01:11 +02:00
El RIDO
811b62b538
workaround PHP 8.4 deprecations
lifted from https://github.com/dmester/jdenticon-php/pull/10
2025-07-05 20:09:43 +02:00
El RIDO
7b444bf62b
update test to use a Jdenticon 2025-07-05 19:40:37 +02:00
El RIDO
2f3fe1a479
Revert "update test to use a Jdenticon"
This reverts commit 12de19444d.

Sorry, this should have gotten committed on a different branch.
2025-07-05 19:36:21 +02:00
El RIDO
12de19444d
update test to use a Jdenticon 2025-07-05 19:27:39 +02:00
El RIDO
07caf3ff64
switch to Jdenticons as the default icon generator 2025-07-05 11:30:16 +02:00
El RIDO
03e0c81fbf
Merge pull request #1590 from Ribas160/adding_attachments_from_clipboard
Adding attachments from clipboard
2025-07-04 18:45:16 +02:00
Ribas160
71db94ccfd CHANGELOG.md updated 2025-07-04 18:27:52 +03:00
Ribas160
38955754f3 Fixed hightlight file upload on bootstrap5 template 2025-07-04 18:18:00 +03:00
Ribas160
0ce8627561 Fixed adding attachments from clipboard 2025-07-04 18:15:28 +03:00
El RIDO
e38b88c12c
Merge pull request #1587 from Ribas160/remove_page_template
Remove page template
2025-07-04 06:57:03 +02:00
Ribas160
99cee27a6d Merge branch 'master' into remove_page_template
# Conflicts:
#	CHANGELOG.md
#	lib/Configuration.php
2025-07-03 13:14:52 +03:00
Ribas160
692e7af196 - window.confirm fallbacks for page template removed
- page template removed from configuration-test-generator
2025-07-03 13:13:42 +03:00
El RIDO
9d6f105ccf
Merge pull request #1586 from Ribas160/name_mismatches_in_attached_files
Name mismatches in attached files fixed
2025-07-03 00:02:15 +02:00
Ribas160
3d3d80c60b Remove page template 2025-07-02 17:38:13 +03:00
Ribas160
9e7fce3792 CHANGELOG.md update 2025-07-02 16:21:50 +03:00
Ribas160
c4e381f523 Name mismatches in attached files fixed 2025-07-02 16:13:38 +03:00
El RIDO
0178bbc075
Merge pull request #1582 from StargazerCel/master
Fixed a Typo in Running Unit Tests.md #HSFDPMUW
2025-07-01 13:25:13 +02:00
Cél
8b204192e9
Fixed a Typo in Running Unit Tests.md #HSFDPMUW
Fixed a typo for a command. 
I need to add this hashtag at the end because I am contributing in a project at my university.
2025-07-01 13:02:45 +02:00
El RIDO
71cce1f4f2
Merge pull request #1581 from PrivateBin/crowdin-translation
New Crowdin updates
2025-07-01 12:49:50 +02:00
PrivateBin Translator Bot
c7f4616074 New translations en.json (Thai) 2025-07-01 07:33:51 +02:00
El RIDO
321b471b71
chore: prepare for next release 2025-06-30 11:02:10 +02:00
El RIDO
d5cd6741c5
incrementing version 2025-06-30 10:56:53 +02:00
El RIDO
1842d356e5
Merge pull request #1579 from Ribas160/page_template_scripts_load_order
Page template scripts loading order fix
2025-06-30 09:57:56 +02:00
Ribas160
207b5ccc5f Page template scripts loading order fix 2025-06-30 09:46:05 +03:00
El RIDO
ce2942a370
Merge pull request #1577 from Ribas160/attachment_bugs_fixes
Attachment bugs fixes
2025-06-30 07:03:17 +02:00
Ribas160
fa662547fe Attachments with empty file name fix 2025-06-29 21:30:11 +03:00
Ribas160
fcce915a5f Duplicate attachment for every comment fix 2025-06-29 21:27:11 +03:00
El RIDO
f282043b9e
Merge pull request #1573 from PrivateBin/crowdin-translation
New Crowdin updates
2025-06-29 20:24:22 +02:00
PrivateBin Translator Bot
3d1b6d2666 New translations en.json (Corsican) 2025-06-29 12:45:45 +02:00
El RIDO
78dd0e2d8e
chore: prepare for next release 2025-06-28 22:50:16 +02:00
El RIDO
20e30b6637
incrementing version 2025-06-28 21:23:37 +02:00
El RIDO
6929a6eb76
Merge pull request #1570 from PrivateBin/crowdin-translation
New Crowdin updates
2025-06-28 21:14:21 +02:00
PrivateBin Translator Bot
7f9d29b13f New translations en.json (French) 2025-06-28 17:18:26 +02:00
El RIDO
989a49852e
Merge pull request #1567 from PrivateBin/crowdin-translation
New Crowdin updates
2025-06-28 17:11:32 +02:00
El RIDO
d8efd4cd2a
Merge branch 'master' into crowdin-translation 2025-06-28 17:07:22 +02:00
El RIDO
541426b400
Merge branch 'master' into crowdin-translation 2025-06-28 17:01:45 +02:00
PrivateBin Translator Bot
4a4cbf1455 New translations en.json (Corsican) 2025-06-28 16:17:54 +02:00
PrivateBin Translator Bot
f68d3cc89c New translations en.json (Occitan) 2025-06-28 16:17:53 +02:00
PrivateBin Translator Bot
b8ee73eacf New translations en.json (Latin) 2025-06-28 16:17:52 +02:00
PrivateBin Translator Bot
b03ca0cdd5 New translations en.json (Lojban) 2025-06-28 16:17:51 +02:00
PrivateBin Translator Bot
1d4c206a7e New translations en.json (Hindi) 2025-06-28 16:17:50 +02:00
PrivateBin Translator Bot
eac1824cb5 New translations en.json (Estonian) 2025-06-28 16:17:49 +02:00
PrivateBin Translator Bot
4df7684ee5 New translations en.json (Thai) 2025-06-28 16:17:48 +02:00
PrivateBin Translator Bot
1a4ac8cd9b New translations en.json (Indonesian) 2025-06-28 16:17:47 +02:00
PrivateBin Translator Bot
8b66002521 New translations en.json (Chinese Simplified) 2025-06-28 16:17:46 +02:00
PrivateBin Translator Bot
4162d0f6c9 New translations en.json (Ukrainian) 2025-06-28 16:17:45 +02:00
PrivateBin Translator Bot
09682de11e New translations en.json (Turkish) 2025-06-28 16:17:44 +02:00
PrivateBin Translator Bot
9437486b10 New translations en.json (Swedish) 2025-06-28 16:17:43 +02:00
PrivateBin Translator Bot
5c33ee094f New translations en.json (Slovenian) 2025-06-28 16:17:42 +02:00
PrivateBin Translator Bot
21d94668a1 New translations en.json (Slovak) 2025-06-28 16:17:41 +02:00
PrivateBin Translator Bot
1285fa935f New translations en.json (Russian) 2025-06-28 16:17:40 +02:00
PrivateBin Translator Bot
12832c05cc New translations en.json (Portuguese) 2025-06-28 16:17:40 +02:00
PrivateBin Translator Bot
8823f30881 New translations en.json (Polish) 2025-06-28 16:17:39 +02:00
PrivateBin Translator Bot
241bcc6d2d New translations en.json (Norwegian) 2025-06-28 16:17:38 +02:00
PrivateBin Translator Bot
e02eb6f56f New translations en.json (Dutch) 2025-06-28 16:17:37 +02:00
PrivateBin Translator Bot
8c318658f8 New translations en.json (Lithuanian) 2025-06-28 16:17:36 +02:00
PrivateBin Translator Bot
ad5d5716c7 New translations en.json (Kurdish) 2025-06-28 16:17:35 +02:00
PrivateBin Translator Bot
a42a5d467e New translations en.json (Korean) 2025-06-28 16:17:34 +02:00
PrivateBin Translator Bot
b893e7c2b5 New translations en.json (Japanese) 2025-06-28 16:17:33 +02:00
PrivateBin Translator Bot
66d0b92ea1 New translations en.json (Italian) 2025-06-28 16:17:32 +02:00
PrivateBin Translator Bot
0da6613cbb New translations en.json (Hungarian) 2025-06-28 16:17:31 +02:00
PrivateBin Translator Bot
6a05598c9b New translations en.json (Hebrew) 2025-06-28 16:17:30 +02:00
PrivateBin Translator Bot
fff9ab3e13 New translations en.json (Finnish) 2025-06-28 16:17:29 +02:00
PrivateBin Translator Bot
03e2b4f4ba New translations en.json (Greek) 2025-06-28 16:17:28 +02:00
PrivateBin Translator Bot
1042a650ec New translations en.json (German) 2025-06-28 16:17:27 +02:00
PrivateBin Translator Bot
1eb694ea27 New translations en.json (Czech) 2025-06-28 16:17:26 +02:00
PrivateBin Translator Bot
32da95dafd New translations en.json (Catalan) 2025-06-28 16:17:25 +02:00
PrivateBin Translator Bot
ac894404c0 New translations en.json (Bulgarian) 2025-06-28 16:17:25 +02:00
PrivateBin Translator Bot
d6ef7a9dc3 New translations en.json (Spanish) 2025-06-28 16:17:23 +02:00
PrivateBin Translator Bot
c2a6f8fddb New translations en.json (French) 2025-06-28 16:17:22 +02:00
PrivateBin Translator Bot
dfed599409 New translations en.json (Romanian) 2025-06-28 16:17:21 +02:00
PrivateBin Translator Bot
f9117ca483 New translations en.json (Arabic) 2025-06-28 16:17:21 +02:00
El RIDO
fb75637dd0
Merge pull request #1568 from PrivateBin/si-unit-kB-spelling
lowercase SI-unit prefix for kilo
2025-06-28 15:33:17 +02:00
PrivateBin Translator Bot
dd99cad66c New translations en.json (Corsican) 2025-06-28 15:07:45 +02:00
PrivateBin Translator Bot
384ea22ba6 New translations en.json (Occitan) 2025-06-28 15:07:44 +02:00
PrivateBin Translator Bot
83a7ad6538 New translations en.json (Ukrainian) 2025-06-28 15:07:43 +02:00
PrivateBin Translator Bot
e409ad6880 New translations en.json (Russian) 2025-06-28 15:07:42 +02:00
PrivateBin Translator Bot
4d38551c08 New translations en.json (French) 2025-06-28 15:07:41 +02:00
PrivateBin Translator Bot
0e42ccdb6b New translations en.json (Arabic) 2025-06-28 15:07:40 +02:00
El RIDO
c35729e23e
lowercase SI-unit prefix for kilo
SI-unit prefix for kilo is small k to distinguish from unit K for Kelvin
2025-06-28 14:47:26 +02:00
PrivateBin Translator Bot
72da9970cd New translations en.json (Corsican) 2025-06-28 14:10:05 +02:00
PrivateBin Translator Bot
1e4d3990b4 New translations en.json (Occitan) 2025-06-28 14:10:04 +02:00
PrivateBin Translator Bot
8180f538c5 New translations en.json (Latin) 2025-06-28 14:10:03 +02:00
PrivateBin Translator Bot
a2a88f7c3e New translations en.json (Lojban) 2025-06-28 14:10:02 +02:00
PrivateBin Translator Bot
427f03e779 New translations en.json (Hindi) 2025-06-28 14:10:01 +02:00
PrivateBin Translator Bot
800ebcc616 New translations en.json (Estonian) 2025-06-28 14:10:00 +02:00
PrivateBin Translator Bot
4151a459ab New translations en.json (Thai) 2025-06-28 14:09:59 +02:00
PrivateBin Translator Bot
d6fe310ded New translations en.json (Indonesian) 2025-06-28 14:09:58 +02:00
PrivateBin Translator Bot
8076649965 New translations en.json (Chinese Simplified) 2025-06-28 14:09:57 +02:00
PrivateBin Translator Bot
d22b9302b1 New translations en.json (Ukrainian) 2025-06-28 14:09:56 +02:00
PrivateBin Translator Bot
a10fb589ca New translations en.json (Turkish) 2025-06-28 14:09:55 +02:00
PrivateBin Translator Bot
f1c4b79652 New translations en.json (Swedish) 2025-06-28 14:09:54 +02:00
PrivateBin Translator Bot
4cbd449d75 New translations en.json (Slovenian) 2025-06-28 14:09:53 +02:00
PrivateBin Translator Bot
cdc0938044 New translations en.json (Slovak) 2025-06-28 14:09:53 +02:00
PrivateBin Translator Bot
8f5a6257a9 New translations en.json (Russian) 2025-06-28 14:09:52 +02:00
PrivateBin Translator Bot
e626f609b0 New translations en.json (Portuguese) 2025-06-28 14:09:51 +02:00
PrivateBin Translator Bot
8d59a37dde New translations en.json (Polish) 2025-06-28 14:09:50 +02:00
PrivateBin Translator Bot
bcdd795c08 New translations en.json (Norwegian) 2025-06-28 14:09:49 +02:00
PrivateBin Translator Bot
6563682fad New translations en.json (Dutch) 2025-06-28 14:09:48 +02:00
PrivateBin Translator Bot
331484b89f New translations en.json (Lithuanian) 2025-06-28 14:09:47 +02:00
PrivateBin Translator Bot
f7bb92d660 New translations en.json (Kurdish) 2025-06-28 14:09:46 +02:00
PrivateBin Translator Bot
58d158b735 New translations en.json (Korean) 2025-06-28 14:09:45 +02:00
PrivateBin Translator Bot
a2eb40946d New translations en.json (Japanese) 2025-06-28 14:09:44 +02:00
PrivateBin Translator Bot
3516bdbd12 New translations en.json (Italian) 2025-06-28 14:09:43 +02:00
PrivateBin Translator Bot
a75e58ae8d New translations en.json (Hungarian) 2025-06-28 14:09:42 +02:00
PrivateBin Translator Bot
eb3396ba9d New translations en.json (Hebrew) 2025-06-28 14:09:41 +02:00
PrivateBin Translator Bot
93cd2ba38b New translations en.json (Finnish) 2025-06-28 14:09:40 +02:00
PrivateBin Translator Bot
de6423866e New translations en.json (Greek) 2025-06-28 14:09:39 +02:00
PrivateBin Translator Bot
fc60d3bee9 New translations en.json (German) 2025-06-28 14:09:38 +02:00
PrivateBin Translator Bot
d10634f3c1 New translations en.json (Czech) 2025-06-28 14:09:37 +02:00
PrivateBin Translator Bot
c005f0954e New translations en.json (Catalan) 2025-06-28 14:09:36 +02:00
PrivateBin Translator Bot
ff52413e6b New translations en.json (Bulgarian) 2025-06-28 14:09:35 +02:00
PrivateBin Translator Bot
3cbade2325 New translations en.json (Spanish) 2025-06-28 14:09:34 +02:00
PrivateBin Translator Bot
869222821e New translations en.json (French) 2025-06-28 14:09:33 +02:00
PrivateBin Translator Bot
3764fc1395 New translations en.json (Romanian) 2025-06-28 14:09:32 +02:00
PrivateBin Translator Bot
fd0b2379b3 New translations en.json (Arabic) 2025-06-28 14:09:31 +02:00
El RIDO
389b215b2f
Merge pull request #1564 from Ribas160/file_name_and_size_on_download_page
Show file name and size on download page
2025-06-28 14:01:41 +02:00
Ribas160
a2ca2ecb37 Use 1024 based file size units to follow consistency 2025-06-28 14:00:50 +03:00
Mikhail Romanov
d15ac590d7
Use decodedData to get file size
Co-authored-by: El RIDO <elrido@gmx.net>
2025-06-28 13:47:43 +03:00
El RIDO
964b4da50a
Merge pull request #1545 from PrivateBin/fixes
Fixes for zlib caching & handling undefined globals
2025-06-27 16:49:00 +02:00
Ribas160
d01c37c59d Show file name and size on download page 2025-06-26 18:12:22 +03:00
El RIDO
409af9b991
Merge pull request #1546 from PrivateBin/dompurify-3.2.6
upgrade DOMpurify library to 3.2.6
2025-06-26 13:37:24 +02:00
Ribas160
c7b9ce0bc2 Merge branch 'master' into dompurify-3.2.6
# Conflicts:
#	lib/Configuration.php
2025-06-26 13:37:00 +03:00
El RIDO
f3d851b0ba
Merge pull request #1560 from PrivateBin/crowdin-translation
New Crowdin updates
2025-06-19 20:40:57 +02:00
PrivateBin Translator Bot
d7b32f0219 New translations en.json (Arabic) 2025-06-19 11:14:42 +02:00
El RIDO
c7f465fe8b
apply StyleCI recommendation 2025-06-18 15:08:05 +02:00
El RIDO
9455fea799
Merge pull request #1559 from Ribas160/custom_template_error
Fix error when a custom template is not in the default available templates list
2025-06-18 15:05:19 +02:00
Ribas160
44f8cfbfb8 Fix error when a custom template is not in the default available templates list 2025-06-18 14:51:11 +03:00
El RIDO
4eb6555e3c
Merge pull request #1555 from PrivateBin/dependabot/github_actions/dawidd6/action-download-artifact-11
Bump dawidd6/action-download-artifact from 10 to 11
2025-06-16 17:58:49 +02:00
dependabot[bot]
d544d1281d
Bump dawidd6/action-download-artifact from 10 to 11
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 10 to 11.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](4c1e823582...ac66b43f0e)

---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
  dependency-version: '11'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-16 12:22:51 +00:00
El RIDO
91bfd2eec1
Merge pull request #1552 from PrivateBin/pdf-csp
Document CSP change necessary to allow PDF preview to work
2025-06-08 08:29:58 +02:00
El RIDO
f49c042cc9
document change necessary to allow PDF preview to work in Firefox & Chrome
Since attachement upload is not enabled by default, I suggest to retain the safer CSP as the default but document what is necassary. Disabling the sandboxing is problematic.
2025-06-07 11:44:02 +02:00
El RIDO
8d720e4990
Merge branch 'master' into dompurify-3.2.6 2025-06-07 10:41:48 +02:00
El RIDO
34028229c8
Merge branch 'master' into fixes 2025-06-07 10:37:23 +02:00
El RIDO
8268a92ebd
Merge pull request #1550 from Ribas160/allow_multiple_files
Allow multiple files
2025-06-07 10:28:48 +02:00
Ribas160
89c5ebb5f2 CHANGELOG.md and CREDITS.md update 2025-06-05 17:41:16 +03:00
El RIDO
d778887cd1
Merge pull request #1551 from PrivateBin/dependabot/github_actions/dawidd6/action-download-artifact-10
Bump dawidd6/action-download-artifact from 9 to 10
2025-06-05 08:21:42 +02:00
dependabot[bot]
3a1eb8d534
Bump dawidd6/action-download-artifact from 9 to 10
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 9 to 10.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](07ab29fd4a...4c1e823582)

---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
  dependency-version: '10'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-02 12:46:39 +00:00
Ribas160
095a5be0b6 Allow multiple files 2025-06-02 14:35:54 +03:00
El RIDO
6ff08b6884
Merge pull request #1548 from Ribas160/hide_comment_reply_button_on_click
Hide Reply button in the discussions once clicked to avoid losing the…
2025-05-24 16:21:15 +02:00
Ribas160
6dac586f41 Fix the duplicated message box in comments 2025-05-24 12:38:39 +03:00
Ribas160
5654ef2db8 Hide Reply button in the discussions once clicked to avoid losing the text input 2025-05-23 13:37:38 +03:00
El RIDO
dededc9935
upgrade DOMpurify library to 3.2.6 2025-05-20 07:51:50 +02:00
El RIDO
c08a792f01
handle undefined global, fixes #1544 2025-05-18 21:15:39 +02:00
El RIDO
6347b6193e
replicate reported error 2025-05-18 20:52:46 +02:00
El RIDO
bace4695ac
update zlib js suffix, as a cache breaker 2025-05-18 20:21:34 +02:00
El RIDO
7a42f31aef
Merge pull request #1540 from PrivateBin/crowdin-translation
New Crowdin updates
2025-04-26 17:05:49 +02:00
PrivateBin Translator Bot
e149e1b412 New translations en.json (Chinese Simplified) 2025-04-26 15:08:46 +02:00
PrivateBin Translator Bot
e091f88544 New translations en.json (Chinese Simplified) 2025-04-26 12:57:02 +02:00
El RIDO
2460caddc8
Merge pull request #1539 from fzxx/master
Update zh.json
2025-04-26 12:51:03 +02:00
风之暇想
95f232232e
Update zh.json
Fix incorrect translations
2025-04-26 15:39:23 +08:00
El RIDO
50a695b609
add missing method added upstream 2025-04-23 19:14:47 +02:00
El RIDO
cfb609814a
remove duplicate options 2025-04-23 19:05:53 +02:00
El RIDO
0199bed133
Merge pull request #1537 from jesussuarz/feature/add-delete-all-option
Add --delete-all option to administration script for mass paste deletion
2025-04-23 19:03:43 +02:00
Jesus Suarez
bce152c890
Update bin/administration
Use spaces instead of tabs for indentation consistency

Co-authored-by: El RIDO <elrido@gmx.net>
2025-04-22 16:44:12 -05:00
Jesus Suarez
abe7874829
Update bin/administration
Replace tabs with spaces for consistent code formatting

Co-authored-by: El RIDO <elrido@gmx.net>
2025-04-22 16:43:54 -05:00
Jesus Suarez
df1f742789
Update bin/administration
Refactor lines 160-165 as suggested for improved readability and consistency

Co-authored-by: El RIDO <elrido@gmx.net>
2025-04-22 16:43:35 -05:00
Jesus Suarez
1f7f6c93b0
Update bin/administration
Refactor code style: replace tabs with spaces, document new option, and maintain alphabetical order

Co-authored-by: El RIDO <elrido@gmx.net>
2025-04-22 16:43:01 -05:00
root
302921a811 Add --delete-all option to administration script for mass paste deletion 2025-04-22 04:12:46 -05:00
El RIDO
d220ba7c2b
Merge pull request #1536 from PrivateBin/crowdin-translation
New Crowdin updates
2025-04-15 21:47:02 +02:00
PrivateBin Translator Bot
9a9eb44102 New translations en.json (Polish) 2025-04-15 13:58:35 +02:00
El RIDO
10ee2fa2e4
Merge pull request #1535 from PrivateBin/crowdin-translation
New Crowdin updates
2025-04-13 07:59:49 +02:00
PrivateBin Translator Bot
e34a35bf30 New translations en.json (Arabic) 2025-04-12 16:30:55 +02:00
El RIDO
75db58800c
Merge pull request #1534 from PrivateBin/crowdin-translation
New Crowdin updates
2025-04-10 06:51:07 +02:00
PrivateBin Translator Bot
cbdd3d50a5 New translations en.json (Arabic) 2025-04-10 02:52:54 +02:00
El RIDO
b1608e5119
Merge pull request #1533 from PrivateBin/crowdin-translation
New Crowdin updates
2025-04-09 21:23:38 +02:00
PrivateBin Translator Bot
f8df10d2e1 New translations en.json (Hebrew) 2025-04-09 21:17:20 +02:00
El RIDO
37871eac69
node 20 seems to fail with the updated jsdom, locally I had tested with 18 - lets downgrade till we can find a solution 2025-04-09 21:11:10 +02:00
PrivateBin Translator Bot
edb753b3d7 New translations en.json (Hebrew) 2025-04-08 07:34:59 +02:00
El RIDO
bb4a3a09b0
Merge pull request #1532 from relspas/update-hebrew-support
Update Hebrew strings
2025-04-07 20:51:57 +02:00
El RIDO
1c72380443
Merge pull request #1531 from PrivateBin/crowdin-translation
New Crowdin updates
2025-04-07 20:49:32 +02:00
Raphael Elspas
a4be833937 Update Hebrew strings file 2025-04-07 12:14:05 -04:00
PrivateBin Translator Bot
16129b610d New translations en.json (Finnish) 2025-04-06 20:12:36 +02:00
El RIDO
31162e8011
upgrading DOMpurify library to 3.2.5 2025-04-06 08:30:49 +02:00
El RIDO
bac849d98a
Merge pull request #1526 from PrivateBin/pass-by-reference
Pass by reference & drop ctype
2025-03-17 06:52:48 +01:00
El RIDO
6ee9563b27
Merge pull request #1528 from fzxx/master
Update zh.json
2025-03-15 19:22:04 +01:00
风之暇想
797bf5eb6a
Update zh.json 2025-03-15 23:12:05 +08:00
El RIDO
abb49609e0
Merge pull request #1523 from jacquesbh/use-another-configuration-loader
Allow to use another Configuration class
2025-03-13 09:39:16 +01:00
El RIDO
46c49e5455
apply StyleCI recommendation 2025-03-13 09:32:39 +01:00
El RIDO
8ad6300c1c
pass by reference, closes #858 2025-03-13 09:22:27 +01:00
Jacques Bodin-Hullin
c04a551215
feat: Allow to change the Configuration in the _construct
So, now we can change the Configuration class, override it even if we
want.
2025-03-13 09:22:22 +01:00
El RIDO
5d4561bd0a
drop ctype requirement (only one use left) 2025-03-13 08:29:53 +01:00
El RIDO
7825471d70
avoid duplication of ID check 2025-03-13 08:14:01 +01:00
El RIDO
629f263cf5
pass by reference, closes #858 2025-03-11 08:22:21 +01:00
El RIDO
e67972417e
Merge pull request #1522 from jacquesbh/avoid-multiple-configuration-instances
Do not instanciate the Configuration more than once
2025-03-09 21:29:41 +01:00
Jacques Bodin-Hullin
c62a3fbd2d
perf(configuration): Do not create multiple instances of Configuration
Since the configuration is loaded in the _init method, and this method
is called in the _construct, there is no reason to instanciate the
Configuration class more than once.
2025-03-09 20:23:01 +01:00
El RIDO
81e9c8672f
Merge pull request #1521 from PrivateBin/crowdin-translation
New Crowdin updates
2025-03-09 13:31:13 +01:00
PrivateBin Translator Bot
24316f3e07 New translations en.json (Finnish) 2025-03-08 21:36:08 +01:00
El RIDO
495a84b292
chore: documentation 2025-03-08 08:44:28 +01:00
El RIDO
1d53f5a054
Merge pull request #1520 from PrivateBin/crowdin-translation
New Crowdin updates
2025-03-08 08:25:15 +01:00
PrivateBin Translator Bot
4d0fbfd02b New translations en.json (Estonian) 2025-03-07 14:34:00 +01:00
El RIDO
dd6537b277
Merge pull request #1518 from ixten/master
Fix available templates configuration and adding custom themes
2025-03-07 07:57:21 +01:00
Michael Kuilboer
9221629d8d Fix available templates configuration and adding custom themes 2025-03-06 02:27:31 +01:00
El RIDO
ebb9e231aa
Merge pull request #1516 from PrivateBin/js-devel-dep-update
update jsdom
2025-02-28 22:39:03 +01:00
El RIDO
e68430e9c5
clarify comments 2025-02-28 21:38:30 +01:00
El RIDO
d0303dce9c
clarify comments 2025-02-28 21:36:51 +01:00
El RIDO
9f82eb64cb
clarify test descriptions 2025-02-28 21:25:40 +01:00
El RIDO
a9ea962adc
Merge pull request #1517 from PrivateBin/dependabot/github_actions/dawidd6/action-download-artifact-9
Bump dawidd6/action-download-artifact from 8 to 9
2025-02-27 22:52:41 +01:00
dependabot[bot]
d89bc1b97b
Bump dawidd6/action-download-artifact from 8 to 9
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 8 to 9.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](20319c5641...07ab29fd4a)

---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-27 11:25:13 +00:00
El RIDO
e0b6aee65a
indentation 2025-02-27 08:17:03 +01:00
El RIDO
4e518b3fce
update jsdom dependency, fix tests 2025-02-27 08:16:30 +01:00
El RIDO
bb98d5b6c1
Merge pull request #1515 from PrivateBin/dependabot/github_actions/slsa-framework/slsa-github-generator-2.1.0
Bump slsa-framework/slsa-github-generator from 2.0.0 to 2.1.0
2025-02-27 06:49:39 +01:00
dependabot[bot]
478b79b7b7
Bump slsa-framework/slsa-github-generator from 2.0.0 to 2.1.0
Bumps [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) from 2.0.0 to 2.1.0.
- [Release notes](https://github.com/slsa-framework/slsa-github-generator/releases)
- [Changelog](https://github.com/slsa-framework/slsa-github-generator/blob/main/CHANGELOG.md)
- [Commits](https://github.com/slsa-framework/slsa-github-generator/compare/v2.0.0...v2.1.0)

---
updated-dependencies:
- dependency-name: slsa-framework/slsa-github-generator
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-25 11:57:15 +00:00
El RIDO
57636ee6d4
Merge pull request #1513 from PrivateBin/crowdin-translation
New Crowdin updates
2025-02-17 22:04:24 +01:00
PrivateBin Translator Bot
bd3486eda7 New translations en.json (Corsican) 2025-02-17 12:36:17 +01:00
PrivateBin Translator Bot
ddc9de345d New translations en.json (Russian) 2025-02-17 07:12:20 +01:00
PrivateBin Translator Bot
e511ab74b1 New translations en.json (Russian) 2025-02-16 09:11:36 +01:00
El RIDO
c32c74a630
Merge pull request #1501 from Ribas160/allow_change_template
Added the ability to web users to change the theme
2025-02-16 09:07:46 +01:00
Ribas160
412987ea5b Merge remote-tracking branch 'origin/master' into allow_change_template
# Conflicts:
#	lib/Configuration.php
2025-02-14 15:36:57 +02:00
Ribas160
b90967a14b Apply StyleCI changes 2025-02-14 15:33:34 +02:00
El RIDO
654bff65cc
add config for older apache releases without included mime type
kudos @cryptomilk for the suggestion
2025-02-13 09:03:13 +01:00
El RIDO
95188eea94
chore: update SRI hash 2025-02-11 19:51:24 +01:00
El RIDO
6bab8b014f
Merge pull request #1510 from PrivateBin/dompurify-remove
Remove SAFE_FOR_JQUERY from DOMPurify as it has been removed
2025-02-11 19:32:55 +01:00
rugk
ac62d909b9
Remove SAFE_FOR_JQUERY from DOMPurify as it has been removed
DOMPurify removed this configuration option, so I guess it has no effect and can be removed.

See docs: https://github.com/cure53/DOMPurify?tab=readme-ov-file#removed-configuration
>  SAFE_FOR_JQUERY 	2.1.0 	No replacement required.

The PR https://github.com/cure53/DOMPurify/pull/474 also links the commits, which removed it.
2025-02-11 17:32:40 +01:00
El RIDO
64b0e33574
update jsdom dependency, fix tests 2025-02-11 08:10:25 +01:00
El RIDO
e4d1f4a26d
update jsdom dependency, disable test 2025-02-11 07:52:23 +01:00
Ribas160
5b54f2cdb0 Use the traditional "template" config key, update unit-tests 2025-02-10 18:19:36 +02:00
El RIDO
0eef8d62d7
Merge pull request #1492 from PrivateBin/oxipng
optimized images
2025-02-09 09:34:46 +01:00
ribas160
bce449de10 Merge remote-tracking branch 'origin/master' into allow_change_template
# Conflicts:
#	CHANGELOG.md
2025-02-08 22:01:10 +02:00
ribas160
edad5ba1e0 Config documentation update 2025-02-08 21:49:27 +02:00
ribas160
dce5a73444 CHANGELOG and CREDITS update 2025-02-08 16:34:23 +02:00
ribas160
a4b0a993c7 Doc blocks added, available templates may be set in the general configuration file 2025-02-08 14:32:20 +02:00
El RIDO
1c2c45ec2d
Merge pull request #1507 from PrivateBin/vulnerability-policy
Change SECURITY.md to hint for acceping vulnerability reports via the GitHub mail
2025-02-07 22:21:07 +01:00
rugk
ec5b72476e
Change SECURITY.md to hint for acceping vulnerability reports via the GitHub mail
This seems to be a new feature and I've had this tested (with a different account) that this can be used by anyone.

IMHO, this is a convenient feature, as we'd need to publish it anyway there.
2025-02-07 21:39:59 +01:00
El RIDO
540172d0f7
update jsdom dependency 2025-02-07 09:00:53 +01:00
El RIDO
3b6b97429d
update jsdom dependency, fix tests 2025-02-07 08:54:55 +01:00
El RIDO
dc983621ac
update jsdom dependency, fix tests 2025-02-07 08:19:09 +01:00
El RIDO
ac63b91a1b
fix prompt test
rngState 883a6d2e518704c9fb fails on a single \n (line feed)

password inputs can't contain carriage returns *or* line feeds
2025-02-06 08:48:36 +01:00
El RIDO
db15ae8b43
fix prompt test
rngState 003ad8214ef0579cb6 fails on a single \n (line feed)

password inputs can't contain carriage returns *or* line feeds
2025-02-06 08:43:02 +01:00
El RIDO
740fd90db9
update jsdom & jsdom-global development dependency, fix cookie test 2025-02-06 08:39:25 +01:00
El RIDO
aa8f77f673
update jsdom-url development dependency 2025-02-06 08:09:15 +01:00
El RIDO
0a37a884e2
chore: document change 2025-02-05 22:27:21 +01:00
El RIDO
bbf6ad76f4
Merge pull request #1500 from PrivateBin/dependabot/composer/mlocati/ip-lib-1.20.0
Bump mlocati/ip-lib from 1.19.0 to 1.20.0
2025-02-05 22:25:25 +01:00
Ribas160
c7a4ced9e1 Added the ability to web users to change the theme 2025-02-05 15:24:15 +02:00
dependabot[bot]
f111def946
Bump mlocati/ip-lib from 1.19.0 to 1.20.0
Bumps [mlocati/ip-lib](https://github.com/mlocati/ip-lib) from 1.19.0 to 1.20.0.
- [Release notes](https://github.com/mlocati/ip-lib/releases)
- [Commits](https://github.com/mlocati/ip-lib/compare/1.19.0...1.20.0)

---
updated-dependencies:
- dependency-name: mlocati/ip-lib
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-05 11:20:36 +00:00
El RIDO
f88c643be9
Merge pull request #1499 from PrivateBin/dependabot/composer/mlocati/ip-lib-1.19.0
Bump mlocati/ip-lib from 1.18.1 to 1.19.0
2025-02-04 21:58:08 +01:00
dependabot[bot]
ed3347e835
Bump mlocati/ip-lib from 1.18.1 to 1.19.0
Bumps [mlocati/ip-lib](https://github.com/mlocati/ip-lib) from 1.18.1 to 1.19.0.
- [Release notes](https://github.com/mlocati/ip-lib/releases)
- [Commits](https://github.com/mlocati/ip-lib/compare/1.18.1...1.19.0)

---
updated-dependencies:
- dependency-name: mlocati/ip-lib
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-04 11:50:21 +00:00
El RIDO
6ba9fe5a93
Merge pull request #1496 from PrivateBin/crowdin-translation
New Crowdin updates
2025-02-04 08:36:23 +01:00
El RIDO
e8ae354c63
Merge branch 'master' into crowdin-translation 2025-02-04 08:34:56 +01:00
PrivateBin Translator Bot
2809403893 New translations en.json (Dutch) 2025-02-03 14:37:24 +01:00
El RIDO
aeba6e24cd
Merge pull request #1498 from AnonymousWP/chore(translation)-update-Dutch-translation
chore(translation): update Dutch translation
2025-02-03 14:23:59 +01:00
Anonymoussaurus
f9ac763e62
chore(translation): update Dutch translation 2025-02-03 11:43:42 +01:00
PrivateBin Translator Bot
d86f502136 New translations en.json (Chinese Simplified) 2025-02-03 08:24:15 +01:00
El RIDO
c963ba4d7a
upgrade webcrypto used in testing
old package got corrupted on npm and fails to install
2025-02-03 07:52:32 +01:00
El RIDO
cf14766d9f
Merge pull request #1495 from fzxx/master
Update zh.json
2025-02-03 07:35:13 +01:00
风之暇想
4b2443f3eb
Update zh.json
Update translations
2025-02-03 12:11:48 +08:00
El RIDO
94ab727139
Merge pull request #1493 from MickGe/master
update new translation in fr.json
2025-02-01 14:55:48 +01:00
MickGe
bbaee2c737
update new translation in fr.json 2025-02-01 14:42:37 +01:00
El RIDO
2a27c767a5
optimized images
using oxipng 9.1.3 and parameters:
oxipng -ao max --preserve --strip safe -Z -r .
2025-02-01 12:32:04 +01:00
El RIDO
e25fe01d82
chore: prepare for next release 2025-02-01 11:40:29 +01:00
170 changed files with 3810 additions and 4369 deletions

View file

@ -43,7 +43,7 @@ jobs:
actions: read
id-token: write
contents: write
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.0.0
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_generic_slsa3.yml@v2.1.0
with:
base64-subjects: "${{ needs.release.outputs.hashes }}"
draft-release: true

View file

@ -24,7 +24,7 @@ jobs:
steps:
- name: Download and Extract Artifacts
uses: dawidd6/action-download-artifact@20319c5641d495c8a52e688b7dc5fada6c3a9fbc
uses: dawidd6/action-download-artifact@ac66b43f0e6a346234dd65d4d0c8fbb31cb316e5
with:
run_id: ${{ github.event.workflow_run.id }}
path: artifacts

View file

@ -22,7 +22,7 @@ jobs:
continue-on-error: "${{ matrix.experimental }}"
strategy:
matrix:
php-versions: ['7.3', '7.4', '8.0', '8.1', '8.2', '8.3', '8.4']
php-versions: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4']
experimental: [false]
# uncomment this to start testing on development release
# include:
@ -121,7 +121,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: '20'
node-version: '18'
cache: 'npm'
cache-dependency-path: 'js/package-lock.json'

View file

@ -2,6 +2,7 @@ RewriteEngine on
RewriteCond !%{HTTP_USER_AGENT} "Let's Encrypt validation server" [NC]
RewriteCond %{HTTP_USER_AGENT} ^.*(bot|spider|crawl|https?://|WhatsApp|SkypeUriPreview|facebookexternalhit) [NC]
RewriteRule .* - [R=403,L]
AddType application/wasm .wasm
<IfModule mod_php7.c>
php_value max_execution_time 30

View file

@ -1,5 +1,31 @@
# PrivateBin version history
## 2.0.0 (not yet released)
* ADDED: Error logging in database and filesystem backend (#1554)
* CHANGED: Remove page template (#265)
* CHANGED: Jdenticons are now used as the default icons
* CHANGED: Upgrading libraries to: jdenticon 2.0.0
* CHANGED: Minimum required PHP version is 7.4, due to a change in the jdenticon library
* FIXED: Name mismatches in attached files (#1584)
* FIXED: Unable to paste attachments from clipboard (#1589)
## 1.7.8 (2025-06-30)
* FIXED: Duplicate attachment for every comment (#1577)
* FIXED: Attachments with empty file names (#1577)
* FIXED: Page template scripts loading order (#1579)
## 1.7.7 (2025-06-28)
* ADDED: Switching templates using the web ui (#1501)
* ADDED: Show file name and size on download page (#603)
* CHANGED: Passing large data structures by reference to reduce memory consumption (#858)
* CHANGED: Removed use of ctype functions and polyfill library for ctype
* CHANGED: Upgrading libraries to: DOMpurify 3.2.6, ip-lib 1.20.0
* CHANGED: Support for multiple file uploads (#1060)
* CHANGED: Documented CSP change necessary to allow PDF attachment preview (#1552)
* FIXED: Hide Reply button in the discussions once clicked to avoid losing the text input (#1508)
* FIXED: Bump zlib library suffix, ensuring cache refresh for WASM streaming change
* FIXED: Handle undefined globals in file based persisted values (#1544)
## 1.7.6 (2025-02-01)
* ADDED: Ability to copy the paste by clicking the copy icon button or using the keyboard shortcut ctrl+c/cmd+c (#1390 & #12)
* CHANGED: Allow toggling tab-key-support using `[Ctrl]+[m]` or `[Esc]` in textarea for keyboard navigation (#1386)

View file

@ -5,6 +5,7 @@
* Simon Rupf - current developer and maintainer
* rugk - security review, doc improvment, JS refactoring & various other stuff
* R4SAS - python client, compression, blob URI to support larger attachments
* Mikhail Romanov - UI improvements, theme switching, clipboard support, multi-file upload, bugfixes, code refactoring
## Past contributions
@ -33,7 +34,6 @@
* 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
* Mikhail Romanov - copying to clipboard, UI/UX improvements
## Translations
* Hexalyse - French

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.7.6
VERSION ?= 1.7.7
CURRENT_VERSION = 1.7.8
VERSION ?= 2.0.0
VERSION_FILES = README.md SECURITY.md doc/Installation.md js/package*.json lib/Controller.php Makefile
REGEX_CURRENT_VERSION := $(shell echo $(CURRENT_VERSION) | sed "s/\./\\\./g")
REGEX_VERSION := $(shell echo $(VERSION) | sed "s/\./\\\./g")

View file

@ -1,6 +1,6 @@
# [![PrivateBin](https://cdn.rawgit.com/PrivateBin/assets/master/images/preview/logoSmall.png)](https://privatebin.info/)
*Current version: 1.7.6*
*Current version: 1.7.8*
**PrivateBin** is a minimalist, open source online
[pastebin](https://en.wikipedia.org/wiki/Pastebin)

View file

@ -4,8 +4,8 @@
| Version | Supported |
| ------- | ------------------ |
| 1.7.6 | :heavy_check_mark: |
| < 1.7.6 | :x: |
| 1.7.8 | :heavy_check_mark: |
| < 1.7.8 | :x: |
## Reporting a Vulnerability
@ -14,5 +14,8 @@ a response within a week (usually during the next weekend). The respondee will
reply from their personal address and can offer you their GPG public key to
support end-to-end encrypted communication on sensitive topics or attachments.
You can also [use the corresponding GitHub form](https://github.com/PrivateBin/PrivateBin/security/advisories/new)
to report a new vulnerability directly on GitHub.
You can also contact us via the regular issue tracker if the risk of early
publication is low or you would request input from other PrivateBin users.

View file

@ -72,6 +72,35 @@ class Administration
exit("paste $pasteId successfully deleted" . PHP_EOL);
}
/**
* lists all stored paste IDs
*
* @access private
*/
private function _list_ids()
{
$ids = $this->_store->getAllPastes();
foreach ($ids as $pasteid) {
echo $pasteid, PHP_EOL;
}
exit;
}
/**
* deletes all stored pastes (regardless of expiration)
*
* @access private
*/
private function _delete_all()
{
$ids = $this->_store->getAllPastes();
foreach ($ids as $pasteid) {
echo "Deleting paste ID: $pasteid" . PHP_EOL;
$this->_store->delete($pasteid);
}
exit("All pastes successfully deleted" . PHP_EOL);
}
/**
* removes empty directories, if current storage model uses Filesystem
*
@ -124,13 +153,15 @@ class Administration
{
echo <<<'EOT'
Usage:
administration [--delete <paste id> | --empty-dirs | --help | --purge | --statistics]
administration [--delete <paste id> | --delete-all | --empty-dirs | --help | --list-ids | --purge | --statistics]
Options:
-d, --delete deletes the requested paste ID
--delete-all deletes all paste IDs
-e, --empty-dirs removes empty directories (only if Filesystem storage is
configured)
-h, --help displays this help message
-l, --list-ids lists all paste IDs
-p, --purge purge all expired pastes
-s, --statistics reads all stored pastes and comments and reports statistics
EOT, PHP_EOL;
@ -177,7 +208,8 @@ EOT, PHP_EOL;
self::_help(2);
}
$this->_opts = getopt('hd:eps', array('help', 'delete:', 'empty-dirs', 'purge', 'statistics'));
$this->_opts = getopt('hd:epsl', array('help', 'delete:', 'empty-dirs', 'purge', 'statistics', 'list-ids', 'delete-all'));
if (!$this->_opts) {
self::_error_echo('unsupported arguments given');
echo PHP_EOL;
@ -308,6 +340,12 @@ EOT, PHP_EOL;
$class = 'PrivateBin\\Data\\' . $this->_conf->getKey('class', 'model');
$this->_store = new $class($this->_conf->getSection('model_options'));
if ($this->_option('l', 'list-ids') !== null) {
$this->_list_ids();
}
if ($this->_option(null, 'delete-all') !== null) {
$this->_delete_all();
}
if (($pasteId = $this->_option('d', 'delete')) !== null) {
$this->_delete($pasteId);
}

View file

@ -164,14 +164,14 @@ new ConfigurationTestGenerator(array(
),
'main/template' => array(
array(
'setting' => 'page',
'setting' => 'bootstrap5',
'tests' => array(
array(
'type' => 'MatchesRegularExpression',
'args' => array(
'#<link[^>]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/privatebin\.css\\?\d[\d\.]+\d+"[^>]*/>#',
'#<link[^>]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/bootstrap5/privatebin\.css\\?\d[\d\.]+\d+"[^>]*/>#',
'$content',
'outputs "page" stylesheet correctly',
'outputs "bootstrap5" stylesheet correctly',
),
), array(
'type' => 'DoesNotMatchRegularExpression',
@ -189,9 +189,9 @@ new ConfigurationTestGenerator(array(
array(
'type' => 'DoesNotMatchRegularExpression',
'args' => array(
'#<link[^>]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/privatebin\.css\\?\d[\d\.]+\d+"[^>]*/>#',
'#<link[^>]+type="text/css"[^>]+rel="stylesheet"[^>]+href="css/bootstrap5/privatebin\.css\\?\d[\d\.]+\d+"[^>]*/>#',
'$content',
'removes "page" stylesheet correctly',
'removes "bootstrap5" stylesheet correctly',
),
), array(
'type' => 'MatchesRegularExpression',

View file

@ -42,13 +42,26 @@ defaultformatter = "plaintext"
; size limit per paste or comment in bytes, defaults to 10 Mebibytes
sizelimit = 10485760
; template to include, default is "bootstrap" (tpl/bootstrap.php), also
; available are "page" (tpl/page.php), the classic ZeroBin style and several
; by default PrivateBin use "bootstrap" template (tpl/bootstrap.php).
; Optionally you can enable the template selection menu, which uses
; a session cookie to store the choice until the browser is closed.
templateselection = false
; List of available for selection templates when "templateselection" option is enabled
availabletemplates[] = "bootstrap5"
availabletemplates[] = "bootstrap"
availabletemplates[] = "bootstrap-page"
availabletemplates[] = "bootstrap-dark"
availabletemplates[] = "bootstrap-dark-page"
availabletemplates[] = "bootstrap-compact"
availabletemplates[] = "bootstrap-compact-page"
; set the template your installs defaults to, defaults to "bootstrap" (tpl/bootstrap.php), also
; bootstrap variants: "bootstrap-dark", "bootstrap-compact", "bootstrap-page",
; which can be combined with "-dark" and "-compact" for "bootstrap-dark-page"
; and finally "bootstrap-compact-page" - previews at:
; which can be combined with "-dark" and "-compact" for "bootstrap-dark-page",
; "bootstrap-compact-page" and finally "bootstrap5" (tpl/bootstrap5.php) - previews at:
; https://privatebin.info/screenshots.html
template = "bootstrap"
; template = "bootstrap"
; (optional) info text to display
; use single, instead of double quotes for HTML attributes
@ -84,7 +97,7 @@ languageselection = false
; used to get the IP of a comment poster if the server salt is leaked and a
; SHA512 HMAC rainbow table is generated for all (relevant) IPs.
; Can be set to one these values:
; "none" / "identicon" (default) / "jdenticon" / "vizhash".
; "none" / "identicon" / "jdenticon" (default) / "vizhash".
; icon = "none"
; Content Security Policy headers allow a website to restrict what sources are
@ -93,8 +106,6 @@ languageselection = false
; scripts or run your site behind certain DDoS-protection services.
; Check the documentation at https://content-security-policy.com/
; Notes:
; - If you use any bootstrap theme, you can remove the allow-popups from the
; sandbox restrictions.
; - If you use the bootstrap5 theme, you must change default-src to 'self' to
; enable display of the svg icons
; - By default this disallows to load images from third-party servers, e.g. when
@ -103,7 +114,15 @@ languageselection = false
; for details.
; - The 'wasm-unsafe-eval' is used to enable webassembly support (used for zlib
; compression). You can remove it if compression doesn't need to be supported.
; cspheader = "default-src 'none'; base-uri 'self'; form-action 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'wasm-unsafe-eval'; style-src 'self'; font-src 'self'; frame-ancestors 'none'; img-src 'self' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-downloads"
; - The 'unsafe-inline' style-src is used by Chrome when displaying PDF previews
; and can be omitted if attachment upload is disabled (which is the default).
; See https://issues.chromium.org/issues/343754409
; - To allow displaying PDF previews in Firefox or Chrome, sandboxing must also
; get turned off. The following CSP allows PDF previews:
; cspheader = "default-src 'none'; base-uri 'self'; form-action 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'wasm-unsafe-eval'; style-src 'self' 'unsafe-inline'; font-src 'self'; frame-ancestors 'none'; frame-src blob:; img-src 'self' data: blob:; media-src blob:; object-src blob:"
;
; The recommended and default used CSP is:
; cspheader = "default-src 'none'; base-uri 'self'; form-action 'none'; manifest-src 'self'; connect-src * blob:; script-src 'self' 'wasm-unsafe-eval'; style-src 'self'; font-src 'self'; frame-ancestors 'none'; frame-src blob:; img-src 'self' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-modals allow-downloads"
; stay compatible with PrivateBin Alpha 0.19, less secure
; if enabled will use base64.js version 1.7 instead of 2.1.9 and sha1 instead of

View file

@ -24,11 +24,10 @@
"docs" : "https://privatebin.info/codedoc/"
},
"require" : {
"php": "^7.3 || ^8.0",
"jdenticon/jdenticon": "1.0.2",
"mlocati/ip-lib": "1.18.1",
"symfony/polyfill-ctype": "^1.31",
"symfony/polyfill-php80": "^1.31",
"php": "^7.4 || ^8.0",
"jdenticon/jdenticon": "2.0.0",
"mlocati/ip-lib": "1.20.0",
"symfony/polyfill-php80": "1.31.0",
"yzalis/identicon": "2.0.0"
},
"suggest" : {
@ -49,7 +48,7 @@
"preferred-install": "dist",
"sort-packages": true,
"platform": {
"php": "7.3"
"php": "7.4"
}
}
}

165
composer.lock generated
View file

@ -4,27 +4,27 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "0fdf0f08646fa2a4cf9c076131f529f5",
"content-hash": "cc778a671eac2ba1ec70bf9398b2e1bf",
"packages": [
{
"name": "jdenticon/jdenticon",
"version": "1.0.2",
"version": "2.0.0",
"source": {
"type": "git",
"url": "https://github.com/dmester/jdenticon-php.git",
"reference": "cabb7a44c413c318392a341c5d3ca30fcdd57a6f"
"reference": "fb39a98a0a54982a130b7e7b06305d4fd8c9717e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/dmester/jdenticon-php/zipball/cabb7a44c413c318392a341c5d3ca30fcdd57a6f",
"reference": "cabb7a44c413c318392a341c5d3ca30fcdd57a6f",
"url": "https://api.github.com/repos/dmester/jdenticon-php/zipball/fb39a98a0a54982a130b7e7b06305d4fd8c9717e",
"reference": "fb39a98a0a54982a130b7e7b06305d4fd8c9717e",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
"php": ">=7.4.0"
},
"require-dev": {
"phpunit/phpunit": "^5.7"
"phpunit/phpunit": "^9"
},
"type": "library",
"autoload": {
@ -53,20 +53,20 @@
"issues": "https://github.com/dmester/jdenticon-php/issues",
"source": "https://github.com/dmester/jdenticon-php"
},
"time": "2022-10-30T17:15:02+00:00"
"time": "2025-07-14T18:30:29+00:00"
},
{
"name": "mlocati/ip-lib",
"version": "1.18.1",
"version": "1.20.0",
"source": {
"type": "git",
"url": "https://github.com/mlocati/ip-lib.git",
"reference": "08bb43b4949069c543ebdf099a6b2c322d0172ab"
"reference": "fd45fc3bf08ed6c7e665e2e70562082ac954afd4"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mlocati/ip-lib/zipball/08bb43b4949069c543ebdf099a6b2c322d0172ab",
"reference": "08bb43b4949069c543ebdf099a6b2c322d0172ab",
"url": "https://api.github.com/repos/mlocati/ip-lib/zipball/fd45fc3bf08ed6c7e665e2e70562082ac954afd4",
"reference": "fd45fc3bf08ed6c7e665e2e70562082ac954afd4",
"shasum": ""
},
"require": {
@ -112,7 +112,7 @@
],
"support": {
"issues": "https://github.com/mlocati/ip-lib/issues",
"source": "https://github.com/mlocati/ip-lib/tree/1.18.1"
"source": "https://github.com/mlocati/ip-lib/tree/1.20.0"
},
"funding": [
{
@ -124,86 +124,7 @@
"type": "other"
}
],
"time": "2024-10-29T15:44:19+00:00"
},
{
"name": "symfony/polyfill-ctype",
"version": "v1.31.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-ctype.git",
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638",
"reference": "a3cc8b044a6ea513310cbd48ef7333b384945638",
"shasum": ""
},
"require": {
"php": ">=7.2"
},
"provide": {
"ext-ctype": "*"
},
"suggest": {
"ext-ctype": "For best performance"
},
"type": "library",
"extra": {
"thanks": {
"url": "https://github.com/symfony/polyfill",
"name": "symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Ctype\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gert de Pagter",
"email": "BackEndTea@gmail.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for ctype functions",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"ctype",
"polyfill",
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.31.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2024-09-09T11:45:10+00:00"
"time": "2025-02-04T17:30:58+00:00"
},
{
"name": "symfony/polyfill-php80",
@ -416,16 +337,16 @@
},
{
"name": "myclabs/deep-copy",
"version": "1.12.1",
"version": "1.13.3",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845"
"reference": "faed855a7b5f4d4637717c2b3863e277116beb36"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845",
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/faed855a7b5f4d4637717c2b3863e277116beb36",
"reference": "faed855a7b5f4d4637717c2b3863e277116beb36",
"shasum": ""
},
"require": {
@ -464,7 +385,7 @@
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.12.1"
"source": "https://github.com/myclabs/DeepCopy/tree/1.13.3"
},
"funding": [
{
@ -472,29 +393,31 @@
"type": "tidelift"
}
],
"time": "2024-11-08T17:47:46+00:00"
"time": "2025-07-05T12:25:42+00:00"
},
{
"name": "nikic/php-parser",
"version": "v4.19.4",
"version": "v5.5.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/PHP-Parser.git",
"reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2"
"reference": "ae59794362fe85e051a58ad36b289443f57be7a9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/715f4d25e225bc47b293a8b997fe6ce99bf987d2",
"reference": "715f4d25e225bc47b293a8b997fe6ce99bf987d2",
"url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9",
"reference": "ae59794362fe85e051a58ad36b289443f57be7a9",
"shasum": ""
},
"require": {
"ext-ctype": "*",
"ext-json": "*",
"ext-tokenizer": "*",
"php": ">=7.1"
"php": ">=7.4"
},
"require-dev": {
"ircmaxell/php-yacc": "^0.0.7",
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0"
"phpunit/phpunit": "^9.0"
},
"bin": [
"bin/php-parse"
@ -502,7 +425,7 @@
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "4.9-dev"
"dev-master": "5.0-dev"
}
},
"autoload": {
@ -526,9 +449,9 @@
],
"support": {
"issues": "https://github.com/nikic/PHP-Parser/issues",
"source": "https://github.com/nikic/PHP-Parser/tree/v4.19.4"
"source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0"
},
"time": "2024-09-29T15:01:53+00:00"
"time": "2025-05-31T08:24:38+00:00"
},
{
"name": "phar-io/manifest",
@ -969,16 +892,16 @@
},
{
"name": "phpunit/phpunit",
"version": "9.6.22",
"version": "9.6.23",
"source": {
"type": "git",
"url": "https://github.com/sebastianbergmann/phpunit.git",
"reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c"
"reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/f80235cb4d3caa59ae09be3adf1ded27521d1a9c",
"reference": "f80235cb4d3caa59ae09be3adf1ded27521d1a9c",
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/43d2cb18d0675c38bd44982a5d1d88f6d53d8d95",
"reference": "43d2cb18d0675c38bd44982a5d1d88f6d53d8d95",
"shasum": ""
},
"require": {
@ -989,7 +912,7 @@
"ext-mbstring": "*",
"ext-xml": "*",
"ext-xmlwriter": "*",
"myclabs/deep-copy": "^1.12.1",
"myclabs/deep-copy": "^1.13.1",
"phar-io/manifest": "^2.0.4",
"phar-io/version": "^3.2.1",
"php": ">=7.3",
@ -1052,7 +975,7 @@
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.22"
"source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.23"
},
"funding": [
{
@ -1063,12 +986,20 @@
"url": "https://github.com/sebastianbergmann",
"type": "github"
},
{
"url": "https://liberapay.com/sebastianbergmann",
"type": "liberapay"
},
{
"url": "https://thanks.dev/u/gh/sebastianbergmann",
"type": "thanks_dev"
},
{
"url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
"type": "tidelift"
}
],
"time": "2024-12-05T13:48:26+00:00"
"time": "2025-05-02T06:40:34+00:00"
},
{
"name": "sebastian/cli-parser",
@ -2090,11 +2021,11 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": "^7.3 || ^8.0"
"php": "^7.4 || ^8.0"
},
"platform-dev": [],
"platform-overrides": {
"php": "7.3"
"php": "7.4"
},
"plugin-api-version": "2.3.0"
}

View file

@ -8,6 +8,12 @@
* @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
*/
#attachmentPreview {
display: flex;
flex-direction: column;
align-items: center;
}
#attachmentPreview img {
max-width: 100%;
height: auto;

View file

@ -1,460 +0,0 @@
/**
* PrivateBin
*
* Cascading style sheets for page template.
*
* @link https://github.com/PrivateBin/PrivateBin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
*/
@import url("common.css");
/* CSS Reset from YUI 3.4.1 (build 4118) - Copyright 2011 Yahoo! Inc. All rights reserved.
Licensed under the BSD License. - http://yuilibrary.com/license/ */
html{color:#000;background:#fff}body,div,dl,dt,dd,ul,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0}table{border-collapse:collapse;border-spacing:0}fieldset,img{border:0}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal}ol,ul{list-style:none}caption,th{text-align:left}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}q:before,q:after{content:''}abbr,acronym{border:0;font-variant:normal}sup{vertical-align:text-top}sub{vertical-align:text-bottom}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit}input,textarea,select{font-size:100%;}legend{color:#000}
html {
background-color: #455463;
color: #fff;
min-height: 100%;
background-image: linear-gradient(bottom, #0f1823 0, #455463 100%);
background-image: -o-linear-gradient(bottom, #0f1823 0, #455463 100%);
background-image: -moz-linear-gradient(bottom, #0f1823 0, #455463 100%);
background-image: -webkit-linear-gradient(bottom, #0f1823 0, #455463 100%);
background-image: -ms-linear-gradient(bottom, #0f1823 0, #455463 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #0f1823), color-stop(1, #455463));
}
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 0.9em;
margin-bottom: 15px;
padding-left: 60px;
padding-right: 60px;
}
a { color: #0f388f; cursor:pointer; }
h1.title {
font-size: 3.5em;
font-weight: bold;
color: #000;
position: relative;
display: inline;
cursor: pointer;
}
h1.title:before {
content: attr(title);
position: absolute;
color: rgba(255,255,255,0.15);
top: 1px;
left: 1px;
cursor: pointer;
}
h2.title {
color: #000;
font-size: 1em;
display: inline;
font-style: italic;
font-weight: bold;
position: relative;
bottom: 8px;
}
h3.title {
color: #94a3b4;
font-size: 0.7em;
display: inline;
margin-top: 10px;
position: relative;
bottom: 8px;
}
#aboutbox {
color: #94a3b4;
padding: 4px 8px 4px 16px;
position: relative;
top: 10px;
border-left: 2px solid #94a3b4;
float: right;
width: 60%;
}
#aboutbox a { color: #94a3b4; }
#message, #cleartext, #prettymessage, #attachment, .replymessage {
position: relative;
clear: both;
color: #000;
background-color: #fff;
font-size: 9pt;
border: 1px solid #28343F;
box-sizing: border-box;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
-o-box-sizing: border-box;
width: 100%;
}
#message, .replymessage {
padding: 5px;
white-space: pre-wrap;
font-family: Consolas, "Lucida Console", "DejaVu Sans Mono", Monaco, monospace;
resize: vertical;
}
#status {
clear: both;
padding: 5px 10px;
}
#pasteresult {
background-color: #1F2833;
color: #fff;
padding: 4px 12px;
clear: both;
-moz-box-shadow: inset 0 2px 2px #000;
-webkit-box-shadow: inset 0 2px 2px #000;
box-shadow: inset 0 2px 2px #000;
}
#pasteresult a { color: #fff; }
#pasteresult button { margin-left: 11px; }
#message, #plaintext, #prettymessage, #toolbar, #status { margin-bottom: 5px; }
#copyhint { color: #666; font-size: 0.85em }
button, .button {
color: #fff;
background-color: #323b47;
background-repeat: no-repeat;
background-position: center left;
padding: 4px 8px;
font-size: 1em;
margin-right: 5px;
display: inline-block;
background-image: linear-gradient(bottom, #323b47 0, #51606e 100%);
background-image: -o-linear-gradient(bottom, #323b47 0, #51606e 100%);
background-image: -moz-linear-gradient(bottom, #323b47 0, #51606e 100%);
background-image: -webkit-linear-gradient(bottom, #323b47 0, #51606e 100%);
background-image: -ms-linear-gradient(bottom, #323b47 0, #51606e 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #323b47), color-stop(1, #51606e));
border: 1px solid #28343F;
-moz-box-shadow: inset 0 1px 2px #647384;
-webkit-box-shadow: inset 0 1px 2px #647384;
box-shadow: inset 0 1px 2px #647384;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
-moz-background-clip: padding;
-webkit-background-clip: padding-box;
background-clip: padding-box;
}
button:hover {
background-image: linear-gradient(bottom, #424b57 0%, #61707e 100%);
background-image: -o-linear-gradient(bottom, #424b57 0%, #61707e 100%);
background-image: -moz-linear-gradient(bottom, #424b57 0%, #61707e 100%);
background-image: -webkit-linear-gradient(bottom, #424b57 0%, #61707e 100%);
background-image: -ms-linear-gradient(bottom, #424b57 0%, #61707e 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #424b57), color-stop(1, #61707e));
}
button:active {
background-image: linear-gradient(bottom, #51606e 0, #323b47 100%);
background-image: -o-linear-gradient(bottom, #51606e 0, #323b47 100%);
background-image: -moz-linear-gradient(bottom, #51606e 0, #323b47 100%);
background-image: -webkit-linear-gradient(bottom, #51606e 0, #323b47 100%);
background-image: -ms-linear-gradient(bottom, #51606e 0, #323b47 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #51606e), color-stop(1, #323b47));
position:relative;
top:1px;
}
button:disabled, .buttondisabled {
background: #ccc;
color: #888;
top: 0;
}
button img {
margin-right: 8px;
position: relative;
top: 2px;
}
.button {
background-color: #414d5a;
padding: 6px 8px;
margin: 0 5px 0 0;
position: relative;
bottom: 1px; /* WTF ? Why is this shifted by 1 pixel ? */
}
.button select {
color: #eee;
background: transparent;
border: none;
}
.button select option {
color:#eee;
background: #414d5a;
}
#rawtextbutton img {
padding: 1px 0 1px 0;
}
#downloadtextbutton img {
padding: 1px 0 1px 0;
}
#remainingtime, #password {
color: #94a3b4;
display: inline;
font-size: 0.85em;
}
#newbutton {
float: right;
margin-left: 0;
margin-right: 0;
margin-bottom: 5px;
display: inline;
}
input {
color: #777;
font-size: 1em;
padding: 6px;
border: 1px solid #28343f;
}
.blink {
text-decoration: blink;
font-size: 0.8em;
color: #a4b3c4;
}
.foryoureyesonly {
color: #ff0 !important;
font-size: 1em !important;
font-weight: bold !important;
}
#attachmentPreview, .nonworking {
background-color: #fff;
color: #000;
width: 100%;
text-align: center;
font-weight: bold;
font-size: 10pt;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
padding: 5px 0;
}
.hidden { display: none !important; }
#ienotice {
background-color: #7e98af;
color: #000;
font-size: 0.85em;
padding: 3px 5px;
text-align: center;
-webkit-border-radius: 4px;
-moz-border-radius: 4px;
border-radius: 4px;
display: none;
}
#ienotice a { color: #000; }
#oldnotice, #httpnotice { display: none; }
#errormessage, .errorMessage {
background-color: #f77 !important;
color:#ff0;
}
.small {
font-size: 80%;
}
/* --- discussion related CSS ------- */
#discussion { /* Discussion container */
margin-top: 20px;
width: 100%;
margin-left: -30px;
min-width: 200px;
}
h4.title {
font-size: 1.2em;
color: #94a3b4;
font-style: italic;
font-weight: bold;
position: relative;
margin-left: 30px;
}
.comment /* One single reply */
{
background-color: #ceced6;
color: #000;
white-space: pre-wrap;
font-family: Consolas,"Lucida Console","DejaVu Sans Mono",Monaco,monospace;
font-size: 9pt;
border-left: 1px solid #859AAE;
border-top: 1px solid #859AAE;
padding: 5px 0px 5px 5px;
margin-left: 30px;
-moz-box-shadow: -3px -3px 5px rgba(0,0,0,0.15);
-webkit-box-shadow: -3px -3px 5px rgba(0,0,0,0.15);
box-shadow: -3px -3px 5px rgba(0,0,0,0.15);
min-width: 200px;
overflow: auto;
}
.reply { margin: 5px 0 0 30px; }
#replystatus {
display: inline;
padding: 1px 7px;
font-family: Arial, Helvetica, sans-serif;
}
.comment button {
color: #446;
background-color: #aab;
background-repeat: no-repeat;
background-position: center left;
padding: 0 2px;
font-size: 0.73em;
margin: 3px 5px 3px 0;
display: inline;
background-image: linear-gradient(bottom, #aab 0, #ccc 100%);
background-image: -o-linear-gradient(bottom, #aab 0, #ccc 100%);
background-image: -moz-linear-gradient(bottom, #aab 0, #ccc 100%);
background-image: -webkit-linear-gradient(bottom, #aab 0, #ccc 100%);
background-image: -ms-linear-gradient(bottom, #aab 0, #ccc 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #aab), color-stop(1, #ccc));
border: 1px solid #ccd;
-moz-box-shadow: inset 0 1px 2px #ddd;
-webkit-box-shadow: inset 0 1px 2px #fff;
box-shadow: inset 0 1px 2px #eee;
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
border-radius: 3px;
-moz-background-clip: padding;
-webkit-background-clip: padding-box;
background-clip: padding-box;
}
.comment button:hover {
background-image: linear-gradient(bottom, #ccd 0, #fff 100%);
background-image: -o-linear-gradient(bottom, #ccd 0, #fff 100%);
background-image: -moz-linear-gradient(bottom, #ccd 0, #fff 100%);
background-image: -webkit-linear-gradient(bottom, #ccd 0, #fff 100%);
background-image: -ms-linear-gradient(bottom, #ccd 0, #fff 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccd), color-stop(1, #fff));
}
.comment button:active {
background-image: linear-gradient(bottom, #fff 0, #889 100%);
background-image: -o-linear-gradient(bottom, #fff 0, #889 100%);
background-image: -moz-linear-gradient(bottom, #fff 0, #889 100%);
background-image: -webkit-linear-gradient(bottom, #fff 0, #889 100%);
background-image: -ms-linear-gradient(bottom, #fff 0, #889 100%);
background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #fff), color-stop(1, #889));
position:relative;
top:1px;
}
.comment input { padding: 2px; }
#replymessage { margin-top: 5px; }
.commentmeta {
color: #fff;
background-color: #8ea0b2;
margin-bottom: 3px;
padding: 0 0 0 3px;
}
.commentdate { color: #bfcede; }
img.vizhash {
width: 16px;
height: 16px;
position: relative;
top: 2px;
left: -3px;
}
#prettyprint {
color: #000000;
font-size: 1.2em;
}
#prettyprint.prettyprinted {
overflow: auto;
}
#cleartext {
padding: 10px;
}
#cleartext * {
margin-bottom: 10px;
}
#cleartext ol {
list-style: auto;
margin-left: 15px;
}
#cleartext ul {
list-style: disc;
margin-left: 15px;
}
#cleartext h1, #cleartext h2, #cleartext h3, #cleartext h4, #cleartext h5, #cleartext h6 {
font-weight: bold;
}
#cleartext h1 {
font-size: 2em;
}
#cleartext h2 {
font-size: 1.5em;
}
#cleartext h3 {
font-size: 1.2em;
}
/* right-to-left overrides */
html[dir="rtl"] #aboutbox, html[dir="rtl"] #deletelink, html[dir="rtl"] #newbutton {
float: left;
}
html[dir="rtl"] button, html[dir="rtl"] .button, html[dir="rtl"] button img {
margin-left: 5px;
margin-right: inherit;
}
html[dir="rtl"] button img {
margin-left: 8px;
}

View file

@ -21,8 +21,7 @@ for more information.
### Minimal Requirements
- PHP version 7.3 or above
- ctype extension
- PHP version 7.4 or above
- GD extension (when using identicon or vizhash icons, jdenticon works without it)
- zlib extension
- some disk space or a database supported by [PDO](https://php.net/manual/book.pdo.php)
@ -201,7 +200,7 @@ CREATE INDEX parent ON prefix_comment(pasteid);
CREATE TABLE prefix_config (
id CHAR(16) NOT NULL, value TEXT, PRIMARY KEY (id)
);
INSERT INTO prefix_config VALUES('VERSION', '1.7.6');
INSERT INTO prefix_config VALUES('VERSION', '1.7.8');
```
In **PostgreSQL**, the `data`, `attachment`, `nickname` and `vizhash` columns

View file

@ -18,7 +18,7 @@ The parameters in detail:
an accidentally destructive test case in it.
- `--read-only` - This image supports running in read-only mode. Only /tmp
may be written into.
- `-rm` - Remove the container after the run. This saves you doing a cleanup
- `--rm` - Remove the container after the run. This saves you doing a cleanup
on your docker environment, if you run the image frequently.
You can also run just the php and javascript test suites instead of both:

View file

@ -164,17 +164,25 @@
"EiB": "إكسابايت",
"ZiB": "زيتابايت",
"YiB": "يوتابايت",
"kB": "كيلوبايت",
"MB": "ميجابايت",
"GB": "جيجابايت",
"TB": "تيرابايت",
"PB": "بيتابايت",
"EB": "إكسابايت",
"ZB": "زيتابايت",
"YB": "يوتابايت",
"Format": "التنسيق",
"Plain Text": "نص عادي",
"Source Code": "كود مصدر",
"Markdown": "ماركداون",
"Download attachment": "تنزيل المرفقات",
"Download attachment": "نزّل المرفق",
"Cloned: '%s'": "مستنسخ: '%s'",
"The cloned file '%s' was attached to this paste.": "تم إرفاق المِلَفّ المستنسخ '%s' بهذا اللصق.",
"Attach a file": "إرفاق مِلَفّ",
"The cloned file '%s' was attached to this paste.": "تم إرفاق الملف المستنسخ '%s' بهذا اللصق.",
"Attach a file": "أرفق ملف",
"alternatively drag & drop a file or paste an image from the clipboard": "بدلاً من ذلك، اسحب ملفًا وأسقطه أو الصق صورة من الحافظة",
"File too large, to display a preview. Please download the attachment.": "المِلَفّ كبير جدًا، بحيث لا يمكن عرض معاينة. الرجاء تنزيل المرفق.",
"Remove attachment": "إزالة المرفق",
"File too large, to display a preview. Please download the attachment.": "الملف كبير جدًا، بحيث لا يمكن عرض معاينة. الرجاء تنزيل المرفق.",
"Remove attachment": "أزِل المرفق",
"Your browser does not support uploading encrypted files. Please use a newer browser.": "متصفحك لا يدعم رفع الملفات المشفرة. الرجاء استخدام متصفح أحدث.",
"Invalid attachment.": "مرفق غير صحيح.",
"Options": "الخيارات",
@ -215,16 +223,17 @@
"Trying to shorten a URL that isn't pointing at our instance.": "محاولة تقصير عنوان URL لا يشير إلى خادمنا.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "خطأ في الاتصال بـ YOURLS. ربما تكون هناك مشكلة في التضبيط، مثل \"apiurl\" أو \"التوقيع\" الخاطئ أو المفقود.",
"Error parsing YOURLS response.": "خطأ في تحليل استجابة YOURLS.",
"This secret message can only be displayed once. Would you like to see it now?": "لا يمكن عرض اللصق احرقه بعد قراءته إلا مرة واحدة عند تحميله. هل تريد فتحه الآن؟",
"Yes, see it": "نعم، حمله",
"This secret message can only be displayed once. Would you like to see it now?": "يمكن عرض هذه الرسالة السرية مرة واحدة فقط. هل ترغب في رؤيتها الآن؟",
"Yes, see it": "نعم، دعني اراها",
"Dark Mode": "الوضع الداكن",
"Error compressing paste, due to missing WebAssembly support.": "Error compressing paste, due to missing WebAssembly support.",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.",
"Start over": "Start over",
"Paste copied to clipboard": "Paste copied to clipboard",
"To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>": "To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>",
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Error compressing paste, due to missing WebAssembly support.": "خطأ في ضغط اللصق، بسبب فقدان دعم WebAssembly.",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "خطأ في فك ضغط اللصق، متصفحك لا يدعم WebAssembly. الرجاء استخدام متصفح آخر لعرض هذه اللصقة.",
"Start over": "ابدأ من جديد",
"Paste copied to clipboard": "نُسخ اللصق إلى الحافظة",
"To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>": "لنسخ اللصق انقر على زر النسخ أو استخدم اختصار الحافظة <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>",
"Copy link": "نسخ الرابط",
"Link copied to clipboard": "نُسخ الرابط إلى الحافظة",
"Paste text": "لصق النص",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "مفتاح التبويب يعمل كشخصية (انقر <kbd>Ctrl</kbd>+<kbd>m</kbd> أو <kbd>Esc</kbd> للتبديل)",
"Theme": "السمة"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Формат",
"Plain Text": "Чист текст",
"Source Code": "Изходен код",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Format",
"Plain Text": "Text sense format",
"Source Code": "Codi font",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -156,14 +156,22 @@
"Could not create paste: %s": "Ùn si pò micca creà lappiccicu : %s",
"Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Ùn si pò micca dicifrà lappiccicu : A chjave di dicifratura hè assente in lindirizzu. Averiate impiegatu un orientadore dindirizzu o un riduttore chì ammuzzeghja una parte di lindirizzu ?",
"B": "o",
"KiB": "Ko",
"MiB": "Mo",
"GiB": "Go",
"TiB": "To",
"PiB": "Po",
"EiB": "Eo",
"ZiB": "Zo",
"YiB": "Yo",
"KiB": "Kio",
"MiB": "Mio",
"GiB": "Gio",
"TiB": "Tio",
"PiB": "Pio",
"EiB": "Eio",
"ZiB": "Zio",
"YiB": "Yio",
"kB": "Ko",
"MB": "Mo",
"GB": "Go",
"TB": "To",
"PB": "Po",
"EB": "Eo",
"ZB": "Zo",
"YB": "Yo",
"Format": "Furmatu",
"Plain Text": "Testu in chjaru",
"Source Code": "Codice di fonte",
@ -226,5 +234,6 @@
"Copy link": "Cupià u liame",
"Link copied to clipboard": "U liame hè statu cupiatu in u premepapei",
"Paste text": "Testu di lappiccicu",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "U tastu di tabulazione ghjova cumè un caratteru (Appughjate nantà <kbd>Ctrl</kbd>+<kbd>m</kbd> o <kbd>Scapp</kbd> per scambià)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "U tastu di tabulazione ghjova cumè un caratteru (Appughjate nantà <kbd>Ctrl</kbd>+<kbd>m</kbd> o <kbd>Scapp</kbd> per scambià)",
"Theme": "Tema"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Formát",
"Plain Text": "Prostý text",
"Source Code": "Zdrojový kód",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Format",
"Plain Text": "Nur Text",
"Source Code": "Quellcode",
@ -226,5 +234,6 @@
"Copy link": "Verknüpfung kopieren",
"Link copied to clipboard": "Verknüpfung wurde in die Zwischenablage kopiert.",
"Paste text": "Text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulatortaste als Zeichen interpretieren (Umschalten durch <kbd>Strg</kbd>+<kbd>m</kbd> oder <kbd>Esc</kbd>)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulatortaste als Zeichen interpretieren (Umschalten durch <kbd>Strg</kbd>+<kbd>m</kbd> oder <kbd>Esc</kbd>)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Μορφοποίηση",
"Plain Text": "Απλό κείμενο",
"Source Code": "Πηγαίος Κώδικας",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Format",
"Plain Text": "Plain Text",
"Source Code": "Source Code",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Formato",
"Plain Text": "Texto sin formato",
"Source Code": "Código fuente",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Formaat",
"Plain Text": "Lihttekst",
"Source Code": "Lähtekood",
@ -215,16 +223,17 @@
"Trying to shorten a URL that isn't pointing at our instance.": "Püüame lühendada URL-i, mis ei viita meie instantsile.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Viga YOURLS-i kutsumisel. Tõenäoliselt konfiguratsiooniprobleem, näiteks vale või puuduv \"apiurl\" või \"signature\".",
"Error parsing YOURLS response.": "Viga YOURLS vastuse parsimisel.",
"This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?",
"Yes, see it": "Yes, see it",
"This secret message can only be displayed once. Would you like to see it now?": "Seda turvalist sõnumit saab kuvada vaid ühe korra. \nKas soovid seda näha nüüd?",
"Yes, see it": "Jah, vaata seda",
"Dark Mode": "Tume režiim",
"Error compressing paste, due to missing WebAssembly support.": "Error compressing paste, due to missing WebAssembly support.",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.",
"Start over": "Start over",
"Paste copied to clipboard": "Paste copied to clipboard",
"Start over": "Alusta uuesti",
"Paste copied to clipboard": "Kleebe kopeeriti lõikelauale",
"To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>": "To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>",
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Copy link": "Kopeeri link",
"Link copied to clipboard": "Link kopeeriti lõikelauale",
"Paste text": "Kleebi tekst",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Teema"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Formaatti",
"Plain Text": "Perusteksti",
"Source Code": "Lähdekoodi",
@ -218,13 +226,14 @@
"This secret message can only be displayed once. Would you like to see it now?": "Tämä salainen viesti voidaan näyttää vain kerran. Haluatko nähdä sen nyt?",
"Yes, see it": "Kyllä, näet sen",
"Dark Mode": "Tumma tila",
"Error compressing paste, due to missing WebAssembly support.": "Error compressing paste, due to missing WebAssembly support.",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.",
"Start over": "Start over",
"Paste copied to clipboard": "Paste copied to clipboard",
"To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>": "To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>",
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Error compressing paste, due to missing WebAssembly support.": "Virhe pakattaessa pastea, koska WebAssembly-tuki puuttuu.",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Virhe pasten purkamisessa, selaimesi ei tue WebAssemblyä. Ole hyvä ja käytä toista selainta nähdäksesi tämä paste.",
"Start over": "Aloita alusta",
"Paste copied to clipboard": "Paste kopioitu leikepöydälle",
"To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>": "Voit kopioida pasten painamalla kopioi-painiketta tai käyttämällä leikepöydän oikotietä <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>",
"Copy link": "Kopioi linkki",
"Link copied to clipboard": "Linkki kopioitu leikepöydälle",
"Paste text": "Liitä teksti",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulaattori toimii merkkinä (Paina <kbd>Ctrl</kbd>+<kbd>m</kbd> tai <kbd>Esc</kbd> vaihtaaksesi)",
"Theme": "Teema"
}

View file

@ -151,7 +151,7 @@
"server error or not responding": "Le serveur ne répond pas ou a rencontré une erreur",
"Could not post comment: %s": "Impossible de poster le commentaire : %s",
"Sending paste…": "Envoi du paste…",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit <kbd>Ctrl</kbd>+<kbd>c</kbd> to copy)</span>": "Votre paste est disponible à l'adresse <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Appuyez sur <kbd>Ctrl</kbd>+<kbd>c</kbd> pour copier)</span>",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit <kbd>Ctrl</kbd>+<kbd>c</kbd> to copy)</span>": "Votre paste est disponible à l'adresse <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Appuyez sur <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd> pour copier)</span>",
"Delete data": "Supprimer les données du paste",
"Could not create paste: %s": "Impossible de créer le paste : %s",
"Cannot decrypt paste: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Impossible de déchiffrer le paste : Clé de déchiffrement manquante dans l'URL (Avez-vous utilisé un redirecteur ou un site de réduction d'URL qui supprime une partie de l'URL ?)",
@ -164,6 +164,14 @@
"EiB": "Eio",
"ZiB": "Zio",
"YiB": "Yio",
"kB": "ko",
"MB": "Mo",
"GB": "Go",
"TB": "To",
"PB": "Po",
"EB": "Eo",
"ZB": "Zo",
"YB": "Yo",
"Format": "Format",
"Plain Text": "Texte brut",
"Source Code": "Code source",
@ -221,10 +229,11 @@
"Error compressing paste, due to missing WebAssembly support.": "Erreur lors de la compression du paste, en raison du support de WebAssembly manquant.",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Erreur lors de la décompression du paste, votre navigateur ne supporte pas WebAssembly. Veuillez utiliser un autre navigateur pour voir ce paste.",
"Start over": "Recommencer",
"Paste copied to clipboard": "Paste copied to clipboard",
"To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>": "To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>",
"Paste copied to clipboard": "Paste copié dans le presse-papier",
"To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>": "Pour copier-coller appuyer sur le bouton To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>",
"Copy link": "Copier le lien",
"Link copied to clipboard": "Link copied to clipboard",
"Link copied to clipboard": "Lien copié dans le presse-papier",
"Paste text": "Texte du paste",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "La touche de tabulation sert de caractère (Presser <kbd>Ctrl</kbd>+<kbd>m</kbd> ou <kbd>Esc</kbd> pour basculer)",
"Theme": "Thème"
}

View file

@ -1,7 +1,7 @@
{
"PrivateBin": "PrivateBin",
"%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.",
"More information on the <a href=\"https://privatebin.info/\">project page</a>.": "More information on the <a href=\"https://privatebin.info/\">project page</a>.",
"%s is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s הוא שירות pastebin מקוון, מינימליסטי וקוד פתוח, שבו לשרת אין כל ידע על המידע שהודבק. הנתונים מוצפנים ומפוענחים %sבדפדפן%s באמצעות הצפנת AES ב-256 סיביות.",
"More information on the <a href=\"https://privatebin.info/\">project page</a>.": "מידע נוסף בדף <a href=\"https://privatebin.info/\">הפרויקט</a>.",
"Because ignorance is bliss": "כיוון שבורות היא ברכה",
"Paste does not exist, has expired or has been deleted.": "ההדבקה לא קיימת, פגה או נמחקה.",
"%s requires php %s or above to work. Sorry.": "%s דורש PHP %s כדי לפעול.",
@ -29,7 +29,7 @@
"Create": "צור",
"Clone": "שכפול",
"Raw text": "טקסט גולמי",
"Expires": "Expires",
"Expires": "יפוג ב",
"Burn after reading": "קוראים-שורפים",
"Open discussion": "פתיחת דיון",
"Password (recommended)": "ססמה (מומלץ)",
@ -53,11 +53,11 @@
],
"%d hours": [
"שעה אחת",
"%d hours (1st plural)",
"%d hours (2nd plural)",
"%d hours (3rd plural)",
"%d hours (4th plural)",
"%d hours (5th plural)"
"%d שעות",
"%d שעות",
"%d שעות",
"%d שעות",
"%d שעות"
],
"%d days": [
"יום אחד",
@ -94,44 +94,44 @@
"Never": "לעולם לא",
"Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "הערה: זהו שירות בדקה: המידע לא ישמר.",
"This document will expire in %d seconds.": [
"This document will expire in %d second. (singular)",
"This document will expire in %d seconds. (1st plural)",
"This document will expire in %d seconds. (2nd plural)",
"This document will expire in %d seconds. (3rd plural)",
"This document will expire in %d seconds. (4th plural)",
"This document will expire in %d seconds. (5th plural)"
"מסמך זה יפוג בעוד שנייה אחת.",
"מסמך זה יפוג בעוד %d שניות.",
"מסמך זה יפוג בעוד %d שניות.",
"מסמך זה יפוג בעוד %d שניות.",
"מסמך זה יפוג בעוד %d שניות.",
"מסמך זה יפוג בעוד %d שניות."
],
"This document will expire in %d minutes.": [
"This document will expire in %d minute. (singular)",
"This document will expire in %d minutes. (1st plural)",
"This document will expire in %d minutes. (2nd plural)",
"This document will expire in %d minutes. (3rd plural)",
"This document will expire in %d minutes. (4th plural)",
"This document will expire in %d minutes. (5th plural)"
"מסמך זה יפוג בעוד דקה אחת.",
"מסמך זה יפוג בעוד %d דקות.",
"מסמך זה יפוג בעוד %d דקות.",
"מסמך זה יפוג בעוד %d דקות.",
"מסמך זה יפוג בעוד %d דקות.",
"מסמך זה יפוג בעוד %d דקות."
],
"This document will expire in %d hours.": [
"This document will expire in %d hour. (singular)",
"This document will expire in %d hours. (1st plural)",
"This document will expire in %d hours. (2nd plural)",
"This document will expire in %d hours. (3rd plural)",
"This document will expire in %d hours. (4th plural)",
"This document will expire in %d hours. (5th plural)"
"מסמך זה יפוג בעוד שעה אחת.",
"מסמך זה יפוג בעוד %d שעות.",
"מסמך זה יפוג בעוד %d שעות.",
"מסמך זה יפוג בעוד %d שעות.",
"מסמך זה יפוג בעוד %d שעות.",
"מסמך זה יפוג בעוד %d שעות."
],
"This document will expire in %d days.": [
"This document will expire in %d day. (singular)",
"This document will expire in %d days. (1st plural)",
"This document will expire in %d days. (2nd plural)",
"This document will expire in %d days. (3rd plural)",
"This document will expire in %d days. (4th plural)",
"This document will expire in %d days. (5th plural)"
"מסמך זה יפוג בעוד יום אחד.",
"מסמך זה יפוג בעוד %d ימים.",
"מסמך זה יפוג בעוד %d ימים.",
"מסמך זה יפוג בעוד %d ימים.",
"מסמך זה יפוג בעוד %d ימים.",
"מסמך זה יפוג בעוד %d ימים."
],
"This document will expire in %d months.": [
"This document will expire in %d month. (singular)",
"This document will expire in %d months. (1st plural)",
"This document will expire in %d months. (2nd plural)",
"This document will expire in %d months. (3rd plural)",
"This document will expire in %d months. (4th plural)",
"This document will expire in %d months. (5th plural)"
"מסמך זה יפוג בעוד חודש אחד.",
"מסמך זה יפוג בעוד %d חודשים.",
"מסמך זה יפוג בעוד %d חודשים.",
"מסמך זה יפוג בעוד %d חודשים.",
"מסמך זה יפוג בעוד %d חודשים.",
"מסמך זה יפוג בעוד %d חודשים."
],
"Please enter the password for this paste:": "נא למלא את הססמה להדבקה הזו:",
"Could not decrypt data (Wrong key?)": "לא ניתן לפענח את הנתונים (מפתח שגוי?)",
@ -164,35 +164,43 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "פורמט",
"Plain Text": "טקסט פשוט",
"Source Code": "קוד מקור",
"Markdown": "Markdown",
"Download attachment": "הורדת קובץ מצורף",
"Cloned: '%s'": "שוכפל: '%s'",
"The cloned file '%s' was attached to this paste.": "The cloned file '%s' was attached to this paste.",
"The cloned file '%s' was attached to this paste.": "הקובץ '%s' שהועתק צורף להדבקה זו.",
"Attach a file": "צירוף קובץ",
"alternatively drag & drop a file or paste an image from the clipboard": "alternatively drag & drop a file or paste an image from the clipboard",
"File too large, to display a preview. Please download the attachment.": "File too large, to display a preview. Please download the attachment.",
"Remove attachment": "Remove attachment",
"Your browser does not support uploading encrypted files. Please use a newer browser.": "Your browser does not support uploading encrypted files. Please use a newer browser.",
"alternatively drag & drop a file or paste an image from the clipboard": "לחלופין, ניתן לגרור ולשחרר קובץ או להדביק תמונה מהלוח.",
"File too large, to display a preview. Please download the attachment.": "הקובץ גדול מדי כדי להציג תצוגה מקדימה. אנא הורד את הקובץ המצורף.",
"Remove attachment": "הסר קובץ מצורף",
"Your browser does not support uploading encrypted files. Please use a newer browser.": "הדפדפן שלך אינו תומך בהעלאת קבצים מוצפנים. אנא השתמש בדפדפן עדכני יותר.",
"Invalid attachment.": "קובץ מצורף שגוי.",
"Options": "אפשרויות",
"Shorten URL": "קיצור כתובת",
"Editor": "עורך",
"Preview": "תצוגה מקדימה",
"%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.",
"%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s דורש שה-PATH יסתיים ב-\"%s\". אנא עדכן את ה-PATH בקובץ index.php שלך.",
"Decrypt": "פענוח",
"Enter password": "נא למלא ססמה",
"Loading…": "בטעינה…",
"Decrypting paste…": "ההדבקה מפוענחת…",
"Preparing new paste…": "ההדבקה החדשה בהכנות…",
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.": "In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.",
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.": "אם הודעה זו לא נעלמת, אנא עיין ב- <a href=\"%s\">שאלות נפוצות אלה למידע לפתרון בעיות</a>.",
"+++ no paste text +++": "+++ אין טקסט להדבקה +++",
"Could not get paste data: %s": "לא ניתן לקבל את נתוני ההדבקה: %s",
"QR code": "קוד QR",
"This website is using an insecure HTTP connection! Please use it only for testing.": "האתר הזה משתמש בחיבור HTTP בלתי מאובטח! נא להשתמש בזה לבדיקות בלבד.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "יש מידע נוסף <a href=\"%s\">ברשומה הזאת בשו״ת</a>.",
"For more information <a href=\"%s\">see this FAQ entry</a>.": "לפרטים נוספים <a href=\"%s\">עיין ברשומת שאלות נפוצות זו</a>.",
"Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "יכול להיות שהדפדפן שלך ידרוש חיבור HTTPS כדי לתמוך ב־API של WebCrypto. כדי לנסות <a href=\"%s\">לעבור ל־HTTPS</a>.",
"Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "הדפדפן שלך לא תומך ב־WebAssembly שמשמש לדחיסת zlib. אפשר ליצור מסמכים בלתי מוצפנים אך אין אפשרות לקרוא מסמכים מוצפנים.",
"waiting on user to provide a password": "בהמתנה למילוי הססמה מצד המשתמש",
@ -209,22 +217,23 @@
"Close": "סגירה",
"Encrypted note on %s": "%sהערה מוצפנת ב־",
"Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "נא לבקר בקישור כדי לצפות בהערה. מסירת הקישור לאנשים כלשהם תאפשר גם להם לגשת להערה.",
"URL shortener may expose your decrypt key in URL.": "URL shortener may expose your decrypt key in URL.",
"Save paste": "Save paste",
"Your IP is not authorized to create pastes.": "Your IP is not authorized to create pastes.",
"Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".",
"Error parsing YOURLS response.": "Error parsing YOURLS response.",
"This secret message can only be displayed once. Would you like to see it now?": "This secret message can only be displayed once. Would you like to see it now?",
"Yes, see it": "Yes, see it",
"Dark Mode": "Dark Mode",
"Error compressing paste, due to missing WebAssembly support.": "Error compressing paste, due to missing WebAssembly support.",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.",
"Start over": "Start over",
"Paste copied to clipboard": "Paste copied to clipboard",
"To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>": "To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>",
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"URL shortener may expose your decrypt key in URL.": "שירות קיצור כתובת URL עשוי לחשוף את מפתח הפענוח שלך בכתובת ה-URL.",
"Save paste": "שמור הדבקה",
"Your IP is not authorized to create pastes.": "ה-IP שלך אינו מורשה ליצור הדבקות.",
"Trying to shorten a URL that isn't pointing at our instance.": "מנסים לקצר כתובת URL שאינה מצביעה על המערכת שלנו.",
"Error calling YOURLS. Probably a configuration issue, like wrong or missing \"apiurl\" or \"signature\".": "שגיאה בעת קריאה ל-YOURLS. כנראה מדובר בבעיה בהגדרות, כמו \"apiurl\" או \"signature\" שגויים או חסרים.",
"Error parsing YOURLS response.": "שגיאה בניתוח התגובה מ-YOURLS.",
"This secret message can only be displayed once. Would you like to see it now?": "ההודעה הסודית הזו יכולה להוצג רק פעם אחת. האם תרצה לראות אותה עכשיו?",
"Yes, see it": "כן, ראה אותה",
"Dark Mode": "מצב כהה",
"Error compressing paste, due to missing WebAssembly support.": "שגיאה בדחיסת ההדבקה, עקב חוסר תמיכה ב-WebAssembly.",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "שגיאה בהפקת ההדבקה, הדפדפן שלך לא תומך ב-WebAssembly. אנא השתמש בדפדפן אחר כדי לצפות בהדבקה זו.",
"Start over": "להתחיל מחדש",
"Paste copied to clipboard": "ההדבקה הועתקה ללוח",
"To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>": "על מנת להעתיק את ההדבקה, לחץ על כפתור ההעתקה או השתמש בקיצור הדרך ללוח <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>",
"Copy link": "העתק קישור",
"Link copied to clipboard": "הקישור הועתק ללוח",
"Paste text": "הדבק טקסט",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "משטח ה-tab פועל כמקש תו (לחץ על <kbd>Ctrl</kbd>+<kbd>m</kbd> או <kbd>Esc</kbd> להחלפה)",
"Theme": "נושא"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Format",
"Plain Text": "Plain Text",
"Source Code": "Source Code",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Formátum",
"Plain Text": "Egyszerű szöveg",
"Source Code": "Forráskód",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Format",
"Plain Text": "Teks Biasa",
"Source Code": "Kode Sumber",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Formato",
"Plain Text": "Solo Testo",
"Source Code": "Codice Sorgente",
@ -226,5 +234,6 @@
"Copy link": "Copia il link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Testo del messaggio",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "形式",
"Plain Text": "プレーンテキスト",
"Source Code": "ソースコード",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Format",
"Plain Text": "Plain Text",
"Source Code": "Source Code",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Format",
"Plain Text": "Plain Text",
"Source Code": "Source Code",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Format",
"Plain Text": "Plain Text",
"Source Code": "Source Code",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Format",
"Plain Text": "Plain Text",
"Source Code": "Source Code",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Formatas",
"Plain Text": "Grynasis tekstas",
"Source Code": "Pirminis kodas",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -143,7 +143,7 @@
"Avatar generated from IP address": "Anonieme avatar (van het IP-adres)",
"Add comment": "Commentaar toevoegen",
"Optional nickname…": "Optionele bijnaam…",
"Post comment": "Plaats een commentaar",
"Post comment": "Plaats commentaar",
"Sending comment…": "Commentaar verzenden…",
"Comment posted.": "Commentaar geplaatst.",
"Could not refresh display: %s": "Kon de weergave niet vernieuwen: %s",
@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Formaat",
"Plain Text": "Platte tekst",
"Source Code": "Broncode",
@ -220,11 +228,12 @@
"Dark Mode": "Donkere modus",
"Error compressing paste, due to missing WebAssembly support.": "Fout bij het comprimeren van notitie door ontbrekende ondersteuning voor WebAssembly.",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Fout bij het decomprimeren van de notitie, uw browser ondersteunt WebAssembly niet. Gebruik een andere browser om deze notitie te bekijken.",
"Start over": "Start over",
"Paste copied to clipboard": "Paste copied to clipboard",
"To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>": "To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>",
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Start over": "Opnieuw beginnen",
"Paste copied to clipboard": "Notitie gekopieerd naar klembord",
"To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>": "Om te kopiëren en plakken druk je op de knop Kopiëren of gebruik je de sneltoets op het klembord <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>",
"Copy link": "Kopieer link",
"Link copied to clipboard": "Link gekopieerd naar klembord",
"Paste text": "Tekst plakken",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulatortoets dient als teken (gebruik <kbd>Ctrl</kbd>+<kbd>m</kbd> of <kbd>Esc</kbd> om te schakelen)",
"Theme": "Thema"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Format",
"Plain Text": "Ren Tekst",
"Source Code": "Kildekode",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "Eio",
"ZiB": "Zio",
"YiB": "Yio",
"kB": "ko",
"MB": "Mo",
"GB": "Go",
"TB": "To",
"PB": "Po",
"EB": "Eo",
"ZB": "Zo",
"YB": "Yo",
"Format": "Format",
"Plain Text": "Tèxte brut",
"Source Code": "Còdi font",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Format",
"Plain Text": "Czysty tekst",
"Source Code": "Kod źródłowy",
@ -220,11 +228,12 @@
"Dark Mode": "Ciemny motyw",
"Error compressing paste, due to missing WebAssembly support.": "Błąd kompresowania wklejenia przez brak obsługi WebAssembly.",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "Błąd dekompresowania wklejenia przez brak obsługi WebAssembly przez przeglądarkę. Użyj innej przeglądarki, aby zobaczyć to wklejenie.",
"Start over": "Start over",
"Paste copied to clipboard": "Paste copied to clipboard",
"To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>": "To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>",
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Start over": "Zacznij od nowa",
"Paste copied to clipboard": "Wklejka skopiowana do schowka",
"To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>": "Aby skopiować wklejkę, naciśnij przycisk kopiowania lub użyj skrótu schowka <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>",
"Copy link": "Kopiuj link",
"Link copied to clipboard": "Link został skopiowany do schowka",
"Paste text": "Wklej tekst",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Klawisz Tabulatora służy jako znak (przytrzymaj <kbd>Ctrl</kbd>+<kbd>m</kbd> lub <kbd>Esc</kbd> aby przełączać)",
"Theme": "Motyw"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Formato",
"Plain Text": "Texto sem formato",
"Source Code": "Código fonte",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Formatare",
"Plain Text": "Text neformatat",
"Source Code": "Cod sursă",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "Эбайт",
"ZiB": "Збайт",
"YiB": "Йбайт",
"kB": "кбайт",
"MB": "Мбайт",
"GB": "Гбайт",
"TB": "Тбайт",
"PB": "Пбайт",
"EB": "Эбайт",
"ZB": "Збайт",
"YB": "Йбайт",
"Format": "Формат",
"Plain Text": "Обычный текст",
"Source Code": "Исходный код",
@ -226,5 +234,6 @@
"Copy link": "Скопировать ссылку",
"Link copied to clipboard": "Ссылка скопирована в буфер обмена",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Тема"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Formát",
"Plain Text": "Čistý text",
"Source Code": "Zdrojový kód",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EB",
"ZiB": "ZB",
"YiB": "YB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Format",
"Plain Text": "Surov tekst",
"Source Code": "Odprta koda",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Format",
"Plain Text": "Plain Text",
"Source Code": "Source Code",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "รูปแบบ",
"Plain Text": "ข้อความล้วน",
"Source Code": "ซอร์สโค้ด",
@ -221,10 +229,11 @@
"Error compressing paste, due to missing WebAssembly support.": "ไม่สามารถบีบอัดข้อมูลที่คุณต้องการฝากโค้ดได้ เนื่องจากอุปกรณ์ของคุณขาดการรองรับ WebAssembly",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "ไม่สามารถอ่านข้อมูลที่คุณได้ฝากโค้ดไว้ เบราว์เซอร์ของคุณไม่รองรับ WebAssembly กรุณาลองเปลี่ยนใช้เบราว์เซอร์ตัวอื่นเพื่อดูการฝากโค้ดนี้อีกครั้ง",
"Start over": "เริ่มใหม่",
"Paste copied to clipboard": "Paste copied to clipboard",
"To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>": "To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>",
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Paste copied to clipboard": "คัดลอกการฝากโค้ดไปที่คลิปบอร์ดแล้ว",
"To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>": "หากต้องการคัดลอกและวาง กรุณากดปุ่มคัดลอก หรือใช้ปุ่มลัด <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd> สำหรับคลิปบอร์ด",
"Copy link": "คัดลอกลิงก์",
"Link copied to clipboard": "คัดลอกลิงก์ไปที่คลิปบอร์ดแล้ว",
"Paste text": "ฝากข้อความ",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "ปุ่ม Tabulator ใช้เป็นอักขระ (กด <kbd>Ctrl</kbd>+<kbd>m</kbd> หรือ <kbd>Esc</kbd> เพื่อสลับ)",
"Theme": "ธีม"
}

View file

@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "Format",
"Plain Text": "Düz Yazı",
"Source Code": "Kaynak Kodu",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -164,6 +164,14 @@
"EiB": "Ебайт",
"ZiB": "Збайт",
"YiB": "Йбайт",
"kB": "кбайт",
"MB": "Мбайт",
"GB": "Гбайт",
"TB": "Тбайт",
"PB": "Пбайт",
"EB": "Ебайт",
"ZB": "Збайт",
"YB": "Йбайт",
"Format": "Формат",
"Plain Text": "Звичайний текст",
"Source Code": "Вихідний код",
@ -226,5 +234,6 @@
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)",
"Theme": "Theme"
}

View file

@ -7,12 +7,12 @@
"%s requires php %s or above to work. Sorry.": "抱歉,%s 需要 PHP %s 及以上版本才能运行。",
"%s requires configuration section [%s] to be present in configuration file.": "%s 需要设置配置文件中的 [%s] 部分。",
"Please wait %d seconds between each post.": [
"每 %d 秒只能粘贴一次。",
"每 %d 秒只能粘贴一次。",
"每 %d 秒只能粘贴一次。",
"每 %d 秒只能粘贴一次。",
"每 %d 秒只能粘贴一次。",
"每 %d 秒只能粘贴一次。"
"每 %d 秒只能创建一次粘贴。",
"每 %d 秒只能创建一次粘贴。",
"每 %d 秒只能创建一次粘贴。",
"每 %d 秒只能创建一次粘贴。",
"每 %d 秒只能创建一次粘贴。",
"每 %d 秒只能创建一次粘贴。"
],
"Paste is limited to %s of encrypted data.": "对于加密数据,上限为 %s。",
"Invalid data.": "无效的数据。",
@ -46,10 +46,10 @@
"%d minutes": [
"%d 分钟",
"%d 分钟",
"%d ",
"%d ",
"%d ",
"%d "
"%d 分钟",
"%d 分钟",
"%d 分钟",
"%d 分钟"
],
"%d hours": [
"%d 小时",
@ -94,7 +94,7 @@
"Never": "永不过期",
"Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "注意:这是一个测试服务,数据随时可能被删除。如果你滥用这个服务的话,小猫咪会死的。",
"This document will expire in %d seconds.": [
"这份文档将在秒后过期。",
"这份文档将在 %d 秒后过期。",
"这份文档将在 %d 秒后过期。",
"这份文档将在 %d 秒后过期。",
"这份文档将在 %d 秒后过期。",
@ -102,7 +102,7 @@
"这份文档将在 %d 秒后过期。"
],
"This document will expire in %d minutes.": [
"这份文档将在分钟后过期。",
"这份文档将在 %d 分钟后过期。",
"这份文档将在 %d 分钟后过期。",
"这份文档将在 %d 分钟后过期。",
"这份文档将在 %d 分钟后过期。",
@ -110,7 +110,7 @@
"这份文档将在 %d 分钟后过期。"
],
"This document will expire in %d hours.": [
"这份文档将在小时后过期。",
"这份文档将在 %d 小时后过期。",
"这份文档将在 %d 小时后过期。",
"这份文档将在 %d 小时后过期。",
"这份文档将在 %d 小时后过期。",
@ -118,7 +118,7 @@
"这份文档将在 %d 小时后过期。"
],
"This document will expire in %d days.": [
"这份文档将在天后过期。",
"这份文档将在 %d 天后过期。",
"这份文档将在 %d 天后过期。",
"这份文档将在 %d 天后过期。",
"这份文档将在 %d 天后过期。",
@ -126,7 +126,7 @@
"这份文档将在 %d 天后过期。"
],
"This document will expire in %d months.": [
"这份文档将在个月后过期。",
"这份文档将在 %d 个月后过期。",
"这份文档将在 %d 个月后过期。",
"这份文档将在 %d 个月后过期。",
"这份文档将在 %d 个月后过期。",
@ -136,7 +136,7 @@
"Please enter the password for this paste:": "请输入这份粘贴内容的密码:",
"Could not decrypt data (Wrong key?)": "无法解密数据(密钥错误?)",
"Could not delete the paste, it was not stored in burn after reading mode.": "无法删除此粘贴内容,它没有以阅后即焚模式保存。",
"FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "看!仔!细!了!不要关闭窗口,否则你再也见不到这条消息了。",
"FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "睁大眼睛看清楚!不要关闭窗口,否则你再也见不到这条消息了。",
"Could not decrypt comment; Wrong key?": "无法解密评论;密钥错误?",
"Reply": "回复",
"Anonymous": "匿名",
@ -150,7 +150,7 @@
"unknown status": "未知状态",
"server error or not responding": "服务器错误或无回应",
"Could not post comment: %s": "无法发送评论: %s",
"Sending paste…": "粘贴内容提交中…",
"Sending paste…": "正在发送粘贴内容…",
"Your paste is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit <kbd>Ctrl</kbd>+<kbd>c</kbd> to copy)</span>": "您粘贴内容的链接是 <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(按下 <kbd>Ctrl</kbd>+<kbd>c</kbd> 以复制)</span>",
"Delete data": "删除数据",
"Could not create paste: %s": "无法创建粘贴:%s",
@ -164,6 +164,14 @@
"EiB": "EiB",
"ZiB": "ZiB",
"YiB": "YiB",
"kB": "kB",
"MB": "MB",
"GB": "GB",
"TB": "TB",
"PB": "PB",
"EB": "EB",
"ZB": "ZB",
"YB": "YB",
"Format": "格式",
"Plain Text": "纯文本",
"Source Code": "源代码",
@ -185,8 +193,8 @@
"Decrypt": "解密",
"Enter password": "输入密码",
"Loading…": "载入中…",
"Decrypting paste…": "正在解密",
"Preparing new paste…": "正在准备新的粘贴内容",
"Decrypting paste…": "正在解密",
"Preparing new paste…": "正在准备新的粘贴内容",
"In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.": "如果此消息一直存在,请参考 <a href=\"%s\">这里的 FAQ英文版</a>排除故障。",
"+++ no paste text +++": "+++ 无粘贴内容 +++",
"Could not get paste data: %s": "无法获取粘贴数据:%s",
@ -200,7 +208,7 @@
"Retry": "重试",
"Showing raw text…": "显示原始文字…",
"Notice:": "注意:",
"This link will expire after %s.": "这个链接将会在 %s 过期。",
"This link will expire after %s.": "链接将会在 %s 过期。",
"This link can only be accessed once, do not use back or refresh button in your browser.": "此链接只能被访问一次,请勿使用浏览器中的返回和刷新按钮。",
"Link:": "链接:",
"Recipient may become aware of your timezone, convert time to UTC?": "收件人可能会知道您的时区,将时间转换为 UTC",
@ -217,14 +225,15 @@
"Error parsing YOURLS response.": "解析 YOURLS 响应时出错。",
"This secret message can only be displayed once. Would you like to see it now?": "读取粘贴后只能在加载时显示一次。您想现在打开吗?",
"Yes, see it": "是的,加载它",
"Dark Mode": "暗黑模式",
"Dark Mode": "夜间模式",
"Error compressing paste, due to missing WebAssembly support.": "由于缺少 WebAssembly 支持,在压缩粘贴时出错。",
"Error decompressing paste, your browser does not support WebAssembly. Please use another browser to view this paste.": "解压粘贴时出错,您的浏览器不支持 WebAssembly。请使用其他浏览器查看此粘贴。",
"Start over": "重新开始",
"Paste copied to clipboard": "Paste copied to clipboard",
"To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>": "To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>",
"Copy link": "Copy link",
"Link copied to clipboard": "Link copied to clipboard",
"Paste text": "Paste text",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)"
"Paste copied to clipboard": "粘贴内容已复制到剪贴板",
"To copy paste press on the copy button or use the clipboard shortcut <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>": "要复制粘贴内容,请点击复制按钮或使用快捷键 <kbd>Ctrl</kbd>+<kbd>c</kbd>/<kbd>Cmd</kbd>+<kbd>c</kbd>。",
"Copy link": "复制链接",
"Link copied to clipboard": "链接已复制到剪贴板",
"Paste text": "粘贴文本",
"Tabulator key serves as character (Hit <kbd>Ctrl</kbd>+<kbd>m</kbd> or <kbd>Esc</kbd> to toggle)": "Tab 键可作为字符(按 <kbd>Ctrl</kbd>+<kbd>m</kbd> 或 <kbd>Esc</kbd> 切换开关)",
"Theme": "主题"
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 749 B

After

Width:  |  Height:  |  Size: 741 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 B

After

Width:  |  Height:  |  Size: 180 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 B

After

Width:  |  Height:  |  Size: 217 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 B

After

Width:  |  Height:  |  Size: 104 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 299 B

After

Width:  |  Height:  |  Size: 200 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 B

After

Width:  |  Height:  |  Size: 174 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 B

After

Width:  |  Height:  |  Size: 144 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 B

After

Width:  |  Height:  |  Size: 149 B

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

Before After
Before After

View file

@ -5,19 +5,18 @@ global.assert = require('assert');
global.jsc = require('jsverify');
global.jsdom = require('jsdom-global');
global.cleanup = global.jsdom();
global.URL = require('jsdom-url').URL;
global.fs = require('fs');
global.WebCrypto = require('@peculiar/webcrypto').Crypto;
// application libraries to test
global.$ = global.jQuery = require('./jquery-3.7.1');
global.RawDeflate = require('./rawinflate-0.3').RawDeflate;
global.zlib = require('./zlib-1.3.1').zlib;
global.zlib = require('./zlib-1.3.1-1').zlib;
require('./prettify');
global.prettyPrint = window.PR.prettyPrint;
global.prettyPrintOne = window.PR.prettyPrintOne;
global.showdown = require('./showdown-2.1.0');
global.DOMPurify = require('./purify-3.2.4');
global.DOMPurify = require('./purify-3.2.6');
global.baseX = require('./base-x-4.0.0').baseX;
global.Legacy = require('./legacy').Legacy;
require('./bootstrap-3.4.1');
@ -79,8 +78,16 @@ function parseMime(line) {
}
// common testing helper functions
exports.atob = atob;
exports.btoa = btoa;
// as of jsDOM 22 the base64 functions provided in the DOM are more restrictive
// than browser implementation and throw when being passed invalid unicode
// codepoints - as we use these in the encryption with binary data, we need
// these to be character encoding agnostic
exports.atob = function(encoded) {
return Buffer.from(encoded, 'base64').toString('binary');
}
exports.btoa = function(text) {
return Buffer.from(text, 'binary').toString('base64');
}
// provides random lowercase characters from a to z
exports.jscA2zString = function() {

2016
js/package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,18 +1,16 @@
{
"name": "privatebin",
"version": "1.7.6",
"version": "1.7.8",
"description": "PrivateBin is a minimalist, open source online pastebin where the server has zero knowledge of pasted data. Data is encrypted/decrypted in the browser using 256 bit AES in Galois Counter mode (GCM).",
"main": "privatebin.js",
"directories": {
"test": "test"
},
"dependencies": {},
"devDependencies": {
"jsdom": "^9.12.0",
"jsdom-global": "^2.1.1",
"jsdom-url": "^2.2.1",
"jsverify": "^0.8.3",
"@peculiar/webcrypto": "^1.1.1"
"@peculiar/webcrypto": "^1.5.0",
"jsdom": "^26.0.0",
"jsdom-global": "^3.0.2",
"jsverify": "^0.8.3"
},
"scripts": {
"test": "mocha",

View file

@ -58,7 +58,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
*/
const purifyHtmlConfig = {
ALLOWED_URI_REGEXP: /^(?:(?:(?:f|ht)tps?|mailto|magnet):)/i,
SAFE_FOR_JQUERY: true,
USE_PROFILES: {
html: true
}
@ -592,6 +591,32 @@ jQuery.PrivateBin = (function($, RawDeflate) {
return expirationDate;
};
/**
* Convert Bytes to KiB/MiB/GiB
*
* @name Helper.formatBytes
* @function
*
* @param {number} bytes
* @return {string}
*/
me.formatBytes = function (bytes)
{
let result = '';
const kilobyte = 1024;
const decimalPoint = 2;
const sizes = [I18n._('B'), I18n._('KiB'), I18n._('MiB'), I18n._('GiB')];
const index = Math.floor(Math.log(bytes) / Math.log(kilobyte));
if (bytes > 0) {
result = parseFloat((bytes / Math.pow(kilobyte, index)).toFixed(decimalPoint)) + ' ' + sizes[index];
} else {
result = `0 ${I18n._('B')}`;
}
return result;
}
/**
* resets state, used for unit testing
*
@ -603,6 +628,17 @@ jQuery.PrivateBin = (function($, RawDeflate) {
baseUri = null;
};
/**
* check if bootstrap5 object detected
*
* @name Helper.isBootstrap5
* @returns {Boolean}
*/
me.isBootstrap5 = function ()
{
return typeof bootstrap !== 'undefined';
};
return me;
})();
@ -2294,26 +2330,19 @@ jQuery.PrivateBin = (function($, RawDeflate) {
me.requestLoadConfirmation = function()
{
const $loadconfirmmodal = $('#loadconfirmmodal');
if ($loadconfirmmodal.length > 0) {
const $loadconfirmOpenNow = $loadconfirmmodal.find('#loadconfirm-open-now');
$loadconfirmOpenNow.off('click.loadPaste');
$loadconfirmOpenNow.on('click.loadPaste', PasteDecrypter.run);
const $loadconfirmClose = $loadconfirmmodal.find('.close');
$loadconfirmClose.off('click.close');
$loadconfirmClose.on('click.close', Controller.newPaste);
if (typeof bootstrap !== 'undefined' && bootstrap.Tooltip.VERSION) {
(new bootstrap.Modal($loadconfirmmodal[0])).show();
} else {
$loadconfirmmodal.modal('show');
}
const $loadconfirmOpenNow = $loadconfirmmodal.find('#loadconfirm-open-now');
$loadconfirmOpenNow.off('click.loadPaste');
$loadconfirmOpenNow.on('click.loadPaste', PasteDecrypter.run);
const $loadconfirmClose = $loadconfirmmodal.find('.close');
$loadconfirmClose.off('click.close');
$loadconfirmClose.on('click.close', Controller.newPaste);
if (typeof bootstrap !== 'undefined' && bootstrap.Tooltip.VERSION) {
(new bootstrap.Modal($loadconfirmmodal[0])).show();
} else {
if (window.confirm(
I18n._('This secret message can only be displayed once. Would you like to see it now?')
)) {
PasteDecrypter.run();
} else {
Controller.newPaste();
}
$loadconfirmmodal.modal('show');
}
}
@ -2335,15 +2364,6 @@ jQuery.PrivateBin = (function($, RawDeflate) {
return;
}
// fallback to old method for page template
password = prompt(I18n._('Please enter the password for this paste:'), '');
if (password === null) {
throw 'password prompt canceled';
}
if (password.length === 0) {
// recurse…
return me.requestPassword();
}
PasteDecrypter.run();
};
@ -2537,11 +2557,18 @@ jQuery.PrivateBin = (function($, RawDeflate) {
// show preview
PasteViewer.setText($message.val());
if (AttachmentViewer.hasAttachmentData()) {
const attachment = AttachmentViewer.getAttachment();
AttachmentViewer.handleBlobAttachmentPreview(
AttachmentViewer.getAttachmentPreview(),
attachment[0], attachment[1]
);
const attachmentsData = AttachmentViewer.getAttachmentsData();
attachmentsData.forEach(attachmentData => {
const mimeType = AttachmentViewer.getAttachmentMimeType(attachmentData);
AttachmentViewer.handleBlobAttachmentPreview(
AttachmentViewer.getAttachmentPreview(),
attachmentData, mimeType
);
});
AttachmentViewer.showAttachment();
}
PasteViewer.run();
@ -2926,14 +2953,12 @@ jQuery.PrivateBin = (function($, RawDeflate) {
const AttachmentViewer = (function () {
const me = {};
let $attachmentLink,
$attachmentPreview,
let $attachmentPreview,
$attachment,
attachmentData,
file,
attachmentsData = [],
files,
$fileInput,
$dragAndDropFileName,
attachmentHasPreview = false,
$dragAndDropFileNames,
$dropzone;
/**
@ -2975,26 +3000,30 @@ jQuery.PrivateBin = (function($, RawDeflate) {
me.setAttachment = function(attachmentData, fileName)
{
// skip, if attachments got disabled
if (!$attachmentLink || !$attachmentPreview) return;
if (!$attachment || !$attachmentPreview) return;
// data URI format: data:[<mimeType>][;base64],<data>
const template = Model.getTemplate('attachment');
const attachmentLink = template.find('a');
// position in data URI string of where data begins
const base64Start = attachmentData.indexOf(',') + 1;
// position in data URI string of where mimeType ends
const mimeTypeEnd = attachmentData.indexOf(';');
// extract mimeType
const mimeType = attachmentData.substring(5, mimeTypeEnd);
const mimeType = me.getAttachmentMimeType(attachmentData);
// extract data and convert to binary
const rawData = attachmentData.substring(base64Start);
const decodedData = rawData.length > 0 ? atob(rawData) : '';
let blobUrl = getBlobUrl(decodedData, mimeType);
$attachmentLink.attr('href', blobUrl);
attachmentLink.attr('href', blobUrl);
if (typeof fileName !== 'undefined') {
$attachmentLink.attr('download', fileName);
attachmentLink.attr('download', fileName);
const fileSize = Helper.formatBytes(decodedData.length);
template.append(`(${fileName}, ${fileSize})`);
}
// sanitize SVG preview
@ -3009,6 +3038,9 @@ jQuery.PrivateBin = (function($, RawDeflate) {
blobUrl = getBlobUrl(sanitizedData, mimeType);
}
template.removeClass('hidden');
$attachment.append(template);
me.handleBlobAttachmentPreview($attachmentPreview, blobUrl, mimeType);
};
@ -3025,7 +3057,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
$attachment.removeClass('hidden');
if (attachmentHasPreview) {
if (me.hasAttachmentPreview()) {
$attachmentPreview.removeClass('hidden');
}
};
@ -3046,11 +3078,9 @@ jQuery.PrivateBin = (function($, RawDeflate) {
}
me.hideAttachment();
me.hideAttachmentPreview();
$attachmentLink.removeAttr('href');
$attachmentLink.removeAttr('download');
$attachmentLink.off('click');
$attachment.html('');
$attachmentPreview.html('');
$dragAndDropFileName.text('');
$dragAndDropFileNames.html('');
AttachmentViewer.removeAttachmentData();
};
@ -3065,8 +3095,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
*/
me.removeAttachmentData = function()
{
file = undefined;
attachmentData = undefined;
files = undefined;
attachmentsData = [];
};
/**
@ -3077,9 +3107,21 @@ jQuery.PrivateBin = (function($, RawDeflate) {
*/
me.clearDragAndDrop = function()
{
$dragAndDropFileName.text('');
$dragAndDropFileNames.html('');
};
/**
* Print file names added via drag & drop
*
* @name AttachmentViewer.printDragAndDropFileNames
* @private
* @function
* @param {array} fileNames
*/
function printDragAndDropFileNames(fileNames) {
$dragAndDropFileNames.html(fileNames.join("<br>"));
}
/**
* hides the attachment
*
@ -3108,6 +3150,18 @@ jQuery.PrivateBin = (function($, RawDeflate) {
}
};
/**
* checks if has any attachment preview
*
* @name AttachmentViewer.hasAttachmentPreview
* @function
* @return {JQuery}
*/
me.hasAttachmentPreview = function()
{
return $attachmentPreview.children().length > 0;
}
/**
* checks if there is an attachment displayed
*
@ -3119,8 +3173,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
if (!$attachment.length) {
return false;
}
const link = $attachmentLink.prop('href');
return (typeof link !== 'undefined' && link !== '');
return [...$attachment.children()].length > 0;
};
/**
@ -3140,20 +3193,38 @@ jQuery.PrivateBin = (function($, RawDeflate) {
};
/**
* return the attachment
* return the attachments
*
* @name AttachmentViewer.getAttachment
* @name AttachmentViewer.getAttachments
* @function
* @returns {array}
*/
me.getAttachment = function()
me.getAttachments = function()
{
return [
$attachmentLink.prop('href'),
$attachmentLink.prop('download')
];
return [...$attachment.find('a')].map(link => (
[
$(link).prop('href'),
$(link).prop('download')
]
));
};
/**
* Get attachment mime type
*
* @name AttachmentViewer.getAttachmentMimeType
* @function
* @param {string} attachmentData - Base64 string
*/
me.getAttachmentMimeType = function(attachmentData)
{
// position in data URI string of where mimeType ends
const mimeTypeEnd = attachmentData.indexOf(';');
// extract mimeType
return attachmentData.substring(5, mimeTypeEnd);
}
/**
* moves the attachment link to another element
*
@ -3162,27 +3233,36 @@ jQuery.PrivateBin = (function($, RawDeflate) {
* @name AttachmentViewer.moveAttachmentTo
* @function
* @param {jQuery} $element - the wrapper/container element where this should be moved to
* @param {array} attachment - attachment data
* @param {string} label - the text to show (%s will be replaced with the file name), will automatically be translated
*/
me.moveAttachmentTo = function($element, label)
me.moveAttachmentTo = function($element, attachment, label)
{
const attachmentLink = $(document.createElement('a'))
.addClass('alert-link')
.prop('href', attachment[0])
.prop('download', attachment[1]);
// move elemement to new place
$attachmentLink.appendTo($element);
attachmentLink.appendTo($element);
// update text - ensuring no HTML is inserted into the text node
I18n._($attachmentLink, label, $attachmentLink.attr('download'));
I18n._(attachmentLink, label, attachment[1]);
};
/**
* read file data as data URL using the FileReader API
* read files data as data URL using the FileReader API
*
* @name AttachmentViewer.readFileData
* @private
* @function
* @param {object} loadedFile (optional) loaded file object
* @param {FileList[]} loadedFiles (optional) loaded files array
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/FileReader#readAsDataURL()}
*/
function readFileData(loadedFile) {
function readFileData(loadedFiles) {
// Clear old cache
me.removeAttachmentData();
if (typeof FileReader === 'undefined') {
// revert loading status…
me.hideAttachment();
@ -3191,28 +3271,35 @@ jQuery.PrivateBin = (function($, RawDeflate) {
return;
}
const fileReader = new FileReader();
if (loadedFile === undefined) {
loadedFile = $fileInput[0].files[0];
$dragAndDropFileName.text('');
if (loadedFiles === undefined) {
loadedFiles = [...$fileInput[0].files];
me.clearDragAndDrop();
} else {
$dragAndDropFileName.text(loadedFile.name);
const fileNames = loadedFiles.map((loadedFile => loadedFile.name));
printDragAndDropFileNames(fileNames);
}
if (typeof loadedFile !== 'undefined') {
file = loadedFile;
fileReader.onload = function (event) {
const dataURL = event.target.result;
attachmentData = dataURL;
if (typeof loadedFiles !== 'undefined') {
files = loadedFiles;
loadedFiles.forEach((loadedFile, index) => {
const fileReader = new FileReader();
if (Editor.isPreview()) {
me.handleAttachmentPreview($attachmentPreview, dataURL);
$attachmentPreview.removeClass('hidden');
}
fileReader.onload = function (event) {
const dataURL = event.target.result;
if (dataURL) {
attachmentsData[index] = dataURL;
}
TopNav.highlightFileupload();
};
fileReader.readAsDataURL(loadedFile);
if (Editor.isPreview()) {
me.handleAttachmentPreview($attachmentPreview, dataURL);
$attachmentPreview.removeClass('hidden');
}
TopNav.highlightFileupload();
};
fileReader.readAsDataURL(loadedFile);
});
} else {
me.removeAttachmentData();
}
@ -3228,16 +3315,17 @@ jQuery.PrivateBin = (function($, RawDeflate) {
* @argument {string} mime type
*/
me.handleBlobAttachmentPreview = function ($targetElement, blobUrl, mimeType) {
if (blobUrl) {
attachmentHasPreview = true;
const alreadyIncludesCurrentAttachment = $targetElement.find(`[src='${blobUrl}']`).length > 0;
if (blobUrl && !alreadyIncludesCurrentAttachment) {
if (mimeType.match(/^image\//i)) {
$targetElement.html(
$targetElement.append(
$(document.createElement('img'))
.attr('src', blobUrl)
.attr('class', 'img-thumbnail')
);
} else if (mimeType.match(/^video\//i)) {
$targetElement.html(
$targetElement.append(
$(document.createElement('video'))
.attr('controls', 'true')
.attr('autoplay', 'true')
@ -3248,7 +3336,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
.attr('src', blobUrl))
);
} else if (mimeType.match(/^audio\//i)) {
$targetElement.html(
$targetElement.append(
$(document.createElement('audio'))
.attr('controls', 'true')
.attr('autoplay', 'true')
@ -3261,15 +3349,13 @@ jQuery.PrivateBin = (function($, RawDeflate) {
// Fallback for browsers, that don't support the vh unit
const clientHeight = $(window).height();
$targetElement.html(
$targetElement.append(
$(document.createElement('embed'))
.attr('src', blobUrl)
.attr('type', 'application/pdf')
.attr('class', 'pdfPreview')
.css('height', clientHeight)
);
} else {
attachmentHasPreview = false;
}
}
};
@ -3302,14 +3388,14 @@ jQuery.PrivateBin = (function($, RawDeflate) {
}
if ($fileInput) {
const file = evt.dataTransfer.files[0];
const files = [...evt.dataTransfer.files];
//Clear the file input:
$fileInput.wrap('<form>').closest('form').get(0).reset();
$fileInput.unwrap();
//Only works in Chrome:
//fileInput[0].files = e.dataTransfer.files;
readFileData(file);
readFileData(files);
}
};
@ -3346,16 +3432,17 @@ jQuery.PrivateBin = (function($, RawDeflate) {
function addClipboardEventHandler() {
$(document).on('paste', function (event) {
const items = (event.clipboardData || event.originalEvent.clipboardData).items;
const lastItem = items[items.length - 1];
if (lastItem.kind === 'file') {
if (TopNav.isAttachmentReadonly()) {
event.stopPropagation();
event.preventDefault();
return false;
} else {
readFileData(lastItem.getAsFile());
}
const files = [...items]
.filter(item => item.kind === 'file')
.map(item => item.getAsFile());
if (TopNav.isAttachmentReadonly()) {
event.stopPropagation();
event.preventDefault();
return false;
}
readFileData(files);
});
}
@ -3363,23 +3450,12 @@ jQuery.PrivateBin = (function($, RawDeflate) {
/**
* getter for attachment data
*
* @name AttachmentViewer.getAttachmentData
* @name AttachmentViewer.getAttachmentsData
* @function
* @return {jQuery}
* @return {string[]}
*/
me.getAttachmentData = function () {
return attachmentData;
};
/**
* getter for attachment link
*
* @name AttachmentViewer.getAttachmentLink
* @function
* @return {jQuery}
*/
me.getAttachmentLink = function () {
return $attachmentLink;
me.getAttachmentsData = function () {
return attachmentsData;
};
/**
@ -3394,14 +3470,14 @@ jQuery.PrivateBin = (function($, RawDeflate) {
};
/**
* getter for file data, returns the file contents
* getter for files data, returns the file list
*
* @name AttachmentViewer.getFile
* @name AttachmentViewer.getFiles
* @function
* @return {string}
* @return {FileList[]}
*/
me.getFile = function () {
return file;
me.getFiles = function () {
return files;
};
/**
@ -3415,9 +3491,8 @@ jQuery.PrivateBin = (function($, RawDeflate) {
me.init = function()
{
$attachment = $('#attachment');
$dragAndDropFileName = $('#dragAndDropFileName');
$dragAndDropFileNames = $('#dragAndDropFileName');
$dropzone = $('#dropzone');
$attachmentLink = $('#attachment a') || $('<a>');
if($attachment.length) {
$attachmentPreview = $('#attachmentPreview');
@ -3478,6 +3553,12 @@ jQuery.PrivateBin = (function($, RawDeflate) {
{
const $source = $(event.target);
// show all reply buttons
$commentContainer.find('button').removeClass('hidden');
// hide the current reply button
$source.addClass('hidden');
// clear input
$replyMessage.val('');
$replyNickname.val('');
@ -3933,7 +4014,26 @@ jQuery.PrivateBin = (function($, RawDeflate) {
*/
function setLanguage(event)
{
document.cookie = 'lang=' + $(event.target).data('lang') + '; SameSite=Lax; Secure';
let lang = $(event.target).data('lang') || event.target.value;
document.cookie = 'lang=' + lang + '; SameSite=Lax; Secure';
window.location.reload();
event.preventDefault();
}
/**
* save the template in a cookie and reloads the page
*
* @name TopNav.setTemplate
* @private
* @function
* @param {Event} event
*/
function setTemplate(event)
{
let template = $(event.target).data('template') || event.target.value;
document.cookie = 'template=' + template + '; SameSite=Lax; Secure';
window.location.reload();
event.preventDefault();
}
@ -4089,59 +4189,42 @@ jQuery.PrivateBin = (function($, RawDeflate) {
expirationDateRoundedToSecond.setUTCSeconds(0);
const $emailconfirmmodal = $('#emailconfirmmodal');
if ($emailconfirmmodal.length > 0) {
if (expirationDate !== null) {
const $emailconfirmTimezoneCurrent = $emailconfirmmodal.find('#emailconfirm-timezone-current');
const $emailconfirmTimezoneUtc = $emailconfirmmodal.find('#emailconfirm-timezone-utc');
let localeConfiguration = { dateStyle: 'long', timeStyle: 'long' };
const bootstrap5EmailConfirmModal = typeof bootstrap !== 'undefined' && bootstrap.Tooltip.VERSION ?
new bootstrap.Modal($emailconfirmmodal[0]) : null;
if (expirationDate !== null) {
const $emailconfirmTimezoneCurrent = $emailconfirmmodal.find('#emailconfirm-timezone-current');
const $emailconfirmTimezoneUtc = $emailconfirmmodal.find('#emailconfirm-timezone-utc');
let localeConfiguration = { dateStyle: 'long', timeStyle: 'long' };
const bootstrap5EmailConfirmModal = typeof bootstrap !== 'undefined' && bootstrap.Tooltip.VERSION ?
new bootstrap.Modal($emailconfirmmodal[0]) : null;
function sendEmailAndHideModal() {
const emailBody = templateEmailBody(
// we don't use Date.prototype.toUTCString() because we would like to avoid GMT
expirationDateRoundedToSecond.toLocaleString(
[], localeConfiguration
), isBurnafterreading
);
if (bootstrap5EmailConfirmModal) {
bootstrap5EmailConfirmModal.hide();
} else {
$emailconfirmmodal.modal('hide');
}
triggerEmailSend(emailBody);
};
$emailconfirmTimezoneCurrent.off('click.sendEmailCurrentTimezone');
$emailconfirmTimezoneCurrent.on('click.sendEmailCurrentTimezone', sendEmailAndHideModal);
$emailconfirmTimezoneUtc.off('click.sendEmailUtcTimezone');
$emailconfirmTimezoneUtc.on('click.sendEmailUtcTimezone', () => {
localeConfiguration.timeZone = 'UTC';
sendEmailAndHideModal();
});
function sendEmailAndHideModal() {
const emailBody = templateEmailBody(
// we don't use Date.prototype.toUTCString() because we would like to avoid GMT
expirationDateRoundedToSecond.toLocaleString(
[], localeConfiguration
), isBurnafterreading
);
if (bootstrap5EmailConfirmModal) {
bootstrap5EmailConfirmModal.show();
bootstrap5EmailConfirmModal.hide();
} else {
$emailconfirmmodal.modal('show');
$emailconfirmmodal.modal('hide');
}
triggerEmailSend(emailBody);
};
$emailconfirmTimezoneCurrent.off('click.sendEmailCurrentTimezone');
$emailconfirmTimezoneCurrent.on('click.sendEmailCurrentTimezone', sendEmailAndHideModal);
$emailconfirmTimezoneUtc.off('click.sendEmailUtcTimezone');
$emailconfirmTimezoneUtc.on('click.sendEmailUtcTimezone', () => {
localeConfiguration.timeZone = 'UTC';
sendEmailAndHideModal();
});
if (bootstrap5EmailConfirmModal) {
bootstrap5EmailConfirmModal.show();
} else {
triggerEmailSend(templateEmailBody(null, isBurnafterreading));
$emailconfirmmodal.modal('show');
}
} else {
let emailBody = '';
if (expirationDate !== null) {
const expirationDateString = window.confirm(
I18n._('Recipient may become aware of your timezone, convert time to UTC?')
) ? expirationDateRoundedToSecond.toLocaleString(
undefined,
// we don't use Date.prototype.toUTCString() because we would like to avoid GMT
{ timeZone: 'UTC', dateStyle: 'long', timeStyle: 'long' }
) : expirationDateRoundedToSecond.toLocaleString();
emailBody = templateEmailBody(expirationDateString, isBurnafterreading);
} else {
emailBody = templateEmailBody(null, isBurnafterreading);
}
triggerEmailSend(emailBody);
triggerEmailSend(templateEmailBody(null, isBurnafterreading));
}
}
@ -4560,7 +4643,11 @@ jQuery.PrivateBin = (function($, RawDeflate) {
// visually indicate file uploaded
const $attachDropdownToggle = $attach.children('.dropdown-toggle');
if ($attachDropdownToggle.attr('aria-expanded') === 'false') {
$attachDropdownToggle.click();
if (Helper.isBootstrap5()) {
new bootstrap.Dropdown($attachDropdownToggle).toggle();
} else {
$attachDropdownToggle.click();
}
}
$fileWrap.addClass('highlight');
setTimeout(function () {
@ -4624,8 +4711,9 @@ jQuery.PrivateBin = (function($, RawDeflate) {
// bootstrap template drop down
$('#language ul.dropdown-menu li a').click(setLanguage);
// page template drop down
$('#language select option').click(setLanguage);
// bootstrap template drop down
$('#template ul.dropdown-menu li a').click(setTemplate);
// bind events
$burnAfterReading.change(changeBurnAfterReading);
@ -4704,7 +4792,10 @@ jQuery.PrivateBin = (function($, RawDeflate) {
* @readonly
* @enum {Object}
*/
const ajaxHeaders = {'X-Requested-With': 'JSONHttpRequest'};
const ajaxHeaders = {
'X-Requested-With': 'JSONHttpRequest',
'Content-Type': 'application/json'
};
/**
* called after successful upload
@ -5106,7 +5197,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
const plainText = Editor.getText(),
format = PasteViewer.getFormat(),
// the methods may return different values if no files are attached (null, undefined or false)
files = TopNav.getFileList() || AttachmentViewer.getFile() || AttachmentViewer.hasAttachment();
files = TopNav.getFileList() || AttachmentViewer.getFiles() || AttachmentViewer.hasAttachment();
// do not send if there is no data
if (plainText.length === 0 && !files) {
@ -5146,62 +5237,64 @@ jQuery.PrivateBin = (function($, RawDeflate) {
PasteViewer.setFormat(format);
// prepare cypher message
let file = AttachmentViewer.getAttachmentData(),
let attachmentsData = AttachmentViewer.getAttachmentsData(),
cipherMessage = {
'paste': plainText
};
if (typeof file !== 'undefined' && file !== null) {
cipherMessage['attachment'] = file;
cipherMessage['attachment_name'] = AttachmentViewer.getFile().name;
if (attachmentsData.length) {
cipherMessage['attachment'] = attachmentsData;
cipherMessage['attachment_name'] = AttachmentViewer.getFiles().map((fileInfo => fileInfo.name));
} else if (AttachmentViewer.hasAttachment()) {
// fall back to cloned part
let attachment = AttachmentViewer.getAttachment();
cipherMessage['attachment'] = attachment[0];
cipherMessage['attachment_name'] = attachment[1];
let attachments = AttachmentViewer.getAttachments();
cipherMessage['attachment'] = attachments.map(attachment => attachment[0]);
cipherMessage['attachment_name'] = attachments.map(attachment => attachment[1]);
// we need to retrieve data from blob if browser already parsed it in memory
if (typeof attachment[0] === 'string' && attachment[0].startsWith('blob:')) {
Alert.showStatus(
[
'Retrieving cloned file \'%s\' from memory...',
attachment[1]
],
'copy'
);
try {
const blobData = await $.ajax({
type: 'GET',
url: `${attachment[0]}`,
processData: false,
timeout: 10000,
xhrFields: {
withCredentials: false,
responseType: 'blob'
}
});
if (blobData instanceof window.Blob) {
const fileReading = new Promise(function(resolve, reject) {
const fileReader = new FileReader();
fileReader.onload = function (event) {
resolve(event.target.result);
};
fileReader.onerror = function (error) {
reject(error);
cipherMessage['attachment'] = await Promise.all(cipherMessage['attachment'].map(async (attachment) => {
// we need to retrieve data from blob if browser already parsed it in memory
if (typeof attachment === 'string' && attachment.startsWith('blob:')) {
Alert.showStatus(
[
'Retrieving cloned file \'%s\' from memory...',
attachment[1]
],
'copy'
);
try {
const blobData = await $.ajax({
type: 'GET',
url: `${attachment}`,
processData: false,
timeout: 10000,
xhrFields: {
withCredentials: false,
responseType: 'blob'
}
fileReader.readAsDataURL(blobData);
});
cipherMessage['attachment'] = await fileReading;
} else {
const error = 'Cannot process attachment data.';
Alert.showError(error);
throw new TypeError(error);
if (blobData instanceof window.Blob) {
const fileReading = new Promise(function(resolve, reject) {
const fileReader = new FileReader();
fileReader.onload = function (event) {
resolve(event.target.result);
};
fileReader.onerror = function (error) {
reject(error);
}
fileReader.readAsDataURL(blobData);
});
return await fileReading;
} else {
const error = 'Cannot process attachment data.';
Alert.showError(error);
throw new TypeError(error);
}
} catch (error) {
Alert.showError('Cannot retrieve attachment.');
throw error;
}
} catch (error) {
console.error(error);
Alert.showError('Cannot retrieve attachment.');
throw error;
}
}
}));
}
// encrypt message
@ -5296,7 +5389,15 @@ jQuery.PrivateBin = (function($, RawDeflate) {
// version 2 paste
const pasteMessage = JSON.parse(pastePlain);
if (pasteMessage.hasOwnProperty('attachment') && pasteMessage.hasOwnProperty('attachment_name')) {
AttachmentViewer.setAttachment(pasteMessage.attachment, pasteMessage.attachment_name);
if (Array.isArray(pasteMessage.attachment) && Array.isArray(pasteMessage.attachment_name)) {
pasteMessage.attachment.forEach((attachment, key) => {
const attachment_name = pasteMessage.attachment_name[key];
AttachmentViewer.setAttachment(attachment, attachment_name);
});
} else {
// Continue to process attachment parameters as strings to ensure backward compatibility
AttachmentViewer.setAttachment(pasteMessage.attachment, pasteMessage.attachment_name);
}
AttachmentViewer.showAttachment();
}
pastePlain = pasteMessage.paste;
@ -5387,6 +5488,7 @@ jQuery.PrivateBin = (function($, RawDeflate) {
me.run = function(paste)
{
Alert.hideMessages();
Alert.setCustomHandler(null);
Alert.showLoading('Decrypting paste…', 'cloud-download');
if (typeof paste === 'undefined' || paste.type === 'click') {
@ -5404,6 +5506,9 @@ jQuery.PrivateBin = (function($, RawDeflate) {
me.run(paste);
});
// Clear attachments to prevent duplicates
AttachmentViewer.removeAttachment();
// decrypt paste & attachments
decryptionPromises.push(decryptPaste(paste, key, password));
@ -5778,10 +5883,14 @@ jQuery.PrivateBin = (function($, RawDeflate) {
history.pushState({type: 'clone'}, document.title, Helper.baseUri());
if (AttachmentViewer.hasAttachment()) {
AttachmentViewer.moveAttachmentTo(
TopNav.getCustomAttachment(),
'Cloned: \'%s\''
);
const attachments = AttachmentViewer.getAttachments();
attachments.forEach(attachment => {
AttachmentViewer.moveAttachmentTo(
TopNav.getCustomAttachment(),
attachment,
'Cloned: \'%s\''
);
});
TopNav.hideFileSelector();
AttachmentViewer.hideAttachment();
// NOTE: it also looks nice without removing the attachment
@ -5789,12 +5898,12 @@ jQuery.PrivateBin = (function($, RawDeflate) {
AttachmentViewer.hideAttachmentPreview();
TopNav.showCustomAttachment();
// show another status message to make the user aware that the
// file was cloned too!
// show another status messages to make the user aware that the
// files were cloned too!
Alert.showStatus(
[
'The cloned file \'%s\' was attached to this paste.',
AttachmentViewer.getAttachment()[1]
attachments.map(attachment => attachment[1]).join(', '),
],
'copy'
);

File diff suppressed because one or more lines are too long

2
js/purify-3.2.6.js Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,5 +1,5 @@
'use strict';
var common = require('../common');
const common = require('../common');
describe('AttachmentViewer', function () {
describe('setAttachment, showAttachment, removeAttachment, hideAttachment, hideAttachmentPreview, hasAttachment, getAttachment & moveAttachmentTo', function () {
@ -14,11 +14,12 @@ describe('AttachmentViewer', function () {
'string',
function (mimeType, rawdata, filename, prefix, postfix) {
let clean = jsdom(),
data = 'data:' + mimeType + ';base64,' + btoa(rawdata),
data = 'data:' + mimeType + ';base64,' + common.btoa(rawdata),
mimePrefix = mimeType.substring(0, 6),
previewSupported = (
mimeType.substring(0, 6) === 'image/' ||
mimeType.substring(0, 6) === 'audio/' ||
mimeType.substring(0, 6) === 'video/' ||
mimePrefix === 'image/' ||
mimePrefix === 'audio/' ||
mimePrefix === 'video/' ||
mimeType.match(/\/pdf/i)
),
results = [],
@ -26,11 +27,14 @@ describe('AttachmentViewer', function () {
prefix = prefix.replace(/%(s|d)/g, '%%');
postfix = postfix.replace(/%(s|d)/g, '%%');
$('body').html(
'<div id="attachment" role="alert" class="hidden alert ' +
'alert-info"><span class="glyphicon glyphicon-download-' +
'alt" aria-hidden="true"></span> <a class="alert-link">' +
'Download attachment</a></div><div id="attachmentPrevie' +
'w" class="hidden"></div>'
'<div id="attachmentPreview" class="col-md-12 text-center hidden"></div>' +
'<div id="attachment" class="hidden"></div>' +
'<div id="templates">' +
'<div id="attachmenttemplate" role="alert" class="attachment hidden alert alert-info">' +
'<span class="glyphicon glyphicon-download-alt" aria-hidden="true"></span>' +
'<a class="alert-link">Download attachment</a>' +
'</div>' +
'</div>'
);
// mock createObjectURL for jsDOM
if (typeof window.URL.createObjectURL === 'undefined') {
@ -43,29 +47,35 @@ describe('AttachmentViewer', function () {
)
}
$.PrivateBin.AttachmentViewer.init();
$.PrivateBin.Model.init();
results.push(
!$.PrivateBin.AttachmentViewer.hasAttachment() &&
$('#attachment').hasClass('hidden') &&
$('#attachment').children().length === 0 &&
$('#attachmenttemplate').hasClass('hidden') &&
$('#attachmentPreview').hasClass('hidden')
);
global.atob = common.atob;
if (filename.length) {
$.PrivateBin.AttachmentViewer.setAttachment(data, filename);
} else {
$.PrivateBin.AttachmentViewer.setAttachment(data);
}
// beyond this point we will get the blob URL instead of the data
// // beyond this point we will get the blob URL instead of the data
data = window.URL.createObjectURL(data);
const attachment = $.PrivateBin.AttachmentViewer.getAttachment();
const attachment = $.PrivateBin.AttachmentViewer.getAttachments();
results.push(
$.PrivateBin.AttachmentViewer.hasAttachment() &&
$('#attachment').hasClass('hidden') &&
$('#attachment').children().length > 0 &&
$('#attachmentPreview').hasClass('hidden') &&
attachment[0] === data &&
attachment[1] === filename
attachment[0][0] === data &&
attachment[0][1] === filename
);
$.PrivateBin.AttachmentViewer.showAttachment();
results.push(
!$('#attachment').hasClass('hidden') &&
$('#attachment').children().length > 0 &&
(previewSupported ? !$('#attachmentPreview').hasClass('hidden') : $('#attachmentPreview').hasClass('hidden'))
);
$.PrivateBin.AttachmentViewer.hideAttachment();
@ -83,7 +93,7 @@ describe('AttachmentViewer', function () {
(previewSupported ? !$('#attachmentPreview').hasClass('hidden') : $('#attachmentPreview').hasClass('hidden'))
);
let element = $('<div>');
$.PrivateBin.AttachmentViewer.moveAttachmentTo(element, prefix + '%s' + postfix);
$.PrivateBin.AttachmentViewer.moveAttachmentTo(element, attachment[0], prefix + '%s' + postfix);
// messageIDs with links get a relaxed treatment
if (prefix.indexOf('<a') === -1 && postfix.indexOf('<a') === -1) {
result = $('<textarea>').text((prefix + filename + postfix)).text();
@ -97,16 +107,17 @@ describe('AttachmentViewer', function () {
}
if (filename.length) {
results.push(
element.children()[0].href === data &&
element.children()[0].getAttribute('download') === filename &&
element.children()[0].text === result
element.find('a')[0].href === data &&
element.find('a')[0].getAttribute('download') === filename &&
element.find('a')[0].text === result
);
} else {
results.push(element.children()[0].href === data);
results.push(element.find('a')[0].href === data);
}
$.PrivateBin.AttachmentViewer.removeAttachment();
results.push(
$('#attachment').hasClass('hidden') &&
$('#attachment').children().length === 0 &&
$('#attachmentPreview').hasClass('hidden')
);
clean();

View file

@ -19,10 +19,9 @@ describe('Check', function () {
}
);
Legacy.Check.init();
const result1 = Legacy.Check.getInit() && !Legacy.Check.getStatus(),
result2 = (document.getElementById('errormessage').className !== 'hidden');
const result = Legacy.Check.getInit() && !Legacy.Check.getStatus();
clean();
return result1 && result2;
return result;
}
),
{tests: 10});
@ -67,7 +66,10 @@ describe('Check', function () {
'url': (secureProtocol ? 'https' : 'http' ) + '://' + domain.join('') + '/'
}
);
window.crypto = new WebCrypto();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false,
});
Legacy.Check.init();
const result1 = Legacy.Check.getInit() && Legacy.Check.getStatus(),
result2 = secureProtocol === (document.getElementById('httpnotice').className === 'hidden');

View file

@ -4,120 +4,136 @@ const common = require('../common');
describe('CopyToClipboard', function() {
this.timeout(30000);
describe ('Copy paste co clipboard', function () {
jsc.property('Copy with button click', common.jscFormats(), 'nestring', async function (format, text) {
var clean = jsdom();
common.enableClipboard();
$('body').html(
'<div id="placeholder" class="hidden">+++ no paste text ' +
'+++</div><div id="prettymessage" class="hidden">' +
'<button type="button" id="prettyMessageCopyBtn"><svg id="copyIcon"></svg>' +
'<svg id="copySuccessIcon"></svg></button><pre ' +
'id="prettyprint" class="prettyprint linenums:1"></pre>' +
'</div><div id="plaintext" class="hidden"></div>'
);
$.PrivateBin.PasteViewer.init();
$.PrivateBin.PasteViewer.setFormat(format);
$.PrivateBin.PasteViewer.setText(text);
$.PrivateBin.PasteViewer.run();
$.PrivateBin.CopyToClipboard.init();
$('#prettyMessageCopyBtn').trigger('click');
describe ('Copy paste to clipboard', function () {
jsc.property('Copy with button click',
common.jscFormats(),
'nestring',
async function (format, text) {
var clean = jsdom();
common.enableClipboard();
const savedToClipboardText = await navigator.clipboard.readText();
clean();
return text === savedToClipboardText;
});
$('body').html(
'<div id="placeholder" class="hidden">+++ no paste text ' +
'+++</div><div id="prettymessage" class="hidden">' +
'<button type="button" id="prettyMessageCopyBtn"><svg id="copyIcon"></svg>' +
'<svg id="copySuccessIcon"></svg></button><pre ' +
'id="prettyprint" class="prettyprint linenums:1"></pre>' +
'</div><div id="plaintext" class="hidden"></div>'
);
$.PrivateBin.PasteViewer.init();
$.PrivateBin.PasteViewer.setFormat(format);
$.PrivateBin.PasteViewer.setText(text);
$.PrivateBin.PasteViewer.run();
$.PrivateBin.CopyToClipboard.init();
$('#prettyMessageCopyBtn').trigger('click');
const savedToClipboardText = await navigator.clipboard.readText();
clean();
return text === savedToClipboardText;
}
);
/**
* Unfortunately in JSVerify impossible to check if copy with shortcut when user selected some text on the page
* (the copy paste to clipboard should not work in this case) due to lucking window.getSelection() in jsdom.
* (the copy paste to clipboard should not work in this case) due to lacking window.getSelection() in jsdom.
*/
jsc.property('Copy with keyboard shortcut', common.jscFormats(), 'nestring', async function (format, text) {
jsc.property('Copy with keyboard shortcut',
common.jscFormats(),
'nestring',
async function (format, text) {
var clean = jsdom();
common.enableClipboard();
$('body').html(
'<div id="placeholder">+++ no paste text ' +
'+++</div><div id="prettymessage" class="hidden">' +
'<button type="button" id="prettyMessageCopyBtn"><svg id="copyIcon"></svg>' +
'<svg id="copySuccessIcon"></svg></button><pre ' +
'id="prettyprint" class="prettyprint linenums:1"></pre>' +
'</div><div id="plaintext" class="hidden"></div>'
);
$.PrivateBin.PasteViewer.init();
$.PrivateBin.PasteViewer.setFormat(format);
$.PrivateBin.PasteViewer.setText(text);
$.PrivateBin.PasteViewer.run();
$.PrivateBin.CopyToClipboard.init();
$('body').trigger('copy');
const copiedTextWithoutSelectedText = await navigator.clipboard.readText();
clean();
return copiedTextWithoutSelectedText === text;
}
);
});
jsc.property('Copy link to clipboard',
'nestring',
async function (text) {
var clean = jsdom();
common.enableClipboard();
$('body').html(
'<div id="placeholder">+++ no paste text ' +
'+++</div><div id="prettymessage" class="hidden">' +
'<button type="button" id="prettyMessageCopyBtn"><svg id="copyIcon"></svg>' +
'<svg id="copySuccessIcon"></svg></button><pre ' +
'id="prettyprint" class="prettyprint linenums:1"></pre>' +
'</div><div id="plaintext" class="hidden"></div>'
);
$.PrivateBin.PasteViewer.init();
$.PrivateBin.PasteViewer.setFormat(format);
$.PrivateBin.PasteViewer.setText(text);
$.PrivateBin.PasteViewer.run();
$('body').html('<button id="copyLink"></button>');
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.setUrl(text);
$('body').trigger('copy');
$('#copyLink').trigger('click');
const copiedTextWithoutSelectedText = await navigator.clipboard.readText();
const copiedText = await navigator.clipboard.readText();
clean();
return copiedTextWithoutSelectedText === text;
});
});
jsc.property('Copy link to clipboard', 'nestring', async function (text) {
var clean = jsdom();
common.enableClipboard();
$('body').html('<button id="copyLink"></button>');
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.setUrl(text);
$('#copyLink').trigger('click');
const copiedText = await navigator.clipboard.readText();
clean();
return text === copiedText;
});
return text === copiedText;
}
);
describe('Keyboard shortcut hint', function () {
jsc.property('Show hint', 'nestring', function (text) {
var clean = jsdom();
$('body').html('<small id="copyShortcutHintText"></small>');
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.showKeyboardShortcutHint();
const keyboardShortcutHint = $('#copyShortcutHintText').text();
clean();
return keyboardShortcutHint.length > 0;
});
jsc.property('Show hint',
'nestring',
function (text) {
var clean = jsdom();
jsc.property('Hide hint', 'nestring', function (text) {
var clean = jsdom();
$('body').html('<small id="copyShortcutHintText">' + text + '</small>');
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.hideKeyboardShortcutHint();
const keyboardShortcutHint = $('#copyShortcutHintText').text();
clean();
return keyboardShortcutHint.length === 0;
});
$('body').html('<small id="copyShortcutHintText"></small>');
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.showKeyboardShortcutHint();
const keyboardShortcutHint = $('#copyShortcutHintText').text();
clean();
return keyboardShortcutHint.length > 0;
}
);
jsc.property('Hide hint',
'nestring',
function (text) {
var clean = jsdom();
$('body').html('<small id="copyShortcutHintText">' + text + '</small>');
$.PrivateBin.CopyToClipboard.init();
$.PrivateBin.CopyToClipboard.hideKeyboardShortcutHint();
const keyboardShortcutHint = $('#copyShortcutHintText').text();
clean();
return keyboardShortcutHint.length === 0;
}
);
});
});

View file

@ -1,5 +1,5 @@
'use strict';
require('../common');
const common = require('../common');
describe('CryptTool', function () {
describe('cipher & decipher', function () {
@ -15,21 +15,26 @@ describe('CryptTool', function () {
'string',
'string',
async function (key, password, message) {
// pause to let async functions conclude
await new Promise(resolve => setTimeout(resolve, 300));
let clean = jsdom();
const clean = jsdom();
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
window.crypto = new WebCrypto();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false,
});
global.atob = common.atob;
global.btoa = common.btoa;
message = message.trim();
let cipherMessage = await $.PrivateBin.CryptTool.cipher(
const cipherMessage = await $.PrivateBin.CryptTool.cipher(
key, password, message, []
),
plaintext = await $.PrivateBin.CryptTool.decipher(
key, password, cipherMessage
);
clean();
return message === plaintext;
const result = (message === plaintext);
if (!result) console.log(plaintext, cipherMessage);
return result;
}
),
{tests: 3});
@ -38,15 +43,19 @@ describe('CryptTool', function () {
// The below static unit tests are included to ensure deciphering of "classic"
// SJCL based pastes still works
it(
'supports PrivateBin v1 ciphertext (SJCL & browser atob)',
function () {
'supports PrivateBin v1 ciphertext with password (SJCL & browser atob)',
async function () {
delete global.Base64;
let clean = jsdom();
window.crypto = new WebCrypto();
const clean = jsdom();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false,
});
global.atob = common.atob;
// Of course you can easily decipher the following texts, if you like.
// Bonus points for finding their sources and hidden meanings.
return $.PrivateBin.CryptTool.decipher(
const paste = await $.PrivateBin.CryptTool.decipher(
'6t2qsmLyfXIokNCL+3/yl15rfTUBQvm5SOnFPvNE7Q8=',
// -- "That's amazing. I've got the same combination on my luggage."
Array.apply(0, Array(6)).map((_,b) => b + 1).join(''),
@ -77,53 +86,76 @@ describe('CryptTool', function () {
'QUxMXI5htsn2rf0HxCFu7Po8DNYLxTS+67hYjDIYWYaEIc8LXWMLyDm9' +
'C5fARPJ4F2BIWgzgzkNj+dVjusft2XnziamWdbS5u3kuRlVuz5LQj+R5' +
'imnqQAincdZTkTT1nYx+DatlOLllCYIHffpI="}'
).then(function (paste1) {
$.PrivateBin.CryptTool.decipher(
's9pmKZKOBN7EVvHpTA8jjLFH3Xlz/0l8lB4+ONPACrM=',
'', // no password
'{"iv":"WA42mdxIVXUwBqZu7JYNiw==","v":1,"iter":10000,"ks"' +
':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' +
'lt":"jN6CjbQMJCM=","ct":"kYYMo5DFG1+w0UHiYXT5pdV0IUuXxzO' +
'lslkW/c3DRCbGFROCVkAskHce7HoRczee1N9c5MhHjVMJUIZE02qIS8U' +
'yHdJ/GqcPVidTUcj9rnDNWsTXkjVv8jCwHS/cwmAjDTWpwp5ThECN+ov' +
'/wNp/NdtTj8Qj7f/T3rfZIOCWfwLH9s4Des35UNcUidfPTNQ1l0Gm0X+' +
'r98CCUSYZjQxkZc6hRZBLPQ8EaNVooUwd5eP4GiYlmSDNA0wOSA+5isP' +
'YxomVCt+kFf58VBlNhpfNi7BLYAUTPpXT4SfH5drR9+C7NTeZ+tTCYjb' +
'U94PzYItOpu8vgnB1/a6BAM5h3m9w+giUb0df4hgTWeZnZxLjo5BN8WV' +
'+kdTXMj3/Vv0gw0DQrDcCuX/cBAjpy3lQGwlAN1vXoOIyZJUjMpQRrOL' +
'dKvLB+zcmVNtGDbgnfP2IYBzk9NtodpUa27ne0T0ZpwOPlVwevsIVZO2' +
'24WLa+iQmmHOWDFFpVDlS0t0fLfOk7Hcb2xFsTxiCIiyKMho/IME1Du3' +
'X4e6BVa3hobSSZv0rRtNgY1KcyYPrUPW2fxZ+oik3y9SgGvb7XpjVIta' +
'8DWlDWRfZ9kzoweWEYqz9IA8Xd373RefpyuWI25zlHoX3nwljzsZU6dC' +
'//h/Dt2DNr+IAvKO3+u23cWoB9kgcZJ2FJuqjLvVfCF+OWcig7zs2pTY' +
'JW6Rg6lqbBCxiUUlae6xJrjfv0pzD2VYCLY7v1bVTagppwKzNI3WaluC' +
'OrdDYUCxUSe56yd1oAoLPRVbYvomRboUO6cjQhEknERyvt45og2kORJO' +
'EJayHW+jZgR0Y0jM3Nk17ubpij2gHxNx9kiLDOiCGSV5mn9mV7qd3HHc' +
'OMSykiBgbyzjobi96LT2dIGLeDXTIdPOog8wyobO4jWq0GGs0vBB8oSY' +
'XhHvixZLcSjX2KQuHmEoWzmJcr3DavdoXZmAurGWLKjzEdJc5dSD/eNr' +
'99gjHX7wphJ6umKMM+fn6PcbYJkhDh2GlJL5COXjXfm/5aj/vuyaRRWZ' +
'MZtmnYpGAtAPg7AUG"}'
).then(function (paste2) {
clean();
assert.ok(
paste1.includes('securely packed in iron') &&
paste2.includes('Sol is right')
);
});
});
);
clean();
const result = typeof paste === 'string' && paste.includes('securely packed in iron');
if (!result) console.log(paste);
assert.ok(result);
}
);
it(
'supports ZeroBin ciphertext (SJCL & Base64 1.7)',
function () {
global.Base64 = require('../base64-1.7').Base64;
var clean = jsdom();
window.crypto = new WebCrypto();
'supports PrivateBin v1 ciphertext no password (SJCL & browser atob)',
async function () {
delete global.Base64;
const clean = jsdom();
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false,
});
global.atob = common.atob;
// Of course you can easily decipher the following texts, if you like.
// Bonus points for finding their sources and hidden meanings.
return $.PrivateBin.CryptTool.decipher(
const paste = await $.PrivateBin.CryptTool.decipher(
's9pmKZKOBN7EVvHpTA8jjLFH3Xlz/0l8lB4+ONPACrM=',
'', // no password
'{"iv":"WA42mdxIVXUwBqZu7JYNiw==","v":1,"iter":10000,"ks"' +
':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' +
'lt":"jN6CjbQMJCM=","ct":"kYYMo5DFG1+w0UHiYXT5pdV0IUuXxzO' +
'lslkW/c3DRCbGFROCVkAskHce7HoRczee1N9c5MhHjVMJUIZE02qIS8U' +
'yHdJ/GqcPVidTUcj9rnDNWsTXkjVv8jCwHS/cwmAjDTWpwp5ThECN+ov' +
'/wNp/NdtTj8Qj7f/T3rfZIOCWfwLH9s4Des35UNcUidfPTNQ1l0Gm0X+' +
'r98CCUSYZjQxkZc6hRZBLPQ8EaNVooUwd5eP4GiYlmSDNA0wOSA+5isP' +
'YxomVCt+kFf58VBlNhpfNi7BLYAUTPpXT4SfH5drR9+C7NTeZ+tTCYjb' +
'U94PzYItOpu8vgnB1/a6BAM5h3m9w+giUb0df4hgTWeZnZxLjo5BN8WV' +
'+kdTXMj3/Vv0gw0DQrDcCuX/cBAjpy3lQGwlAN1vXoOIyZJUjMpQRrOL' +
'dKvLB+zcmVNtGDbgnfP2IYBzk9NtodpUa27ne0T0ZpwOPlVwevsIVZO2' +
'24WLa+iQmmHOWDFFpVDlS0t0fLfOk7Hcb2xFsTxiCIiyKMho/IME1Du3' +
'X4e6BVa3hobSSZv0rRtNgY1KcyYPrUPW2fxZ+oik3y9SgGvb7XpjVIta' +
'8DWlDWRfZ9kzoweWEYqz9IA8Xd373RefpyuWI25zlHoX3nwljzsZU6dC' +
'//h/Dt2DNr+IAvKO3+u23cWoB9kgcZJ2FJuqjLvVfCF+OWcig7zs2pTY' +
'JW6Rg6lqbBCxiUUlae6xJrjfv0pzD2VYCLY7v1bVTagppwKzNI3WaluC' +
'OrdDYUCxUSe56yd1oAoLPRVbYvomRboUO6cjQhEknERyvt45og2kORJO' +
'EJayHW+jZgR0Y0jM3Nk17ubpij2gHxNx9kiLDOiCGSV5mn9mV7qd3HHc' +
'OMSykiBgbyzjobi96LT2dIGLeDXTIdPOog8wyobO4jWq0GGs0vBB8oSY' +
'XhHvixZLcSjX2KQuHmEoWzmJcr3DavdoXZmAurGWLKjzEdJc5dSD/eNr' +
'99gjHX7wphJ6umKMM+fn6PcbYJkhDh2GlJL5COXjXfm/5aj/vuyaRRWZ' +
'MZtmnYpGAtAPg7AUG"}'
);
clean();
const result = typeof paste === 'string' && paste.includes('Sol is right');
if (!result) console.log(paste);
assert.ok(result);
}
);
it(
'supports ZeroBin ciphertext with password (SJCL & Base64 1.7)',
async function () {
global.Base64 = require('../base64-1.7').Base64;
const clean = jsdom();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false,
});
global.atob = common.atob;
// Of course you can easily decipher the following texts, if you like.
// Bonus points for finding their sources and hidden meanings.
const paste = await $.PrivateBin.CryptTool.decipher(
'6t2qsmLyfXIokNCL+3/yl15rfTUBQvm5SOnFPvNE7Q8=',
// -- "That's amazing. I've got the same combination on my luggage."
Array.apply(0, Array(6)).map((_,b) => b + 1).join(''),
@ -146,54 +178,74 @@ describe('CryptTool', function () {
'7mNNo7xba/YT9KoPDaniqnYqb+q2pX1WNWE7dLS2wfroMAS3kh8P22DA' +
'V37AeiNoD2PcI6ZcHbRdPa+XRrRcJhSPPW7UQ0z4OvBfjdu/w390QxAx' +
'SxvZewoh49fKKB6hTsRnZb4tpHkjlww=="}'
).then(function (paste1) {
$.PrivateBin.CryptTool.decipher(
's9pmKZKOBN7EVvHpTA8jjLFH3Xlz/0l8lB4+ONPACrM=',
'', // no password
'{"iv":"Z7lAZQbkrqGMvruxoSm6Pw==","v":1,"iter":10000,"ks"' +
':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' +
'lt":"jN6CjbQMJCM=","ct":"PuOPWB3i2FPcreSrLYeQf84LdE8RHjs' +
'c+MGtiOr4b7doNyWKYtkNorbRadxaPnEee2/Utrp1MIIfY5juJSy8RGw' +
'EPX5ciWcYe6EzsXWznsnvhmpKNj9B7eIIrfSbxfy8E2e/g7xav1nive+' +
'ljToka3WT1DZ8ILQd/NbnJeHWaoSEOfvz8+d8QJPb1tNZvs7zEY95Dum' +
'QwbyOsIMKAvcZHJ9OJNpujXzdMyt6DpcFcqlldWBZ/8q5rAUTw0HNx/r' +
'CgbhAxRYfNoTLIcMM4L0cXbPSgCjwf5FuO3EdE13mgEDhcClW79m0Qvc' +
'nIh8xgzYoxLbp0+AwvC/MbZM8savN/0ieWr2EKkZ04ggiOIEyvfCUuNp' +
'rQBYO+y8kKduNEN6by0Yf4LRCPfmwN+GezDLuzTnZIMhPbGqUAdgV6Ex' +
'qK2ULEEIrQEMoOuQIxfoMhqLlzG79vXGt2O+BY+4IiYfvmuRLks4UXfy' +
'HqxPXTJg48IYbGs0j4TtJPUgp3523EyYLwEGyVTAuWhYAmVIwd/hoV7d' +
'7tmfcF73w9dufDFI3LNca2KxzBnWNPYvIZKBwWbq8ncxkb191dP6mjEi' +
'7NnhqVk5A6vIBbu4AC5PZf76l6yep4xsoy/QtdDxCMocCXeAML9MQ9uP' +
'QbuspOKrBvMfN5igA1kBqasnxI472KBNXsdZnaDddSVUuvhTcETM="}'
).then(function (paste2) {
clean();
delete global.Base64;
assert.ok(
paste1.includes('securely packed in iron') &&
paste2.includes('Sol is right')
);
});
);
clean();
delete global.Base64;
const result = typeof paste === 'string' && paste.includes('securely packed in iron');
if (!result) console.log(paste);
assert.ok(result);
}
);
it(
'supports ZeroBin ciphertext no password (SJCL & Base64 1.7)',
async function () {
global.Base64 = require('../base64-1.7').Base64;
const clean = jsdom();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false,
});
global.atob = common.atob;
const paste = await $.PrivateBin.CryptTool.decipher(
's9pmKZKOBN7EVvHpTA8jjLFH3Xlz/0l8lB4+ONPACrM=',
'', // no password
'{"iv":"Z7lAZQbkrqGMvruxoSm6Pw==","v":1,"iter":10000,"ks"' +
':256,"ts":128,"mode":"gcm","adata":"","cipher":"aes","sa' +
'lt":"jN6CjbQMJCM=","ct":"PuOPWB3i2FPcreSrLYeQf84LdE8RHjs' +
'c+MGtiOr4b7doNyWKYtkNorbRadxaPnEee2/Utrp1MIIfY5juJSy8RGw' +
'EPX5ciWcYe6EzsXWznsnvhmpKNj9B7eIIrfSbxfy8E2e/g7xav1nive+' +
'ljToka3WT1DZ8ILQd/NbnJeHWaoSEOfvz8+d8QJPb1tNZvs7zEY95Dum' +
'QwbyOsIMKAvcZHJ9OJNpujXzdMyt6DpcFcqlldWBZ/8q5rAUTw0HNx/r' +
'CgbhAxRYfNoTLIcMM4L0cXbPSgCjwf5FuO3EdE13mgEDhcClW79m0Qvc' +
'nIh8xgzYoxLbp0+AwvC/MbZM8savN/0ieWr2EKkZ04ggiOIEyvfCUuNp' +
'rQBYO+y8kKduNEN6by0Yf4LRCPfmwN+GezDLuzTnZIMhPbGqUAdgV6Ex' +
'qK2ULEEIrQEMoOuQIxfoMhqLlzG79vXGt2O+BY+4IiYfvmuRLks4UXfy' +
'HqxPXTJg48IYbGs0j4TtJPUgp3523EyYLwEGyVTAuWhYAmVIwd/hoV7d' +
'7tmfcF73w9dufDFI3LNca2KxzBnWNPYvIZKBwWbq8ncxkb191dP6mjEi' +
'7NnhqVk5A6vIBbu4AC5PZf76l6yep4xsoy/QtdDxCMocCXeAML9MQ9uP' +
'QbuspOKrBvMfN5igA1kBqasnxI472KBNXsdZnaDddSVUuvhTcETM="}'
);
clean();
delete global.Base64;
const result = typeof paste === 'string' && paste.includes('Sol is right');
if (!result) console.log(paste);
assert.ok(result);
}
);
it('does not truncate messages', async function () {
let message = fs.readFileSync('test/compression-sample.txt', 'utf8'),
const message = fs.readFileSync('test/compression-sample.txt', 'ascii').trim(),
clean = jsdom();
window.crypto = new WebCrypto();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false,
});
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
let cipherMessage = await $.PrivateBin.CryptTool.cipher(
global.atob = common.atob;
global.btoa = common.btoa;
const cipherMessage = await $.PrivateBin.CryptTool.cipher(
'foo', 'bar', message, []
),
plaintext = await $.PrivateBin.CryptTool.decipher(
'foo', 'bar', cipherMessage
'foo', 'bar', cipherMessage
);
clean();
assert.strictEqual(
message,
plaintext
);
const result = (message === plaintext);
if (!result) console.log(plaintext, cipherMessage);
assert.ok(result);
});
it('can en- and decrypt a particular message (#260)', function () {
@ -201,8 +253,6 @@ describe('CryptTool', function () {
'string',
'string',
async function (key, password) {
// pause to let async functions conclude
await new Promise(resolve => setTimeout(resolve, 300));
const message = `
1 subgoal
@ -225,18 +275,23 @@ isWhile : interp (while expr sBody) (MemElem mem) =
======================== ( 1 / 1 )
conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem))
`;
let clean = jsdom();
const clean = jsdom();
// ensure zlib is getting loaded
$.PrivateBin.Controller.initZ();
window.crypto = new WebCrypto();
let cipherMessage = await $.PrivateBin.CryptTool.cipher(
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false,
});
const cipherMessage = await $.PrivateBin.CryptTool.cipher(
key, password, message, []
),
plaintext = await $.PrivateBin.CryptTool.decipher(
key, password, cipherMessage
);
clean();
return message === plaintext;
const result = (message === plaintext);
if (!result) console.log(plaintext, cipherMessage);
return result;
}
),
{tests: 3});
@ -244,23 +299,27 @@ conseq_or_bottom inv (interp (nth_iterate sBody n) (MemElem mem))
});
describe('getSymmetricKey', function () {
this.timeout(30000);
var keys = [];
this.timeout(10000);
let keys = [];
// the parameter is used to ensure the test is run more then one time
jsc.property(
'returns random, non-empty keys',
'integer',
function(counter) {
var clean = jsdom();
window.crypto = new WebCrypto();
var key = $.PrivateBin.CryptTool.getSymmetricKey(),
result = (key !== '' && keys.indexOf(key) === -1);
keys.push(key);
clean();
return result;
}
);
it('returns random, non-empty keys', function () {
jsc.assert(jsc.forall(
'integer',
function(counter) {
const clean = jsdom();
Object.defineProperty(window, 'crypto', {
value: new WebCrypto(),
writeable: false,
});
const key = $.PrivateBin.CryptTool.getSymmetricKey(),
result = (key !== '' && keys.indexOf(key) === -1);
keys.push(key);
clean();
return result;
}
),
{tests: 10});
});
});
});

View file

@ -229,30 +229,30 @@ describe('Helper', function () {
cleanup();
});
/* TODO test fails since jsDOM version 17 - document.cookie remains empty
jsc.property(
'returns the requested cookie',
jsc.nearray(jsc.nearray(common.jscAlnumString())),
jsc.nearray(jsc.nearray(common.jscAlnumString())),
function (labels, values) {
var selectedKey = '', selectedValue = '',
cookieArray = [];
let selectedKey = '', selectedValue = '';
const clean = jsdom();
labels.forEach(function(item, i) {
var key = item.join(''),
const key = item.join(''),
value = (values[i] || values[0]).join('');
cookieArray.push(key + '=' + value);
document.cookie = key + '=' + value;
if (Math.random() < 1 / i || selectedKey === key)
{
selectedKey = key;
selectedValue = value;
}
});
var clean = jsdom('', {cookie: cookieArray}),
result = $.PrivateBin.Helper.getCookie(selectedKey);
const result = $.PrivateBin.Helper.getCookie(selectedKey);
$.PrivateBin.Helper.reset();
clean();
return result === selectedValue;
}
);
); */
});
describe('baseUri', function () {
@ -290,5 +290,44 @@ describe('Helper', function () {
}
);
});
describe('formatBytes', function () {
jsc.property('returns 0 B for 0 bytes', function () {
return $.PrivateBin.Helper.formatBytes(0) === '0 B';
});
jsc.property('formats bytes < 1000 as B', function () {
return $.PrivateBin.Helper.formatBytes(500) === '500 B';
});
jsc.property('formats kibibytes correctly', function () {
return $.PrivateBin.Helper.formatBytes(1500) === '1.46 KiB';
});
jsc.property('formats mebibytes correctly', function () {
return $.PrivateBin.Helper.formatBytes(2 * 1000 * 1000) === '1.91 MiB';
});
jsc.property('formats gibibytes correctly', function () {
return $.PrivateBin.Helper.formatBytes(3.45 * 1000 * 1000 * 1000) === '3.21 GiB';
});
jsc.property('rounds to two decimal places', function () {
return $.PrivateBin.Helper.formatBytes(1234567) === '1.18 MiB';
});
});
describe('isBootstrap5', function () {
jsc.property('Bootstrap 5 has been detected', function () {
global.bootstrap = {};
return $.PrivateBin.Helper.isBootstrap5() === true;
});
jsc.property('Bootstrap 5 has not been detected', function () {
delete global.bootstrap;
return $.PrivateBin.Helper.isBootstrap5() === false;
});
});
});

View file

@ -94,7 +94,6 @@ describe('Model', function () {
url.query = queryStart.concat(pasteId, queryEnd);
const pasteIdString = pasteId.join(''),
clean = jsdom('', {url: common.urlToString(url)});
global.URL = require('jsdom-url').URL;
const result = $.PrivateBin.Model.getPasteId();
$.PrivateBin.Model.reset();
clean();
@ -107,7 +106,6 @@ describe('Model', function () {
function (url) {
let clean = jsdom('', {url: common.urlToString(url)}),
result = false;
global.URL = require('jsdom-url').URL;
try {
$.PrivateBin.Model.getPasteId();
}
@ -131,7 +129,7 @@ describe('Model', function () {
'returns the fragment of a v1 URL',
common.jscUrl(),
function (url) {
url.fragment = common.btoa(url.fragment.padStart(32, '\u0000'));
url.fragment = '0OIl'; // any non-base58 string
const clean = jsdom('', {url: common.urlToString(url)}),
result = $.PrivateBin.Model.getPasteKey();
$.PrivateBin.Model.reset();
@ -140,17 +138,17 @@ describe('Model', function () {
}
);
jsc.property(
'returns the v1 fragment stripped of trailing query parts',
'returns the fragment stripped of trailing query parts',
common.jscUrl(),
jsc.array(common.jscHashString()),
function (url, trail) {
const fragmentString = common.btoa(url.fragment.padStart(32, '\u0000'));
url.fragment = fragmentString + '&' + trail.join('');
const fragment = url.fragment.padStart(32, '\u0000');
url.fragment = $.PrivateBin.CryptTool.base58encode(fragment) + '&' + trail.join('');
const clean = jsdom('', {url: common.urlToString(url)}),
result = $.PrivateBin.Model.getPasteKey();
$.PrivateBin.Model.reset();
clean();
return fragmentString === result;
return fragment === result;
}
);
jsc.property(

View file

@ -2,8 +2,6 @@
require('../common');
describe('Prompt', function () {
// TODO: this does not test the prompt() fallback, since that isn't available
// in nodejs -> replace the prompt in the "page" template with a modal
describe('requestPassword & getPassword', function () {
this.timeout(30000);
@ -11,7 +9,7 @@ describe('Prompt', function () {
'returns the password fed into the dialog',
'string',
function (password) {
password = password.replace(/\r+/g, '');
password = password.replace(/\r+|\n+/g, '');
var clean = jsdom('', {url: 'ftp://example.com/?0000000000000000'});
$('body').html(
'<div id="passwordmodal" class="modal fade" role="dialog">' +
@ -32,7 +30,8 @@ describe('Prompt', function () {
//var result = $.PrivateBin.Prompt.getPassword();
var result = $('#passworddecrypt').val();
$.PrivateBin.Model.reset();
clean();
// TODO triggers error messages in jsDOM since version 11
//clean();
return result === password;
}
);

View file

@ -621,7 +621,7 @@ describe('TopNav', function () {
'returns the contents of the password input',
'string',
function (password) {
password = password.replace(/\r+/g, '');
password = password.replace(/\r+|\n+/g, '');
var results = [];
$('body').html(
'<nav><div id="navbar"><ul><li><div id="password" ' +
@ -727,11 +727,11 @@ describe('TopNav', function () {
cleanup();
});
// TODO triggers error messages in jsDOM since version 12, but passes
it(
'displays raw text view correctly',
function () {
const clean = jsdom('', {url: 'https://privatebin.net/?0123456789abcdef#0'});
global.URL = require('jsdom-url').URL;
$('body').html('<button id="rawtextbutton"></button>');
const sample = 'example';
$.PrivateBin.PasteViewer.setText(sample);

View file

@ -18,11 +18,6 @@ describe('UiHelper', function () {
const expected = common.urlToString(url),
clean = jsdom('', {url: expected});
// make window.location.href writable
Object.defineProperty(window.location, 'href', {
writable: true,
value: window.location.href
});
$.PrivateBin.UiHelper.mockHistoryChange();
$.PrivateBin.Helper.reset();
var result = window.location.href;
@ -40,11 +35,6 @@ describe('UiHelper', function () {
const expected = common.urlToString(url),
clean = jsdom('', {url: expected});
// make window.location.href writable
Object.defineProperty(window.location, 'href', {
writable: true,
value: window.location.href
});
$.PrivateBin.UiHelper.mockHistoryChange([
{type: 'newpaste'}, '', expected
]);
@ -57,6 +47,8 @@ describe('UiHelper', function () {
});
describe('reloadHome', function () {
// TODO triggers error messages in jsDOM since version 11
/*
this.timeout(30000);
before(function () {
$.PrivateBin.Helper.reset();
@ -71,11 +63,6 @@ describe('UiHelper', function () {
delete(url.fragment);
const expected = common.urlToString(url);
// make window.location.href writable
Object.defineProperty(window.location, 'href', {
writable: true,
value: window.location.href
});
$.PrivateBin.UiHelper.reloadHome();
$.PrivateBin.Helper.reset();
var result = window.location.href;
@ -83,6 +70,7 @@ describe('UiHelper', function () {
return expected === result;
}
);
*/
});
describe('isVisible', function () {

View file

@ -45,7 +45,17 @@ class Configuration
'defaultformatter' => 'plaintext',
'syntaxhighlightingtheme' => '',
'sizelimit' => 10485760,
'templateselection' => false,
'template' => 'bootstrap',
'availabletemplates' => array(
'bootstrap5',
'bootstrap',
'bootstrap-page',
'bootstrap-dark',
'bootstrap-dark-page',
'bootstrap-compact',
'bootstrap-compact-page',
),
'info' => 'More information on the <a href=\'https://privatebin.info/\'>project page</a>.',
'notice' => '',
'languageselection' => false,
@ -53,8 +63,8 @@ class Configuration
'urlshortener' => '',
'qrcode' => true,
'email' => true,
'icon' => 'identicon',
'cspheader' => 'default-src \'none\'; base-uri \'self\'; form-action \'none\'; manifest-src \'self\'; connect-src * blob:; script-src \'self\' \'wasm-unsafe-eval\'; style-src \'self\'; font-src \'self\'; frame-ancestors \'none\'; 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',
'icon' => 'jdenticon',
'cspheader' => 'default-src \'none\'; base-uri \'self\'; form-action \'none\'; manifest-src \'self\'; connect-src * blob:; script-src \'self\' \'wasm-unsafe-eval\'; style-src \'self\'; font-src \'self\'; frame-ancestors \'none\'; frame-src blob:; img-src \'self\' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-modals allow-downloads',
'zerobincompatibility' => false,
'httpwarning' => true,
'compression' => 'zlib',
@ -108,11 +118,11 @@ class Configuration
'js/kjua-0.9.0.js' => 'sha512-CVn7af+vTMBd9RjoS4QM5fpLFEOtBCoB0zPtaqIDC7sF4F8qgUSRFQQpIyEDGsr6yrjbuOLzdf20tkHHmpaqwQ==',
'js/legacy.js' => 'sha512-UxW/TOZKon83n6dk/09GsYKIyeO5LeBHokxyIq+r7KFS5KMBeIB/EM7NrkVYIezwZBaovnyNtY2d9tKFicRlXg==',
'js/prettify.js' => 'sha512-puO0Ogy++IoA2Pb9IjSxV1n4+kQkKXYAEUtVzfZpQepyDPyXk8hokiYDS7ybMogYlyyEIwMLpZqVhCkARQWLMg==',
'js/privatebin.js' => 'sha512-POa+8KNXFFwJFsqp7r9APmR5Rc1w2l363y+OScSzLCySrHN7UhOOgt1VH/o8mVddFvvUozj3FZVmdkTxRlrS5g==',
'js/purify-3.2.4.js' => 'sha512-Mu9BqoHURMeycg6AgqTpokUv9guq88pajfaFqz53fx1OxohyROkydXPLEIbdKCQ7EdDs9hgcrYeZ9zTiPQQ4CA==',
'js/privatebin.js' => 'sha512-mPPCBJRbTT7LCOhjv2xL01yhJqwKOgwalktUuQVgsno14vXAs8iAr7qQ6aYh9jUqTarUoXpZJSqxijpziSzhuA==',
'js/purify-3.2.6.js' => 'sha512-zqwL4OoBLFx89QPewkz4Lz5CSA2ktU+f31fuECkF0iK3Id5qd3Zpq5dMby8KwHjIEpsUgOqwF58cnmcaNem0EA==',
'js/rawinflate-0.3.js' => 'sha512-g8uelGgJW9A/Z1tB6Izxab++oj5kdD7B4qC7DHwZkB6DGMXKyzx7v5mvap2HXueI2IIn08YlRYM56jwWdm2ucQ==',
'js/showdown-2.1.0.js' => 'sha512-WYXZgkTR0u/Y9SVIA4nTTOih0kXMEd8RRV6MLFdL6YU8ymhR528NLlYQt1nlJQbYz4EW+ZsS0fx1awhiQJme1Q==',
'js/zlib-1.3.1.js' => 'sha512-5bU9IIP4PgBrOKLZvGWJD4kgfQrkTz8Z3Iqeu058mbQzW3mCumOU6M3UVbVZU9rrVoVwaW4cZK8U8h5xjF88eQ==',
'js/zlib-1.3.1-1.js' => 'sha512-5bU9IIP4PgBrOKLZvGWJD4kgfQrkTz8Z3Iqeu058mbQzW3mCumOU6M3UVbVZU9rrVoVwaW4cZK8U8h5xjF88eQ==',
),
);

View file

@ -27,14 +27,14 @@ class Controller
*
* @const string
*/
const VERSION = '1.7.6';
const VERSION = '1.7.8';
/**
* minimal required PHP version
*
* @const string
*/
const MIN_PHP_VERSION = '7.3.0';
const MIN_PHP_VERSION = '7.4.0';
/**
* show the same error message if the paste expired or does not exist
@ -112,10 +112,12 @@ class Controller
*
* initializes and runs PrivateBin
*
* @param ?Configuration $config
*
* @access public
* @throws Exception
*/
public function __construct()
public function __construct(?Configuration $config = null)
{
if (version_compare(PHP_VERSION, self::MIN_PHP_VERSION) < 0) {
error_log(I18n::_('%s requires php %s or above to work. Sorry.', I18n::_('PrivateBin'), self::MIN_PHP_VERSION));
@ -126,7 +128,8 @@ class Controller
return;
}
// load config from ini file, initialize required classes
// load config (using ini file by default) & initialize required classes
$this->_conf = $config ?? new Configuration();
$this->_init();
switch ($this->_request->getOperation()) {
@ -174,12 +177,21 @@ class Controller
*/
private function _init()
{
$this->_conf = new Configuration;
$this->_model = new Model($this->_conf);
$this->_request = new Request;
$this->_urlBase = $this->_request->getRequestUri();
// set default language
$this->_setDefaultLanguage();
$this->_setDefaultTemplate();
}
/**
* Set default language
*
* @access private
*/
private function _setDefaultLanguage()
{
$lang = $this->_conf->getKey('languagedefault');
I18n::setLanguageFallback($lang);
// force default language, if language selection is disabled and a default is set
@ -189,6 +201,25 @@ class Controller
}
}
/**
* Set default template
*
* @access private
*/
private function _setDefaultTemplate()
{
$templates = $this->_conf->getKey('availabletemplates');
$template = $this->_conf->getKey('template');
TemplateSwitcher::setAvailableTemplates($templates);
TemplateSwitcher::setTemplateFallback($template);
// force default template, if template selection is disabled and a default is set
if (!$this->_conf->getKey('templateselection') && !empty($template)) {
$_COOKIE['template'] = $template;
setcookie('template', $template, array('SameSite' => 'Lax', 'Secure' => true));
}
}
/**
* Turn off browser caching
*
@ -400,11 +431,18 @@ class Controller
setcookie('lang', $languageselection, array('SameSite' => 'Lax', 'Secure' => true));
}
// set template cookie if that functionality was enabled
$templateselection = '';
if ($this->_conf->getKey('templateselection')) {
$templateselection = TemplateSwitcher::getTemplate();
setcookie('template', $templateselection, array('SameSite' => 'Lax', 'Secure' => true));
}
// strip policies that are unsupported in meta tag
$metacspheader = str_replace(
array(
'frame-ancestors \'none\'; ',
'; sandbox allow-same-origin allow-scripts allow-forms allow-popups allow-modals allow-downloads',
'; sandbox allow-same-origin allow-scripts allow-forms allow-modals allow-downloads',
),
'',
$this->_conf->getKey('cspheader')
@ -438,6 +476,8 @@ class Controller
$page->assign('ZEROBINCOMPATIBILITY', $this->_conf->getKey('zerobincompatibility'));
$page->assign('LANGUAGESELECTION', $languageselection);
$page->assign('LANGUAGES', I18n::getLanguageLabels(I18n::getAvailableLanguages()));
$page->assign('TEMPLATESELECTION', $templateselection);
$page->assign('TEMPLATES', TemplateSwitcher::getAvailableTemplates());
$page->assign('EXPIRE', $expire);
$page->assign('EXPIREDEFAULT', $this->_conf->getKey('default', 'expire'));
$page->assign('URLSHORTENER', $this->_conf->getKey('urlshortener'));
@ -447,7 +487,7 @@ class Controller
$page->assign('HTTPSLINK', 'https://' . $this->_request->getHost() . $this->_request->getRequestUri());
$page->assign('COMPRESSION', $this->_conf->getKey('compression'));
$page->assign('SRI', $this->_conf->getSection('sri'));
$page->draw($this->_conf->getKey('template'));
$page->draw(TemplateSwitcher::getTemplate());
}
/**

View file

@ -34,7 +34,7 @@ abstract class AbstractData
* @param array $paste
* @return bool
*/
abstract public function create($pasteid, array $paste);
abstract public function create($pasteid, array &$paste);
/**
* Read a paste.
@ -72,7 +72,7 @@ abstract class AbstractData
* @param array $comment
* @return bool
*/
abstract public function createComment($pasteid, $parentid, $commentid, array $comment);
abstract public function createComment($pasteid, $parentid, $commentid, array &$comment);
/**
* Read all comments of paste.
@ -199,7 +199,7 @@ abstract class AbstractData
* @param array $paste
* @return array
*/
protected static function upgradePreV1Format(array $paste)
protected static function upgradePreV1Format(array &$paste)
{
if (array_key_exists('attachment', $paste['meta'])) {
$paste['attachment'] = $paste['meta']['attachment'];

View file

@ -140,7 +140,7 @@ class Database extends AbstractData
* @param array $paste
* @return bool
*/
public function create($pasteid, array $paste)
public function create($pasteid, array &$paste)
{
$expire_date = 0;
$opendiscussion = $burnafterreading = false;
@ -188,6 +188,7 @@ class Database extends AbstractData
)
);
} catch (Exception $e) {
error_log('Error while attempting to insert a paste into the database: ' . $e->getMessage() . PHP_EOL);
return false;
}
}
@ -297,14 +298,18 @@ class Database extends AbstractData
* @param array $comment
* @return bool
*/
public function createComment($pasteid, $parentid, $commentid, array $comment)
public function createComment($pasteid, $parentid, $commentid, array &$comment)
{
if (array_key_exists('data', $comment)) {
$version = 1;
$data = $comment['data'];
} else {
$version = 2;
$data = Json::encode($comment);
try {
$version = 2;
$data = Json::encode($comment);
} catch (Exception $e) {
return false;
}
}
list($createdKey, $iconKey) = $this->_getVersionedKeys($version);
$meta = $comment['meta'];
@ -329,6 +334,7 @@ class Database extends AbstractData
)
);
} catch (Exception $e) {
error_log('Error while attempting to insert a comment into the database: ' . $e->getMessage() . PHP_EOL);
return false;
}
}
@ -911,8 +917,12 @@ class Database extends AbstractData
try {
$row = $this->_select('SELECT sqlite_version() AS "v"', array(), true);
$supportsDropColumn = version_compare($row['v'], '3.35.0', '>=');
if (!$supportsDropColumn) {
error_log('Error: the available SQLite version (' . $row['v'] . ') does not support dropping columns. SQLite version 3.35.0 or later is necessary. The migration will not be fully complete, and you will need to delete the "postdate" column of the "paste" table yourself!');
}
} catch (PDOException $e) {
$supportsDropColumn = false;
error_log('Error while checking the SQLite version. The migration will not be fully complete, and you will need to delete the "postdate" column of the "paste" table yourself!');
}
}
if ($supportsDropColumn) {

View file

@ -85,7 +85,7 @@ class Filesystem extends AbstractData
* @param array $paste
* @return bool
*/
public function create($pasteid, array $paste)
public function create($pasteid, array &$paste)
{
$storagedir = $this->_dataid2path($pasteid);
$file = $storagedir . $pasteid . '.php';
@ -188,7 +188,7 @@ class Filesystem extends AbstractData
* @param array $comment
* @return bool
*/
public function createComment($pasteid, $parentid, $commentid, array $comment)
public function createComment($pasteid, $parentid, $commentid, array &$comment)
{
$storagedir = $this->_dataid2discussionpath($pasteid);
$file = $storagedir . $pasteid . '.' . $commentid . '.' . $parentid . '.php';
@ -276,7 +276,7 @@ class Filesystem extends AbstractData
case 'purge_limiter':
return $this->_storeString(
$this->_path . DIRECTORY_SEPARATOR . 'purge_limiter.php',
'<?php' . PHP_EOL . '$GLOBALS[\'purge_limiter\'] = ' . $value . ';'
'<?php' . PHP_EOL . '$GLOBALS[\'purge_limiter\'] = ' . var_export($value, true) . ';'
);
case 'salt':
return $this->_storeString(
@ -308,7 +308,9 @@ class Filesystem extends AbstractData
$file = $this->_path . DIRECTORY_SEPARATOR . 'purge_limiter.php';
if (is_readable($file)) {
require $file;
return $GLOBALS['purge_limiter'];
if (array_key_exists('purge_limiter', $GLOBALS)) {
return $GLOBALS['purge_limiter'];
}
}
break;
case 'salt':
@ -324,9 +326,11 @@ class Filesystem extends AbstractData
$file = $this->_path . DIRECTORY_SEPARATOR . 'traffic_limiter.php';
if (is_readable($file)) {
require $file;
$this->_last_cache = $GLOBALS['traffic_limiter'];
if (array_key_exists($key, $this->_last_cache)) {
return $this->_last_cache[$key];
if (array_key_exists('traffic_limiter', $GLOBALS)) {
$this->_last_cache = $GLOBALS['traffic_limiter'];
if (array_key_exists($key, $this->_last_cache)) {
return $this->_last_cache[$key];
}
}
}
break;
@ -343,12 +347,11 @@ class Filesystem extends AbstractData
*/
private function _get($filename)
{
return Json::decode(
substr(
file_get_contents($filename),
strlen(self::PROTECTION_LINE . PHP_EOL)
)
$data = substr(
file_get_contents($filename),
strlen(self::PROTECTION_LINE . PHP_EOL)
);
return Json::decode($data);
}
/**
@ -453,6 +456,7 @@ class Filesystem extends AbstractData
self::PROTECTION_LINE . PHP_EOL . Json::encode($data)
);
} catch (Exception $e) {
error_log('Error while trying to store data to the filesystem at path "' . $filename . '": ' . $e->getMessage() . PHP_EOL);
return false;
}
}

View file

@ -105,7 +105,7 @@ class GoogleCloudStorage extends AbstractData
* @param $payload array to store
* @return bool true if successful, otherwise false.
*/
private function _upload($key, $payload)
private function _upload($key, &$payload)
{
$metadata = array_key_exists('meta', $payload) ? $payload['meta'] : array();
unset($metadata['attachment'], $metadata['attachmentname'], $metadata['salt']);
@ -136,7 +136,7 @@ class GoogleCloudStorage extends AbstractData
/**
* @inheritDoc
*/
public function create($pasteid, array $paste)
public function create($pasteid, array &$paste)
{
if ($this->exists($pasteid)) {
return false;
@ -201,7 +201,7 @@ class GoogleCloudStorage extends AbstractData
/**
* @inheritDoc
*/
public function createComment($pasteid, $parentid, $commentid, array $comment)
public function createComment($pasteid, $parentid, $commentid, array &$comment)
{
if ($this->existsComment($pasteid, $parentid, $commentid)) {
return false;
@ -219,7 +219,8 @@ class GoogleCloudStorage extends AbstractData
$prefix = $this->_getKey($pasteid) . '/discussion/';
try {
foreach ($this->_bucket->objects(array('prefix' => $prefix)) as $key) {
$comment = JSON::decode($this->_bucket->object($key->name())->downloadAsString());
$data = $this->_bucket->object($key->name())->downloadAsString();
$comment = Json::decode($data);
$comment['id'] = basename($key->name());
$slot = $this->getOpenSlot($comments, (int) $comment['meta']['created']);
$comments[$slot] = $comment;

View file

@ -165,7 +165,7 @@ class S3Storage extends AbstractData
* @param $payload array to store
* @return bool true if successful, otherwise false.
*/
private function _upload($key, $payload)
private function _upload($key, &$payload)
{
$metadata = array_key_exists('meta', $payload) ? $payload['meta'] : array();
unset($metadata['attachment'], $metadata['attachmentname'], $metadata['salt']);
@ -191,7 +191,7 @@ class S3Storage extends AbstractData
/**
* @inheritDoc
*/
public function create($pasteid, array $paste)
public function create($pasteid, array &$paste)
{
if ($this->exists($pasteid)) {
return false;
@ -263,7 +263,7 @@ class S3Storage extends AbstractData
/**
* @inheritDoc
*/
public function createComment($pasteid, $parentid, $commentid, array $comment)
public function createComment($pasteid, $parentid, $commentid, array &$comment)
{
if ($this->existsComment($pasteid, $parentid, $commentid)) {
return false;

View file

@ -29,7 +29,7 @@ class FormatV2
* @param bool $isComment
* @return bool
*/
public static function isValid($message, $isComment = false)
public static function isValid(&$message, $isComment = false)
{
$required_keys = array('adata', 'v', 'ct');
if ($isComment) {

View file

@ -183,9 +183,12 @@ class I18n
// load translations
self::$_language = $match;
self::$_translations = ($match == 'en') ? array() : Json::decode(
file_get_contents(self::_getPath($match . '.json'))
);
if ($match == 'en') {
self::$_translations = array();
} else {
$data = file_get_contents(self::_getPath($match . '.json'));
self::$_translations = Json::decode($data);
}
}
/**
@ -273,7 +276,8 @@ class I18n
{
$file = self::_getPath('languages.json');
if (count(self::$_languageLabels) == 0 && is_readable($file)) {
self::$_languageLabels = Json::decode(file_get_contents($file));
$data = file_get_contents($file);
self::$_languageLabels = Json::decode($data);
}
if (count($languages) == 0) {
return self::$_languageLabels;

View file

@ -29,7 +29,7 @@ class Json
* @throws Exception
* @return string
*/
public static function encode($input)
public static function encode(&$input)
{
$jsonString = json_encode($input);
self::_detectError();
@ -45,7 +45,7 @@ class Json
* @throws Exception
* @return mixed
*/
public static function decode($input)
public static function decode(&$input)
{
$output = json_decode($input, true);
self::_detectError();

View file

@ -100,9 +100,9 @@ abstract class AbstractModel
* @param array $data
* @throws Exception
*/
public function setData(array $data)
public function setData(array &$data)
{
$data = $this->_sanitize($data);
$this->_sanitize($data);
$this->_validate($data);
$this->_data = $data;
@ -155,7 +155,7 @@ abstract class AbstractModel
*/
public static function isValidId($id)
{
return (bool) preg_match('#\A[a-f\d]{16}\z#', (string) $id);
return (bool) preg_match('#\A[a-f0-9]{16}\z#', (string) $id);
}
/**
@ -163,9 +163,8 @@ abstract class AbstractModel
*
* @access protected
* @param array $data
* @return array
*/
abstract protected function _sanitize(array $data);
abstract protected function _sanitize(array &$data);
/**
* Validate data.
@ -174,7 +173,7 @@ abstract class AbstractModel
* @param array $data
* @throws Exception
*/
protected function _validate(array $data)
protected function _validate(array &$data)
{
}
}

View file

@ -104,7 +104,7 @@ class Comment extends AbstractModel
* @param Paste $paste
* @throws Exception
*/
public function setPaste(Paste $paste)
public function setPaste(Paste &$paste)
{
$this->_paste = $paste;
$this->_data['pasteid'] = $paste->getId();
@ -155,9 +155,8 @@ class Comment extends AbstractModel
*
* @access protected
* @param array $data
* @return array
*/
protected function _sanitize(array $data)
protected function _sanitize(array &$data)
{
// we generate an icon based on a SHA512 HMAC of the users IP, if configured
$icon = $this->_conf->getKey('icon');
@ -190,6 +189,5 @@ class Comment extends AbstractModel
$data['meta']['icon'] = $pngdata;
}
}
return $data;
}
}

View file

@ -219,11 +219,10 @@ class Paste extends AbstractModel
*
* @access protected
* @param array $data
* @return array
*/
protected function _sanitize(array $data)
protected function _sanitize(array &$data)
{
$expiration = $data['meta']['expire'];
$expiration = $data['meta']['expire'] ?? 0;
unset($data['meta']['expire']);
$expire_options = $this->_conf->getSection('expire_options');
if (array_key_exists($expiration, $expire_options)) {
@ -235,7 +234,6 @@ class Paste extends AbstractModel
if ($expire > 0) {
$data['meta']['expire_date'] = time() + $expire;
}
return $data;
}
/**
@ -245,7 +243,7 @@ class Paste extends AbstractModel
* @param array $data
* @throws Exception
*/
protected function _validate(array $data)
protected function _validate(array &$data)
{
// reject invalid or disabled formatters
if (!array_key_exists($data['adata'][1], $this->_conf->getSection('formatter_options'))) {

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