Compare commits

..

91 Commits

Author SHA1 Message Date
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
123 changed files with 2051 additions and 2237 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@07ab29fd4a977ae4d2b275087cf67563dfdf0295
with:
run_id: ${{ github.event.workflow_run.id }}
path: artifacts

View File

@ -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,11 @@
# PrivateBin version history
## 1.7.7 (not yet released)
* ADDED: Switching templates using the web ui (#1501)
* 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.5, ip-lib 1.20.0
## 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

@ -33,7 +33,7 @@
* 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
* Mikhail Romanov - copying to clipboard, UI/UX improvements, templates switching
## Translations
* Hexalyse - French

View File

@ -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

@ -42,13 +42,28 @@ 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
; 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[] = "bootstrap"
availabletemplates[] = "bootstrap-page"
availabletemplates[] = "bootstrap-dark"
availabletemplates[] = "bootstrap-dark-page"
availabletemplates[] = "bootstrap-compact"
availabletemplates[] = "bootstrap-compact-page"
availabletemplates[] = "bootstrap5"
availabletemplates[] = "page"
; set the template your installs defaults to, defaults to "bootstrap" (tpl/bootstrap.php), also
; available are "page" (tpl/page.php), the classic ZeroBin style and several
; 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

View File

@ -26,9 +26,8 @@
"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",
"mlocati/ip-lib": "1.20.0",
"symfony/polyfill-php80": "1.31.0",
"yzalis/identicon": "2.0.0"
},
"suggest" : {

105
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "0fdf0f08646fa2a4cf9c076131f529f5",
"content-hash": "6c7e6dea19e8bfd5641b220cb68c4b65",
"packages": [
{
"name": "jdenticon/jdenticon",
@ -57,16 +57,16 @@
},
{
"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.0",
"source": {
"type": "git",
"url": "https://github.com/myclabs/DeepCopy.git",
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845"
"reference": "024473a478be9df5fdaca2c793f2232fe788e414"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/123267b2c49fbf30d78a7b2d333f6be754b94845",
"reference": "123267b2c49fbf30d78a7b2d333f6be754b94845",
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/024473a478be9df5fdaca2c793f2232fe788e414",
"reference": "024473a478be9df5fdaca2c793f2232fe788e414",
"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.0"
},
"funding": [
{
@ -472,7 +393,7 @@
"type": "tidelift"
}
],
"time": "2024-11-08T17:47:46+00:00"
"time": "2025-02-12T12:17:51+00:00"
},
{
"name": "nikic/php-parser",

View File

@ -22,7 +22,6 @@ for more information.
### Minimal Requirements
- PHP version 7.3 or above
- ctype extension
- 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)

View File

@ -218,13 +218,14 @@
"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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -215,16 +215,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

@ -218,13 +218,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 ?)",
@ -221,10 +221,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": "Theme"
}

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?)": "לא ניתן לפענח את הנתונים (מפתח שגוי?)",
@ -170,29 +170,29 @@
"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 +209,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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",
@ -220,11 +220,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": "Theme"
}

View File

@ -226,5 +226,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

@ -226,5 +226,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

@ -220,11 +220,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -226,5 +226,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

@ -221,10 +221,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)": "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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 749 B

After

Width:  |  Height:  |  Size: 741 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 266 B

After

Width:  |  Height:  |  Size: 180 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 B

After

Width:  |  Height:  |  Size: 217 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 B

After

Width:  |  Height:  |  Size: 104 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 299 B

After

Width:  |  Height:  |  Size: 200 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 183 B

After

Width:  |  Height:  |  Size: 174 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 B

After

Width:  |  Height:  |  Size: 144 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 196 B

After

Width:  |  Height:  |  Size: 149 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -5,7 +5,6 @@ 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;
@ -17,7 +16,7 @@ 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.5');
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() {

2012
js/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -6,13 +6,11 @@
"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
}
@ -3933,7 +3932,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();
}
@ -4625,7 +4643,12 @@ 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);
$('#language select').change(setLanguage);
// bootstrap template drop down
$('#template ul.dropdown-menu li a').click(setTemplate);
// page template drop down
$('#template select').change(setTemplate);
// bind events
$burnAfterReading.change(changeBurnAfterReading);

File diff suppressed because one or more lines are too long

2
js/purify-3.2.5.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 = [],
@ -48,6 +49,7 @@ describe('AttachmentViewer', function () {
$('#attachment').hasClass('hidden') &&
$('#attachmentPreview').hasClass('hidden')
);
global.atob = common.atob;
if (filename.length) {
$.PrivateBin.AttachmentViewer.setAttachment(data, filename);
} else {

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 () {

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

@ -11,7 +11,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 +32,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,18 @@ 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',
'page',
),
'info' => 'More information on the <a href=\'https://privatebin.info/\'>project page</a>.',
'notice' => '',
'languageselection' => false,
@ -108,8 +119,8 @@ 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-yN0ZaVFrXpiYaeFRcofdCrlHVcw4ZJAXU3K1l6H9rsoY//iLKegX0GdWxRCFWzhd1xO4eDJKCT7qyaA1Vt65bg==',
'js/purify-3.2.5.js' => 'sha512-eLlLLL/zYuf5JuG0x4WQm687MToqOGP9cDQHIdmOy1ZpjiY4J48BBcOM7DtZheKk1UogW920+9RslWYB4KGuuA==',
'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==',

View File

@ -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,6 +431,13 @@ 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(
@ -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;
@ -297,14 +297,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'];

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';
@ -343,12 +343,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);
}
/**

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'))) {

View File

@ -12,6 +12,7 @@
namespace PrivateBin;
use Exception;
use PrivateBin\Model\Paste;
/**
* Request
@ -84,7 +85,7 @@ class Request
foreach ($_GET as $key => $value) {
// only return if value is empty and key is 16 hex chars
$key = (string) $key;
if (($value === '') && strlen($key) === 16 && ctype_xdigit($key)) {
if (empty($value) && Paste::isValidId($key)) {
return $key;
}
}
@ -110,9 +111,8 @@ class Request
// it might be a creation or a deletion, the latter is detected below
$this->_operation = 'create';
try {
$this->_params = Json::decode(
file_get_contents(self::$_inputStream)
);
$data = file_get_contents(self::$_inputStream);
$this->_params = Json::decode($data);
} catch (Exception $e) {
// ignore error, $this->_params will remain empty
}

120
lib/TemplateSwitcher.php Normal file
View File

@ -0,0 +1,120 @@
<?php declare(strict_types=1);
/**
* PrivateBin
*
* a zero-knowledge paste bin
*
* @link https://github.com/PrivateBin/PrivateBin
* @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
* @license https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
*/
namespace PrivateBin;
/**
* TemplateSwitcher
*
* Provides tool to change application template
*/
class TemplateSwitcher
{
/**
* template fallback
*
* @access protected
* @static
* @var string
*/
protected static $_templateFallback;
/**
* available templates
*
* @access protected
* @static
* @var array
*/
protected static $_availableTemplates = array();
/**
* set available templates
*
* @access public
* @static
* @param array $templates
*/
public static function setAvailableTemplates(array $templates)
{
self::$_availableTemplates = $templates;
}
/**
* set the default template
*
* @access public
* @static
* @param string $template
*/
public static function setTemplateFallback(string $template)
{
if (self::isTemplateAvailable($template)) {
self::$_templateFallback = $template;
}
}
/**
* get currently loaded template
*
* @access public
* @static
* @return string
*/
public static function getTemplate(): string
{
$selectedTemplate = self::getSelectedByUserTemplate();
return $selectedTemplate ?? self::$_templateFallback;
}
/**
* get list of available templates
*
* @access public
* @static
* @return array
*/
public static function getAvailableTemplates(): array
{
return self::$_availableTemplates;
}
/**
* check if the provided template is available
*
* @access public
* @static
* @return bool
*/
public static function isTemplateAvailable(string $template): bool
{
return in_array($template, self::getAvailableTemplates());
}
/**
* get the template selected by user
*
* @access private
* @static
* @return string|null
*/
private static function getSelectedByUserTemplate(): ?string
{
$selectedTemplate = null;
$templateCookieValue = $_COOKIE['template'] ?? '';
if (self::isTemplateAvailable($templateCookieValue)) {
$selectedTemplate = $templateCookieValue;
}
return $selectedTemplate;
}
}

View File

@ -70,7 +70,7 @@ class View
$sri = array_key_exists($file, $this->_variables['SRI']) ?
' integrity="' . $this->_variables['SRI'][$file] . '"' : '';
// if the file isn't versioned (ends in a digit), add our own version
$cacheBuster = ctype_digit(substr($file, -4, 1)) ?
$cacheBuster = (bool) preg_match('#[0-9]\.js$#', (string) $file) ?
'' : '?' . rawurlencode($this->_variables['VERSION']);
echo '<script ', $attributes,
' type="text/javascript" data-cfasync="false" src="', $file,

View File

@ -71,7 +71,7 @@ if ($MARKDOWN) :
<?php
endif;
?>
<?php $this->_scriptTag('js/purify-3.2.4.js', 'async'); ?>
<?php $this->_scriptTag('js/purify-3.2.5.js', 'async'); ?>
<?php $this->_scriptTag('js/legacy.js', 'async'); ?>
<?php $this->_scriptTag('js/privatebin.js', 'defer'); ?>
<!-- icon -->
@ -457,6 +457,28 @@ if (!empty($LANGUAGESELECTION)) :
</li>
<?php
endif;
?>
<?php
if (!empty($TEMPLATESELECTION)) :
?>
<li id="template" class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"><?php echo I18n::_('Theme'); ?>: <?php echo $TEMPLATESELECTION; ?> <span class="caret"></span></a>
<ul class="dropdown-menu dropdown-menu-right">
<?php
foreach ($TEMPLATES as $value) :
?>
<li>
<a href="#" data-template="<?php echo $value; ?>">
<?php echo $value; ?>
</a>
</li>
<?php
endforeach;
?>
</ul>
</li>
<?php
endif;
?>
</ul>
</div>
@ -553,8 +575,8 @@ if (!empty($URLSHORTENER)) :
?>
<p>
<button id="shortenbutton" data-shortener="<?php echo I18n::encode($URLSHORTENER); ?>" type="button" class="btn btn-<?php echo $isDark ? 'warning' : 'primary'; ?> btn-block">
<span class="glyphicon glyphicon-send" aria-hidden="true"></span> <?php echo I18n::_('Shorten URL'), PHP_EOL; ?>
</button>
<span class="glyphicon glyphicon-send" aria-hidden="true"></span> <?php echo I18n::_('Shorten URL'), PHP_EOL; ?>
</button>
</p>
<div role="alert" class="alert alert-danger">
<span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>

View File

@ -55,7 +55,7 @@ if ($MARKDOWN) :
<?php
endif;
?>
<?php $this->_scriptTag('js/purify-3.2.4.js', 'defer'); ?>
<?php $this->_scriptTag('js/purify-3.2.5.js', 'defer'); ?>
<?php $this->_scriptTag('js/legacy.js', 'async'); ?>
<?php $this->_scriptTag('js/privatebin.js', 'defer'); ?>
<!-- icon -->
@ -323,6 +323,30 @@ if (!empty($LANGUAGESELECTION)) :
</li>
<?php
endif;
?>
<?php
if (!empty($TEMPLATESELECTION)) :
?>
<li id="template" class="nav-item dropdown">
<a href="#" class="nav-link dropdown-toggle d-flex align-items-center gap-1" data-bs-toggle="dropdown" role="button" aria-expanded="false">
<?php echo I18n::_('Theme'); ?>: <?php echo $TEMPLATESELECTION, PHP_EOL; ?>
</a>
<ul class="dropdown-menu dropdown-menu-end" role="menu">
<?php
foreach ($TEMPLATES as $value) :
?>
<li>
<a href="#" class="dropdown-item" data-template="<?php echo $value; ?>">
<?php echo $value; ?>
</a>
</li>
<?php
endforeach;
?>
</ul>
</li>
<?php
endif;
?>
</ul>
</div>
@ -418,8 +442,8 @@ if (!empty($URLSHORTENER)) :
?>
<p>
<button id="shortenbutton" data-shortener="<?php echo I18n::encode($URLSHORTENER); ?>" type="button" class="btn btn-primary btn-block d-flex justify-content-center align-items-center gap-1">
<svg width="16" height="16" fill="currentColor" aria-hidden="true"><use href="img/bootstrap-icons.svg#send" /></svg> <?php echo I18n::_('Shorten URL'), PHP_EOL; ?>
</button>
<svg width="16" height="16" fill="currentColor" aria-hidden="true"><use href="img/bootstrap-icons.svg#send" /></svg> <?php echo I18n::_('Shorten URL'), PHP_EOL; ?>
</button>
</p>
<div role="alert" class="alert alert-danger">
<svg width="16" height="16" fill="currentColor" aria-hidden="true"><use href="img/bootstrap-icons.svg#exclamation-circle" /></svg>

View File

@ -49,7 +49,7 @@ if ($MARKDOWN):
<?php
endif;
?>
<?php $this->_scriptTag('js/purify-3.2.4.js', 'async'); ?>
<?php $this->_scriptTag('js/purify-3.2.5.js', 'async'); ?>
<?php $this->_scriptTag('js/legacy.js', 'async'); ?>
<?php $this->_scriptTag('js/privatebin.js', 'defer'); ?>
<!-- icon -->
@ -222,6 +222,27 @@ if (!empty($LANGUAGESELECTION)):
</div>
<?php
endif;
?>
<?php
if (!empty($TEMPLATESELECTION)):
?>
<div id="template" class="button"><?php echo I18n::_('Theme'); ?>:
<select name="template">
<?php
foreach ($TEMPLATES as $value):
?>
<option data-template="<?php echo $value; ?>" value="<?php echo $value; ?>"<?php
if ($value == $TEMPLATESELECTION):
?> selected="selected"<?php
endif;
?>><?php echo $value; ?></option>
<?php
endforeach;
?>
</select>
</div>
<?php
endif;
?>
</div>
<?php

View File

@ -1,6 +1,7 @@
<?php declare(strict_types=1);
use PHPUnit\Framework\TestCase;
use PrivateBin\Configuration;
use PrivateBin\Controller;
use PrivateBin\Data\Filesystem;
use PrivateBin\Persistence\ServerSalt;
@ -147,6 +148,20 @@ class ControllerTest extends TestCase
new Controller;
}
/**
* @runInSeparateProcess
*/
public function testNonDefaultConf()
{
$newConfig = new class extends Configuration {};
$configValue = (new ReflectionClass(Controller::class))->getProperty('_conf');
$configValue->setAccessible(true);
ob_start();
$controller = new Controller($newConfig);
ob_end_clean();
$this->assertSame($newConfig, $configValue->getValue($controller));
}
/**
* @runInSeparateProcess
*/
@ -273,7 +288,8 @@ class ControllerTest extends TestCase
$options = parse_ini_file(CONF, true);
$options['traffic']['limit'] = 0;
Helper::createIniFile(CONF, $options);
$this->_data->create(Helper::getPasteId(), Helper::getPaste());
$paste = Helper::getPaste();
$this->_data->create(Helper::getPasteId(), $paste);
$paste = Helper::getPasteJson();
$file = tempnam(sys_get_temp_dir(), 'FOO');
file_put_contents($file, $paste);
@ -523,7 +539,8 @@ class ControllerTest extends TestCase
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REMOTE_ADDR'] = '::1';
$this->_data->create(Helper::getPasteId(), Helper::getPaste());
$paste = Helper::getPaste();
$this->_data->create(Helper::getPasteId(), $paste);
ob_start();
new Controller;
$content = ob_get_contents();
@ -549,7 +566,8 @@ class ControllerTest extends TestCase
$_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
$_SERVER['REQUEST_METHOD'] = 'POST';
$_SERVER['REMOTE_ADDR'] = '::1';
$this->_data->create(Helper::getPasteId(), Helper::getPaste());
$paste = Helper::getPaste();
$this->_data->create(Helper::getPasteId(), $paste);
ob_start();
new Controller;
$content = ob_get_contents();
@ -618,8 +636,10 @@ class ControllerTest extends TestCase
$options = parse_ini_file(CONF, true);
$options['traffic']['limit'] = 0;
Helper::createIniFile(CONF, $options);
$this->_data->create(Helper::getPasteId(), Helper::getPaste());
$this->_data->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId(), Helper::getComment());
$paste = Helper::getPaste();
$this->_data->create(Helper::getPasteId(), $paste);
$comment = Helper::getComment();
$this->_data->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId(), $comment);
$this->assertTrue($this->_data->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId()), 'comment exists before posting data');
$comment = Helper::getCommentJson();
$file = tempnam(sys_get_temp_dir(), 'FOO');
@ -804,7 +824,8 @@ class ControllerTest extends TestCase
*/
public function testDelete()
{
$this->_data->create(Helper::getPasteId(), Helper::getPaste());
$paste = Helper::getPaste();
$this->_data->create(Helper::getPasteId(), $paste);
$this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data');
$paste = $this->_data->read(Helper::getPasteId());
$_GET['pasteid'] = Helper::getPasteId();
@ -826,7 +847,8 @@ class ControllerTest extends TestCase
*/
public function testDeleteInvalidId()
{
$this->_data->create(Helper::getPasteId(), Helper::getPaste());
$paste = Helper::getPaste();
$this->_data->create(Helper::getPasteId(), $paste);
$_GET['pasteid'] = 'foo';
$_GET['deletetoken'] = 'bar';
ob_start();
@ -864,7 +886,8 @@ class ControllerTest extends TestCase
*/
public function testDeleteInvalidToken()
{
$this->_data->create(Helper::getPasteId(), Helper::getPaste());
$paste = Helper::getPaste();
$this->_data->create(Helper::getPasteId(), $paste);
$_GET['pasteid'] = Helper::getPasteId();
$_GET['deletetoken'] = 'bar';
ob_start();
@ -884,7 +907,8 @@ class ControllerTest extends TestCase
*/
public function testDeleteInvalidBurnAfterReading()
{
$this->_data->create(Helper::getPasteId(), Helper::getPaste());
$paste = Helper::getPaste();
$this->_data->create(Helper::getPasteId(), $paste);
$this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data');
$file = tempnam(sys_get_temp_dir(), 'FOO');
file_put_contents($file, json_encode(array(

View File

@ -60,18 +60,22 @@ class DatabaseTest extends TestCase
$this->assertEquals($paste, $this->_model->read(Helper::getPasteId()));
// storing comments
$comment1 = Helper::getComment(1);
$comment2 = Helper::getComment(2);
$meta1 = $comment1['meta'];
$meta2 = $comment2['meta'];
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'v1 comment does not yet exist');
$this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), Helper::getComment(1)) !== false, 'store v1 comment');
$this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment1) !== false, 'store v1 comment');
$this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'v1 comment exists after storing it');
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId()), 'v2 comment does not yet exist');
$this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId(), Helper::getComment(2)) !== false, 'store v2 comment');
$this->assertTrue($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId(), $comment2) !== false, 'store v2 comment');
$this->assertTrue($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getPasteId()), 'v2 comment exists after storing it');
$comment1 = Helper::getComment(1);
$comment1['id'] = Helper::getCommentId();
$comment1['parentid'] = Helper::getPasteId();
$comment2 = Helper::getComment(2);
$comment1['meta'] = $meta1;
$comment2['id'] = Helper::getPasteId();
$comment2['parentid'] = Helper::getPasteId();
$comment2['meta'] = $meta2;
$this->assertEquals(
array(
$comment1['meta']['postdate'] => $comment1,
@ -120,7 +124,8 @@ class DatabaseTest extends TestCase
if (in_array($key, array('y', 'z'))) {
$this->assertTrue($this->_model->create($ids[$key], $paste), "store $key paste");
} elseif ($key === 'x') {
$this->assertTrue($this->_model->create($ids[$key], Helper::getPaste()), "store $key paste");
$data = Helper::getPaste();
$this->assertTrue($this->_model->create($ids[$key], $data), "store $key paste");
} else {
$this->assertTrue($this->_model->create($ids[$key], $expired), "store $key paste");
}
@ -137,6 +142,28 @@ class DatabaseTest extends TestCase
}
}
public function testErrorDetection()
{
$this->_model->delete(Helper::getPasteId());
$paste = Helper::getPaste(2, array('expire' => "Invalid UTF-8 sequence: \xB1\x31"));
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
$this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store broken paste');
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist');
}
public function testCommentErrorDetection()
{
$this->_model->delete(Helper::getPasteId());
$data = Helper::getPaste();
$comment = Helper::getComment(2, array('nickname' => "Invalid UTF-8 sequence: \xB1\x31"));
$this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
$this->assertTrue($this->_model->create(Helper::getPasteId(), $data), 'store new paste');
$this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does not yet exist');
$this->assertFalse($this->_model->createComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId(), $comment), 'unable to store broken comment');
$this->assertFalse($this->_model->existsComment(Helper::getPasteId(), Helper::getPasteId(), Helper::getCommentId()), 'comment does still not exist');
}
public function testGetIbmInstance()
{
$this->expectException(PDOException::class);

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