102 Commits 89e5853197 ... 13019339d9

Author SHA1 Message Date
  rugk 13019339d9 chore: update SRI hash 3 weeks ago
  rugk d616d8f28c style: upgrade JsHint to EcmaScript 2018 as ESLint to align them 3 weeks ago
  rugk 62a74624df style: add missing semicolons & properly use Error exception class 3 weeks ago
  rugk 693cd994f1 refactor: remove last jQuery bit for attachment upload 3 weeks ago
  rugk 26d08a1b32 style(jshint): predef seems to be deprecated 3 weeks ago
  rugk 974f7983e3 style: remove another ? operator due to EsLint complaining about it 3 weeks ago
  rugk 48089c0462 chore: update SRI hash again 3 weeks ago
  rugk 0992b03847 style: align EsLint and JsHint to require use-strict in global mode 3 weeks ago
  rugk 526e795b03 style: do not use ? yet as we have no support for it/ESLint cmplains 3 weeks ago
  rugk 72bfa150dc chore: add JSHint as explicit dev dependency for JS code 3 weeks ago
  rugk 4be914099b chore: refresh SRI hash 3 weeks ago
  rugk 23cf7d1d9a Merge branch 'js/removeJQuery' of https://github.com/PrivateBin/PrivateBin into js/removeJQuery 3 weeks ago
  rugk d3732a6d5c fix: close button in one-time-confirm model could not be found yielding in problem loading such pastes 3 weeks ago
  rugk 6580d2c6b2 Merge branch 'master' into js/removeJQuery 3 weeks ago
  El RIDO c501d36b04 apply StyleCI recommendation 3 weeks ago
  El RIDO 734b555a09 Merge pull request #1870 from PrivateBin/crowdin-translation 3 weeks ago
  PrivateBin Translator Bot 9004d9bfbc New translations en.json (Polish) 3 weeks ago
  PrivateBin Translator Bot efa84253b4 New translations en.json (Slovak) 3 weeks ago
  PrivateBin Translator Bot 386cdb84fb New translations en.json (Polish) 3 weeks ago
  PrivateBin Translator Bot 89e2549e84 New translations en.json (Swedish) 3 weeks ago
  PrivateBin Translator Bot e76247fbc0 New translations en.json (Slovak) 3 weeks ago
  PrivateBin Translator Bot f0fe7a3402 New translations en.json (Portuguese) 3 weeks ago
  PrivateBin Translator Bot f1b3deb566 New translations en.json (Polish) 3 weeks ago
  PrivateBin Translator Bot bf379c4809 New translations en.json (Occitan) 3 weeks ago
  PrivateBin Translator Bot 32d260ff29 New translations en.json (Estonian) 3 weeks ago
  PrivateBin Translator Bot fd93225154 New translations en.json (Thai) 3 weeks ago
  PrivateBin Translator Bot cd8d1cff10 New translations en.json (Persian) 3 weeks ago
  PrivateBin Translator Bot 225420ca72 New translations en.json (Indonesian) 3 weeks ago
  PrivateBin Translator Bot 80b6d85934 New translations en.json (Ukrainian) 3 weeks ago
  PrivateBin Translator Bot eee5941c7a New translations en.json (Turkish) 3 weeks ago
  PrivateBin Translator Bot 4f0e0e8d33 New translations en.json (Slovenian) 3 weeks ago
  PrivateBin Translator Bot eb66b3b148 New translations en.json (Slovak) 3 weeks ago
  PrivateBin Translator Bot 3c46f8edcf New translations en.json (Russian) 3 weeks ago
  PrivateBin Translator Bot 3f9f7ba104 New translations en.json (Polish) 3 weeks ago
  PrivateBin Translator Bot e978256b04 New translations en.json (Norwegian) 3 weeks ago
  PrivateBin Translator Bot b8d80ccf71 New translations en.json (Dutch) 3 weeks ago
  PrivateBin Translator Bot 9e4521d9e5 New translations en.json (Lithuanian) 3 weeks ago
  PrivateBin Translator Bot f01a9ec9f0 New translations en.json (Korean) 3 weeks ago
  PrivateBin Translator Bot 6c3cf0b121 New translations en.json (Japanese) 3 weeks ago
  PrivateBin Translator Bot 28d7238cbe New translations en.json (Italian) 3 weeks ago
  PrivateBin Translator Bot d9739e9770 New translations en.json (Hungarian) 3 weeks ago
  PrivateBin Translator Bot 85d3914005 New translations en.json (Hebrew) 3 weeks ago
  PrivateBin Translator Bot ad13b00d50 New translations en.json (Finnish) 3 weeks ago
  PrivateBin Translator Bot b92bb330e8 New translations en.json (Greek) 3 weeks ago
  PrivateBin Translator Bot dd8c1f8796 New translations en.json (German) 3 weeks ago
  PrivateBin Translator Bot bd6a2d2242 New translations en.json (Czech) 3 weeks ago
  PrivateBin Translator Bot 2816b8cb90 New translations en.json (Bulgarian) 3 weeks ago
  PrivateBin Translator Bot e31f73780a New translations en.json (Arabic) 3 weeks ago
  PrivateBin Translator Bot ef84ad446a New translations en.json (Spanish) 3 weeks ago
  PrivateBin Translator Bot f9138ce5fd New translations en.json (French) 3 weeks ago
  PrivateBin Translator Bot dfb0ea43e7 New translations en.json (Romanian) 3 weeks ago
  El RIDO 78d782a936 Merge pull request #1840 from mvanhorn/style/short-array-syntax-1640 3 weeks ago
  Matt Van Horn ae1943669c ci: drop unsupported short_array_syntax fixer from StyleCI config 4 weeks ago
  El RIDO b6f0cb2632 Merge pull request #1888 from marouane-hassine/fix/dead-path-validation-guard 4 weeks ago
  El RIDO 96d1ac9754 Merge pull request #1889 from PrivateBin/json-exception 4 weeks ago
  El RIDO 310c2efbab Switch to PHP native JsonException type 4 weeks ago
  El RIDO 9e1ac5a147 Merge branch 'master' into fix/dead-path-validation-guard 4 weeks ago
  marouanehassine 3551c87038 fix: run PATH trailing-separator check instead of dead guard 4 weeks ago
  El RIDO 8a77305838 Merge pull request #1885 from marouane-hassine/fix/1883-malformed-v2-json-500 4 weeks ago
  marouanehassine abd1418bc8 fix: reject malformed JSON API bodies instead of crashing 1 month ago
  Matt Van Horn 077fc16695 Merge remote-tracking branch 'upstream/master' into style/short-array-syntax-1640 1 month ago
  marouanehassine e80efda7c2 fix: return "Invalid data." instead of HTTP 500 on malformed v2 payloads 1 month ago
  El RIDO 886d4419d7 Merge pull request #1881 from PrivateBin/dompurify-3.4.12 1 month ago
  Matt Van Horn 1359c30247 style: enforce short array syntax via StyleCI 1 month ago
  El RIDO 2f17c5f1d6 chore(deps): update DOMpurify to 3.4.12 1 month ago
  El RIDO 360f2adeca Merge pull request #1879 from PrivateBin/dependabot/github_actions/actions/setup-node-7 1 month ago
  El RIDO b6f4278e07 Merge pull request #1878 from TowyTowy/fix/yourls-shorturl-null-fallback 1 month ago
  dependabot[bot] 4a50fed678 chore(deps): bump actions/setup-node from 6 to 7 1 month ago
  TowyTowy bb8b77d714 Use a string statusCode in the YourlsProxy test 1 month ago
  TowyTowy a0c0d154ee fix: handle YOURLS 200 response without shorturl gracefully 1 month ago
  PrivateBin Translator Bot 76173b8e65 New translations en.json (Corsican) 1 month ago
  PrivateBin Translator Bot b3553697e4 New translations en.json (Corsican) 1 month ago
  PrivateBin Translator Bot 153abf1381 New translations en.json (Occitan) 1 month ago
  PrivateBin Translator Bot be6aff19fe New translations en.json (Estonian) 1 month ago
  PrivateBin Translator Bot 00c0bcb0b2 New translations en.json (Thai) 1 month ago
  PrivateBin Translator Bot 5a2a1540b6 New translations en.json (Persian) 1 month ago
  PrivateBin Translator Bot 93543df42c New translations en.json (Indonesian) 1 month ago
  PrivateBin Translator Bot 1c99609829 New translations en.json (Ukrainian) 1 month ago
  PrivateBin Translator Bot 5ae5127cc0 New translations en.json (Turkish) 1 month ago
  PrivateBin Translator Bot 39c6fd046a New translations en.json (Swedish) 1 month ago
  PrivateBin Translator Bot ef0e1d437f New translations en.json (Slovenian) 1 month ago
  PrivateBin Translator Bot 5040a4e9a0 New translations en.json (Slovak) 1 month ago
  PrivateBin Translator Bot 007bc73bbf New translations en.json (Russian) 1 month ago
  PrivateBin Translator Bot 873f2aedd4 New translations en.json (Portuguese) 1 month ago
  PrivateBin Translator Bot 4f85d048ef New translations en.json (Polish) 1 month ago
  PrivateBin Translator Bot f218c19277 New translations en.json (Norwegian) 1 month ago
  PrivateBin Translator Bot dfbd349f80 New translations en.json (Dutch) 1 month ago
  PrivateBin Translator Bot e0a8a8d1bc New translations en.json (Lithuanian) 1 month ago
  PrivateBin Translator Bot 99873e5c55 New translations en.json (Japanese) 1 month ago
  PrivateBin Translator Bot 6509190c29 New translations en.json (Italian) 1 month ago
  PrivateBin Translator Bot 0956ab85a4 New translations en.json (Hungarian) 1 month ago
  PrivateBin Translator Bot 5a741a8322 New translations en.json (Hebrew) 1 month ago
  PrivateBin Translator Bot d000a76c73 New translations en.json (Finnish) 1 month ago
  PrivateBin Translator Bot a5e4c9a7f2 New translations en.json (Greek) 1 month ago
  PrivateBin Translator Bot 52364d2493 New translations en.json (German) 1 month ago
  PrivateBin Translator Bot c14f78e1b3 New translations en.json (Czech) 1 month ago
  PrivateBin Translator Bot 6bf4edda59 New translations en.json (Bulgarian) 1 month ago
  PrivateBin Translator Bot 1ffcdb952e New translations en.json (Arabic) 1 month ago
  PrivateBin Translator Bot 7abc33aff8 New translations en.json (Spanish) 1 month ago
  PrivateBin Translator Bot 0acb950bce New translations en.json (French) 1 month ago
  PrivateBin Translator Bot ec7734bc4d New translations en.json (Romanian) 1 month ago
  Matt Van Horn c5c910a537 Switch to short array syntax (#1640) 3 months ago
62 changed files with 1144 additions and 856 deletions
  1. 1 1
      .github/workflows/eslint.yml
  2. 1 1
      .github/workflows/tests.yml
  3. 4 5
      .jshintrc
  4. 0 2
      .styleci.yml
  5. 5 0
      CHANGELOG.md
  6. 15 32
      composer.lock
  7. 198 198
      i18n/ko.json
  8. 3 3
      i18n/sl.json
  9. 2 2
      i18n/sv.json
  10. 1 1
      js/common.js
  11. 2 2
      js/eslint.config.js
  12. 281 0
      js/package-lock.json
  13. 1 0
      js/package.json
  14. 34 38
      js/privatebin.js
  15. 0 1
      js/purify-3.4.1.js
  16. 1 0
      js/purify-3.4.12.js
  17. 2 2
      js/test/PasteStatus.js
  18. 42 42
      lib/Configuration.php
  19. 17 18
      lib/Controller.php
  20. 1 1
      lib/Data/AbstractData.php
  21. 28 28
      lib/Data/Database.php
  22. 4 4
      lib/Data/Filesystem.php
  23. 22 22
      lib/Data/GoogleCloudStorage.php
  24. 32 32
      lib/Data/S3Storage.php
  25. 0 38
      lib/Exception/JsonException.php
  26. 2 2
      lib/Filter.php
  27. 21 6
      lib/FormatV2.php
  28. 10 10
      lib/I18n.php
  29. 2 24
      lib/Json.php
  30. 1 1
      lib/Model/AbstractModel.php
  31. 5 5
      lib/Model/Comment.php
  32. 2 2
      lib/Persistence/TrafficLimiter.php
  33. 4 4
      lib/Proxy/AbstractProxy.php
  34. 6 6
      lib/Proxy/ShlinkProxy.php
  35. 5 5
      lib/Proxy/YourlsProxy.php
  36. 14 11
      lib/Request.php
  37. 1 1
      lib/TemplateSwitcher.php
  38. 1 1
      lib/View.php
  39. 5 5
      lib/Vizhash16x16.php
  40. 1 1
      tpl/bootstrap5.php
  41. 101 101
      tst/Bootstrap.php
  42. 10 10
      tst/ControllerTest.php
  43. 6 6
      tst/ControllerWithDbTest.php
  44. 7 7
      tst/ControllerWithGcsTest.php
  45. 36 36
      tst/Data/DatabaseTest.php
  46. 16 16
      tst/Data/FilesystemTest.php
  47. 14 14
      tst/Data/GoogleCloudStorageTest.php
  48. 37 0
      tst/FormatV2Test.php
  49. 4 4
      tst/I18nTest.php
  50. 18 18
      tst/JsonApiTest.php
  51. 5 5
      tst/MigrateTest.php
  52. 36 36
      tst/ModelTest.php
  53. 1 1
      tst/Persistence/PurgeLimiterTest.php
  54. 9 9
      tst/Persistence/ServerSaltTest.php
  55. 1 1
      tst/Persistence/TrafficLimiterTest.php
  56. 25 5
      tst/RequestTest.php
  57. 6 6
      tst/ViewTest.php
  58. 1 1
      tst/Vizhash16x16Test.php
  59. 32 19
      tst/YourlsProxyTest.php
  60. 0 1
      vendor/composer/autoload_classmap.php
  61. 0 1
      vendor/composer/autoload_static.php
  62. 2 2
      vendor/composer/installed.php

+ 1 - 1
.github/workflows/eslint.yml

@@ -24,7 +24,7 @@ jobs:
           persist-credentials: false
           persist-credentials: false
 
 
       - name: Set up Node.js
       - name: Set up Node.js
-        uses: actions/setup-node@v6
+        uses: actions/setup-node@v7
         with:
         with:
           node-version: '20'
           node-version: '20'
 
 

+ 1 - 1
.github/workflows/tests.yml

@@ -224,7 +224,7 @@ jobs:
         persist-credentials: false
         persist-credentials: false
 
 
     - name: Setup Node
     - name: Setup Node
-      uses: actions/setup-node@v6
+      uses: actions/setup-node@v7
       with:
       with:
         node-version: '20'
         node-version: '20'
         cache: 'npm'
         cache: 'npm'

+ 4 - 5
.jshintrc

@@ -2,7 +2,7 @@
     "bitwise": true,
     "bitwise": true,
     "curly": true,
     "curly": true,
     "eqeqeq": true,
     "eqeqeq": true,
-    "esversion": 6,
+    "esversion": 2018,
     "forin": true,
     "forin": true,
     "freeze": true,
     "freeze": true,
     "futurehostile": true,
     "futurehostile": true,
@@ -17,11 +17,12 @@
     "quotmark": "single",
     "quotmark": "single",
     "singleGroups": true,
     "singleGroups": true,
     "strict": true,
     "strict": true,
+    "globalstrict": true,
     "undef": true,
     "undef": true,
     "unused": true,
     "unused": true,
     "jquery": false,
     "jquery": false,
     "browser": true,
     "browser": true,
-    "predef": {
+    "globals": {
       "after": true,
       "after": true,
       "before": true,
       "before": true,
       "cleanup": true,
       "cleanup": true,
@@ -36,9 +37,7 @@
       "jsdom": true,
       "jsdom": true,
       "require": false,
       "require": false,
       "setTimeout": false,
       "setTimeout": false,
-      "window": true
-    },
-    "globals": {
+      "window": true,
       "DOMPurify": true,
       "DOMPurify": true,
       "kjua": true
       "kjua": true
     }
     }

+ 0 - 2
.styleci.yml

@@ -5,7 +5,6 @@ risky: false
 enabled:
 enabled:
   - align_equals
   - align_equals
   - concat_with_spaces
   - concat_with_spaces
-  - long_array_syntax
   - no_empty_comment
   - no_empty_comment
   - pre_increment
   - pre_increment
 
 
@@ -26,7 +25,6 @@ disabled:
   - phpdoc_single_line_var_spacing
   - phpdoc_single_line_var_spacing
   - phpdoc_summary
   - phpdoc_summary
   - post_increment
   - post_increment
-  - short_array_syntax
   - single_line_after_imports
   - single_line_after_imports
   - unalign_equals
   - unalign_equals
 
 

+ 5 - 0
CHANGELOG.md

@@ -7,6 +7,11 @@
 * CHANGED: Removed support for Bootstrap 3 as it requires jQuery.
 * CHANGED: Removed support for Bootstrap 3 as it requires jQuery.
 
 
 ## 2.0.6 (not yet released)
 ## 2.0.6 (not yet released)
+* CHANGED: Upgrading libraries to: DOMpurify 3.4.12
+* CHANGED: Switch to PHP native JsonException type
+* FIXED: Gracefully handle YOURLS replies with a 200 status code but no shorturl, instead of raising a TypeError
+* FIXED: Return "Invalid data." instead of HTTP 500 on malformed v2 JSON payloads (#1883)
+* FIXED: Dead PATH validation guard in Controller, the check for a missing trailing directory separator never ran (#1887)
 
 
 ## 2.0.5 (2026-07-11)
 ## 2.0.5 (2026-07-11)
 * CHANGED: Show OS-specific copy hotkey hint (Cmd+c on Mac, Ctrl+c on others) (#1506)
 * CHANGED: Show OS-specific copy hotkey hint (Cmd+c on Mac, Ctrl+c on others) (#1506)

+ 15 - 32
composer.lock

@@ -396,20 +396,19 @@
         },
         },
         {
         {
             "name": "nikic/php-parser",
             "name": "nikic/php-parser",
-            "version": "v5.7.0",
+            "version": "v5.8.0",
             "source": {
             "source": {
                 "type": "git",
                 "type": "git",
                 "url": "https://github.com/nikic/PHP-Parser.git",
                 "url": "https://github.com/nikic/PHP-Parser.git",
-                "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82"
+                "reference": "044a6a392ff8ad0d61f14370a5fbbd0a0107152f"
             },
             },
             "dist": {
             "dist": {
                 "type": "zip",
                 "type": "zip",
-                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82",
-                "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82",
+                "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/044a6a392ff8ad0d61f14370a5fbbd0a0107152f",
+                "reference": "044a6a392ff8ad0d61f14370a5fbbd0a0107152f",
                 "shasum": ""
                 "shasum": ""
             },
             },
             "require": {
             "require": {
-                "ext-ctype": "*",
                 "ext-json": "*",
                 "ext-json": "*",
                 "ext-tokenizer": "*",
                 "ext-tokenizer": "*",
                 "php": ">=7.4"
                 "php": ">=7.4"
@@ -448,9 +447,9 @@
             ],
             ],
             "support": {
             "support": {
                 "issues": "https://github.com/nikic/PHP-Parser/issues",
                 "issues": "https://github.com/nikic/PHP-Parser/issues",
-                "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0"
+                "source": "https://github.com/nikic/PHP-Parser/tree/v5.8.0"
             },
             },
-            "time": "2025-12-06T11:56:16+00:00"
+            "time": "2026-07-04T14:30:18+00:00"
         },
         },
         {
         {
             "name": "phar-io/manifest",
             "name": "phar-io/manifest",
@@ -891,25 +890,25 @@
         },
         },
         {
         {
             "name": "phpunit/phpunit",
             "name": "phpunit/phpunit",
-            "version": "9.6.34",
+            "version": "9.6.35",
             "source": {
             "source": {
                 "type": "git",
                 "type": "git",
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
                 "url": "https://github.com/sebastianbergmann/phpunit.git",
-                "reference": "b36f02317466907a230d3aa1d34467041271ef4a"
+                "reference": "0edba2f3a0c48df3553cb9b640810b30df60302b"
             },
             },
             "dist": {
             "dist": {
                 "type": "zip",
                 "type": "zip",
-                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/b36f02317466907a230d3aa1d34467041271ef4a",
-                "reference": "b36f02317466907a230d3aa1d34467041271ef4a",
+                "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/0edba2f3a0c48df3553cb9b640810b30df60302b",
+                "reference": "0edba2f3a0c48df3553cb9b640810b30df60302b",
                 "shasum": ""
                 "shasum": ""
             },
             },
             "require": {
             "require": {
                 "doctrine/instantiator": "^1.5.0 || ^2",
                 "doctrine/instantiator": "^1.5.0 || ^2",
                 "ext-dom": "*",
                 "ext-dom": "*",
+                "ext-filter": "*",
                 "ext-json": "*",
                 "ext-json": "*",
                 "ext-libxml": "*",
                 "ext-libxml": "*",
                 "ext-mbstring": "*",
                 "ext-mbstring": "*",
-                "ext-xml": "*",
                 "ext-xmlwriter": "*",
                 "ext-xmlwriter": "*",
                 "myclabs/deep-copy": "^1.13.4",
                 "myclabs/deep-copy": "^1.13.4",
                 "phar-io/manifest": "^2.0.4",
                 "phar-io/manifest": "^2.0.4",
@@ -974,31 +973,15 @@
             "support": {
             "support": {
                 "issues": "https://github.com/sebastianbergmann/phpunit/issues",
                 "issues": "https://github.com/sebastianbergmann/phpunit/issues",
                 "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
                 "security": "https://github.com/sebastianbergmann/phpunit/security/policy",
-                "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.34"
+                "source": "https://github.com/sebastianbergmann/phpunit/tree/9.6.35"
             },
             },
             "funding": [
             "funding": [
                 {
                 {
-                    "url": "https://phpunit.de/sponsors.html",
-                    "type": "custom"
-                },
-                {
-                    "url": "https://github.com/sebastianbergmann",
-                    "type": "github"
-                },
-                {
-                    "url": "https://liberapay.com/sebastianbergmann",
-                    "type": "liberapay"
-                },
-                {
-                    "url": "https://thanks.dev/u/gh/sebastianbergmann",
-                    "type": "thanks_dev"
-                },
-                {
-                    "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit",
-                    "type": "tidelift"
+                    "url": "https://phpunit.de/sponsoring.html",
+                    "type": "other"
                 }
                 }
             ],
             ],
-            "time": "2026-01-27T05:45:00+00:00"
+            "time": "2026-07-06T14:48:07+00:00"
         },
         },
         {
         {
             "name": "sebastian/cli-parser",
             "name": "sebastian/cli-parser",

+ 198 - 198
i18n/ko.json

@@ -1,160 +1,160 @@
 {
 {
     "PrivateBin": "PrivateBin",
     "PrivateBin": "PrivateBin",
-    "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored 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 stored 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>.",
-    "Because ignorance is bliss": "Because ignorance is bliss",
-    "Document does not exist, has expired or has been deleted.": "Document does not exist, has expired or has been deleted.",
-    "%s requires php %s or above to work. Sorry.": "%s requires php %s or above to work. Sorry.",
-    "%s requires configuration section [%s] to be present in configuration file.": "%s requires configuration section [%s] to be present in configuration file.",
+    "%s is a minimalist, open source online pastebin where the server has zero knowledge of stored data. Data is encrypted/decrypted %sin the browser%s using 256 bits AES.": "%s은 서버가 저장된 데이터에 대해 전혀 알 수 없는 미니멀한 오픈소스 온라인 텍스트 공유 플랫폼(페이스트빈)입니다. 데이터는 256비트 AES를 사용하여 %s브라우저에서%s 암호화/복호화됩니다.",
+    "More information on the <a href=\"https://privatebin.info/\">project page</a>.": "자세한 정보는 <a href=\"https://privatebin.info/\">프로젝트 페이지</a>에서 확인하세요.",
+    "Because ignorance is bliss": "모르는 게 약이니까요",
+    "Document does not exist, has expired or has been deleted.": "존재하지 않거나 만료 또는 삭제된 문서입니다.",
+    "%s requires php %s or above to work. Sorry.": "%s을(를) 실행하려면 PHP %s 이상의 버전이 필요합니다. 죄송합니다.",
+    "%s requires configuration section [%s] to be present in configuration file.": "%s을(를) 실행하려면 설정 파일에 [%s] 설정 섹션이 있어야 합니다.",
     "Please wait %d seconds between each post.": [
     "Please wait %d seconds between each post.": [
-        "Please wait %d second between each post. (singular)",
-        "Please wait %d seconds between each post. (1st plural)",
-        "Please wait %d seconds between each post. (2nd plural)",
-        "Please wait %d seconds between each post. (3rd plural)",
-        "Please wait %d seconds between each post. (4th plural)",
-        "Please wait %d seconds between each post. (5th plural)"
+        "다음 게시글을 작성할 때까지 %d초 동안 기다려 주세요.",
+        "다음 게시글을 작성할 때까지 %d초 동안 기다려 주세요.",
+        "다음 게시글을 작성할 때까지 %d초 동안 기다려 주세요.",
+        "다음 게시글을 작성할 때까지 %d초 동안 기다려 주세요.",
+        "다음 게시글을 작성할 때까지 %d초 동안 기다려 주세요.",
+        "다음 게시글을 작성할 때까지 %d초 동안 기다려 주세요."
     ],
     ],
-    "Document is limited to %s of encrypted data.": "Document is limited to %s of encrypted data.",
-    "Invalid data.": "Invalid data.",
-    "You are unlucky. Try again.": "You are unlucky. Try again.",
-    "Error saving comment. Sorry.": "Error saving comment. Sorry.",
-    "Error saving document. Sorry.": "Error saving document. Sorry.",
-    "Invalid document ID.": "Invalid document ID.",
-    "Document is not of burn-after-reading type.": "Document is not of burn-after-reading type.",
-    "Wrong deletion token. Document was not deleted.": "Wrong deletion token. Document was not deleted.",
-    "Document was properly deleted.": "Document was properly deleted.",
-    "JavaScript is required for %s to work. Sorry for the inconvenience.": "JavaScript is required for %s to work. Sorry for the inconvenience.",
-    "%s requires a modern browser to work.": "%s requires a modern browser to work.",
-    "New": "New",
-    "Create": "Create",
-    "Clone": "Clone",
-    "Raw text": "Raw text",
-    "Expires": "Expires",
-    "Burn after reading": "Burn after reading",
-    "Open discussion": "Open discussion",
-    "Password (recommended)": "Password (recommended)",
-    "Discussion": "Discussion",
-    "Toggle navigation": "Toggle navigation",
+    "Document is limited to %s of encrypted data.": "문서 크기는 암호화된 데이터 기준 %s로 제한됩니다.",
+    "Invalid data.": "유효하지 않은 데이터입니다.",
+    "You are unlucky. Try again.": "운이 나빴네요. 다시 시도해 주세요.",
+    "Error saving comment. Sorry.": "댓글을 저장하는 중 오류가 발생했습니다. 죄송합니다.",
+    "Error saving document. Sorry.": "문서를 저장하는 중 오류가 발생했습니다. 죄송합니다.",
+    "Invalid document ID.": "유효하지 않은 문서 ID입니다.",
+    "Document is not of burn-after-reading type.": "이 문서는 '읽은 후 삭제' 설정이 적용되지 않았습니다.",
+    "Wrong deletion token. Document was not deleted.": "삭제 토큰이 일치하지 않습니다. 문서가 삭제되지 않았습니다.",
+    "Document was properly deleted.": "문서가 정상적으로 삭제되었습니다.",
+    "JavaScript is required for %s to work. Sorry for the inconvenience.": "%s을(를) 실행하려면 JavaScript가 필요합니다. 이용에 불편을 드려 죄송합니다.",
+    "%s requires a modern browser to work.": "%s을(를) 실행하려면 최신 브라우저가 필요합니다.",
+    "New": "새 문서",
+    "Create": "생성",
+    "Clone": "복제",
+    "Raw text": "원본 텍스트",
+    "Expires": "만료 기간",
+    "Burn after reading": "읽은 후 삭제",
+    "Open discussion": "댓글 허용",
+    "Password (recommended)": "비밀번호 (권장)",
+    "Discussion": "댓글",
+    "Toggle navigation": "네비게이션 토글",
     "%d seconds": [
     "%d seconds": [
-        "%d second (singular)",
-        "%d seconds (1st plural)",
-        "%d seconds (2nd plural)",
-        "%d seconds (3rd plural)",
-        "%d seconds (4th plural)",
-        "%d seconds (5th plural)"
+        "%d",
+        "%d",
+        "%d",
+        "%d",
+        "%d",
+        "%d"
     ],
     ],
     "%d minutes": [
     "%d minutes": [
-        "%d minute (singular)",
-        "%d minutes (1st plural)",
-        "%d minutes (2nd plural)",
-        "%d minutes (3rd plural)",
-        "%d minutes (4th plural)",
-        "%d minutes (5th plural)"
+        "%d",
+        "%d",
+        "%d",
+        "%d",
+        "%d",
+        "%d"
     ],
     ],
     "%d hours": [
     "%d hours": [
-        "%d hour (singular)",
-        "%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시간"
     ],
     ],
     "%d days": [
     "%d days": [
-        "%d day (singular)",
-        "%d days (1st plural)",
-        "%d days (2nd plural)",
-        "%d days (3rd plural)",
-        "%d days (4th plural)",
-        "%d days (5th plural)"
+        "%d",
+        "%d",
+        "%d",
+        "%d",
+        "%d",
+        "%d"
     ],
     ],
     "%d weeks": [
     "%d weeks": [
-        "%d week (singular)",
-        "%d weeks (1st plural)",
-        "%d weeks (2nd plural)",
-        "%d weeks (3rd plural)",
-        "%d weeks (4th plural)",
-        "%d weeks (5th plural)"
+        "%d",
+        "%d",
+        "%d",
+        "%d",
+        "%d",
+        "%d"
     ],
     ],
     "%d months": [
     "%d months": [
-        "%d month (singular)",
-        "%d months (1st plural)",
-        "%d months (2nd plural)",
-        "%d months (3rd plural)",
-        "%d months (4th plural)",
-        "%d months (5th plural)"
+        "%d개월",
+        "%d개월",
+        "%d개월",
+        "%d개월",
+        "%d개월",
+        "%d개월"
     ],
     ],
     "%d years": [
     "%d years": [
-        "%d year (singular)",
-        "%d years (1st plural)",
-        "%d years (2nd plural)",
-        "%d years (3rd plural)",
-        "%d years (4th plural)",
-        "%d years (5th plural)"
+        "%d",
+        "%d",
+        "%d",
+        "%d",
+        "%d",
+        "%d"
     ],
     ],
-    "Never": "Never",
-    "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.": "Note: This is a test service: Data may be deleted anytime. Kittens will die if you abuse this service.",
+    "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 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초 후에 만료됩니다.",
+        "이 문서는 %d초 후에 만료됩니다."
     ],
     ],
     "This document will expire in %d minutes.": [
     "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분 후에 만료됩니다.",
+        "이 문서는 %d분 후에 만료됩니다."
     ],
     ],
     "This document will expire in %d hours.": [
     "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시간 후에 만료됩니다.",
+        "이 문서는 %d시간 후에 만료됩니다."
     ],
     ],
     "This document will expire in %d days.": [
     "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일 후에 만료됩니다.",
+        "이 문서는 %d일 후에 만료됩니다."
     ],
     ],
     "This document will expire in %d months.": [
     "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개월 후에 만료됩니다.",
+        "이 문서는 %d개월 후에 만료됩니다."
     ],
     ],
-    "Please enter the password for this document:": "Please enter the password for this document:",
-    "Could not decrypt data (Wrong key?)": "Could not decrypt data (Wrong key?)",
-    "Could not delete the document, it was not stored in burn after reading mode.": "Could not delete the document, it was not stored in burn after reading mode.",
-    "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.",
-    "Could not decrypt comment; Wrong key?": "Could not decrypt comment; Wrong key?",
-    "Reply": "Reply",
-    "Anonymous": "Anonymous",
-    "Avatar generated from IP address": "Avatar generated from IP address",
-    "Add comment": "Add comment",
-    "Optional nickname…": "Optional nickname…",
-    "Post comment": "Post comment",
-    "Sending comment…": "Sending comment…",
-    "Comment posted.": "Comment posted.",
-    "Could not refresh display: %s": "Could not refresh display: %s",
-    "unknown status": "unknown status",
-    "server error or not responding": "server error or not responding",
-    "Could not post comment: %s": "Could not post comment: %s",
-    "Sending document…": "Sending document…",
-    "Your document is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit <kbd>%s</kbd>+<kbd>c</kbd> to copy)</span>": "Your document is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit <kbd>%s</kbd>+<kbd>c</kbd> to copy)</span>",
-    "Delete data": "Delete data",
-    "Could not create document: %s": "Could not create document: %s",
-    "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)",
+    "Please enter the password for this document:": "이 문서의 비밀번호를 입력해 주세요:",
+    "Could not decrypt data (Wrong key?)": "데이터를 복호화할 수 없음 (잘못된 키인지 확인해 주세요.)",
+    "Could not delete the document, it was not stored in burn after reading mode.": "문서를 삭제할 수 없습니다. '읽은 후 삭제' 모드로 저장되지 않은 문서입니다.",
+    "FOR YOUR EYES ONLY. Don't close this window, this message can't be displayed again.": "본인만 확인 가능한 메시지입니다. 이 창을 닫지 마세요. 이 메시지는 다시 표시되지 않습니다.",
+    "Could not decrypt comment; Wrong key?": "댓글을 복호화할 수 없습니다. 잘못된 키인지 확인해 주세요.",
+    "Reply": "답글",
+    "Anonymous": "익명",
+    "Avatar generated from IP address": "IP 주소로 생성된 아바타",
+    "Add comment": "댓글 추가",
+    "Optional nickname…": "닉네임 (선택 사항)…",
+    "Post comment": "댓글 등록",
+    "Sending comment…": "댓글 전송 중…",
+    "Comment posted.": "댓글이 등록되었습니다.",
+    "Could not refresh display: %s": "화면을 새로고침할 수 없음: %s",
+    "unknown status": "알 수 없는 상태",
+    "server error or not responding": "서버 오류가 발생했거나 응답 없음",
+    "Could not post comment: %s": "댓글을 등록할 수 없음: %s",
+    "Sending document…": "문서 전송 중…",
+    "Your document is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit <kbd>%s</kbd>+<kbd>c</kbd> to copy)</span>": "문서 주소: <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(복사하려면 <kbd>%s</kbd>+<kbd>c</kbd> 키를 누르세요)</span>",
+    "Delete data": "데이터 삭제",
+    "Could not create document: %s": "문서를 생성할 수 없음: %s",
+    "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "문서를 복호화할 수 없음: URL에 복호화 키가 없습니다 (URL의 일부를 누락시키는 리다이렉터나 URL 단축 서비스를 사용하셨나요?)",
     "B": "B",
     "B": "B",
     "kB": "kB",
     "kB": "kB",
     "MB": "MB",
     "MB": "MB",
@@ -164,75 +164,75 @@
     "EB": "EB",
     "EB": "EB",
     "ZB": "ZB",
     "ZB": "ZB",
     "YB": "YB",
     "YB": "YB",
-    "Format": "Format",
-    "Plain Text": "Plain Text",
-    "Source Code": "Source Code",
-    "Markdown": "Markdown",
-    "Download attachment": "Download attachment",
-    "Cloned: '%s'": "Cloned: '%s'",
-    "The cloned file '%s' was attached to this document.": "The cloned file '%s' was attached to this document.",
-    "Attach a file": "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.",
-    "Invalid attachment.": "Invalid attachment.",
-    "Options": "Options",
-    "Shorten URL": "Shorten URL",
-    "Editor": "Editor",
-    "Preview": "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.",
-    "Decrypt": "Decrypt",
-    "Enter password": "Enter password",
-    "Loading…": "Loading…",
-    "Decrypting document…": "Decrypting document…",
-    "Preparing new document…": "Preparing new document…",
-    "In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.": "In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.",
-    "+++ no document text +++": "+++ no document text +++",
-    "Could not get document data: %s": "Could not get document data: %s",
-    "QR code": "QR code",
-    "This website is using an insecure HTTP connection! Please use it only for testing.": "This website is using an insecure HTTP connection! Please use it only for testing.",
-    "For more information <a href=\"%s\">see this FAQ entry</a>.": "For more information <a href=\"%s\">see this FAQ entry</a>.",
-    "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.",
-    "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.",
-    "waiting on user to provide a password": "waiting on user to provide a password",
-    "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.",
-    "Retry": "Retry",
-    "Showing raw text…": "Showing raw text…",
-    "Notice:": "Notice:",
-    "This link will expire after %s.": "This link will expire after %s.",
-    "This link can only be accessed once, do not use back or refresh button in your browser.": "This link can only be accessed once, do not use back or refresh button in your browser.",
-    "Link:": "Link:",
-    "Recipient may become aware of your timezone, convert time to UTC?": "Recipient may become aware of your timezone, convert time to UTC?",
-    "Use Current Timezone": "Use Current Timezone",
-    "Convert To UTC": "Convert To UTC",
-    "Close": "Close",
-    "Encrypted note on %s": "Encrypted note on %s",
-    "Visit this link to see the note. Giving the URL to anyone allows them to access the note, too.": "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.",
-    "URL shortener is enabled by default.": "URL shortener is enabled by default.",
-    "Save document": "Save document",
-    "Your IP is not authorized to create documents.": "Your IP is not authorized to create documents.",
-    "Trying to shorten a URL that isn't pointing at our instance.": "Trying to shorten a URL that isn't pointing at our instance.",
-    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.",
-    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.",
-    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.",
-    "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 document, due to missing WebAssembly support.": "Error compressing document, due to missing WebAssembly support.",
-    "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.",
-    "Start over": "Start over",
-    "Document copied to clipboard": "Document copied to clipboard",
-    "To copy document press on the copy button or use the clipboard shortcut <kbd>%s</kbd>+<kbd>c</kbd>": "To copy document press on the copy button or use the clipboard shortcut <kbd>%s</kbd>+<kbd>c</kbd>",
-    "Copy link": "Copy link",
-    "Link copied to clipboard": "Link copied to clipboard",
-    "Document text": "Document 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)",
-    "Show password": "Show password",
-    "Hide password": "Hide password",
-    "Theme": "Theme",
-    "Copy": "Copy",
+    "Format": "형식",
+    "Plain Text": "일반 텍스트",
+    "Source Code": "소스 코드",
+    "Markdown": "마크다운",
+    "Download attachment": "첨부 파일 다운로드",
+    "Cloned: '%s'": "복제됨: '%s'",
+    "The cloned file '%s' was attached to this document.": "복제된 파일 '%s'이(가) 이 문서에 첨부되었습니다.",
+    "Attach a file": "파일 첨부",
+    "alternatively drag & drop a file or paste an image from the clipboard": "또는 파일을 끌어다 놓거나 클립보드에서 이미지를 붙여넣으세요",
+    "File too large, to display a preview. Please download the attachment.": "파일이 너무 커서 미리 보기를 표시할 수 없습니다. 첨부 파일을 다운로드해 주세요.",
+    "Remove attachment": "첨부 파일 삭제",
+    "Your browser does not support uploading encrypted files. Please use a newer browser.": "브라우저가 암호화된 파일 업로드를 지원하지 않습니다. 최신 브라우저를 사용해 주세요.",
+    "Invalid attachment.": "유효하지 않은 첨부 파일입니다.",
+    "Options": "옵션",
+    "Shorten URL": "URL 단축",
+    "Editor": "편집기",
+    "Preview": "미리 보기",
+    "%s requires the PATH to end in a \"%s\". Please update the PATH in your index.php.": "%s을(를) 실행하려면 PATH가 \"%s\"(으)로 끝나야 합니다. index.php 파일의 PATH 설정을 업데이트해 주세요.",
+    "Decrypt": "복호화",
+    "Enter password": "비밀번호 입력",
+    "Loading…": "로딩 중…",
+    "Decrypting document…": "문서 복호화 중…",
+    "Preparing new document…": "새 문서 준비 중…",
+    "In case this message never disappears please have a look at <a href=\"%s\">this FAQ for information to troubleshoot</a>.": "이 메시지가 사라지지 않는 경우, 문제 해결을 위해 <a href=\"%s\">이 FAQ 항목</a>을 확인해 주세요.",
+    "+++ no document text +++": "+++ 문서 내용 없음 +++",
+    "Could not get document data: %s": "문서 데이터를 가져올 수 없음: %s",
+    "QR code": "QR 코드",
+    "This website is using an insecure HTTP connection! Please use it only for testing.": "이 웹사이트는 안전하지 않은 HTTP 연결을 사용하고 있습니다! 테스트 용도로만 사용해 주세요.",
+    "For more information <a href=\"%s\">see this FAQ entry</a>.": "자세한 정보는 <a href=\"%s\">이 FAQ 항목</a>을 참조하세요.",
+    "Your browser may require an HTTPS connection to support the WebCrypto API. Try <a href=\"%s\">switching to HTTPS</a>.": "WebCrypto API를 지원하려면 브라우저에서 HTTPS 연결이 필요할 수 있습니다. <a href=\"%s\">HTTPS로 전환</a>해 보세요.",
+    "Your browser doesn't support WebAssembly, used for zlib compression. You can create uncompressed documents, but can't read compressed ones.": "브라우저가 zlib 압축에 사용되는 WebAssembly를 지원하지 않습니다. 압축되지 않은 문서는 생성할 수 있으나, 압축된 문서는 읽을 수 없습니다.",
+    "waiting on user to provide a password": "사용자가 비밀번호를 입력하기를 기다리는 중",
+    "Could not decrypt data. Did you enter a wrong password? Retry with the button at the top.": "데이터를 복호화할 수 없습니다. 비밀번호를 잘못 입력하셨나요? 상단의 버튼을 눌러 다시 시도해 주세요.",
+    "Retry": "다시 시도",
+    "Showing raw text…": "원본 텍스트 표시 중…",
+    "Notice:": "알림:",
+    "This link will expire after %s.": "이 링크는 %s 후에 만료됩니다.",
+    "This link can only be accessed once, do not use back or refresh button in your browser.": "이 링크는 한 번만 접속할 수 있으므로, 브라우저의 뒤로 가기나 새로고침 버튼을 사용하지 마세요.",
+    "Link:": "링크:",
+    "Recipient may become aware of your timezone, convert time to UTC?": "수신자가 귀하의 시간대를 알게 될 수 있습니다. 시간을 UTC로 변환하시겠습니까?",
+    "Use Current Timezone": "현재 시간대 사용",
+    "Convert To UTC": "UTC로 변환",
+    "Close": "닫기",
+    "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을 공유하면 그 사람도 메모에 접근할 수 있게 됩니다.",
+    "URL shortener may expose your decrypt key in URL.": "URL 단축 서비스를 사용하면 URL에 포함된 복호화 키가 노출될 수 있습니다.",
+    "URL shortener is enabled by default.": "URL 단축 기능이 기본으로 활성화되어 있습니다.",
+    "Save document": "문서 저장",
+    "Your IP is not authorized to create documents.": "귀하의 IP는 문서 생성 권한이 없습니다.",
+    "Trying to shorten a URL that isn't pointing at our instance.": "현재 인스턴스를 가리키지 않는 URL을 단축하려고 시도했습니다.",
+    "Proxy error: Proxy URL is empty. This can be a configuration issue, like wrong or missing config keys.": "프록시 오류: 프록시 URL이 비어 있습니다. 잘못된 설정 키이거나 누락된 설정 때문일 수 있습니다.",
+    "Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.": "프록시 오류: 프록시 응답을 구문 분석하는 중 오류가 발생했습니다. 잘못된 설정 키이거나 누락된 설정 때문일 수 있습니다.",
+    "Proxy error: Bad response. This can be a configuration issue, like wrong or missing config keys or a temporary outage.": "프록시 오류: 잘못된 응답입니다. 키 누락이나 잘못된 값 입력과 같은 설정 오류이거나 일시적인 서버 장애일 수 있습니다.",
+    "This secret message can only be displayed once. Would you like to see it now?": "이 비밀 메시지는 단 한 번만 표시됩니다. 지금 확인하시겠습니까?",
+    "Yes, see it": "네, 확인하겠습니다",
+    "Dark Mode": "다크 모드",
+    "Error compressing document, due to missing WebAssembly support.": "WebAssembly 지원이 누락되어 문서를 압축하는 동안 오류가 발생했습니다.",
+    "Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.": "문서 압축 해제 오류: 브라우저가 WebAssembly를 지원하지 않습니다. 이 문서를 보려면 다른 브라우저를 사용해 주세요.",
+    "Start over": "처음부터 다시 시작",
+    "Document copied to clipboard": "문서가 클립보드에 복사됨",
+    "To copy document press on the copy button or use the clipboard shortcut <kbd>%s</kbd>+<kbd>c</kbd>": "문서를 복사하려면 복사 버튼을 누르거나 클립보드 단축키 <kbd>%s</kbd>+<kbd>c</kbd>를 사용하세요",
+    "Copy link": "링크 복사",
+    "Link copied to clipboard": "링크가 클립보드에 복사됨",
+    "Document 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> 키를 누르세요)",
+    "Show password": "비밀번호 표시",
+    "Hide password": "비밀번호 숨기기",
+    "Theme": "테마",
+    "Copy": "복사",
     "Cmd": "Cmd",
     "Cmd": "Cmd",
     "Ctrl": "Ctrl"
     "Ctrl": "Ctrl"
 }
 }

+ 3 - 3
i18n/sl.json

@@ -105,7 +105,7 @@
         "Ta dokument bo potekel čez %d minuto.",
         "Ta dokument bo potekel čez %d minuto.",
         "Ta dokument bo potekel čez %d minuti.",
         "Ta dokument bo potekel čez %d minuti.",
         "Ta dokument bo potekel čez %d minute.",
         "Ta dokument bo potekel čez %d minute.",
-        "Ta dokument bo potekel čez %d minut.",
+        "Ta dokument bo potekel čez %d minute.",
         "Ta dokument bo potekel čez %d minut.",
         "Ta dokument bo potekel čez %d minut.",
         "Ta dokument bo potekel čez %d minut."
         "Ta dokument bo potekel čez %d minut."
     ],
     ],
@@ -113,13 +113,13 @@
         "Ta dokument bo potekel čez %d uro.",
         "Ta dokument bo potekel čez %d uro.",
         "Ta dokument bo potekel čez %d uri.",
         "Ta dokument bo potekel čez %d uri.",
         "Ta dokument bo potekel čez %d ure.",
         "Ta dokument bo potekel čez %d ure.",
-        "Ta dokument bo potekel čez %d ur.",
+        "Ta dokument bo potekel čez %d ure.",
         "Ta dokument bo potekel čez %d ur.",
         "Ta dokument bo potekel čez %d ur.",
         "Ta dokument bo potekel čez %d ur."
         "Ta dokument bo potekel čez %d ur."
     ],
     ],
     "This document will expire in %d days.": [
     "This document will expire in %d days.": [
         "Ta dokument bo potekel čez %d dan.",
         "Ta dokument bo potekel čez %d dan.",
-        "Ta dokument bo potekel čez %d dni.",
+        "Ta dokument bo potekel čez %d dneva.",
         "Ta dokument bo potekel čez %d dni.",
         "Ta dokument bo potekel čez %d dni.",
         "Ta dokument bo potekel čez %d dni.",
         "Ta dokument bo potekel čez %d dni.",
         "Ta dokument bo potekel čez %d dni.",
         "Ta dokument bo potekel čez %d dni.",

+ 2 - 2
i18n/sv.json

@@ -151,7 +151,7 @@
     "server error or not responding": "serverfel eller inget svar",
     "server error or not responding": "serverfel eller inget svar",
     "Could not post comment: %s": "Kunde inte publicera kommentar: %s",
     "Could not post comment: %s": "Kunde inte publicera kommentar: %s",
     "Sending document…": "Skickar dokument…",
     "Sending document…": "Skickar dokument…",
-    "Your document is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit <kbd>%s</kbd>+<kbd>c</kbd> to copy)</span>": "Ditt dokument är <a id=\\\"pasteurl\\\" href=\\\"%s\\\">%s</a> <span id=\\\"copyhint\\\">(Tryck <kbd>%s</kbd>+<kbd>c</kbd> för att kopiera)</span>",
+    "Your document is <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Hit <kbd>%s</kbd>+<kbd>c</kbd> to copy)</span>": "Ditt dokument är <a id=\"pasteurl\" href=\"%s\">%s</a> <span id=\"copyhint\">(Tryck <kbd>%s</kbd>+<kbd>c</kbd> för att kopiera)</span>",
     "Delete data": "Radera data",
     "Delete data": "Radera data",
     "Could not create document: %s": "Kunde inte skapa dokument: %s",
     "Could not create document: %s": "Kunde inte skapa dokument: %s",
     "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Kan inte dekryptera dokument: Dekrypteringsnyckel saknas i URL:en (använde du en omdirigerare eller URL-förkortare som tar bort delar av URL:en?)",
     "Cannot decrypt document: Decryption key missing in URL (Did you use a redirector or an URL shortener which strips part of the URL?)": "Kan inte dekryptera dokument: Dekrypteringsnyckel saknas i URL:en (använde du en omdirigerare eller URL-förkortare som tar bort delar av URL:en?)",
@@ -232,7 +232,7 @@
     "Show password": "Visa lösenord",
     "Show password": "Visa lösenord",
     "Hide password": "Dölj lösenord",
     "Hide password": "Dölj lösenord",
     "Theme": "Tema",
     "Theme": "Tema",
-    "Copy": "Copy",
+    "Copy": "Kopiera",
     "Cmd": "Cmd",
     "Cmd": "Cmd",
     "Ctrl": "Ctrl"
     "Ctrl": "Ctrl"
 }
 }

+ 1 - 1
js/common.js

@@ -31,7 +31,7 @@ require('./prettify');
 global.prettyPrint = window.PR ? window.PR.prettyPrint : function() {};
 global.prettyPrint = window.PR ? window.PR.prettyPrint : function() {};
 global.prettyPrintOne = window.PR ? window.PR.prettyPrintOne : function() {};
 global.prettyPrintOne = window.PR ? window.PR.prettyPrintOne : function() {};
 global.showdown = require('./showdown-2.1.0');
 global.showdown = require('./showdown-2.1.0');
-global.DOMPurify = require('./purify-3.4.1');
+global.DOMPurify = require('./purify-3.4.12');
 global.baseX = require('./base-x-5.0.1').baseX;
 global.baseX = require('./base-x-5.0.1').baseX;
 global.Legacy = require('./legacy').Legacy;
 global.Legacy = require('./legacy').Legacy;
 require('./privatebin');
 require('./privatebin');

+ 2 - 2
js/eslint.config.js

@@ -1,5 +1,5 @@
 const globals = require('globals');
 const globals = require('globals');
-const { globalIgnores } = require('eslint/config')
+const { globalIgnores } = require('eslint/config');
 
 
 module.exports = [globalIgnores(["./*.*js", "!./privatebin.js"]), {
 module.exports = [globalIgnores(["./*.*js", "!./privatebin.js"]), {
     languageOptions: {
     languageOptions: {
@@ -111,7 +111,7 @@ module.exports = [globalIgnores(["./*.*js", "!./privatebin.js"]), {
         yoda: 0,
         yoda: 0,
 
 
         // Strict
         // Strict
-        strict: 0,
+        strict: 2,
 
 
         // Variables
         // Variables
         "init-declarations": 0,
         "init-declarations": 0,

+ 281 - 0
js/package-lock.json

@@ -14,6 +14,7 @@
         "fast-check": "^4.7.0",
         "fast-check": "^4.7.0",
         "jsdom": "^26.1.0",
         "jsdom": "^26.1.0",
         "jsdom-global": "^3.0.2",
         "jsdom-global": "^3.0.2",
+        "jshint": "^2.13.6",
         "jsverify": "^0.8.3",
         "jsverify": "^0.8.3",
         "mime-types": "^3.0.2",
         "mime-types": "^3.0.2",
         "mocha": "^11.7.5",
         "mocha": "^11.7.5",
@@ -1122,6 +1123,42 @@
         "node": ">=6"
         "node": ">=6"
       }
       }
     },
     },
+    "node_modules/cli": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz",
+      "integrity": "sha512-41U72MB56TfUMGndAKK8vJ78eooOD4Z5NOL4xEfjc0c23s+6EYKXlXsmACBVclLP1yOfWCgEganVzddVrSNoTg==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "exit": "0.1.2",
+        "glob": "^7.1.1"
+      },
+      "engines": {
+        "node": ">=0.2.5"
+      }
+    },
+    "node_modules/cli/node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
     "node_modules/cliui": {
     "node_modules/cliui": {
       "version": "8.0.1",
       "version": "8.0.1",
       "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
       "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
@@ -1224,12 +1261,28 @@
       "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
       "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
       "dev": true
       "dev": true
     },
     },
+    "node_modules/console-browserify": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
+      "integrity": "sha512-duS7VP5pvfsNLDvL1O4VOEbw37AI3A4ZUQYemvDlnpGrNu9tprR7BYWpDYwC0Xia0Zxz5ZupdiIrUp0GH1aXfg==",
+      "dev": true,
+      "dependencies": {
+        "date-now": "^0.1.4"
+      }
+    },
     "node_modules/convert-source-map": {
     "node_modules/convert-source-map": {
       "version": "1.9.0",
       "version": "1.9.0",
       "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
       "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
       "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
       "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
       "dev": true
       "dev": true
     },
     },
+    "node_modules/core-util-is": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
+      "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/cross-spawn": {
     "node_modules/cross-spawn": {
       "version": "7.0.6",
       "version": "7.0.6",
       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
       "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@@ -1270,6 +1323,12 @@
         "node": ">=18"
         "node": ">=18"
       }
       }
     },
     },
+    "node_modules/date-now": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
+      "integrity": "sha512-AsElvov3LoNB7tf5k37H2jYSB+ZZPMT5sG2QjJCcdlV5chIv6htBUBUui2IKRjgtKAKtCBN7Zbwa+MtwLjSeNw==",
+      "dev": true
+    },
     "node_modules/debug": {
     "node_modules/debug": {
       "version": "4.4.3",
       "version": "4.4.3",
       "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
       "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
@@ -1332,6 +1391,66 @@
         "node": ">=0.3.1"
         "node": ">=0.3.1"
       }
       }
     },
     },
+    "node_modules/dom-serializer": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
+      "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "domelementtype": "^2.0.1",
+        "entities": "^2.0.0"
+      }
+    },
+    "node_modules/dom-serializer/node_modules/domelementtype": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+      "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/fb55"
+        }
+      ],
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/dom-serializer/node_modules/entities": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
+      "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
+      "dev": true,
+      "license": "BSD-2-Clause",
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/domelementtype": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
+      "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
+      "dev": true,
+      "license": "BSD-2-Clause"
+    },
+    "node_modules/domhandler": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz",
+      "integrity": "sha512-q9bUwjfp7Eif8jWxxxPSykdRZAb6GkguBGSgvvCrhI9wB71W2K/Kvv4E61CF/mcCfnVJDeDWx/Vb/uAqbDj6UQ==",
+      "dev": true,
+      "dependencies": {
+        "domelementtype": "1"
+      }
+    },
+    "node_modules/domutils": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
+      "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==",
+      "dev": true,
+      "dependencies": {
+        "dom-serializer": "0",
+        "domelementtype": "1"
+      }
+    },
     "node_modules/eastasianwidth": {
     "node_modules/eastasianwidth": {
       "version": "0.2.0",
       "version": "0.2.0",
       "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
       "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
@@ -1548,6 +1667,15 @@
         "node": ">=0.10.0"
         "node": ">=0.10.0"
       }
       }
     },
     },
+    "node_modules/exit": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz",
+      "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==",
+      "dev": true,
+      "engines": {
+        "node": ">= 0.8.0"
+      }
+    },
     "node_modules/fast-check": {
     "node_modules/fast-check": {
       "version": "4.7.0",
       "version": "4.7.0",
       "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.7.0.tgz",
       "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-4.7.0.tgz",
@@ -1698,6 +1826,13 @@
         }
         }
       ]
       ]
     },
     },
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+      "dev": true,
+      "license": "ISC"
+    },
     "node_modules/gensync": {
     "node_modules/gensync": {
       "version": "1.0.0-beta.2",
       "version": "1.0.0-beta.2",
       "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
       "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@@ -1852,6 +1987,27 @@
       "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
       "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==",
       "dev": true
       "dev": true
     },
     },
+    "node_modules/htmlparser2": {
+      "version": "3.8.3",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz",
+      "integrity": "sha512-hBxEg3CYXe+rPIua8ETe7tmG3XDn9B0edOE/e9wH2nLczxzgdu0m0aNHY+5wFZiviLWLdANPJTssa92dMcXQ5Q==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "domelementtype": "1",
+        "domhandler": "2.3",
+        "domutils": "1.5",
+        "entities": "1.0",
+        "readable-stream": "1.1"
+      }
+    },
+    "node_modules/htmlparser2/node_modules/entities": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz",
+      "integrity": "sha512-LbLqfXgJMmy81t+7c14mnulFHJ170cM6E+0vMXR9k/ZiZwgX8i5pNgjTCX3SO4VeUsFLV+8InixoretwU+MjBQ==",
+      "dev": true,
+      "license": "BSD-like"
+    },
     "node_modules/http-proxy-agent": {
     "node_modules/http-proxy-agent": {
       "version": "7.0.2",
       "version": "7.0.2",
       "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
       "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
@@ -1934,6 +2090,25 @@
         "node": ">=8"
         "node": ">=8"
       }
       }
     },
     },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "dev": true,
+      "license": "ISC"
+    },
     "node_modules/is-extglob": {
     "node_modules/is-extglob": {
       "version": "2.1.1",
       "version": "2.1.1",
       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
       "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@@ -2028,6 +2203,13 @@
         "node": ">=0.10.0"
         "node": ">=0.10.0"
       }
       }
     },
     },
+    "node_modules/isarray": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+      "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/isexe": {
     "node_modules/isexe": {
       "version": "2.0.0",
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
       "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
@@ -2237,6 +2419,51 @@
         "node": ">=6"
         "node": ">=6"
       }
       }
     },
     },
+    "node_modules/jshint": {
+      "version": "2.13.6",
+      "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.13.6.tgz",
+      "integrity": "sha512-IVdB4G0NTTeQZrBoM8C5JFVLjV2KtZ9APgybDA1MK73xb09qFs0jCXyQLnCOp1cSZZZbvhq/6mfXHUTaDkffuQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "cli": "~1.0.0",
+        "console-browserify": "1.1.x",
+        "exit": "0.1.x",
+        "htmlparser2": "3.8.x",
+        "lodash": "~4.17.21",
+        "minimatch": "~3.0.2",
+        "strip-json-comments": "1.0.x"
+      },
+      "bin": {
+        "jshint": "bin/jshint"
+      }
+    },
+    "node_modules/jshint/node_modules/minimatch": {
+      "version": "3.0.8",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz",
+      "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/jshint/node_modules/strip-json-comments": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz",
+      "integrity": "sha512-AOPG8EBc5wAikaG1/7uFCNFJwnKOuQwFTpYBdTW6OvWHeZBQBrAA/amefHGrEiOnCPcLFZK6FUPtWVKpQVIRgg==",
+      "dev": true,
+      "license": "MIT",
+      "bin": {
+        "strip-json-comments": "cli.js"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
     "node_modules/json-buffer": {
     "node_modules/json-buffer": {
       "version": "3.0.1",
       "version": "3.0.1",
       "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
       "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
@@ -2328,6 +2555,13 @@
         "url": "https://github.com/sponsors/sindresorhus"
         "url": "https://github.com/sponsors/sindresorhus"
       }
       }
     },
     },
+    "node_modules/lodash": {
+      "version": "4.17.23",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz",
+      "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/lodash.flattendeep": {
     "node_modules/lodash.flattendeep": {
       "version": "4.4.0",
       "version": "4.4.0",
       "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
       "resolved": "https://registry.npmjs.org/lodash.flattendeep/-/lodash.flattendeep-4.4.0.tgz",
@@ -2843,6 +3077,16 @@
         "node": ">=6"
         "node": ">=6"
       }
       }
     },
     },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dev": true,
+      "license": "ISC",
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
     "node_modules/optionator": {
     "node_modules/optionator": {
       "version": "0.9.4",
       "version": "0.9.4",
       "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
       "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
@@ -2966,6 +3210,16 @@
         "node": ">=8"
         "node": ">=8"
       }
       }
     },
     },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
     "node_modules/path-key": {
     "node_modules/path-key": {
       "version": "3.1.1",
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
       "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@@ -3144,6 +3398,19 @@
         "node": ">=0.10.0"
         "node": ">=0.10.0"
       }
       }
     },
     },
+    "node_modules/readable-stream": {
+      "version": "1.1.14",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+      "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "core-util-is": "~1.0.0",
+        "inherits": "~2.0.1",
+        "isarray": "0.0.1",
+        "string_decoder": "~0.10.x"
+      }
+    },
     "node_modules/readdirp": {
     "node_modules/readdirp": {
       "version": "4.1.2",
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
       "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
@@ -3456,6 +3723,13 @@
       "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
       "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
       "dev": true
       "dev": true
     },
     },
+    "node_modules/string_decoder": {
+      "version": "0.10.31",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+      "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==",
+      "dev": true,
+      "license": "MIT"
+    },
     "node_modules/string-width": {
     "node_modules/string-width": {
       "version": "5.1.2",
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
       "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
@@ -4015,6 +4289,13 @@
         "url": "https://github.com/chalk/ansi-styles?sponsor=1"
         "url": "https://github.com/chalk/ansi-styles?sponsor=1"
       }
       }
     },
     },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
+      "dev": true,
+      "license": "ISC"
+    },
     "node_modules/write-file-atomic": {
     "node_modules/write-file-atomic": {
       "version": "3.0.3",
       "version": "3.0.3",
       "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
       "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",

+ 1 - 0
js/package.json

@@ -12,6 +12,7 @@
     "fast-check": "^4.7.0",
     "fast-check": "^4.7.0",
     "jsdom": "^26.1.0",
     "jsdom": "^26.1.0",
     "jsdom-global": "^3.0.2",
     "jsdom-global": "^3.0.2",
+    "jshint": "^2.13.6",
     "jsverify": "^0.8.3",
     "jsverify": "^0.8.3",
     "mime-types": "^3.0.2",
     "mime-types": "^3.0.2",
     "mocha": "^11.7.5",
     "mocha": "^11.7.5",

+ 34 - 38
js/privatebin.js

@@ -1,3 +1,4 @@
+'use strict';
 /**
 /**
  * PrivateBin
  * PrivateBin
  *
  *
@@ -15,7 +16,6 @@
  * adds draghoverstart and draghoverend events to an element
  * adds draghoverstart and draghoverend events to an element
  */
  */
 function draghover(element) {
 function draghover(element) {
-    'use strict';
     let collection = new Set();
     let collection = new Set();
 
 
     element.addEventListener('dragenter', function (e) {
     element.addEventListener('dragenter', function (e) {
@@ -41,7 +41,6 @@ function draghover(element) {
 }
 }
 
 
 window.PrivateBin = (function () {
 window.PrivateBin = (function () {
-    'use strict';
 
 
     /**
     /**
      * zlib library interface
      * zlib library interface
@@ -205,7 +204,7 @@ window.PrivateBin = (function () {
          */
          */
         this.getCreated = function () {
         this.getCreated = function () {
             return this.meta.created || 0;
             return this.meta.created || 0;
-        }
+        };
 
 
         /**
         /**
          * gets the icon of the comment submitter
          * gets the icon of the comment submitter
@@ -1088,7 +1087,7 @@ window.PrivateBin = (function () {
             );
             );
             if (mode === 'zlib') {
             if (mode === 'zlib') {
                 if (typeof zlib === 'undefined') {
                 if (typeof zlib === 'undefined') {
-                    throw 'Error compressing document, due to missing WebAssembly support.'
+                    throw new Error('Error compressing document, due to missing WebAssembly support.');
                 }
                 }
                 return zlib.deflate(message).buffer;
                 return zlib.deflate(message).buffer;
             }
             }
@@ -1111,7 +1110,7 @@ window.PrivateBin = (function () {
         async function decompress(data, mode, zlib) {
         async function decompress(data, mode, zlib) {
             if (mode === 'zlib') {
             if (mode === 'zlib') {
                 if (typeof zlib === 'undefined') {
                 if (typeof zlib === 'undefined') {
-                    throw 'Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.'
+                    throw new Error('Error decompressing document, your browser does not support WebAssembly. Please use another browser to view this document.');
                 }
                 }
                 data = zlib.inflate(
                 data = zlib.inflate(
                     new Uint8Array(data)
                     new Uint8Array(data)
@@ -1343,7 +1342,7 @@ window.PrivateBin = (function () {
             return base58.encode(
             return base58.encode(
                 stringToArraybuffer(input)
                 stringToArraybuffer(input)
             );
             );
-        }
+        };
 
 
         /**
         /**
          * base58 decode a DOMString (UTF-16)
          * base58 decode a DOMString (UTF-16)
@@ -1357,7 +1356,7 @@ window.PrivateBin = (function () {
             return arraybufferToString(
             return arraybufferToString(
                 base58.decode(input)
                 base58.decode(input)
             );
             );
-        }
+        };
 
 
         return me;
         return me;
     })();
     })();
@@ -1480,7 +1479,7 @@ window.PrivateBin = (function () {
             }
             }
 
 
             return id;
             return id;
-        }
+        };
 
 
         /**
         /**
          * returns true, when the URL has a delete token and the current call was used for deleting a document.
          * returns true, when the URL has a delete token and the current call was used for deleting a document.
@@ -1491,7 +1490,7 @@ window.PrivateBin = (function () {
          */
          */
         me.hasDeleteToken = function () {
         me.hasDeleteToken = function () {
             return window.location.search.indexOf('deletetoken') !== -1;
             return window.location.search.indexOf('deletetoken') !== -1;
-        }
+        };
 
 
         /**
         /**
          * return the deciphering key stored in anchor part of the URL
          * return the deciphering key stored in anchor part of the URL
@@ -2046,7 +2045,7 @@ window.PrivateBin = (function () {
                 // we do not remove the button, in case shortener fails
                 // we do not remove the button, in case shortener fails
                 sendToShortener();
                 sendToShortener();
             }
             }
-        }
+        };
 
 
         /**
         /**
          * extracts URLs from given string
          * extracts URLs from given string
@@ -2217,7 +2216,7 @@ window.PrivateBin = (function () {
             loadconfirmOpenNow.removeEventListener('click', PasteDecrypter.run);
             loadconfirmOpenNow.removeEventListener('click', PasteDecrypter.run);
             loadconfirmOpenNow.addEventListener('click', PasteDecrypter.run);
             loadconfirmOpenNow.addEventListener('click', PasteDecrypter.run);
 
 
-            const loadconfirmClose = loadconfirmmodal.querySelector('.close');
+            const loadconfirmClose = loadconfirmmodal.querySelector('.btn-close');
             loadconfirmClose.removeEventListener('click', Controller.newPaste);
             loadconfirmClose.removeEventListener('click', Controller.newPaste);
             loadconfirmClose.addEventListener('click', Controller.newPaste);
             loadconfirmClose.addEventListener('click', Controller.newPaste);
 
 
@@ -2805,7 +2804,7 @@ window.PrivateBin = (function () {
         /**
         /**
          * init status manager
          * init status manager
          *
          *
-         * preloads jQuery elements
+         * preloads DOM elements
          *
          *
          * @name   PasteViewer.init
          * @name   PasteViewer.init
          * @function
          * @function
@@ -2956,7 +2955,7 @@ window.PrivateBin = (function () {
                 mimeType.startsWith('audio/') ||
                 mimeType.startsWith('audio/') ||
                 mimeType.endsWith('/pdf') ||
                 mimeType.endsWith('/pdf') ||
                 mimeType === 'text/plain';
                 mimeType === 'text/plain';
-        }
+        };
 
 
         /**
         /**
          * Evaluates whether this is known a safe mime type.
          * Evaluates whether this is known a safe mime type.
@@ -2977,7 +2976,7 @@ window.PrivateBin = (function () {
                 mimeType.startsWith('audio/') ||
                 mimeType.startsWith('audio/') ||
                 mimeType.endsWith('/pdf') ||
                 mimeType.endsWith('/pdf') ||
                 mimeType === 'text/plain';
                 mimeType === 'text/plain';
-        }
+        };
 
 
         /**
         /**
          * displays the attachment and (if possible) the preview
          * displays the attachment and (if possible) the preview
@@ -3100,7 +3099,7 @@ window.PrivateBin = (function () {
          */
          */
         me.hasAttachmentPreview = function () {
         me.hasAttachmentPreview = function () {
             return attachmentPreview.children.length > 0;
             return attachmentPreview.children.length > 0;
-        }
+        };
 
 
         /**
         /**
          * checks if there is an attachment displayed
          * checks if there is an attachment displayed
@@ -3164,7 +3163,7 @@ window.PrivateBin = (function () {
 
 
             // extract mimeType
             // extract mimeType
             return attachmentData.substring(5, mimeTypeEnd);
             return attachmentData.substring(5, mimeTypeEnd);
-        }
+        };
 
 
         /**
         /**
          * moves the attachment link to another element
          * moves the attachment link to another element
@@ -3441,7 +3440,7 @@ window.PrivateBin = (function () {
                 addDragDropHandler();
                 addDragDropHandler();
                 addClipboardEventHandler();
                 addClipboardEventHandler();
             }
             }
-        }
+        };
 
 
         return me;
         return me;
     })();
     })();
@@ -4351,7 +4350,7 @@ window.PrivateBin = (function () {
          */
          */
         me.showRetryButton = function () {
         me.showRetryButton = function () {
             retryButton.classList.remove('hidden');
             retryButton.classList.remove('hidden');
-        }
+        };
 
 
         /**
         /**
          * hides the "retry" button
          * hides the "retry" button
@@ -4361,7 +4360,7 @@ window.PrivateBin = (function () {
          */
          */
         me.hideRetryButton = function () {
         me.hideRetryButton = function () {
             retryButton.classList.add('hidden');
             retryButton.classList.add('hidden');
-        }
+        };
 
 
         /**
         /**
          * show the "email" button
          * show the "email" button
@@ -4388,7 +4387,7 @@ window.PrivateBin = (function () {
                 console.error(error);
                 console.error(error);
                 Alert.showError('Cannot calculate expiration date.');
                 Alert.showError('Cannot calculate expiration date.');
             }
             }
-        }
+        };
 
 
         /**
         /**
          * hide the "email" button
          * hide the "email" button
@@ -4403,7 +4402,7 @@ window.PrivateBin = (function () {
 
 
             emailLink.classList.add('hidden');
             emailLink.classList.add('hidden');
             emailLink.removeEventListener('click', sendEmail);
             emailLink.removeEventListener('click', sendEmail);
-        }
+        };
 
 
         /**
         /**
          * only hides the clone button
          * only hides the clone button
@@ -4443,7 +4442,7 @@ window.PrivateBin = (function () {
          */
          */
         me.hideQrCodeButton = function () {
         me.hideQrCodeButton = function () {
             qrCodeLink.classList.add('hidden');
             qrCodeLink.classList.add('hidden');
-        }
+        };
 
 
         /**
         /**
          * hide irrelevant buttons when viewing burn after reading document
          * hide irrelevant buttons when viewing burn after reading document
@@ -4455,7 +4454,7 @@ window.PrivateBin = (function () {
             me.hideCloneButton();
             me.hideCloneButton();
             me.hideQrCodeButton();
             me.hideQrCodeButton();
             me.hideEmailButton();
             me.hideEmailButton();
-        }
+        };
 
 
         /**
         /**
          * hides the file selector in attachment
          * hides the file selector in attachment
@@ -4640,7 +4639,7 @@ window.PrivateBin = (function () {
          */
          */
         me.setRetryCallback = function (callback) {
         me.setRetryCallback = function (callback) {
             retryButtonCallback = callback;
             retryButtonCallback = callback;
-        }
+        };
 
 
         /**
         /**
          * Highlight file upload
          * Highlight file upload
@@ -5336,17 +5335,15 @@ window.PrivateBin = (function () {
                             'copy'
                             'copy'
                         );
                         );
                         try {
                         try {
-                            const blobData = await $.ajax({
-                                type: 'GET',
-                                url: attachment,
-                                processData: false,
-                                timeout: 10000,
-                                dataType: 'binary',
-                                xhrFields: {
-                                    withCredentials: false,
-                                    responseType: 'blob'
-                                }
+                            const response = await fetch(attachment, {
+                                method: 'GET',
+                                credentials: 'omit',
+                                signal: AbortSignal.timeout(10000)
                             });
                             });
+                            if (!response.ok) {
+                                throw new Error('HTTP ' + response.status);
+                            }
+                            const blobData = await response.blob();
                             if (blobData instanceof window.Blob) {
                             if (blobData instanceof window.Blob) {
                                 const fileReading = new Promise(function (resolve, reject) {
                                 const fileReading = new Promise(function (resolve, reject) {
                                     const fileReader = new FileReader();
                                     const fileReader = new FileReader();
@@ -5969,7 +5966,7 @@ window.PrivateBin = (function () {
                 });
                 });
                 ServerInteraction.run();
                 ServerInteraction.run();
             }, false); // this false is important as it circumvents the cache
             }, false); // this false is important as it circumvents the cache
-        }
+        };
 
 
         /**
         /**
          * clone the current document
          * clone the current document
@@ -6039,7 +6036,7 @@ window.PrivateBin = (function () {
                     Alert.showWarning('Your browser doesn\'t support WebAssembly, used for zlib compression. You can create uncompressed documents, but can\'t read compressed ones.');
                     Alert.showWarning('Your browser doesn\'t support WebAssembly, used for zlib compression. You can create uncompressed documents, but can\'t read compressed ones.');
                 }
                 }
             });
             });
-        }
+        };
 
 
         /**
         /**
          * application start
          * application start
@@ -6121,7 +6118,7 @@ window.PrivateBin = (function () {
 
 
             // display an existing document
             // display an existing document
             return me.showPaste();
             return me.showPaste();
-        }
+        };
 
 
         return me;
         return me;
     })(window, document);
     })(window, document);
@@ -6153,7 +6150,6 @@ window.PrivateBin = (function () {
 // skip auto-initialization in test environments (Node.js)
 // skip auto-initialization in test environments (Node.js)
 if (typeof module === 'undefined' || !module.exports) {
 if (typeof module === 'undefined' || !module.exports) {
     window.addEventListener('DOMContentLoaded', function () {
     window.addEventListener('DOMContentLoaded', function () {
-        'use strict';
         // run main controller
         // run main controller
         window.PrivateBin.Controller.init();
         window.PrivateBin.Controller.init();
     });
     });

File diff suppressed because it is too large
+ 0 - 1
js/purify-3.4.1.js


File diff suppressed because it is too large
+ 1 - 0
js/purify-3.4.12.js


+ 2 - 2
js/test/PasteStatus.js

@@ -72,7 +72,7 @@ describe('PasteStatus', function () {
                 PrivateBin.PasteStatus.init();
                 PrivateBin.PasteStatus.init();
                 PrivateBin.PasteStatus.createPasteNotification('https://example.com/', 'https://example.com/delete');
                 PrivateBin.PasteStatus.createPasteNotification('https://example.com/', 'https://example.com/delete');
 
 
-                const hotkey = document.querySelector('#copyhint kbd')?.textContent;
+                const hotkey = document.querySelector('#copyhint kbd').textContent;
 
 
                 assert.strictEqual(hotkey, 'Cmd');
                 assert.strictEqual(hotkey, 'Cmd');
             }
             }
@@ -92,7 +92,7 @@ describe('PasteStatus', function () {
                 PrivateBin.PasteStatus.init();
                 PrivateBin.PasteStatus.init();
                 PrivateBin.PasteStatus.createPasteNotification('https://example.com/', 'https://example.com/delete');
                 PrivateBin.PasteStatus.createPasteNotification('https://example.com/', 'https://example.com/delete');
 
 
-                const hotkey = document.querySelector('#copyhint kbd')?.textContent;
+                const hotkey = document.querySelector('#copyhint kbd').textContent;
 
 
                 assert.strictEqual(hotkey, 'Ctrl');
                 assert.strictEqual(hotkey, 'Ctrl');
             }
             }

+ 42 - 42
lib/Configuration.php

@@ -33,8 +33,8 @@ class Configuration
      *
      *
      * @var array
      * @var array
      */
      */
-    private static $_defaults = array(
-        'main' => array(
+    private static $_defaults = [
+        'main' => [
             'name'                     => 'PrivateBin',
             'name'                     => 'PrivateBin',
             'basepath'                 => '',
             'basepath'                 => '',
             'discussion'               => true,
             'discussion'               => true,
@@ -48,7 +48,7 @@ class Configuration
             'sizelimit'                => 10485760,
             'sizelimit'                => 10485760,
             'templateselection'        => false,
             'templateselection'        => false,
             'template'                 => 'bootstrap5',
             'template'                 => 'bootstrap5',
-            'availabletemplates'       => array(
+            'availabletemplates'       => [
                 'bootstrap5',
                 'bootstrap5',
                 'bootstrap',
                 'bootstrap',
                 'bootstrap-page',
                 'bootstrap-page',
@@ -56,7 +56,7 @@ class Configuration
                 'bootstrap-dark-page',
                 'bootstrap-dark-page',
                 'bootstrap-compact',
                 'bootstrap-compact',
                 'bootstrap-compact-page',
                 'bootstrap-compact-page',
-            ),
+            ],
             'info'                     => 'More information on the <a href=\'https://privatebin.info/\'>project page</a>.',
             'info'                     => 'More information on the <a href=\'https://privatebin.info/\'>project page</a>.',
             'notice'                   => '',
             'notice'                   => '',
             'languageselection'        => false,
             'languageselection'        => false,
@@ -69,11 +69,11 @@ class Configuration
             'cspheader'                => 'default-src \'none\'; base-uri \'self\'; form-action \'none\'; manifest-src \'self\'; connect-src * blob:; script-src \'self\' \'wasm-unsafe-eval\'; style-src \'self\'; font-src \'self\'; frame-ancestors \'none\'; frame-src blob:; img-src \'self\' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-modals allow-downloads',
             'cspheader'                => 'default-src \'none\'; base-uri \'self\'; form-action \'none\'; manifest-src \'self\'; connect-src * blob:; script-src \'self\' \'wasm-unsafe-eval\'; style-src \'self\'; font-src \'self\'; frame-ancestors \'none\'; frame-src blob:; img-src \'self\' data: blob:; media-src blob:; object-src blob:; sandbox allow-same-origin allow-scripts allow-forms allow-modals allow-downloads',
             'httpwarning'              => true,
             'httpwarning'              => true,
             'compression'              => 'zlib',
             'compression'              => 'zlib',
-        ),
-        'expire' => array(
+        ],
+        'expire' => [
             'default' => '1week',
             'default' => '1week',
-        ),
-        'expire_options' => array(
+        ],
+        'expire_options' => [
             '5min'   => 300,
             '5min'   => 300,
             '10min'  => 600,
             '10min'  => 600,
             '1hour'  => 3600,
             '1hour'  => 3600,
@@ -82,51 +82,51 @@ class Configuration
             '1month' => 2592000,
             '1month' => 2592000,
             '1year'  => 31536000,
             '1year'  => 31536000,
             'never'  => 0,
             'never'  => 0,
-        ),
-        'formatter_options' => array(
+        ],
+        'formatter_options' => [
             'plaintext'          => 'Plain Text',
             'plaintext'          => 'Plain Text',
             'syntaxhighlighting' => 'Source Code',
             'syntaxhighlighting' => 'Source Code',
             'markdown'           => 'Markdown',
             'markdown'           => 'Markdown',
-        ),
-        'traffic' => array(
+        ],
+        'traffic' => [
             'limit'     => 10,
             'limit'     => 10,
             'header'    => '',
             'header'    => '',
             'exempted'  => '',
             'exempted'  => '',
             'creators'  => '',
             'creators'  => '',
-        ),
-        'purge' => array(
+        ],
+        'purge' => [
             'limit'     => 300,
             'limit'     => 300,
             'batchsize' => 10,
             'batchsize' => 10,
-        ),
-        'model' => array(
+        ],
+        'model' => [
             'class' => 'Filesystem',
             'class' => 'Filesystem',
-        ),
-        'model_options' => array(
+        ],
+        'model_options' => [
             'dir' => 'data',
             'dir' => 'data',
-        ),
-        'yourls' => array(
+        ],
+        'yourls' => [
             'signature' => '',
             'signature' => '',
             'apiurl'    => '',
             'apiurl'    => '',
-        ),
-        'shlink' => array(
+        ],
+        'shlink' => [
             'apikey'    => '',
             'apikey'    => '',
             'apiurl'    => '',
             'apiurl'    => '',
-        ),
+        ],
         // update this array when adding/changing/removing js files
         // update this array when adding/changing/removing js files
-        'sri' => array(
+        'sri' => [
             'js/base-x-5.0.1.js'     => 'sha512-FmhlnjIxQyxkkxQmzf0l6IRGsGbgyCdgqPxypFsEtHMF1naRqaLLo6mcyN5rEaT16nKx1PeJ4g7+07D6gnk/Tg==',
             'js/base-x-5.0.1.js'     => 'sha512-FmhlnjIxQyxkkxQmzf0l6IRGsGbgyCdgqPxypFsEtHMF1naRqaLLo6mcyN5rEaT16nKx1PeJ4g7+07D6gnk/Tg==',
             'js/bootstrap-5.3.8.js'  => 'sha512-BkZvJ5rZ3zbDCod5seWHpRGg+PRd6ZgE8Nua/OMtcxqm8Wtg0PqwhUUXK5bqvl3oclMt5O+3zjRVX0L+L2j7fA==',
             'js/bootstrap-5.3.8.js'  => 'sha512-BkZvJ5rZ3zbDCod5seWHpRGg+PRd6ZgE8Nua/OMtcxqm8Wtg0PqwhUUXK5bqvl3oclMt5O+3zjRVX0L+L2j7fA==',
             'js/dark-mode-switch.js' => 'sha512-BhY7dNU14aDN5L+muoUmA66x0CkYUWkQT0nxhKBLP/o2d7jE025+dvWJa4OiYffBGEFgmhrD/Sp+QMkxGMTz2g==',
             'js/dark-mode-switch.js' => 'sha512-BhY7dNU14aDN5L+muoUmA66x0CkYUWkQT0nxhKBLP/o2d7jE025+dvWJa4OiYffBGEFgmhrD/Sp+QMkxGMTz2g==',
             'js/kjua-0.10.0.js'      => 'sha512-BYj4xggowR7QD150VLSTRlzH62YPfhpIM+b/1EUEr7RQpdWAGKulxWnOvjFx1FUlba4m6ihpNYuQab51H6XlYg==',
             'js/kjua-0.10.0.js'      => 'sha512-BYj4xggowR7QD150VLSTRlzH62YPfhpIM+b/1EUEr7RQpdWAGKulxWnOvjFx1FUlba4m6ihpNYuQab51H6XlYg==',
             'js/legacy.js'           => 'sha512-pRofxsrf5UItjiP22Dcjh3FAcBjF/n7h8U9/W5xqJk17U0N2U1oajhXypq/omo9jhwS1iVGOhWrRepoPeFns+w==',
             'js/legacy.js'           => 'sha512-pRofxsrf5UItjiP22Dcjh3FAcBjF/n7h8U9/W5xqJk17U0N2U1oajhXypq/omo9jhwS1iVGOhWrRepoPeFns+w==',
             'js/prettify.js'         => 'sha512-puO0Ogy++IoA2Pb9IjSxV1n4+kQkKXYAEUtVzfZpQepyDPyXk8hokiYDS7ybMogYlyyEIwMLpZqVhCkARQWLMg==',
             'js/prettify.js'         => 'sha512-puO0Ogy++IoA2Pb9IjSxV1n4+kQkKXYAEUtVzfZpQepyDPyXk8hokiYDS7ybMogYlyyEIwMLpZqVhCkARQWLMg==',
-            'js/privatebin.js'       => 'sha512-/lTaFNkvi1jyd9K8AdzohD/8jI2RMFmsnFArbqam3GdDpP60HZGMlf5gGqjzCjHrjcuCDQM66utUv6NmK9v3IQ==',
-            'js/purify-3.4.1.js'     => 'sha512-280a/Vb6fVFsYaeRrkuDp4EDmdYlt2XS+dlDEO/U9qljPrAraA2bIzHTNmP+9dpwPDDwTML+RS+h5iaagPwTzA==',
+            'js/privatebin.js'       => 'sha512-ah/QdETig/ovH1QPl9Ne+T3VvaP7Bj4Rd9Or9wqQgo5BHge9o02MxAlRGXUZpKviy/27OSzHgz2PwpnH/B2RZg==',
+            'js/purify-3.4.12.js'    => 'sha512-Akf6HnAJZm0sWWWI4gp2GYff0NDnHUB02XJE5S7Hdq/Z5xtMjkuFacsDA8ZtViv1gi+onBxMhEMIaGyQeGxBng==',
             'js/showdown-2.1.0.js'   => 'sha512-WYXZgkTR0u/Y9SVIA4nTTOih0kXMEd8RRV6MLFdL6YU8ymhR528NLlYQt1nlJQbYz4EW+ZsS0fx1awhiQJme1Q==',
             'js/showdown-2.1.0.js'   => 'sha512-WYXZgkTR0u/Y9SVIA4nTTOih0kXMEd8RRV6MLFdL6YU8ymhR528NLlYQt1nlJQbYz4EW+ZsS0fx1awhiQJme1Q==',
             'js/zlib-1.3.2.js'       => 'sha512-RAhJgxg9siMIA8ky4c10Rc2zUgnK80olHB8Tt1IOYWY4Eh1WmrviQkDn+sgBlb38ZHq3tzufGC41kP360gmosQ==',
             'js/zlib-1.3.2.js'       => 'sha512-RAhJgxg9siMIA8ky4c10Rc2zUgnK80olHB8Tt1IOYWY4Eh1WmrviQkDn+sgBlb38ZHq3tzufGC41kP360gmosQ==',
             'js/zlib.js'             => 'sha512-QOaEwssHqHRRcWJ2Un3Kl2Zhyprzl7T8zmsKN2FppFxW3VR+8UChYOx2iuL0HbXK42fuBWJm5PNQJxufulrt/w==',
             'js/zlib.js'             => 'sha512-QOaEwssHqHRRcWJ2Un3Kl2Zhyprzl7T8zmsKN2FppFxW3VR+8UChYOx2iuL0HbXK42fuBWJm5PNQJxufulrt/w==',
-        ),
-    );
+        ],
+    ];
 
 
     /**
     /**
      * parse configuration file and ensure default configuration values are present
      * parse configuration file and ensure default configuration values are present
@@ -135,8 +135,8 @@ class Configuration
      */
      */
     public function __construct()
     public function __construct()
     {
     {
-        $basePaths  = array();
-        $config     = array();
+        $basePaths  = [];
+        $config     = [];
         $configPath = getenv('CONFIG_PATH');
         $configPath = getenv('CONFIG_PATH');
         if ($configPath !== false && !empty($configPath)) {
         if ($configPath !== false && !empty($configPath)) {
             $basePaths[] = $configPath;
             $basePaths[] = $configPath;
@@ -146,10 +146,10 @@ class Configuration
             $configFile = $basePath . DIRECTORY_SEPARATOR . 'conf.php';
             $configFile = $basePath . DIRECTORY_SEPARATOR . 'conf.php';
             if (is_readable($configFile)) {
             if (is_readable($configFile)) {
                 $config = parse_ini_file($configFile, true);
                 $config = parse_ini_file($configFile, true);
-                foreach (array('main', 'model', 'model_options') as $section) {
+                foreach (['main', 'model', 'model_options'] as $section) {
                     if (!array_key_exists($section, $config)) {
                     if (!array_key_exists($section, $config)) {
                         $name = $config['main']['name'] ?? self::getDefaults()['main']['name'];
                         $name = $config['main']['name'] ?? self::getDefaults()['main']['name'];
-                        throw new TranslatedException(array('%s requires configuration section [%s] to be present in configuration file.', I18n::_($name), $section), 2);
+                        throw new TranslatedException(['%s requires configuration section [%s] to be present in configuration file.', I18n::_($name), $section], 2);
                     }
                     }
                 }
                 }
                 break;
                 break;
@@ -171,27 +171,27 @@ class Configuration
                 $section === 'model_options' &&
                 $section === 'model_options' &&
                 $this->_configuration['model']['class'] === 'Database'
                 $this->_configuration['model']['class'] === 'Database'
             ) {
             ) {
-                $values = array(
+                $values = [
                     'dsn' => 'sqlite:' . PATH . 'data' . DIRECTORY_SEPARATOR . 'db.sq3',
                     'dsn' => 'sqlite:' . PATH . 'data' . DIRECTORY_SEPARATOR . 'db.sq3',
                     'tbl' => null,
                     'tbl' => null,
                     'usr' => null,
                     'usr' => null,
                     'pwd' => null,
                     'pwd' => null,
-                    'opt' => array(),
-                );
+                    'opt' => [],
+                ];
             } elseif (
             } elseif (
                 $section === 'model_options' &&
                 $section === 'model_options' &&
                 $this->_configuration['model']['class'] === 'GoogleCloudStorage'
                 $this->_configuration['model']['class'] === 'GoogleCloudStorage'
             ) {
             ) {
-                $values = array(
+                $values = [
                     'bucket'     => getenv('PRIVATEBIN_GCS_BUCKET') ? getenv('PRIVATEBIN_GCS_BUCKET') : null,
                     'bucket'     => getenv('PRIVATEBIN_GCS_BUCKET') ? getenv('PRIVATEBIN_GCS_BUCKET') : null,
                     'prefix'     => 'pastes',
                     'prefix'     => 'pastes',
                     'uniformacl' => false,
                     'uniformacl' => false,
-                );
+                ];
             } elseif (
             } elseif (
                 $section === 'model_options' &&
                 $section === 'model_options' &&
                 $this->_configuration['model']['class'] === 'S3Storage'
                 $this->_configuration['model']['class'] === 'S3Storage'
             ) {
             ) {
-                $values = array(
+                $values = [
                     'region'                  => null,
                     'region'                  => null,
                     'version'                 => null,
                     'version'                 => null,
                     'endpoint'                => null,
                     'endpoint'                => null,
@@ -200,7 +200,7 @@ class Configuration
                     'use_path_style_endpoint' => null,
                     'use_path_style_endpoint' => null,
                     'bucket'                  => null,
                     'bucket'                  => null,
                     'prefix'                  => '',
                     'prefix'                  => '',
-                );
+                ];
             }
             }
 
 
             // "*_options" sections don't require all defaults to be set
             // "*_options" sections don't require all defaults to be set
@@ -230,9 +230,9 @@ class Configuration
                             $result = $config[$section][$key];
                             $result = $config[$section][$key];
                         } elseif (is_bool($val)) {
                         } elseif (is_bool($val)) {
                             $val = strtolower($config[$section][$key]);
                             $val = strtolower($config[$section][$key]);
-                            if (in_array($val, array('true', 'yes', 'on'))) {
+                            if (in_array($val, ['true', 'yes', 'on'])) {
                                 $result = true;
                                 $result = true;
-                            } elseif (in_array($val, array('false', 'no', 'off'))) {
+                            } elseif (in_array($val, ['false', 'no', 'off'])) {
                                 $result = false;
                                 $result = false;
                             } else {
                             } else {
                                 $result = (bool) $config[$section][$key];
                                 $result = (bool) $config[$section][$key];
@@ -311,7 +311,7 @@ class Configuration
     public function getSection($section)
     public function getSection($section)
     {
     {
         if (!array_key_exists($section, $this->_configuration)) {
         if (!array_key_exists($section, $this->_configuration)) {
-            throw new TranslatedException(array('%s requires configuration section [%s] to be present in configuration file.', I18n::_($this->getKey('name')), $section), 3);
+            throw new TranslatedException(['%s requires configuration section [%s] to be present in configuration file.', I18n::_($this->getKey('name')), $section], 3);
         }
         }
         return $this->_configuration[$section];
         return $this->_configuration[$section];
     }
     }

+ 17 - 18
lib/Controller.php

@@ -12,7 +12,6 @@
 namespace PrivateBin;
 namespace PrivateBin;
 
 
 use Exception;
 use Exception;
-use PrivateBin\Exception\JsonException;
 use PrivateBin\Exception\TranslatedException;
 use PrivateBin\Exception\TranslatedException;
 use PrivateBin\Persistence\ServerSalt;
 use PrivateBin\Persistence\ServerSalt;
 use PrivateBin\Persistence\TrafficLimiter;
 use PrivateBin\Persistence\TrafficLimiter;
@@ -128,7 +127,7 @@ class Controller
             error_log(I18n::_('%s requires php %s or above to work. Sorry.', I18n::_('PrivateBin'), self::MIN_PHP_VERSION));
             error_log(I18n::_('%s requires php %s or above to work. Sorry.', I18n::_('PrivateBin'), self::MIN_PHP_VERSION));
             return;
             return;
         }
         }
-        if (strlen(PATH) < 0 && substr(PATH, -1) !== DIRECTORY_SEPARATOR) {
+        if (strlen(PATH) > 0 && substr(PATH, -1) !== DIRECTORY_SEPARATOR) {
             error_log(I18n::_('%s requires the PATH to end in a "%s". Please update the PATH in your index.php.', I18n::_('PrivateBin'), DIRECTORY_SEPARATOR));
             error_log(I18n::_('%s requires the PATH to end in a "%s". Please update the PATH in your index.php.', I18n::_('PrivateBin'), DIRECTORY_SEPARATOR));
             return;
             return;
         }
         }
@@ -206,7 +205,7 @@ class Controller
         // force default language, if language selection is disabled and a default is set
         // force default language, if language selection is disabled and a default is set
         if (!$this->_conf->getKey('languageselection') && strlen($lang) === 2) {
         if (!$this->_conf->getKey('languageselection') && strlen($lang) === 2) {
             $_COOKIE['lang'] = $lang;
             $_COOKIE['lang'] = $lang;
-            setcookie('lang', $lang, array('SameSite' => 'Lax', 'Secure' => true));
+            setcookie('lang', $lang, ['SameSite' => 'Lax', 'Secure' => true]);
         }
         }
     }
     }
 
 
@@ -230,7 +229,7 @@ class Controller
         if (!$this->_conf->getKey('templateselection') && array_key_exists('template', $_COOKIE)) {
         if (!$this->_conf->getKey('templateselection') && array_key_exists('template', $_COOKIE)) {
             unset($_COOKIE['template']); // ensure value is not re-used in template switcher
             unset($_COOKIE['template']); // ensure value is not re-used in template switcher
             $expiredInAllTimezones = time() - 86400;
             $expiredInAllTimezones = time() - 86400;
-            setcookie('template', '', array('expires' => $expiredInAllTimezones, 'SameSite' => 'Lax', 'Secure' => true));
+            setcookie('template', '', ['expires' => $expiredInAllTimezones, 'SameSite' => 'Lax', 'Secure' => true]);
         }
         }
     }
     }
 
 
@@ -324,7 +323,7 @@ class Controller
                 $paste = $this->_model->getPaste();
                 $paste = $this->_model->getPaste();
                 $paste->setData($data);
                 $paste->setData($data);
                 $paste->store();
                 $paste->store();
-                $this->_json_result($paste->getId(), array('deletetoken' => $paste->getDeleteToken()));
+                $this->_json_result($paste->getId(), ['deletetoken' => $paste->getDeleteToken()]);
             } catch (Exception $e) {
             } catch (Exception $e) {
                 $this->_json_error($e->getMessage());
                 $this->_json_error($e->getMessage());
             }
             }
@@ -418,7 +417,7 @@ class Controller
         header('X-Frame-Options: deny');
         header('X-Frame-Options: deny');
 
 
         // label all the expiration options
         // label all the expiration options
-        $expire = array();
+        $expire = [];
         foreach ($this->_conf->getSection('expire_options') as $time => $seconds) {
         foreach ($this->_conf->getSection('expire_options') as $time => $seconds) {
             $expire[$time] = ($seconds === 0) ? I18n::_(ucfirst($time)) : Filter::formatHumanReadableTime($time);
             $expire[$time] = ($seconds === 0) ? I18n::_(ucfirst($time)) : Filter::formatHumanReadableTime($time);
         }
         }
@@ -430,22 +429,22 @@ class Controller
         $languageselection = '';
         $languageselection = '';
         if ($this->_conf->getKey('languageselection')) {
         if ($this->_conf->getKey('languageselection')) {
             $languageselection = I18n::getLanguage();
             $languageselection = I18n::getLanguage();
-            setcookie('lang', $languageselection, array('SameSite' => 'Lax', 'Secure' => true));
+            setcookie('lang', $languageselection, ['SameSite' => 'Lax', 'Secure' => true]);
         }
         }
 
 
         // set template cookie if that functionality was enabled
         // set template cookie if that functionality was enabled
         $templateselection = '';
         $templateselection = '';
         if ($this->_conf->getKey('templateselection')) {
         if ($this->_conf->getKey('templateselection')) {
             $templateselection = TemplateSwitcher::getTemplate();
             $templateselection = TemplateSwitcher::getTemplate();
-            setcookie('template', $templateselection, array('SameSite' => 'Lax', 'Secure' => true));
+            setcookie('template', $templateselection, ['SameSite' => 'Lax', 'Secure' => true]);
         }
         }
 
 
         // strip policies that are unsupported in meta tag
         // strip policies that are unsupported in meta tag
         $metacspheader = str_replace(
         $metacspheader = str_replace(
-            array(
+            [
                 'frame-ancestors \'none\'; ',
                 'frame-ancestors \'none\'; ',
                 '; sandbox allow-same-origin allow-scripts allow-forms allow-modals allow-downloads',
                 '; sandbox allow-same-origin allow-scripts allow-forms allow-modals allow-downloads',
-            ),
+            ],
             '',
             '',
             $this->_conf->getKey('cspheader')
             $this->_conf->getKey('cspheader')
         );
         );
@@ -454,7 +453,7 @@ class Controller
         $page->assign('CSPHEADER', $metacspheader);
         $page->assign('CSPHEADER', $metacspheader);
         $page->assign('ERROR', I18n::_($this->_error));
         $page->assign('ERROR', I18n::_($this->_error));
         $page->assign('NAME', $this->_conf->getKey('name'));
         $page->assign('NAME', $this->_conf->getKey('name'));
-        if (in_array($this->_request->getOperation(), array('shlinkproxy', 'yourlsproxy'), true)) {
+        if (in_array($this->_request->getOperation(), ['shlinkproxy', 'yourlsproxy'], true)) {
             $page->assign('SHORTURL', $this->_status);
             $page->assign('SHORTURL', $this->_status);
             $page->draw('shortenerproxy');
             $page->draw('shortenerproxy');
             return;
             return;
@@ -500,13 +499,13 @@ class Controller
      */
      */
     private function _jsonld($type)
     private function _jsonld($type)
     {
     {
-        if (!in_array($type, array(
+        if (!in_array($type, [
             'comment',
             'comment',
             'commentmeta',
             'commentmeta',
             'paste',
             'paste',
             'pastemeta',
             'pastemeta',
             'types',
             'types',
-        ))) {
+        ])) {
             $type = '';
             $type = '';
         }
         }
         $content = '{}';
         $content = '{}';
@@ -541,10 +540,10 @@ class Controller
      */
      */
     private function _json_error($error)
     private function _json_error($error)
     {
     {
-        $result = array(
+        $result = [
             'status'  => 1,
             'status'  => 1,
             'message' => $error,
             'message' => $error,
-        );
+        ];
         $this->_json = Json::encode($result);
         $this->_json = Json::encode($result);
     }
     }
 
 
@@ -556,13 +555,13 @@ class Controller
      * @param  array $other
      * @param  array $other
      * @throws JsonException
      * @throws JsonException
      */
      */
-    private function _json_result($dataid, $other = array())
+    private function _json_result($dataid, $other = [])
     {
     {
-        $result = array(
+        $result = [
             'status' => 0,
             'status' => 0,
             'id'     => $dataid,
             'id'     => $dataid,
             'url'    => $this->_urlBase . '?' . $dataid,
             'url'    => $this->_urlBase . '?' . $dataid,
-        ) + $other;
+        ] + $other;
         $this->_json = Json::encode($result);
         $this->_json = Json::encode($result);
     }
     }
 
 

+ 1 - 1
lib/Data/AbstractData.php

@@ -24,7 +24,7 @@ abstract class AbstractData
      * @access protected
      * @access protected
      * @var    array
      * @var    array
      */
      */
-    protected $_last_cache = array();
+    protected $_last_cache = [];
 
 
     /**
     /**
      * Create a paste.
      * Create a paste.

+ 28 - 28
lib/Data/Database.php

@@ -12,10 +12,10 @@
 namespace PrivateBin\Data;
 namespace PrivateBin\Data;
 
 
 use Exception;
 use Exception;
+use JsonException;
 use PDO;
 use PDO;
 use PDOException;
 use PDOException;
 use PrivateBin\Controller;
 use PrivateBin\Controller;
-use PrivateBin\Exception\JsonException;
 use PrivateBin\Json;
 use PrivateBin\Json;
 
 
 /**
 /**
@@ -158,12 +158,12 @@ class Database extends AbstractData
             return $this->_exec(
             return $this->_exec(
                 'INSERT INTO "' . $this->_sanitizeIdentifier('paste') .
                 'INSERT INTO "' . $this->_sanitizeIdentifier('paste') .
                 '" VALUES(?,?,?,?)',
                 '" VALUES(?,?,?,?)',
-                array(
+                [
                     $pasteid,
                     $pasteid,
                     Json::encode($paste),
                     Json::encode($paste),
                     $expire_date,
                     $expire_date,
                     Json::encode($meta),
                     Json::encode($meta),
-                )
+                ]
             );
             );
         } catch (Exception $e) {
         } catch (Exception $e) {
             error_log('Error while attempting to insert a paste into the database: ' . $e->getMessage());
             error_log('Error while attempting to insert a paste into the database: ' . $e->getMessage());
@@ -183,7 +183,7 @@ class Database extends AbstractData
         try {
         try {
             $row = $this->_select(
             $row = $this->_select(
                 'SELECT * FROM "' . $this->_sanitizeIdentifier('paste') .
                 'SELECT * FROM "' . $this->_sanitizeIdentifier('paste') .
-                '" WHERE "dataid" = ?', array($pasteid), true
+                '" WHERE "dataid" = ?', [$pasteid], true
             );
             );
         } catch (PDOException $e) {
         } catch (PDOException $e) {
             $row = false;
             $row = false;
@@ -196,14 +196,14 @@ class Database extends AbstractData
             $paste = Json::decode($row['data']);
             $paste = Json::decode($row['data']);
         } catch (JsonException $e) {
         } catch (JsonException $e) {
             error_log('Error while reading a paste from the database: ' . $e->getMessage());
             error_log('Error while reading a paste from the database: ' . $e->getMessage());
-            $paste = array();
+            $paste = [];
         }
         }
 
 
         try {
         try {
             $paste['meta'] = Json::decode($row['meta']);
             $paste['meta'] = Json::decode($row['meta']);
         } catch (JsonException $e) {
         } catch (JsonException $e) {
             error_log('Error while reading a paste from the database: ' . $e->getMessage());
             error_log('Error while reading a paste from the database: ' . $e->getMessage());
-            $paste['meta'] = array();
+            $paste['meta'] = [];
         }
         }
         $expire_date = (int) $row['expiredate'];
         $expire_date = (int) $row['expiredate'];
         if ($expire_date > 0) {
         if ($expire_date > 0) {
@@ -223,11 +223,11 @@ class Database extends AbstractData
     {
     {
         $this->_exec(
         $this->_exec(
             'DELETE FROM "' . $this->_sanitizeIdentifier('paste') .
             'DELETE FROM "' . $this->_sanitizeIdentifier('paste') .
-            '" WHERE "dataid" = ?', array($pasteid)
+            '" WHERE "dataid" = ?', [$pasteid]
         );
         );
         $this->_exec(
         $this->_exec(
             'DELETE FROM "' . $this->_sanitizeIdentifier('comment') .
             'DELETE FROM "' . $this->_sanitizeIdentifier('comment') .
-            '" WHERE "pasteid" = ?', array($pasteid)
+            '" WHERE "pasteid" = ?', [$pasteid]
         );
         );
     }
     }
 
 
@@ -243,7 +243,7 @@ class Database extends AbstractData
         try {
         try {
             $row = $this->_select(
             $row = $this->_select(
                 'SELECT "dataid" FROM "' . $this->_sanitizeIdentifier('paste') .
                 'SELECT "dataid" FROM "' . $this->_sanitizeIdentifier('paste') .
-                '" WHERE "dataid" = ?', array($pasteid), true
+                '" WHERE "dataid" = ?', [$pasteid], true
             );
             );
         } catch (PDOException $e) {
         } catch (PDOException $e) {
             return false;
             return false;
@@ -277,14 +277,14 @@ class Database extends AbstractData
             return $this->_exec(
             return $this->_exec(
                 'INSERT INTO "' . $this->_sanitizeIdentifier('comment') .
                 'INSERT INTO "' . $this->_sanitizeIdentifier('comment') .
                 '" VALUES(?,?,?,?,?,?)',
                 '" VALUES(?,?,?,?,?,?)',
-                array(
+                [
                     $commentid,
                     $commentid,
                     $pasteid,
                     $pasteid,
                     $parentid,
                     $parentid,
                     $data,
                     $data,
                     $meta['icon'],
                     $meta['icon'],
                     $meta['created'],
                     $meta['created'],
-                )
+                ]
             );
             );
         } catch (PDOException $e) {
         } catch (PDOException $e) {
             error_log('Error while attempting to insert a comment into the database: ' . $e->getMessage());
             error_log('Error while attempting to insert a comment into the database: ' . $e->getMessage());
@@ -303,24 +303,24 @@ class Database extends AbstractData
     {
     {
         $rows = $this->_select(
         $rows = $this->_select(
             'SELECT * FROM "' . $this->_sanitizeIdentifier('comment') .
             'SELECT * FROM "' . $this->_sanitizeIdentifier('comment') .
-            '" WHERE "pasteid" = ?', array($pasteid)
+            '" WHERE "pasteid" = ?', [$pasteid]
         );
         );
 
 
         // create comment list
         // create comment list
-        $comments = array();
+        $comments = [];
         if (count($rows)) {
         if (count($rows)) {
             foreach ($rows as $row) {
             foreach ($rows as $row) {
                 try {
                 try {
                     $data = Json::decode($row['data']);
                     $data = Json::decode($row['data']);
                 } catch (JsonException $e) {
                 } catch (JsonException $e) {
                     error_log('Error while reading a comment from the database: ' . $e->getMessage());
                     error_log('Error while reading a comment from the database: ' . $e->getMessage());
-                    $data = array();
+                    $data = [];
                 }
                 }
                 $i                          = $this->getOpenSlot($comments, (int) $row['postdate']);
                 $i                          = $this->getOpenSlot($comments, (int) $row['postdate']);
                 $comments[$i]               = $data;
                 $comments[$i]               = $data;
                 $comments[$i]['id']         = $row['dataid'];
                 $comments[$i]['id']         = $row['dataid'];
                 $comments[$i]['parentid']   = $row['parentid'];
                 $comments[$i]['parentid']   = $row['parentid'];
-                $comments[$i]['meta']       = array('created' => (int) $row['postdate']);
+                $comments[$i]['meta']       = ['created' => (int) $row['postdate']];
                 if (array_key_exists('vizhash', $row) && !empty($row['vizhash'])) {
                 if (array_key_exists('vizhash', $row) && !empty($row['vizhash'])) {
                     $comments[$i]['meta']['icon'] = $row['vizhash'];
                     $comments[$i]['meta']['icon'] = $row['vizhash'];
                 }
                 }
@@ -345,7 +345,7 @@ class Database extends AbstractData
             return (bool) $this->_select(
             return (bool) $this->_select(
                 'SELECT "dataid" FROM "' . $this->_sanitizeIdentifier('comment') .
                 'SELECT "dataid" FROM "' . $this->_sanitizeIdentifier('comment') .
                 '" WHERE "pasteid" = ? AND "parentid" = ? AND "dataid" = ?',
                 '" WHERE "pasteid" = ? AND "parentid" = ? AND "dataid" = ?',
-                array($pasteid, $parentid, $commentid), true
+                [$pasteid, $parentid, $commentid], true
             );
             );
         } catch (PDOException $e) {
         } catch (PDOException $e) {
             return false;
             return false;
@@ -375,7 +375,7 @@ class Database extends AbstractData
         return $this->_exec(
         return $this->_exec(
             'UPDATE "' . $this->_sanitizeIdentifier('config') .
             'UPDATE "' . $this->_sanitizeIdentifier('config') .
             '" SET "value" = ? WHERE "id" = ?',
             '" SET "value" = ? WHERE "id" = ?',
-            array($value, strtoupper($namespace))
+            [$value, strtoupper($namespace)]
         );
         );
     }
     }
 
 
@@ -396,13 +396,13 @@ class Database extends AbstractData
             $this->_exec(
             $this->_exec(
                 'INSERT INTO "' . $this->_sanitizeIdentifier('config') .
                 'INSERT INTO "' . $this->_sanitizeIdentifier('config') .
                 '" VALUES(?,?)',
                 '" VALUES(?,?)',
-                array($configKey, '')
+                [$configKey, '']
             );
             );
 
 
             // migrate filesystem based salt into database
             // migrate filesystem based salt into database
             $file = 'data' . DIRECTORY_SEPARATOR . 'salt.php';
             $file = 'data' . DIRECTORY_SEPARATOR . 'salt.php';
             if ($namespace === 'salt' && is_readable($file)) {
             if ($namespace === 'salt' && is_readable($file)) {
-                $fs    = new Filesystem(array('dir' => 'data'));
+                $fs    = new Filesystem(['dir' => 'data']);
                 $value = $fs->getValue('salt');
                 $value = $fs->getValue('salt');
                 $this->setValue($value, 'salt');
                 $this->setValue($value, 'salt');
                 if (!unlink($file)) {
                 if (!unlink($file)) {
@@ -416,7 +416,7 @@ class Database extends AbstractData
                 $this->_last_cache = Json::decode($value);
                 $this->_last_cache = Json::decode($value);
             } catch (JsonException $e) {
             } catch (JsonException $e) {
                 error_log('Error decoding JSON from table "config", row "traffic_limiter": ' . $e->getMessage());
                 error_log('Error decoding JSON from table "config", row "traffic_limiter": ' . $e->getMessage());
-                $this->_last_cache = array();
+                $this->_last_cache = [];
             }
             }
             if (array_key_exists($key, $this->_last_cache)) {
             if (array_key_exists($key, $this->_last_cache)) {
                 return $this->_last_cache[$key];
                 return $this->_last_cache[$key];
@@ -440,11 +440,11 @@ class Database extends AbstractData
                 '" WHERE "expiredate" < ? AND "expiredate" != ? ' .
                 '" WHERE "expiredate" < ? AND "expiredate" != ? ' .
                 ($this->_type === 'oci' ? 'FETCH NEXT ? ROWS ONLY' : 'LIMIT ?')
                 ($this->_type === 'oci' ? 'FETCH NEXT ? ROWS ONLY' : 'LIMIT ?')
             );
             );
-            $statement->execute(array(time(), 0, $batchsize));
+            $statement->execute([time(), 0, $batchsize]);
             return $statement->fetchAll(PDO::FETCH_COLUMN, 0);
             return $statement->fetchAll(PDO::FETCH_COLUMN, 0);
         } catch (PDOException $e) {
         } catch (PDOException $e) {
             error_log('Error while attempting to find expired pastes in the database: ' . $e->getMessage());
             error_log('Error while attempting to find expired pastes in the database: ' . $e->getMessage());
-            return array();
+            return [];
         }
         }
     }
     }
 
 
@@ -508,7 +508,7 @@ class Database extends AbstractData
             }
             }
         } elseif ($this->_type === 'oci') {
         } elseif ($this->_type === 'oci') {
             // workaround for https://bugs.php.net/bug.php?id=46728
             // workaround for https://bugs.php.net/bug.php?id=46728
-            $result = array();
+            $result = [];
             while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
             while ($row = $statement->fetch(PDO::FETCH_ASSOC)) {
                 $result[] = array_map('PrivateBin\Data\Database::_sanitizeClob', $row);
                 $result[] = array_map('PrivateBin\Data\Database::_sanitizeClob', $row);
             }
             }
@@ -576,7 +576,7 @@ class Database extends AbstractData
         try {
         try {
             $row = $this->_select(
             $row = $this->_select(
                 'SELECT "value" FROM "' . $this->_sanitizeIdentifier('config') .
                 'SELECT "value" FROM "' . $this->_sanitizeIdentifier('config') .
-                '" WHERE "id" = ?', array($key), true
+                '" WHERE "id" = ?', [$key], true
             );
             );
         } catch (PDOException $e) {
         } catch (PDOException $e) {
             error_log('Error while attempting to fetch configuration key "' . $key . '" in the database: ' . $e->getMessage());
             error_log('Error while attempting to fetch configuration key "' . $key . '" in the database: ' . $e->getMessage());
@@ -604,7 +604,7 @@ class Database extends AbstractData
                 $main_key = ' PRIMARY KEY';
                 $main_key = ' PRIMARY KEY';
                 break;
                 break;
         }
         }
-        return array($main_key, $after_key);
+        return [$main_key, $after_key];
     }
     }
 
 
     /**
     /**
@@ -743,7 +743,7 @@ class Database extends AbstractData
         $this->_exec(
         $this->_exec(
             'INSERT INTO "' . $this->_sanitizeIdentifier('config') .
             'INSERT INTO "' . $this->_sanitizeIdentifier('config') .
             '" VALUES(?,?)',
             '" VALUES(?,?)',
-            array('VERSION', Controller::VERSION)
+            ['VERSION', Controller::VERSION]
         );
         );
     }
     }
 
 
@@ -788,7 +788,7 @@ class Database extends AbstractData
         $supportsDropColumn = true;
         $supportsDropColumn = true;
         if ($this->_type === 'sqlite') {
         if ($this->_type === 'sqlite') {
             try {
             try {
-                $row                = $this->_select('SELECT sqlite_version() AS "v"', array(), true);
+                $row                = $this->_select('SELECT sqlite_version() AS "v"', [], true);
                 $supportsDropColumn = (bool) version_compare($row['v'], '3.35.0', '>=');
                 $supportsDropColumn = (bool) version_compare($row['v'], '3.35.0', '>=');
             } catch (PDOException $e) {
             } catch (PDOException $e) {
                 $supportsDropColumn = false;
                 $supportsDropColumn = false;
@@ -902,7 +902,7 @@ class Database extends AbstractData
         $this->_exec(
         $this->_exec(
             'UPDATE "' . $this->_sanitizeIdentifier('config') .
             'UPDATE "' . $this->_sanitizeIdentifier('config') .
             '" SET "value" = ? WHERE "id" = ?',
             '" SET "value" = ? WHERE "id" = ?',
-            array(Controller::VERSION, 'VERSION')
+            [Controller::VERSION, 'VERSION']
         );
         );
     }
     }
 }
 }

+ 4 - 4
lib/Data/Filesystem.php

@@ -13,7 +13,7 @@ namespace PrivateBin\Data;
 
 
 use DirectoryIterator;
 use DirectoryIterator;
 use GlobIterator;
 use GlobIterator;
-use PrivateBin\Exception\JsonException;
+use JsonException;
 use PrivateBin\Json;
 use PrivateBin\Json;
 
 
 /**
 /**
@@ -205,7 +205,7 @@ class Filesystem extends AbstractData
      */
      */
     public function readComments($pasteid)
     public function readComments($pasteid)
     {
     {
-        $comments = array();
+        $comments = [];
         $discdir  = $this->_dataid2discussionpath($pasteid);
         $discdir  = $this->_dataid2discussionpath($pasteid);
         if (is_dir($discdir)) {
         if (is_dir($discdir)) {
             foreach (new DirectoryIterator($discdir) as $file) {
             foreach (new DirectoryIterator($discdir) as $file) {
@@ -359,7 +359,7 @@ class Filesystem extends AbstractData
      */
      */
     protected function _getExpiredPastes($batchsize)
     protected function _getExpiredPastes($batchsize)
     {
     {
-        $pastes = array();
+        $pastes = [];
         $count  = 0;
         $count  = 0;
         $opened = 0;
         $opened = 0;
         $limit  = $batchsize * 10; // try at most 10 times $batchsize pastes before giving up
         $limit  = $batchsize * 10; // try at most 10 times $batchsize pastes before giving up
@@ -388,7 +388,7 @@ class Filesystem extends AbstractData
      */
      */
     public function getAllPastes()
     public function getAllPastes()
     {
     {
-        $pastes = array();
+        $pastes = [];
         foreach (new GlobIterator($this->_path . self::PASTE_FILE_PATTERN) as $file) {
         foreach (new GlobIterator($this->_path . self::PASTE_FILE_PATTERN) as $file) {
             if ($file->isFile()) {
             if ($file->isFile()) {
                 $pastes[] = $file->getBasename('.php');
                 $pastes[] = $file->getBasename('.php');

+ 22 - 22
lib/Data/GoogleCloudStorage.php

@@ -15,7 +15,7 @@ use Exception;
 use Google\Cloud\Core\Exception\NotFoundException;
 use Google\Cloud\Core\Exception\NotFoundException;
 use Google\Cloud\Storage\Bucket;
 use Google\Cloud\Storage\Bucket;
 use Google\Cloud\Storage\StorageClient;
 use Google\Cloud\Storage\StorageClient;
-use PrivateBin\Exception\JsonException;
+use JsonException;
 use PrivateBin\Json;
 use PrivateBin\Json;
 
 
 class GoogleCloudStorage extends AbstractData
 class GoogleCloudStorage extends AbstractData
@@ -74,8 +74,8 @@ class GoogleCloudStorage extends AbstractData
         }
         }
 
 
         $this->_client = class_exists('StorageClientStub', false) ?
         $this->_client = class_exists('StorageClientStub', false) ?
-            new \StorageClientStub(array()) :
-            new StorageClient(array('suppressKeyFileNotice' => true));
+            new \StorageClientStub([]) :
+            new StorageClient(['suppressKeyFileNotice' => true]);
         if (isset($bucket)) {
         if (isset($bucket)) {
             $this->_bucket = $this->_client->bucket($bucket);
             $this->_bucket = $this->_client->bucket($bucket);
         }
         }
@@ -107,20 +107,20 @@ class GoogleCloudStorage extends AbstractData
      */
      */
     private function _upload($key, &$payload)
     private function _upload($key, &$payload)
     {
     {
-        $metadata = $payload['meta'] ?? array();
+        $metadata = $payload['meta'] ?? [];
         unset($metadata['salt']);
         unset($metadata['salt']);
         foreach ($metadata as $k => $v) {
         foreach ($metadata as $k => $v) {
             $metadata[$k] = strval($v);
             $metadata[$k] = strval($v);
         }
         }
         try {
         try {
-            $data = array(
+            $data = [
                 'name'          => $key,
                 'name'          => $key,
                 'chunkSize'     => 262144,
                 'chunkSize'     => 262144,
-                'metadata'      => array(
+                'metadata'      => [
                     'content-type' => 'application/json',
                     'content-type' => 'application/json',
                     'metadata'     => $metadata,
                     'metadata'     => $metadata,
-                ),
-            );
+                ],
+            ];
             if (!$this->_uniformacl) {
             if (!$this->_uniformacl) {
                 $data['predefinedAcl'] = 'private';
                 $data['predefinedAcl'] = 'private';
             }
             }
@@ -171,7 +171,7 @@ class GoogleCloudStorage extends AbstractData
         $name = $this->_getKey($pasteid);
         $name = $this->_getKey($pasteid);
 
 
         try {
         try {
-            foreach ($this->_bucket->objects(array('prefix' => $name . '/discussion/')) as $comment) {
+            foreach ($this->_bucket->objects(['prefix' => $name . '/discussion/']) as $comment) {
                 try {
                 try {
                     $this->_bucket->object($comment->name())->delete();
                     $this->_bucket->object($comment->name())->delete();
                 } catch (NotFoundException $e) {
                 } catch (NotFoundException $e) {
@@ -215,16 +215,16 @@ class GoogleCloudStorage extends AbstractData
      */
      */
     public function readComments($pasteid)
     public function readComments($pasteid)
     {
     {
-        $comments = array();
+        $comments = [];
         $prefix   = $this->_getKey($pasteid) . '/discussion/';
         $prefix   = $this->_getKey($pasteid) . '/discussion/';
         try {
         try {
-            foreach ($this->_bucket->objects(array('prefix' => $prefix)) as $key) {
+            foreach ($this->_bucket->objects(['prefix' => $prefix]) as $key) {
                 $data            = $this->_bucket->object($key->name())->downloadAsString();
                 $data            = $this->_bucket->object($key->name())->downloadAsString();
                 try {
                 try {
                     $comment = Json::decode($data);
                     $comment = Json::decode($data);
                 } catch (JsonException $e) {
                 } catch (JsonException $e) {
                     error_log('failed to read comment from ' . $key->name() . ', ' . $e->getMessage());
                     error_log('failed to read comment from ' . $key->name() . ', ' . $e->getMessage());
-                    $comment = array();
+                    $comment = [];
                 }
                 }
                 $comment['id']   = basename($key->name());
                 $comment['id']   = basename($key->name());
                 $slot            = $this->getOpenSlot($comments, (int) $comment['meta']['created']);
                 $slot            = $this->getOpenSlot($comments, (int) $comment['meta']['created']);
@@ -253,7 +253,7 @@ class GoogleCloudStorage extends AbstractData
     {
     {
         $path = 'config/' . $namespace;
         $path = 'config/' . $namespace;
         try {
         try {
-            foreach ($this->_bucket->objects(array('prefix' => $path)) as $object) {
+            foreach ($this->_bucket->objects(['prefix' => $path]) as $object) {
                 $name = $object->name();
                 $name = $object->name();
                 if (strlen($name) > strlen($path) && substr($name, strlen($path), 1) !== '/') {
                 if (strlen($name) > strlen($path) && substr($name, strlen($path), 1) !== '/') {
                     continue;
                     continue;
@@ -285,19 +285,19 @@ class GoogleCloudStorage extends AbstractData
             $key = 'config/' . $namespace . '/' . $key;
             $key = 'config/' . $namespace . '/' . $key;
         }
         }
 
 
-        $metadata = array('namespace' => $namespace);
+        $metadata = ['namespace' => $namespace];
         if ($namespace !== 'salt') {
         if ($namespace !== 'salt') {
             $metadata['value'] = strval($value);
             $metadata['value'] = strval($value);
         }
         }
         try {
         try {
-            $data = array(
+            $data = [
                 'name'          => $key,
                 'name'          => $key,
                 'chunkSize'     => 262144,
                 'chunkSize'     => 262144,
-                'metadata'      => array(
+                'metadata'      => [
                     'content-type' => 'application/json',
                     'content-type' => 'application/json',
                     'metadata'     => $metadata,
                     'metadata'     => $metadata,
-                ),
-            );
+                ],
+            ];
             if (!$this->_uniformacl) {
             if (!$this->_uniformacl) {
                 $data['predefinedAcl'] = 'private';
                 $data['predefinedAcl'] = 'private';
             }
             }
@@ -333,7 +333,7 @@ class GoogleCloudStorage extends AbstractData
      */
      */
     protected function _getExpiredPastes($batchsize)
     protected function _getExpiredPastes($batchsize)
     {
     {
-        $expired = array();
+        $expired = [];
 
 
         $now    = time();
         $now    = time();
         $prefix = $this->_prefix;
         $prefix = $this->_prefix;
@@ -341,7 +341,7 @@ class GoogleCloudStorage extends AbstractData
             $prefix .= '/';
             $prefix .= '/';
         }
         }
         try {
         try {
-            foreach ($this->_bucket->objects(array('prefix' => $prefix)) as $object) {
+            foreach ($this->_bucket->objects(['prefix' => $prefix]) as $object) {
                 $expire_at = $object->info()['metadata']['expire_date'] ?? '';
                 $expire_at = $object->info()['metadata']['expire_date'] ?? '';
                 if (is_numeric($expire_at) && intval($expire_at) < $now) {
                 if (is_numeric($expire_at) && intval($expire_at) < $now) {
                     array_push($expired, basename($object->name()));
                     array_push($expired, basename($object->name()));
@@ -362,14 +362,14 @@ class GoogleCloudStorage extends AbstractData
      */
      */
     public function getAllPastes()
     public function getAllPastes()
     {
     {
-        $pastes = array();
+        $pastes = [];
         $prefix = $this->_prefix;
         $prefix = $this->_prefix;
         if (!empty($prefix)) {
         if (!empty($prefix)) {
             $prefix .= '/';
             $prefix .= '/';
         }
         }
 
 
         try {
         try {
-            foreach ($this->_bucket->objects(array('prefix' => $prefix)) as $object) {
+            foreach ($this->_bucket->objects(['prefix' => $prefix]) as $object) {
                 $candidate = substr($object->name(), strlen($prefix));
                 $candidate = substr($object->name(), strlen($prefix));
                 if (!str_contains($candidate, '/')) {
                 if (!str_contains($candidate, '/')) {
                     $pastes[] = $candidate;
                     $pastes[] = $candidate;

+ 32 - 32
lib/Data/S3Storage.php

@@ -37,7 +37,7 @@ namespace PrivateBin\Data;
 
 
 use Aws\S3\Exception\S3Exception;
 use Aws\S3\Exception\S3Exception;
 use Aws\S3\S3Client;
 use Aws\S3\S3Client;
-use PrivateBin\Exception\JsonException;
+use JsonException;
 use PrivateBin\Json;
 use PrivateBin\Json;
 
 
 class S3Storage extends AbstractData
 class S3Storage extends AbstractData
@@ -56,7 +56,7 @@ class S3Storage extends AbstractData
      * @access private
      * @access private
      * @var    array
      * @var    array
      */
      */
-    private $_options = array();
+    private $_options = [];
 
 
     /**
     /**
      * S3 bucket
      * S3 bucket
@@ -85,7 +85,7 @@ class S3Storage extends AbstractData
         // AWS SDK will try to load credentials from environment if credentials are not passed via configuration
         // AWS SDK will try to load credentials from environment if credentials are not passed via configuration
         // ref: https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/guide_credentials.html#default-credential-chain
         // ref: https://docs.aws.amazon.com/sdk-for-php/v3/developer-guide/guide_credentials.html#default-credential-chain
         if (isset($options['accesskey']) && isset($options['secretkey'])) {
         if (isset($options['accesskey']) && isset($options['secretkey'])) {
-            $this->_options['credentials'] = array();
+            $this->_options['credentials'] = [];
 
 
             $this->_options['credentials']['key']    = $options['accesskey'];
             $this->_options['credentials']['key']    = $options['accesskey'];
             $this->_options['credentials']['secret'] = $options['secretkey'];
             $this->_options['credentials']['secret'] = $options['secretkey'];
@@ -121,15 +121,15 @@ class S3Storage extends AbstractData
      */
      */
     private function _listAllObjects($prefix)
     private function _listAllObjects($prefix)
     {
     {
-        $allObjects = array();
-        $options    = array(
+        $allObjects = [];
+        $options    = [
             'Bucket' => $this->_bucket,
             'Bucket' => $this->_bucket,
             'Prefix' => $prefix,
             'Prefix' => $prefix,
-        );
+        ];
 
 
         do {
         do {
             $objectsListResponse = $this->_client->listObjects($options);
             $objectsListResponse = $this->_client->listObjects($options);
-            $objects             = $objectsListResponse['Contents'] ?? array();
+            $objects             = $objectsListResponse['Contents'] ?? [];
             foreach ($objects as $object) {
             foreach ($objects as $object) {
                 $allObjects[]      = $object;
                 $allObjects[]      = $object;
                 $options['Marker'] = $object['Key'];
                 $options['Marker'] = $object['Key'];
@@ -165,19 +165,19 @@ class S3Storage extends AbstractData
      */
      */
     private function _upload($key, &$payload)
     private function _upload($key, &$payload)
     {
     {
-        $metadata = $payload['meta'] ?? array();
+        $metadata = $payload['meta'] ?? [];
         unset($metadata['salt']);
         unset($metadata['salt']);
         foreach ($metadata as $k => $v) {
         foreach ($metadata as $k => $v) {
             $metadata[$k] = strval($v);
             $metadata[$k] = strval($v);
         }
         }
         try {
         try {
-            $this->_client->putObject(array(
+            $this->_client->putObject([
                 'Bucket'      => $this->_bucket,
                 'Bucket'      => $this->_bucket,
                 'Key'         => $key,
                 'Key'         => $key,
                 'Body'        => Json::encode($payload),
                 'Body'        => Json::encode($payload),
                 'ContentType' => 'application/json',
                 'ContentType' => 'application/json',
                 'Metadata'    => $metadata,
                 'Metadata'    => $metadata,
-            ));
+            ]);
             return true;
             return true;
         } catch (S3Exception $e) {
         } catch (S3Exception $e) {
             error_log('failed to upload ' . $key . ' to ' . $this->_bucket . ', ' .
             error_log('failed to upload ' . $key . ' to ' . $this->_bucket . ', ' .
@@ -206,10 +206,10 @@ class S3Storage extends AbstractData
     public function read($pasteid)
     public function read($pasteid)
     {
     {
         try {
         try {
-            $object = $this->_client->getObject(array(
+            $object = $this->_client->getObject([
                 'Bucket' => $this->_bucket,
                 'Bucket' => $this->_bucket,
                 'Key'    => $this->_getKey($pasteid),
                 'Key'    => $this->_getKey($pasteid),
-            ));
+            ]);
             $data = $object['Body']->getContents();
             $data = $object['Body']->getContents();
             return Json::decode($data);
             return Json::decode($data);
         } catch (S3Exception $e) {
         } catch (S3Exception $e) {
@@ -232,10 +232,10 @@ class S3Storage extends AbstractData
             $comments = $this->_listAllObjects($name . '/discussion/');
             $comments = $this->_listAllObjects($name . '/discussion/');
             foreach ($comments as $comment) {
             foreach ($comments as $comment) {
                 try {
                 try {
-                    $this->_client->deleteObject(array(
+                    $this->_client->deleteObject([
                         'Bucket' => $this->_bucket,
                         'Bucket' => $this->_bucket,
                         'Key'    => $comment['Key'],
                         'Key'    => $comment['Key'],
-                    ));
+                    ]);
                 } catch (S3Exception $e) {
                 } catch (S3Exception $e) {
                     // ignore if already deleted.
                     // ignore if already deleted.
                 }
                 }
@@ -245,10 +245,10 @@ class S3Storage extends AbstractData
         }
         }
 
 
         try {
         try {
-            $this->_client->deleteObject(array(
+            $this->_client->deleteObject([
                 'Bucket' => $this->_bucket,
                 'Bucket' => $this->_bucket,
                 'Key'    => $name,
                 'Key'    => $name,
-            ));
+            ]);
         } catch (S3Exception $e) {
         } catch (S3Exception $e) {
             // ignore if already deleted
             // ignore if already deleted
         }
         }
@@ -279,15 +279,15 @@ class S3Storage extends AbstractData
      */
      */
     public function readComments($pasteid)
     public function readComments($pasteid)
     {
     {
-        $comments = array();
+        $comments = [];
         $prefix   = $this->_getKey($pasteid) . '/discussion/';
         $prefix   = $this->_getKey($pasteid) . '/discussion/';
         try {
         try {
             $entries = $this->_listAllObjects($prefix);
             $entries = $this->_listAllObjects($prefix);
             foreach ($entries as $entry) {
             foreach ($entries as $entry) {
-                $object = $this->_client->getObject(array(
+                $object = $this->_client->getObject([
                     'Bucket' => $this->_bucket,
                     'Bucket' => $this->_bucket,
                     'Key'    => $entry['Key'],
                     'Key'    => $entry['Key'],
-                ));
+                ]);
                 $data             = $object['Body']->getContents();
                 $data             = $object['Body']->getContents();
                 $body             = JSON::decode($data);
                 $body             = JSON::decode($data);
                 $items            = explode('/', $entry['Key']);
                 $items            = explode('/', $entry['Key']);
@@ -328,17 +328,17 @@ class S3Storage extends AbstractData
                 if (strlen($name) > strlen($path) && substr($name, strlen($path), 1) !== '/') {
                 if (strlen($name) > strlen($path) && substr($name, strlen($path), 1) !== '/') {
                     continue;
                     continue;
                 }
                 }
-                $head = $this->_client->headObject(array(
+                $head = $this->_client->headObject([
                     'Bucket' => $this->_bucket,
                     'Bucket' => $this->_bucket,
                     'Key'    => $name,
                     'Key'    => $name,
-                ));
+                ]);
                 $value = $head->get('Metadata')['value'] ?? '';
                 $value = $head->get('Metadata')['value'] ?? '';
                 if (is_numeric($value) && intval($value) < $time) {
                 if (is_numeric($value) && intval($value) < $time) {
                     try {
                     try {
-                        $this->_client->deleteObject(array(
+                        $this->_client->deleteObject([
                             'Bucket' => $this->_bucket,
                             'Bucket' => $this->_bucket,
                             'Key'    => $name,
                             'Key'    => $name,
-                        ));
+                        ]);
                     } catch (S3Exception $e) {
                     } catch (S3Exception $e) {
                         // deleted by another instance.
                         // deleted by another instance.
                     }
                     }
@@ -367,18 +367,18 @@ class S3Storage extends AbstractData
             $key = $prefix . 'config/' . $namespace . '/' . $key;
             $key = $prefix . 'config/' . $namespace . '/' . $key;
         }
         }
 
 
-        $metadata = array('namespace' => $namespace);
+        $metadata = ['namespace' => $namespace];
         if ($namespace !== 'salt') {
         if ($namespace !== 'salt') {
             $metadata['value'] = strval($value);
             $metadata['value'] = strval($value);
         }
         }
         try {
         try {
-            $this->_client->putObject(array(
+            $this->_client->putObject([
                 'Bucket'      => $this->_bucket,
                 'Bucket'      => $this->_bucket,
                 'Key'         => $key,
                 'Key'         => $key,
                 'Body'        => $value,
                 'Body'        => $value,
                 'ContentType' => 'application/json',
                 'ContentType' => 'application/json',
                 'Metadata'    => $metadata,
                 'Metadata'    => $metadata,
-            ));
+            ]);
         } catch (S3Exception $e) {
         } catch (S3Exception $e) {
             error_log('failed to set key ' . $key . ' to ' . $this->_bucket . ', ' .
             error_log('failed to set key ' . $key . ' to ' . $this->_bucket . ', ' .
                 trim(preg_replace('/\s\s+/', ' ', $e->getMessage())));
                 trim(preg_replace('/\s\s+/', ' ', $e->getMessage())));
@@ -404,10 +404,10 @@ class S3Storage extends AbstractData
         }
         }
 
 
         try {
         try {
-            $object = $this->_client->getObject(array(
+            $object = $this->_client->getObject([
                 'Bucket' => $this->_bucket,
                 'Bucket' => $this->_bucket,
                 'Key'    => $key,
                 'Key'    => $key,
-            ));
+            ]);
             return $object['Body']->getContents();
             return $object['Body']->getContents();
         } catch (S3Exception $e) {
         } catch (S3Exception $e) {
             return '';
             return '';
@@ -419,7 +419,7 @@ class S3Storage extends AbstractData
      */
      */
     protected function _getExpiredPastes($batchsize)
     protected function _getExpiredPastes($batchsize)
     {
     {
-        $expired = array();
+        $expired = [];
         $now     = time();
         $now     = time();
         $prefix  = $this->_prefix;
         $prefix  = $this->_prefix;
         if (!empty($prefix)) {
         if (!empty($prefix)) {
@@ -428,10 +428,10 @@ class S3Storage extends AbstractData
 
 
         try {
         try {
             foreach ($this->_listAllObjects($prefix) as $object) {
             foreach ($this->_listAllObjects($prefix) as $object) {
-                $head = $this->_client->headObject(array(
+                $head = $this->_client->headObject([
                     'Bucket' => $this->_bucket,
                     'Bucket' => $this->_bucket,
                     'Key'    => $object['Key'],
                     'Key'    => $object['Key'],
-                ));
+                ]);
                 $expire_at = $head->get('Metadata')['expire_date'] ?? '';
                 $expire_at = $head->get('Metadata')['expire_date'] ?? '';
                 if (is_numeric($expire_at) && intval($expire_at) < $now) {
                 if (is_numeric($expire_at) && intval($expire_at) < $now) {
                     array_push($expired, $object['Key']);
                     array_push($expired, $object['Key']);
@@ -452,7 +452,7 @@ class S3Storage extends AbstractData
      */
      */
     public function getAllPastes()
     public function getAllPastes()
     {
     {
-        $pastes = array();
+        $pastes = [];
         $prefix = $this->_prefix;
         $prefix = $this->_prefix;
         if (!empty($prefix)) {
         if (!empty($prefix)) {
             $prefix .= '/';
             $prefix .= '/';

+ 0 - 38
lib/Exception/JsonException.php

@@ -1,38 +0,0 @@
-<?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\Exception;
-
-use Exception;
-
-/**
- * JsonException
- *
- * An Exception representing JSON en- or decoding errors.
- */
-class JsonException extends Exception
-{
-    /**
-     * Exception constructor with mandatory JSON error code.
-     *
-     * @access public
-     * @param  int $code
-     */
-    public function __construct(int $code)
-    {
-        $message = 'A JSON error occurred';
-        if (function_exists('json_last_error_msg')) {
-            $message .= ': ' . json_last_error_msg();
-        }
-        $message .= ' (' . $code . ')';
-        parent::__construct($message, 90);
-    }
-}

+ 2 - 2
lib/Filter.php

@@ -46,7 +46,7 @@ class Filter
             default:
             default:
                 $unit = rtrim($matches[2], 's');
                 $unit = rtrim($matches[2], 's');
         }
         }
-        return I18n::_(array('%d ' . $unit, '%d ' . $unit . 's'), (int) $matches[1]);
+        return I18n::_(['%d ' . $unit, '%d ' . $unit . 's'], (int) $matches[1]);
     }
     }
 
 
     /**
     /**
@@ -59,7 +59,7 @@ class Filter
      */
      */
     public static function formatHumanReadableSize($size)
     public static function formatHumanReadableSize($size)
     {
     {
-        $iec = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
+        $iec = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
         $i   = 0;
         $i   = 0;
         while (($size / 1000) >= 1) {
         while (($size / 1000) >= 1) {
             $size = $size / 1000;
             $size = $size / 1000;

+ 21 - 6
lib/FormatV2.php

@@ -31,7 +31,7 @@ class FormatV2
      */
      */
     public static function isValid(&$message, $isComment = false)
     public static function isValid(&$message, $isComment = false)
     {
     {
-        $required_keys = array('adata', 'v', 'ct');
+        $required_keys = ['adata', 'v', 'ct'];
         if ($isComment) {
         if ($isComment) {
             $required_keys[] = 'pasteid';
             $required_keys[] = 'pasteid';
             $required_keys[] = 'parentid';
             $required_keys[] = 'parentid';
@@ -56,7 +56,21 @@ class FormatV2
             return false;
             return false;
         }
         }
 
 
-        $cipherParams = $isComment ? $message['adata'] : $message['adata'][0];
+        $cipherParams = $isComment ? $message['adata'] : ($message['adata'][0] ?? null);
+
+        // Make sure the cipher parameters are a properly sized array.
+        if (!is_array($cipherParams) || count($cipherParams) < 8) {
+            return false;
+        }
+
+        // Make sure the ciphertext and the cipher parameters used in the
+        // string operations below are actually strings, so that malformed
+        // input yields "Invalid data." instead of a fatal type error.
+        if (!is_string($message['ct']) ||
+            !is_string($cipherParams[0] ?? null) ||
+            !is_string($cipherParams[1] ?? null)) {
+            return false;
+        }
 
 
         // Make sure some fields are base64 data:
         // Make sure some fields are base64 data:
         // - initialization vector
         // - initialization vector
@@ -92,11 +106,11 @@ class FormatV2
             return false;
             return false;
         }
         }
         // - key size
         // - key size
-        if (!in_array($cipherParams[3], array(128, 192, 256), true)) {
+        if (!in_array($cipherParams[3], [128, 192, 256], true)) {
             return false;
             return false;
         }
         }
         // - tag size
         // - tag size
-        if (!in_array($cipherParams[4], array(64, 96, 128), true)) {
+        if (!in_array($cipherParams[4], [64, 96, 128], true)) {
             return false;
             return false;
         }
         }
         // - algorithm, must be AES
         // - algorithm, must be AES
@@ -104,11 +118,11 @@ class FormatV2
             return false;
             return false;
         }
         }
         // - mode
         // - mode
-        if (!in_array($cipherParams[6], array('ctr', 'cbc', 'gcm'), true)) {
+        if (!in_array($cipherParams[6], ['ctr', 'cbc', 'gcm'], true)) {
             return false;
             return false;
         }
         }
         // - compression
         // - compression
-        if (!in_array($cipherParams[7], array('zlib', 'none'), true)) {
+        if (!in_array($cipherParams[7], ['zlib', 'none'], true)) {
             return false;
             return false;
         }
         }
 
 
@@ -119,6 +133,7 @@ class FormatV2
 
 
         // require only the key 'expire' in the metadata of pastes
         // require only the key 'expire' in the metadata of pastes
         if (!$isComment && (
         if (!$isComment && (
+            !is_array($message['meta']) ||
             count($message['meta']) === 0 ||
             count($message['meta']) === 0 ||
             !array_key_exists('expire', $message['meta']) ||
             !array_key_exists('expire', $message['meta']) ||
             count($message['meta']) > 1
             count($message['meta']) > 1

+ 10 - 10
lib/I18n.php

@@ -46,7 +46,7 @@ class I18n
      * @static
      * @static
      * @var    array
      * @var    array
      */
      */
-    protected static $_languageLabels = array();
+    protected static $_languageLabels = [];
 
 
     /**
     /**
      * available languages
      * available languages
@@ -55,7 +55,7 @@ class I18n
      * @static
      * @static
      * @var    array
      * @var    array
      */
      */
-    protected static $_availableLanguages = array();
+    protected static $_availableLanguages = [];
 
 
     /**
     /**
      * path to language files
      * path to language files
@@ -73,7 +73,7 @@ class I18n
      * @static
      * @static
      * @var    array
      * @var    array
      */
      */
-    protected static $_translations = array();
+    protected static $_translations = [];
 
 
     /**
     /**
      * translate a string, alias for translate()
      * translate a string, alias for translate()
@@ -183,7 +183,7 @@ class I18n
 
 
         // load translations
         // load translations
         if (self::$_language === 'en') {
         if (self::$_language === 'en') {
-            self::$_translations = array();
+            self::$_translations = [];
         } else {
         } else {
             $data                = file_get_contents(self::_getPath(self::$_language . '.json'));
             $data                = file_get_contents(self::_getPath(self::$_language . '.json'));
             self::$_translations = Json::decode($data);
             self::$_translations = Json::decode($data);
@@ -225,7 +225,7 @@ class I18n
      */
      */
     public static function getBrowserLanguages()
     public static function getBrowserLanguages()
     {
     {
-        $languages = array();
+        $languages = [];
         if (array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER)) {
         if (array_key_exists('HTTP_ACCEPT_LANGUAGE', $_SERVER)) {
             $languageRanges = explode(',', trim($_SERVER['HTTP_ACCEPT_LANGUAGE']));
             $languageRanges = explode(',', trim($_SERVER['HTTP_ACCEPT_LANGUAGE']));
             foreach ($languageRanges as $languageRange) {
             foreach ($languageRanges as $languageRange) {
@@ -239,7 +239,7 @@ class I18n
                         $match[2] = (string) floatval($match[2]);
                         $match[2] = (string) floatval($match[2]);
                     }
                     }
                     if (!isset($languages[$match[2]])) {
                     if (!isset($languages[$match[2]])) {
-                        $languages[$match[2]] = array();
+                        $languages[$match[2]] = [];
                     }
                     }
                     $languages[$match[2]][] = strtolower($match[1]);
                     $languages[$match[2]][] = strtolower($match[1]);
                 }
                 }
@@ -272,7 +272,7 @@ class I18n
      * @throws JsonException
      * @throws JsonException
      * @return array
      * @return array
      */
      */
-    public static function getLanguageLabels($languages = array())
+    public static function getLanguageLabels($languages = [])
     {
     {
         $file = self::_getPath('languages.json');
         $file = self::_getPath('languages.json');
         if (count(self::$_languageLabels) === 0 && is_readable($file)) {
         if (count(self::$_languageLabels) === 0 && is_readable($file)) {
@@ -294,7 +294,7 @@ class I18n
      */
      */
     public static function isRtl()
     public static function isRtl()
     {
     {
-        return in_array(self::$_language, array('ar', 'he'));
+        return in_array(self::$_language, ['ar', 'he']);
     }
     }
 
 
     /**
     /**
@@ -402,7 +402,7 @@ class I18n
      */
      */
     protected static function _getMatchingLanguage($acceptedLanguages, $availableLanguages)
     protected static function _getMatchingLanguage($acceptedLanguages, $availableLanguages)
     {
     {
-        $matches = array();
+        $matches = [];
         $any     = false;
         $any     = false;
         foreach ($acceptedLanguages as $acceptedQuality => $acceptedValues) {
         foreach ($acceptedLanguages as $acceptedQuality => $acceptedValues) {
             $acceptedQuality = floatval($acceptedQuality);
             $acceptedQuality = floatval($acceptedQuality);
@@ -419,7 +419,7 @@ class I18n
                     if ($matchingGrade > 0) {
                     if ($matchingGrade > 0) {
                         $q = (string) ($acceptedQuality * $availableQuality * $matchingGrade);
                         $q = (string) ($acceptedQuality * $availableQuality * $matchingGrade);
                         if (!isset($matches[$q])) {
                         if (!isset($matches[$q])) {
-                            $matches[$q] = array();
+                            $matches[$q] = [];
                         }
                         }
                         if (!in_array($availableValue, $matches[$q])) {
                         if (!in_array($availableValue, $matches[$q])) {
                             $matches[$q][] = $availableValue;
                             $matches[$q][] = $availableValue;

+ 2 - 24
lib/Json.php

@@ -11,8 +11,6 @@
 
 
 namespace PrivateBin;
 namespace PrivateBin;
 
 
-use PrivateBin\Exception\JsonException;
-
 /**
 /**
  * Json
  * Json
  *
  *
@@ -31,9 +29,7 @@ class Json
      */
      */
     public static function encode(&$input)
     public static function encode(&$input)
     {
     {
-        $jsonString = json_encode($input);
-        self::_detectError();
-        return $jsonString;
+        return json_encode($input, JSON_THROW_ON_ERROR);
     }
     }
 
 
     /**
     /**
@@ -47,24 +43,6 @@ class Json
      */
      */
     public static function decode(&$input)
     public static function decode(&$input)
     {
     {
-        $output = json_decode($input, true);
-        self::_detectError();
-        return $output;
-    }
-
-    /**
-     * Detects JSON errors and raises an exception if one is found
-     *
-     * @access private
-     * @static
-     * @throws JsonException
-     * @return void
-     */
-    private static function _detectError()
-    {
-        $errorCode = json_last_error();
-        if ($errorCode !== JSON_ERROR_NONE) {
-            throw new JsonException($errorCode);
-        }
+        return json_decode($input, true, 10, JSON_THROW_ON_ERROR);
     }
     }
 }
 }

+ 1 - 1
lib/Model/AbstractModel.php

@@ -50,7 +50,7 @@ abstract class AbstractModel
      * @access protected
      * @access protected
      * @var array
      * @var array
      */
      */
-    protected $_data = array('meta' => array());
+    protected $_data = ['meta' => []];
 
 
     /**
     /**
      * Configuration.
      * Configuration.

+ 5 - 5
lib/Model/Comment.php

@@ -155,14 +155,14 @@ class Comment extends AbstractModel
                 $identicon = new Identicon();
                 $identicon = new Identicon();
                 $pngdata   = $identicon->getImageDataUri($hmac, 16);
                 $pngdata   = $identicon->getImageDataUri($hmac, 16);
             } elseif ($icon === 'jdenticon') {
             } elseif ($icon === 'jdenticon') {
-                $jdenticon = new Jdenticon(array(
+                $jdenticon = new Jdenticon([
                     'hash'  => $hmac,
                     'hash'  => $hmac,
                     'size'  => 16,
                     'size'  => 16,
-                    'style' => array(
+                    'style' => [
                         'backgroundColor'   => '#fff0', // fully transparent, for dark mode
                         'backgroundColor'   => '#fff0', // fully transparent, for dark mode
                         'padding'           => 0,
                         'padding'           => 0,
-                    ),
-                ));
+                    ],
+                ]);
                 $pngdata   = $jdenticon->getImageDataUri('png');
                 $pngdata   = $jdenticon->getImageDataUri('png');
             } elseif ($icon === 'vizhash') {
             } elseif ($icon === 'vizhash') {
                 $vh      = new Vizhash16x16();
                 $vh      = new Vizhash16x16();
@@ -172,7 +172,7 @@ class Comment extends AbstractModel
             }
             }
             if (!empty($pngdata)) {
             if (!empty($pngdata)) {
                 if (!array_key_exists('meta', $data)) {
                 if (!array_key_exists('meta', $data)) {
-                    $data['meta'] = array();
+                    $data['meta'] = [];
                 }
                 }
                 $data['meta']['icon'] = $pngdata;
                 $data['meta']['icon'] = $pngdata;
             }
             }

+ 2 - 2
lib/Persistence/TrafficLimiter.php

@@ -209,9 +209,9 @@ class TrafficLimiter extends AbstractPersistence
             }
             }
             return true;
             return true;
         }
         }
-        throw new TranslatedException(array(
+        throw new TranslatedException([
             'Please wait %d seconds between each post.',
             'Please wait %d seconds between each post.',
             self::$_limit,
             self::$_limit,
-        ));
+        ]);
     }
     }
 }
 }

+ 4 - 4
lib/Proxy/AbstractProxy.php

@@ -11,8 +11,8 @@
 
 
 namespace PrivateBin\Proxy;
 namespace PrivateBin\Proxy;
 
 
+use JsonException;
 use PrivateBin\Configuration;
 use PrivateBin\Configuration;
-use PrivateBin\Exception\JsonException;
 use PrivateBin\Json;
 use PrivateBin\Json;
 
 
 /**
 /**
@@ -71,14 +71,14 @@ abstract class AbstractProxy
 
 
         $data = file_get_contents($proxyUrl, false,
         $data = file_get_contents($proxyUrl, false,
             stream_context_create(
             stream_context_create(
-                array(
+                [
                     'http' => $this->_getProxyPayload($conf, $link),
                     'http' => $this->_getProxyPayload($conf, $link),
-                )
+                ]
             )
             )
         );
         );
 
 
         if ($data === false) {
         if ($data === false) {
-            $http_response_header = $http_response_header ?? array();
+            $http_response_header = $http_response_header ?? [];
             $statusCode           = '';
             $statusCode           = '';
             if (!empty($http_response_header) && preg_match('/HTTP\/\d+\.\d+\s+(\d+)/', $http_response_header[0], $matches)) {
             if (!empty($http_response_header) && preg_match('/HTTP\/\d+\.\d+\s+(\d+)/', $http_response_header[0], $matches)) {
                 $statusCode = $matches[1];
                 $statusCode = $matches[1];

+ 6 - 6
lib/Proxy/ShlinkProxy.php

@@ -11,8 +11,8 @@
 
 
 namespace PrivateBin\Proxy;
 namespace PrivateBin\Proxy;
 
 
+use JsonException;
 use PrivateBin\Configuration;
 use PrivateBin\Configuration;
-use PrivateBin\Exception\JsonException;
 use PrivateBin\Json;
 use PrivateBin\Json;
 
 
 /**
 /**
@@ -45,20 +45,20 @@ class ShlinkProxy extends AbstractProxy
     {
     {
         $shlink_api_key = $conf->getKey('apikey', 'shlink');
         $shlink_api_key = $conf->getKey('apikey', 'shlink');
 
 
-        $body = array(
+        $body = [
             'longUrl' => $link,
             'longUrl' => $link,
-        );
+        ];
 
 
         try {
         try {
-            return array(
+            return [
                 'method'  => 'POST',
                 'method'  => 'POST',
                 'header'  => "Content-Type: application/json\r\n" .
                 'header'  => "Content-Type: application/json\r\n" .
                             'X-Api-Key: ' . $shlink_api_key . "\r\n",
                             'X-Api-Key: ' . $shlink_api_key . "\r\n",
                 'content' => Json::encode($body),
                 'content' => Json::encode($body),
-            );
+            ];
         } catch (JsonException $e) {
         } catch (JsonException $e) {
             error_log('[' . get_class($this) . '] Error encoding body: ' . $e->getMessage());
             error_log('[' . get_class($this) . '] Error encoding body: ' . $e->getMessage());
-            return array();
+            return [];
         }
         }
     }
     }
 
 

+ 5 - 5
lib/Proxy/YourlsProxy.php

@@ -42,18 +42,18 @@ class YourlsProxy extends AbstractProxy
      */
      */
     protected function _getProxyPayload(Configuration $conf, string $link): array
     protected function _getProxyPayload(Configuration $conf, string $link): array
     {
     {
-        return array(
+        return [
             'method'  => 'POST',
             'method'  => 'POST',
             'header'  => "Content-Type: application/x-www-form-urlencoded\r\n",
             'header'  => "Content-Type: application/x-www-form-urlencoded\r\n",
             'content' => http_build_query(
             'content' => http_build_query(
-                array(
+                [
                     'signature' => $conf->getKey('signature', 'yourls'),
                     'signature' => $conf->getKey('signature', 'yourls'),
                     'format'    => 'json',
                     'format'    => 'json',
                     'action'    => 'shorturl',
                     'action'    => 'shorturl',
                     'url'       => $link,
                     'url'       => $link,
-                )
+                ]
             ),
             ),
-        );
+        ];
     }
     }
 
 
     /**
     /**
@@ -66,7 +66,7 @@ class YourlsProxy extends AbstractProxy
     protected function _extractShortUrl(array $data): ?string
     protected function _extractShortUrl(array $data): ?string
     {
     {
         if ((int) ($data['statusCode'] ?? 0) === 200) {
         if ((int) ($data['statusCode'] ?? 0) === 200) {
-            return $data['shorturl'] ?? 0;
+            return $data['shorturl'] ?? null;
         }
         }
         return null;
         return null;
     }
     }

+ 14 - 11
lib/Request.php

@@ -11,7 +11,7 @@
 
 
 namespace PrivateBin;
 namespace PrivateBin;
 
 
-use PrivateBin\Exception\JsonException;
+use JsonException;
 use PrivateBin\Model\Paste;
 use PrivateBin\Model\Paste;
 
 
 /**
 /**
@@ -64,7 +64,7 @@ class Request
      * @access private
      * @access private
      * @var array
      * @var array
      */
      */
-    private $_params = array();
+    private $_params = [];
 
 
     /**
     /**
      * If we are in a JSON API context
      * If we are in a JSON API context
@@ -113,19 +113,24 @@ class Request
                 try {
                 try {
                     $data          = file_get_contents(self::$_inputStream);
                     $data          = file_get_contents(self::$_inputStream);
                     $this->_params = Json::decode($data);
                     $this->_params = Json::decode($data);
+                    // a valid JSON scalar (number, bool or string) decodes
+                    // without error, but is not a usable set of parameters
+                    if (!is_array($this->_params)) {
+                        $this->_params = [];
+                    }
                 } catch (JsonException $e) {
                 } catch (JsonException $e) {
                     // ignore error, $this->_params will remain empty
                     // ignore error, $this->_params will remain empty
                 }
                 }
                 break;
                 break;
             default:
             default:
-                $this->_params = filter_var_array($_GET, array(
+                $this->_params = filter_var_array($_GET, [
                     'deletetoken'      => FILTER_SANITIZE_SPECIAL_CHARS,
                     'deletetoken'      => FILTER_SANITIZE_SPECIAL_CHARS,
                     'jsonld'           => FILTER_SANITIZE_SPECIAL_CHARS,
                     'jsonld'           => FILTER_SANITIZE_SPECIAL_CHARS,
                     'link'             => FILTER_SANITIZE_URL,
                     'link'             => FILTER_SANITIZE_URL,
                     'pasteid'          => FILTER_SANITIZE_SPECIAL_CHARS,
                     'pasteid'          => FILTER_SANITIZE_SPECIAL_CHARS,
                     'shortenviayourls' => FILTER_SANITIZE_SPECIAL_CHARS,
                     'shortenviayourls' => FILTER_SANITIZE_SPECIAL_CHARS,
                     'shortenviashlink' => FILTER_SANITIZE_SPECIAL_CHARS,
                     'shortenviashlink' => FILTER_SANITIZE_SPECIAL_CHARS,
-                ), false);
+                ], false);
         }
         }
         if (
         if (
             !array_key_exists('pasteid', $this->_params) &&
             !array_key_exists('pasteid', $this->_params) &&
@@ -175,10 +180,10 @@ class Request
      */
      */
     public function getData()
     public function getData()
     {
     {
-        $data = array(
+        $data = [
             'adata' => $this->getParam('adata'),
             'adata' => $this->getParam('adata'),
-        );
-        $required_keys = array('v', 'ct');
+        ];
+        $required_keys = ['v', 'ct'];
         $meta          = $this->getParam('meta');
         $meta          = $this->getParam('meta');
         if (empty($meta)) {
         if (empty($meta)) {
             $required_keys[] = 'pasteid';
             $required_keys[] = 'pasteid';
@@ -189,8 +194,6 @@ class Request
         foreach ($required_keys as $key) {
         foreach ($required_keys as $key) {
             $data[$key] = $this->getParam($key, $key === 'v' ? 1 : '');
             $data[$key] = $this->getParam($key, $key === 'v' ? 1 : '');
         }
         }
-        // forcing a cast to int or float
-        $data['v'] = $data['v'] + 0;
         return $data;
         return $data;
     }
     }
 
 
@@ -278,7 +281,7 @@ class Request
 
 
         // advanced case: media type negotiation
         // advanced case: media type negotiation
         if (!empty($acceptHeader)) {
         if (!empty($acceptHeader)) {
-            $mediaTypes = array();
+            $mediaTypes = [];
             foreach (explode(',', trim($acceptHeader)) as $mediaTypeRange) {
             foreach (explode(',', trim($acceptHeader)) as $mediaTypeRange) {
                 if (preg_match(
                 if (preg_match(
                     '#(\*/\*|[a-z\-]+/[a-z\-+*]+(?:\s*;\s*[^q]\S*)*)(?:\s*;\s*q\s*=\s*(0(?:\.\d{0,3})|1(?:\.0{0,3})))?#',
                     '#(\*/\*|[a-z\-]+/[a-z\-+*]+(?:\s*;\s*[^q]\S*)*)(?:\s*;\s*q\s*=\s*(0(?:\.\d{0,3})|1(?:\.0{0,3})))?#',
@@ -293,7 +296,7 @@ class Request
                         }
                         }
                     }
                     }
                     if (!isset($mediaTypes[$match[2]])) {
                     if (!isset($mediaTypes[$match[2]])) {
-                        $mediaTypes[$match[2]] = array();
+                        $mediaTypes[$match[2]] = [];
                     }
                     }
                     $mediaTypes[$match[2]][] = strtolower($match[1]);
                     $mediaTypes[$match[2]][] = strtolower($match[1]);
                 }
                 }

+ 1 - 1
lib/TemplateSwitcher.php

@@ -34,7 +34,7 @@ class TemplateSwitcher
      * @static
      * @static
      * @var    array
      * @var    array
      */
      */
-    protected static $_availableTemplates = array();
+    protected static $_availableTemplates = [];
 
 
     /**
     /**
      * set available templates
      * set available templates

+ 1 - 1
lib/View.php

@@ -26,7 +26,7 @@ class View
      * @access private
      * @access private
      * @var    array
      * @var    array
      */
      */
-    private $_variables = array();
+    private $_variables = [];
 
 
     /**
     /**
      * assign variables to be used inside of the template
      * assign variables to be used inside of the template

+ 5 - 5
lib/Vizhash16x16.php

@@ -85,7 +85,7 @@ class Vizhash16x16
         $textlen = strlen($text);
         $textlen = strlen($text);
 
 
         // We convert the hash into an array of integers.
         // We convert the hash into an array of integers.
-        $this->VALUES = array();
+        $this->VALUES = [];
         for ($i = 0; $i < $textlen; $i = $i + 2) {
         for ($i = 0; $i < $textlen; $i = $i + 2) {
             array_push($this->VALUES, hexdec(substr($text, $i, 2)));
             array_push($this->VALUES, hexdec(substr($text, $i, 2)));
         }
         }
@@ -106,7 +106,7 @@ class Vizhash16x16
         if (($this->getInt() % 2) === 0) {
         if (($this->getInt() % 2) === 0) {
             $op = 'h';
             $op = 'h';
         }
         }
-        $image = $this->degrade($image, $op, array($r0, $g0, $b0), array(0, 0, 0));
+        $image = $this->degrade($image, $op, [$r0, $g0, $b0], [0, 0, 0]);
 
 
         for ($i = 0; $i < 7; ++$i) {
         for ($i = 0; $i < 7; ++$i) {
             $action = $this->getInt();
             $action = $this->getInt();
@@ -186,11 +186,11 @@ class Vizhash16x16
             $size    = imagesy($img);
             $size    = imagesy($img);
             $sizeinv = imagesx($img);
             $sizeinv = imagesx($img);
         }
         }
-        $diffs = array(
+        $diffs = [
             ($color2[0] - $color1[0]) / $size,
             ($color2[0] - $color1[0]) / $size,
             ($color2[1] - $color1[1]) / $size,
             ($color2[1] - $color1[1]) / $size,
             ($color2[2] - $color1[2]) / $size,
             ($color2[2] - $color1[2]) / $size,
-        );
+        ];
         for ($i = 0; $i < $size; ++$i) {
         for ($i = 0; $i < $size; ++$i) {
             $r = $color1[0] + ((int) $diffs[0] * $i);
             $r = $color1[0] + ((int) $diffs[0] * $i);
             $g = $color1[1] + ((int) $diffs[1] * $i);
             $g = $color1[1] + ((int) $diffs[1] * $i);
@@ -223,7 +223,7 @@ class Vizhash16x16
                 imagefilledellipse($image, $this->getX(), $this->getY(), $this->getX(), $this->getY(), $color);
                 imagefilledellipse($image, $this->getX(), $this->getY(), $this->getX(), $this->getY(), $color);
                 break;
                 break;
             case 3:
             case 3:
-                $points = array($this->getX(), $this->getY(), $this->getX(), $this->getY(), $this->getX(), $this->getY(), $this->getX(), $this->getY());
+                $points = [$this->getX(), $this->getY(), $this->getX(), $this->getY(), $this->getX(), $this->getY(), $this->getX(), $this->getY()];
                 version_compare(PHP_VERSION, '8.1', '<') ? imagefilledpolygon($image, $points, 4, $color) : imagefilledpolygon($image, $points, $color);
                 version_compare(PHP_VERSION, '8.1', '<') ? imagefilledpolygon($image, $points, 4, $color) : imagefilledpolygon($image, $points, $color);
                 break;
                 break;
             default:
             default:

+ 1 - 1
tpl/bootstrap5.php

@@ -49,7 +49,7 @@ if ($MARKDOWN) :
 <?php
 <?php
 endif;
 endif;
 ?>
 ?>
-		<?php $this->_scriptTag('js/purify-3.4.1.js', 'defer'); ?>
+		<?php $this->_scriptTag('js/purify-3.4.12.js', 'defer'); ?>
 		<?php $this->_scriptTag('js/legacy.js', 'defer'); ?>
 		<?php $this->_scriptTag('js/legacy.js', 'defer'); ?>
 		<?php $this->_scriptTag('js/privatebin.js', 'defer'); ?>
 		<?php $this->_scriptTag('js/privatebin.js', 'defer'); ?>
 		<!-- icon -->
 		<!-- icon -->

+ 101 - 101
tst/Bootstrap.php

@@ -47,9 +47,9 @@ class Helper
      *
      *
      * @var array
      * @var array
      */
      */
-    private static $pasteV2 = array(
-        'adata' => array(
-            array(
+    private static $pasteV2 = [
+        'adata' => [
+            [
                 'gMSNoLOk4z0RnmsYwXZ8mw==',
                 'gMSNoLOk4z0RnmsYwXZ8mw==',
                 'TZO+JWuIuxs=',
                 'TZO+JWuIuxs=',
                 100000,
                 100000,
@@ -58,17 +58,17 @@ class Helper
                 'aes',
                 'aes',
                 'gcm',
                 'gcm',
                 'zlib',
                 'zlib',
-            ),
+            ],
             'plaintext',
             'plaintext',
             1,
             1,
             0,
             0,
-        ),
-        'meta' => array(
+        ],
+        'meta' => [
             'expire'  => '5min',
             'expire'  => '5min',
-        ),
+        ],
         'v'  => 2,
         'v'  => 2,
         'ct' => 'ME5JF/YBEijp2uYMzLZozbKtWc5wfy6R59NBb7SmRig=',
         'ct' => 'ME5JF/YBEijp2uYMzLZozbKtWc5wfy6R59NBb7SmRig=',
-    );
+    ];
 
 
     /**
     /**
      * example ID of a comment
      * example ID of a comment
@@ -82,17 +82,17 @@ class Helper
      *
      *
      * @var array
      * @var array
      */
      */
-    private static $commentV2 = array(
+    private static $commentV2 = [
         'icon'    => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGUlEQVQokWOsl5/94983CNKQMjnxaOePf98MeKwPfNjkLZ3AgARab6b9+PeNEVnDj3/ff/z7ZiHnzsDA8Pv7H2TVPJw8EAYLAwb48OaVgIgYKycLsrYv378wMDB8//qdCVMDRA9EKSsnCwRBxNsepaLboMFlyMDAICAi9uHNK24GITQ/MDAwoNhgIGMLtwGrzegaLjw5jMz9+vUdnN17uwDCQDhJgk0O07yvX9+teDX1x79v6DYIsIjgcgMaYGFgYOBg4kJx2JejkAiBxAw+PzAwMNz4dp6wDXDw4MdNNOl0rWYsNkD89OLXI/xmo9sgzatJjAYmBgYGDiauD3/ePP18nVgb4MF89+M5ZX6js293wUMpnr8KTQMAxsCJnJ30apMAAAAASUVORK5CYII=',
         'icon'    => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGUlEQVQokWOsl5/94983CNKQMjnxaOePf98MeKwPfNjkLZ3AgARab6b9+PeNEVnDj3/ff/z7ZiHnzsDA8Pv7H2TVPJw8EAYLAwb48OaVgIgYKycLsrYv378wMDB8//qdCVMDRA9EKSsnCwRBxNsepaLboMFlyMDAICAi9uHNK24GITQ/MDAwoNhgIGMLtwGrzegaLjw5jMz9+vUdnN17uwDCQDhJgk0O07yvX9+teDX1x79v6DYIsIjgcgMaYGFgYOBg4kJx2JejkAiBxAw+PzAwMNz4dp6wDXDw4MdNNOl0rWYsNkD89OLXI/xmo9sgzatJjAYmBgYGDiauD3/ePP18nVgb4MF89+M5ZX6js293wUMpnr8KTQMAxsCJnJ30apMAAAAASUVORK5CYII=',
         'created' => 1344803528,
         'created' => 1344803528,
-    );
+    ];
 
 
     /**
     /**
      * JS files and their SRI hashes
      * JS files and their SRI hashes
      *
      *
      * @var array
      * @var array
      */
      */
-    private static $hashes = array();
+    private static $hashes = [];
 
 
     /**
     /**
      * get example paste ID
      * get example paste ID
@@ -110,7 +110,7 @@ class Helper
      * @param  array $meta
      * @param  array $meta
      * @return array
      * @return array
      */
      */
-    public static function getPaste(array $meta = array()): array
+    public static function getPaste(array $meta = []): array
     {
     {
         $example                 = self::$pasteV2;
         $example                 = self::$pasteV2;
         $example['meta']['salt'] = ServerSalt::generate();
         $example['meta']['salt'] = ServerSalt::generate();
@@ -124,10 +124,10 @@ class Helper
      * @param  array $meta
      * @param  array $meta
      * @return array
      * @return array
      */
      */
-    public static function getPastePost(array $meta = array()): array
+    public static function getPastePost(array $meta = []): array
     {
     {
         $example         = self::getPaste($meta);
         $example         = self::getPaste($meta);
-        $example['meta'] = array('expire' => $example['meta']['expire']);
+        $example['meta'] = ['expire' => $example['meta']['expire']];
         return $example;
         return $example;
     }
     }
 
 
@@ -137,7 +137,7 @@ class Helper
      * @param  array $meta
      * @param  array $meta
      * @return string
      * @return string
      */
      */
-    public static function getPasteJson(array $meta = array()): string
+    public static function getPasteJson(array $meta = []): string
     {
     {
         return json_encode(self::getPastePost($meta));
         return json_encode(self::getPastePost($meta));
     }
     }
@@ -158,7 +158,7 @@ class Helper
      * @param  array $meta
      * @param  array $meta
      * @return array
      * @return array
      */
      */
-    public static function getComment(array $meta = array()): array
+    public static function getComment(array $meta = []): array
     {
     {
         $example            = self::$pasteV2;
         $example            = self::$pasteV2;
         $example['adata']   = $example['adata'][0];
         $example['adata']   = $example['adata'][0];
@@ -319,7 +319,7 @@ class Helper
     public static function varExportMin($var, $return = false): string
     public static function varExportMin($var, $return = false): string
     {
     {
         if (is_array($var)) {
         if (is_array($var)) {
-            $toImplode = array();
+            $toImplode = [];
             foreach ($var as $key => $value) {
             foreach ($var as $key => $value) {
                 $toImplode[] = var_export($key, true) . ' => ' . self::varExportMin($value, true);
                 $toImplode[] = var_export($key, true) . ' => ' . self::varExportMin($value, true);
             }
             }
@@ -383,12 +383,12 @@ class BucketStub extends Bucket
     private $_connection;
     private $_connection;
     private $_client;
     private $_client;
 
 
-    public function __construct(ConnectionInterface $connection, $name, array $info = array(), $client = null)
+    public function __construct(ConnectionInterface $connection, $name, array $info = [], $client = null)
     {
     {
         $this->_name       = $name;
         $this->_name       = $name;
         $this->_info       = $info;
         $this->_info       = $info;
         $this->_connection = $connection;
         $this->_connection = $connection;
-        $this->_objects    = array();
+        $this->_objects    = [];
         $this->_client     = $client;
         $this->_client     = $client;
     }
     }
 
 
@@ -402,12 +402,12 @@ class BucketStub extends Bucket
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function exists(array $options = array())
+    public function exists(array $options = [])
     {
     {
         return true;
         return true;
     }
     }
 
 
-    public function upload($data, array $options = array())
+    public function upload($data, array $options = [])
     {
     {
         if (!is_string($data) || !array_key_exists('name', $options)) {
         if (!is_string($data) || !array_key_exists('name', $options)) {
             throw new BadMethodCallException('not supported by this stub');
             throw new BadMethodCallException('not supported by this stub');
@@ -420,27 +420,27 @@ class BucketStub extends Bucket
         $o->setData($data);
         $o->setData($data);
     }
     }
 
 
-    public function uploadAsync($data, array $options = array())
+    public function uploadAsync($data, array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function getResumableUploader($data, array $options = array())
+    public function getResumableUploader($data, array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function getStreamableUploader($data, array $options = array())
+    public function getStreamableUploader($data, array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function object($name, array $options = array())
+    public function object($name, array $options = [])
     {
     {
         return $this->_objects[$name] ?? new StorageObjectStub($this->_connection, $name, $this, null, $options);
         return $this->_objects[$name] ?? new StorageObjectStub($this->_connection, $name, $this, null, $options);
     }
     }
 
 
-    public function objects(array $options = array())
+    public function objects(array $options = [])
     {
     {
         $prefix = $options['prefix'] ?? '';
         $prefix = $options['prefix'] ?? '';
 
 
@@ -452,7 +452,7 @@ class BucketStub extends Bucket
         );
         );
     }
     }
 
 
-    public function createNotification($topic, array $options = array())
+    public function createNotification($topic, array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
@@ -462,32 +462,32 @@ class BucketStub extends Bucket
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function notifications(array $options = array())
+    public function notifications(array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function delete(array $options = array())
+    public function delete(array $options = [])
     {
     {
         $this->_client->deleteBucket($this->_name);
         $this->_client->deleteBucket($this->_name);
     }
     }
 
 
-    public function update(array $options = array())
+    public function update(array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function compose(array $sourceObjects, $name, array $options = array())
+    public function compose(array $sourceObjects, $name, array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function info(array $options = array())
+    public function info(array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function reload(array $options = array())
+    public function reload(array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
@@ -497,12 +497,12 @@ class BucketStub extends Bucket
         return $this->_name;
         return $this->_name;
     }
     }
 
 
-    public static function lifecycle(array $lifecycle = array())
+    public static function lifecycle(array $lifecycle = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function currentLifecycle(array $options = array())
+    public function currentLifecycle(array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
@@ -517,17 +517,17 @@ class BucketStub extends Bucket
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function lockRetentionPolicy(array $options = array())
+    public function lockRetentionPolicy(array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function signedUrl($expires, array $options = array())
+    public function signedUrl($expires, array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function generateSignedPostPolicyV4($objectName, $expires, array $options = array())
+    public function generateSignedPostPolicyV4($objectName, $expires, array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
@@ -546,7 +546,7 @@ class StorageObjectStub extends StorageObject
     private $_exists = false;
     private $_exists = false;
     private $_connection;
     private $_connection;
 
 
-    public function __construct(ConnectionInterface $connection, $name, $bucket, $generation = null, array $info = array(), $encryptionKey = null, $encryptionKeySHA256 = null)
+    public function __construct(ConnectionInterface $connection, $name, $bucket, $generation = null, array $info = [], $encryptionKey = null, $encryptionKeySHA256 = null)
     {
     {
         $this->_name                            = $name;
         $this->_name                            = $name;
         $this->_bucket                          = $bucket;
         $this->_bucket                          = $bucket;
@@ -562,7 +562,7 @@ class StorageObjectStub extends StorageObject
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function exists(array $options = array())
+    public function exists(array $options = [])
     {
     {
         return array_key_exists($this->_name, $this->_bucket->_objects);
         return array_key_exists($this->_name, $this->_bucket->_objects);
     }
     }
@@ -570,7 +570,7 @@ class StorageObjectStub extends StorageObject
     /**
     /**
      * @throws NotFoundException
      * @throws NotFoundException
      */
      */
-    public function delete(array $options = array())
+    public function delete(array $options = [])
     {
     {
         if (array_key_exists($this->_name, $this->_bucket->_objects)) {
         if (array_key_exists($this->_name, $this->_bucket->_objects)) {
             unset($this->_bucket->_objects[$this->_name]);
             unset($this->_bucket->_objects[$this->_name]);
@@ -582,7 +582,7 @@ class StorageObjectStub extends StorageObject
     /**
     /**
      * @throws NotFoundException
      * @throws NotFoundException
      */
      */
-    public function update(array $metadata, array $options = array())
+    public function update(array $metadata, array $options = [])
     {
     {
         if (!$this->_exists) {
         if (!$this->_exists) {
             throw new NotFoundException('key ' . $this->_name . ' not found.');
             throw new NotFoundException('key ' . $this->_name . ' not found.');
@@ -590,17 +590,17 @@ class StorageObjectStub extends StorageObject
         $this->_info = $metadata;
         $this->_info = $metadata;
     }
     }
 
 
-    public function copy($destination, array $options = array())
+    public function copy($destination, array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function rewrite($destination, array $options = array())
+    public function rewrite($destination, array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function rename($name, array $options = array())
+    public function rename($name, array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
@@ -608,7 +608,7 @@ class StorageObjectStub extends StorageObject
     /**
     /**
      * @throws NotFoundException
      * @throws NotFoundException
      */
      */
-    public function downloadAsString(array $options = array())
+    public function downloadAsString(array $options = [])
     {
     {
         if (!$this->_exists) {
         if (!$this->_exists) {
             throw new NotFoundException('key ' . $this->_name . ' not found.');
             throw new NotFoundException('key ' . $this->_name . ' not found.');
@@ -616,42 +616,42 @@ class StorageObjectStub extends StorageObject
         return $this->_data;
         return $this->_data;
     }
     }
 
 
-    public function downloadToFile($path, array $options = array())
+    public function downloadToFile($path, array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function downloadAsStream(array $options = array())
+    public function downloadAsStream(array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function downloadAsStreamAsync(array $options = array())
+    public function downloadAsStreamAsync(array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function signedUrl($expires, array $options = array())
+    public function signedUrl($expires, array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function signedUploadUrl($expires, array $options = array())
+    public function signedUploadUrl($expires, array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function beginSignedUploadSession(array $options = array())
+    public function beginSignedUploadSession(array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function info(array $options = array())
+    public function info(array $options = [])
     {
     {
-        return $this->_info['metadata'] ?? array();
+        return $this->_info['metadata'] ?? [];
     }
     }
 
 
-    public function reload(array $options = array())
+    public function reload(array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
@@ -687,52 +687,52 @@ class StorageObjectStub extends StorageObject
  */
  */
 class ConnectionInterfaceStub implements ConnectionInterface
 class ConnectionInterfaceStub implements ConnectionInterface
 {
 {
-    public function deleteAcl(array $args = array())
+    public function deleteAcl(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function getAcl(array $args = array())
+    public function getAcl(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function listAcl(array $args = array())
+    public function listAcl(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function insertAcl(array $args = array())
+    public function insertAcl(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function patchAcl(array $args = array())
+    public function patchAcl(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function deleteBucket(array $args = array())
+    public function deleteBucket(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function restoreBucket(array $args = array())
+    public function restoreBucket(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function getBucket(array $args = array())
+    public function getBucket(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function listBuckets(array $args = array())
+    public function listBuckets(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function insertBucket(array $args = array())
+    public function insertBucket(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
@@ -752,122 +752,122 @@ class ConnectionInterfaceStub implements ConnectionInterface
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function patchBucket(array $args = array())
+    public function patchBucket(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function deleteObject(array $args = array())
+    public function deleteObject(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function restoreObject(array $args = array())
+    public function restoreObject(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function copyObject(array $args = array())
+    public function copyObject(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function rewriteObject(array $args = array())
+    public function rewriteObject(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function moveObject(array $args = array())
+    public function moveObject(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function composeObject(array $args = array())
+    public function composeObject(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function getObject(array $args = array())
+    public function getObject(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function headObject(array $args = array()): array
+    public function headObject(array $args = []): array
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function listObjects(array $args = array())
+    public function listObjects(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function patchObject(array $args = array())
+    public function patchObject(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function downloadObject(array $args = array())
+    public function downloadObject(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function insertObject(array $args = array())
+    public function insertObject(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function getNotification(array $args = array())
+    public function getNotification(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function deleteNotification(array $args = array())
+    public function deleteNotification(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function insertNotification(array $args = array())
+    public function insertNotification(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function listNotifications(array $args = array())
+    public function listNotifications(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function getServiceAccount(array $args = array())
+    public function getServiceAccount(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function lockRetentionPolicy(array $args = array())
+    public function lockRetentionPolicy(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function createHmacKey(array $args = array())
+    public function createHmacKey(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function deleteHmacKey(array $args = array())
+    public function deleteHmacKey(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function getHmacKey(array $args = array())
+    public function getHmacKey(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function updateHmacKey(array $args = array())
+    public function updateHmacKey(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function listHmacKeys(array $args = array())
+    public function listHmacKeys(array $args = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
@@ -880,18 +880,18 @@ class StorageClientStub extends StorageClient
 {
 {
     private $_config         = null;
     private $_config         = null;
     private $_connection     = null;
     private $_connection     = null;
-    private static $_buckets = array();
+    private static $_buckets = [];
 
 
-    public function __construct(array $config = array())
+    public function __construct(array $config = [])
     {
     {
         $this->_config     = $config;
         $this->_config     = $config;
         $this->_connection =  new ConnectionInterfaceStub();
         $this->_connection =  new ConnectionInterfaceStub();
     }
     }
 
 
-    public function bucket($name, $userProject = false, array $config = array())
+    public function bucket($name, $userProject = false, array $config = [])
     {
     {
         if (!array_key_exists($name, self::$_buckets)) {
         if (!array_key_exists($name, self::$_buckets)) {
-            self::$_buckets[$name] = new BucketStub($this->_connection, $name, array(), $this);
+            self::$_buckets[$name] = new BucketStub($this->_connection, $name, [], $this);
         }
         }
         return self::$_buckets[$name];
         return self::$_buckets[$name];
     }
     }
@@ -908,7 +908,7 @@ class StorageClientStub extends StorageClient
         }
         }
     }
     }
 
 
-    public function buckets(array $options = array())
+    public function buckets(array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
@@ -923,7 +923,7 @@ class StorageClientStub extends StorageClient
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function signedUrlUploader($uri, $data, array $options = array())
+    public function signedUrlUploader($uri, $data, array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
@@ -933,32 +933,32 @@ class StorageClientStub extends StorageClient
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function getServiceAccount(array $options = array())
+    public function getServiceAccount(array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function hmacKeys(array $options = array())
+    public function hmacKeys(array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function hmacKey($accessId, $projectId = null, array $metadata = array())
+    public function hmacKey($accessId, $projectId = null, array $metadata = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function createHmacKey($serviceAccountEmail, array $options = array())
+    public function createHmacKey($serviceAccountEmail, array $options = [])
     {
     {
         throw new BadMethodCallException('not supported by this stub');
         throw new BadMethodCallException('not supported by this stub');
     }
     }
 
 
-    public function createBucket($name, array $options = array())
+    public function createBucket($name, array $options = [])
     {
     {
         if (array_key_exists($name, self::$_buckets)) {
         if (array_key_exists($name, self::$_buckets)) {
             throw new BadRequestException('already exists');
             throw new BadRequestException('already exists');
         }
         }
-        $b                     = new BucketStub($this->_connection, $name, array(), $this);
+        $b                     = new BucketStub($this->_connection, $name, [], $this);
         self::$_buckets[$name] = $b;
         self::$_buckets[$name] = $b;
         return $b;
         return $b;
     }
     }

+ 10 - 10
tst/ControllerTest.php

@@ -18,7 +18,7 @@ class ControllerTest extends TestCase
     {
     {
         /* Setup Routine */
         /* Setup Routine */
         $this->_path  = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
         $this->_path  = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
-        $this->_data  = new Filesystem(array('dir' => $this->_path));
+        $this->_data  = new Filesystem(['dir' => $this->_path]);
         ServerSalt::setStore($this->_data);
         ServerSalt::setStore($this->_data);
         TrafficLimiter::setStore($this->_data);
         TrafficLimiter::setStore($this->_data);
         $this->reset();
         $this->reset();
@@ -34,9 +34,9 @@ class ControllerTest extends TestCase
 
 
     public function reset()
     public function reset()
     {
     {
-        $_POST   = array();
-        $_GET    = array();
-        $_SERVER = array();
+        $_POST   = [];
+        $_GET    = [];
+        $_SERVER = [];
         if ($this->_data->exists(Helper::getPasteId())) {
         if ($this->_data->exists(Helper::getPasteId())) {
             $this->_data->delete(Helper::getPasteId());
             $this->_data->delete(Helper::getPasteId());
         }
         }
@@ -202,7 +202,7 @@ class ControllerTest extends TestCase
         $options                     = parse_ini_file(CONF, true);
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
         $options['traffic']['limit'] = 0;
         Helper::createIniFile(CONF, $options);
         Helper::createIniFile(CONF, $options);
-        $paste = Helper::getPasteJson(array('expire' => 25));
+        $paste = Helper::getPasteJson(['expire' => 25]);
         $file  = Helper::createTempFile();
         $file  = Helper::createTempFile();
         file_put_contents($file, $paste);
         file_put_contents($file, $paste);
         Request::setInputStream($file);
         Request::setInputStream($file);
@@ -381,7 +381,7 @@ class ControllerTest extends TestCase
         $options                     = parse_ini_file(CONF, true);
         $options                     = parse_ini_file(CONF, true);
         $options['traffic']['limit'] = 0;
         $options['traffic']['limit'] = 0;
         Helper::createIniFile(CONF, $options);
         Helper::createIniFile(CONF, $options);
-        $paste = Helper::getPasteJson(array('expire' => 'foo'));
+        $paste = Helper::getPasteJson(['expire' => 'foo']);
         $file  = Helper::createTempFile();
         $file  = Helper::createTempFile();
         file_put_contents($file, $paste);
         file_put_contents($file, $paste);
         Request::setInputStream($file);
         Request::setInputStream($file);
@@ -698,7 +698,7 @@ class ControllerTest extends TestCase
      */
      */
     public function testReadExpired()
     public function testReadExpired()
     {
     {
-        $expiredPaste = Helper::getPaste(array('expire_date' => 1344803344));
+        $expiredPaste = Helper::getPaste(['expire_date' => 1344803344]);
         $this->_data->create(Helper::getPasteId(), $expiredPaste);
         $this->_data->create(Helper::getPasteId(), $expiredPaste);
         $_SERVER['QUERY_STRING']          = Helper::getPasteId();
         $_SERVER['QUERY_STRING']          = Helper::getPasteId();
         $_GET[Helper::getPasteId()]       = '';
         $_GET[Helper::getPasteId()]       = '';
@@ -882,9 +882,9 @@ class ControllerTest extends TestCase
         $this->_data->create(Helper::getPasteId(), $paste);
         $this->_data->create(Helper::getPasteId(), $paste);
         $this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data');
         $this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data');
         $file  = Helper::createTempFile();
         $file  = Helper::createTempFile();
-        file_put_contents($file, json_encode(array(
+        file_put_contents($file, json_encode([
             'deletetoken' => 'burnafterreading',
             'deletetoken' => 'burnafterreading',
-        )));
+        ]));
         Request::setInputStream($file);
         Request::setInputStream($file);
         $_SERVER['QUERY_STRING']          = Helper::getPasteId();
         $_SERVER['QUERY_STRING']          = Helper::getPasteId();
         $_GET[Helper::getPasteId()]       = '';
         $_GET[Helper::getPasteId()]       = '';
@@ -904,7 +904,7 @@ class ControllerTest extends TestCase
      */
      */
     public function testDeleteExpired()
     public function testDeleteExpired()
     {
     {
-        $expiredPaste = Helper::getPaste(array('expire_date' => 1000));
+        $expiredPaste = Helper::getPaste(['expire_date' => 1000]);
         $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste does not exist before being created');
         $this->assertFalse($this->_data->exists(Helper::getPasteId()), 'paste does not exist before being created');
         $this->_data->create(Helper::getPasteId(), $expiredPaste);
         $this->_data->create(Helper::getPasteId(), $expiredPaste);
         $this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data');
         $this->assertTrue($this->_data->exists(Helper::getPasteId()), 'paste exists before deleting data');

+ 6 - 6
tst/ControllerWithDbTest.php

@@ -8,14 +8,14 @@ require_once 'ControllerTest.php';
 
 
 class ControllerWithDbTest extends ControllerTest
 class ControllerWithDbTest extends ControllerTest
 {
 {
-    private $_options = array(
+    private $_options = [
         'usr' => null,
         'usr' => null,
         'pwd' => null,
         'pwd' => null,
-        'opt' => array(
+        'opt' => [
             PDO::ATTR_ERRMODE    => PDO::ERRMODE_EXCEPTION,
             PDO::ATTR_ERRMODE    => PDO::ERRMODE_EXCEPTION,
             PDO::ATTR_PERSISTENT => true,
             PDO::ATTR_PERSISTENT => true,
-        ),
-    );
+        ],
+    ];
 
 
     public function setUp(): void
     public function setUp(): void
     {
     {
@@ -36,9 +36,9 @@ class ControllerWithDbTest extends ControllerTest
         parent::reset();
         parent::reset();
         // but then inject a db config
         // but then inject a db config
         $options          = parse_ini_file(CONF, true);
         $options          = parse_ini_file(CONF, true);
-        $options['model'] = array(
+        $options['model'] = [
             'class' => 'Database',
             'class' => 'Database',
-        );
+        ];
         $options['model_options'] = $this->_options;
         $options['model_options'] = $this->_options;
         Helper::createIniFile(CONF, $options);
         Helper::createIniFile(CONF, $options);
     }
     }

+ 7 - 7
tst/ControllerWithGcsTest.php

@@ -12,11 +12,11 @@ class ControllerWithGcsTest extends ControllerTest
 {
 {
     private static $_client;
     private static $_client;
     private static $_bucket;
     private static $_bucket;
-    private $_options = array();
+    private $_options = [];
 
 
     public static function setUpBeforeClass(): void
     public static function setUpBeforeClass(): void
     {
     {
-        $httpClient = new Client(array('debug'=>false));
+        $httpClient = new Client(['debug'=>false]);
         $handler    = HttpHandlerFactory::build($httpClient);
         $handler    = HttpHandlerFactory::build($httpClient);
 
 
         $name     = 'pb-';
         $name     = 'pb-';
@@ -24,7 +24,7 @@ class ControllerWithGcsTest extends ControllerTest
         for ($i = 0; $i < 29; ++$i) {
         for ($i = 0; $i < 29; ++$i) {
             $name .= $alphabet[rand(0, strlen($alphabet) - 1)];
             $name .= $alphabet[rand(0, strlen($alphabet) - 1)];
         }
         }
-        self::$_client = new StorageClientStub(array());
+        self::$_client = new StorageClientStub([]);
         self::$_bucket = self::$_client->createBucket($name);
         self::$_bucket = self::$_client->createBucket($name);
     }
     }
 
 
@@ -35,10 +35,10 @@ class ControllerWithGcsTest extends ControllerTest
         if (!is_dir($this->_path)) {
         if (!is_dir($this->_path)) {
             mkdir($this->_path);
             mkdir($this->_path);
         }
         }
-        $this->_options = array(
+        $this->_options = [
             'bucket' => self::$_bucket->name(),
             'bucket' => self::$_bucket->name(),
             'prefix' => 'pastes',
             'prefix' => 'pastes',
-        );
+        ];
         $this->_data    = new GoogleCloudStorage($this->_options);
         $this->_data    = new GoogleCloudStorage($this->_options);
         ServerSalt::setStore($this->_data);
         ServerSalt::setStore($this->_data);
         TrafficLimiter::setStore($this->_data);
         TrafficLimiter::setStore($this->_data);
@@ -50,9 +50,9 @@ class ControllerWithGcsTest extends ControllerTest
         parent::reset();
         parent::reset();
         // but then inject a db config
         // but then inject a db config
         $options          = parse_ini_file(CONF, true);
         $options          = parse_ini_file(CONF, true);
-        $options['model'] = array(
+        $options['model'] = [
             'class' => 'GoogleCloudStorage',
             'class' => 'GoogleCloudStorage',
-        );
+        ];
         $options['model_options'] = $this->_options;
         $options['model_options'] = $this->_options;
         Helper::createIniFile(CONF, $options);
         Helper::createIniFile(CONF, $options);
     }
     }

+ 36 - 36
tst/Data/DatabaseTest.php

@@ -12,12 +12,12 @@ class DatabaseTest extends TestCase
 
 
     private $_path;
     private $_path;
 
 
-    private $_options = array(
+    private $_options = [
         'dsn' => 'sqlite::memory:',
         'dsn' => 'sqlite::memory:',
         'usr' => null,
         'usr' => null,
         'pwd' => null,
         'pwd' => null,
-        'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
-    );
+        'opt' => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION],
+    ];
 
 
     public function setUp(): void
     public function setUp(): void
     {
     {
@@ -36,7 +36,7 @@ class DatabaseTest extends TestCase
 
 
     public function testSaltMigration()
     public function testSaltMigration()
     {
     {
-        ServerSalt::setStore(new Filesystem(array('dir' => 'data')));
+        ServerSalt::setStore(new Filesystem(['dir' => 'data']));
         $salt = ServerSalt::get();
         $salt = ServerSalt::get();
         $file = 'data' . DIRECTORY_SEPARATOR . 'salt.php';
         $file = 'data' . DIRECTORY_SEPARATOR . 'salt.php';
         $this->assertFileExists($file, 'ServerSalt got initialized and stored on disk');
         $this->assertFileExists($file, 'ServerSalt got initialized and stored on disk');
@@ -80,10 +80,10 @@ class DatabaseTest extends TestCase
         $comment2['parentid'] = Helper::getPasteId();
         $comment2['parentid'] = Helper::getPasteId();
         $comment2['meta']     = $meta2;
         $comment2['meta']     = $meta2;
         $this->assertEquals(
         $this->assertEquals(
-            array(
+            [
                 $comment1['meta']['created']        => $comment1,
                 $comment1['meta']['created']        => $comment1,
                 $comment2['meta']['created'] . '.1' => $comment2,
                 $comment2['meta']['created'] . '.1' => $comment2,
-            ),
+            ],
             $this->_model->readComments(Helper::getPasteId())
             $this->_model->readComments(Helper::getPasteId())
         );
         );
 
 
@@ -98,7 +98,7 @@ class DatabaseTest extends TestCase
     {
     {
         $error_log_setting = ini_get('error_log');
         $error_log_setting = ini_get('error_log');
         $this->_model->delete(Helper::getPasteId());
         $this->_model->delete(Helper::getPasteId());
-        $original                          = $paste                                = Helper::getPaste(array('expire_date' => 1344803344));
+        $original                          = $paste                                = Helper::getPaste(['expire_date' => 1344803344]);
         $paste['meta']['burnafterreading'] = $original['meta']['burnafterreading'] = true;
         $paste['meta']['burnafterreading'] = $original['meta']['burnafterreading'] = true;
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
         $this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste');
         $this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste');
@@ -115,15 +115,15 @@ class DatabaseTest extends TestCase
     public function testPurge()
     public function testPurge()
     {
     {
         $this->_model->delete(Helper::getPasteId());
         $this->_model->delete(Helper::getPasteId());
-        $expired = Helper::getPaste(array('expire_date' => 1344803344));
-        $paste   = Helper::getPaste(array('expire_date' => time() + 3600));
-        $keys    = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z');
-        $ids     = array();
+        $expired = Helper::getPaste(['expire_date' => 1344803344]);
+        $paste   = Helper::getPaste(['expire_date' => time() + 3600]);
+        $keys    = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z'];
+        $ids     = [];
         foreach ($keys as $key) {
         foreach ($keys as $key) {
             $ids[$key] = hash('fnv164', $key);
             $ids[$key] = hash('fnv164', $key);
             $this->_model->delete($ids[$key]);
             $this->_model->delete($ids[$key]);
             $this->assertFalse($this->_model->exists($ids[$key]), "paste $key does not yet exist");
             $this->assertFalse($this->_model->exists($ids[$key]), "paste $key does not yet exist");
-            if (in_array($key, array('y', 'z'))) {
+            if (in_array($key, ['y', 'z'])) {
                 $this->assertTrue($this->_model->create($ids[$key], $paste), "store $key paste");
                 $this->assertTrue($this->_model->create($ids[$key], $paste), "store $key paste");
             } elseif ($key === 'x') {
             } elseif ($key === 'x') {
                 $data = Helper::getPaste();
                 $data = Helper::getPaste();
@@ -135,7 +135,7 @@ class DatabaseTest extends TestCase
         }
         }
         $this->_model->purge(10);
         $this->_model->purge(10);
         foreach ($ids as $key => $id) {
         foreach ($ids as $key => $id) {
-            if (in_array($key, array('x', 'y', 'z'))) {
+            if (in_array($key, ['x', 'y', 'z'])) {
                 $this->assertTrue($this->_model->exists($id), "paste $key exists after purge");
                 $this->assertTrue($this->_model->exists($id), "paste $key exists after purge");
                 $this->_model->delete($id);
                 $this->_model->delete($id);
             } else {
             } else {
@@ -148,7 +148,7 @@ class DatabaseTest extends TestCase
     {
     {
         $error_log_setting = ini_get('error_log');
         $error_log_setting = ini_get('error_log');
         $this->_model->delete(Helper::getPasteId());
         $this->_model->delete(Helper::getPasteId());
-        $paste = Helper::getPaste(array('expire' => "Invalid UTF-8 sequence: \xB1\x31"));
+        $paste = Helper::getPaste(['expire' => "Invalid UTF-8 sequence: \xB1\x31"]);
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
         ini_set('error_log', '/dev/null');
         ini_set('error_log', '/dev/null');
         $this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store broken paste');
         $this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store broken paste');
@@ -161,7 +161,7 @@ class DatabaseTest extends TestCase
         $error_log_setting = ini_get('error_log');
         $error_log_setting = ini_get('error_log');
         $this->_model->delete(Helper::getPasteId());
         $this->_model->delete(Helper::getPasteId());
         $data    = Helper::getPaste();
         $data    = Helper::getPaste();
-        $comment = Helper::getComment(array('icon' => "Invalid UTF-8 sequence: \xB1\x31"));
+        $comment = Helper::getComment(['icon' => "Invalid UTF-8 sequence: \xB1\x31"]);
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
         $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->create(Helper::getPasteId(), $data), 'store new paste');
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
@@ -175,64 +175,64 @@ class DatabaseTest extends TestCase
     public function testGetIbmInstance()
     public function testGetIbmInstance()
     {
     {
         $this->expectException(PDOException::class);
         $this->expectException(PDOException::class);
-        new Database(array(
+        new Database([
             'dsn' => 'ibm:', 'usr' => null, 'pwd' => null,
             'dsn' => 'ibm:', 'usr' => null, 'pwd' => null,
-            'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
-        ));
+            'opt' => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION],
+        ]);
     }
     }
 
 
     public function testGetInformixInstance()
     public function testGetInformixInstance()
     {
     {
         $this->expectException(PDOException::class);
         $this->expectException(PDOException::class);
-        new Database(array(
+        new Database([
             'dsn' => 'informix:', 'usr' => null, 'pwd' => null,
             'dsn' => 'informix:', 'usr' => null, 'pwd' => null,
-            'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
-        ));
+            'opt' => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION],
+        ]);
     }
     }
 
 
     public function testGetMssqlInstance()
     public function testGetMssqlInstance()
     {
     {
         $this->expectException(PDOException::class);
         $this->expectException(PDOException::class);
-        new Database(array(
+        new Database([
             'dsn' => 'mssql:', 'usr' => null, 'pwd' => null,
             'dsn' => 'mssql:', 'usr' => null, 'pwd' => null,
-            'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
-        ));
+            'opt' => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION],
+        ]);
     }
     }
 
 
     public function testGetMysqlInstance()
     public function testGetMysqlInstance()
     {
     {
         $this->expectException(PDOException::class);
         $this->expectException(PDOException::class);
-        new Database(array(
+        new Database([
             'dsn' => 'mysql:', 'usr' => null, 'pwd' => null,
             'dsn' => 'mysql:', 'usr' => null, 'pwd' => null,
-            'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
-        ));
+            'opt' => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION],
+        ]);
     }
     }
 
 
     public function testGetOciInstance()
     public function testGetOciInstance()
     {
     {
         $this->expectException(PDOException::class);
         $this->expectException(PDOException::class);
-        new Database(array(
+        new Database([
             'dsn' => 'oci:', 'usr' => null, 'pwd' => null,
             'dsn' => 'oci:', 'usr' => null, 'pwd' => null,
-            'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
-        ));
+            'opt' => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION],
+        ]);
     }
     }
 
 
     public function testGetPgsqlInstance()
     public function testGetPgsqlInstance()
     {
     {
         $this->expectException(PDOException::class);
         $this->expectException(PDOException::class);
-        new Database(array(
+        new Database([
             'dsn' => 'pgsql:', 'usr' => null, 'pwd' => null,
             'dsn' => 'pgsql:', 'usr' => null, 'pwd' => null,
-            'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
-        ));
+            'opt' => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION],
+        ]);
     }
     }
 
 
     public function testGetFooInstance()
     public function testGetFooInstance()
     {
     {
         $this->expectException(Exception::class);
         $this->expectException(Exception::class);
         $this->expectExceptionCode(5);
         $this->expectExceptionCode(5);
-        new Database(array(
+        new Database([
             'dsn' => 'foo:', 'usr' => null, 'pwd' => null, 'opt' => null,
             'dsn' => 'foo:', 'usr' => null, 'pwd' => null, 'opt' => null,
-        ));
+        ]);
     }
     }
 
 
     public function testMissingDsn()
     public function testMissingDsn()
@@ -309,7 +309,7 @@ class DatabaseTest extends TestCase
 
 
         // check if version number was upgraded in created configuration table
         // check if version number was upgraded in created configuration table
         $statement = $db->prepare('SELECT value FROM foo_config WHERE id LIKE ?');
         $statement = $db->prepare('SELECT value FROM foo_config WHERE id LIKE ?');
-        $statement->execute(array('VERSION'));
+        $statement->execute(['VERSION']);
         $result = $statement->fetch(PDO::FETCH_ASSOC);
         $result = $statement->fetch(PDO::FETCH_ASSOC);
         $statement->closeCursor();
         $statement->closeCursor();
         $this->assertEquals(Controller::VERSION, $result['value']);
         $this->assertEquals(Controller::VERSION, $result['value']);

+ 16 - 16
tst/Data/FilesystemTest.php

@@ -16,7 +16,7 @@ class FilesystemTest extends TestCase
         /* Setup Routine */
         /* Setup Routine */
         $this->_path        = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
         $this->_path        = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'privatebin_data';
         $this->_invalidPath = $this->_path . DIRECTORY_SEPARATOR . 'bar';
         $this->_invalidPath = $this->_path . DIRECTORY_SEPARATOR . 'bar';
-        $this->_model       = new Filesystem(array('dir' => $this->_path));
+        $this->_model       = new Filesystem(['dir' => $this->_path]);
         if (!is_dir($this->_path)) {
         if (!is_dir($this->_path)) {
             mkdir($this->_path);
             mkdir($this->_path);
         }
         }
@@ -37,7 +37,7 @@ class FilesystemTest extends TestCase
         $this->_model->delete(Helper::getPasteId());
         $this->_model->delete(Helper::getPasteId());
 
 
         // storing pastes
         // storing pastes
-        $paste = Helper::getPaste(array('expire_date' => 1344803344));
+        $paste = Helper::getPaste(['expire_date' => 1344803344]);
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
         $this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste');
         $this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste');
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
@@ -53,7 +53,7 @@ class FilesystemTest extends TestCase
         $comment['id']       = Helper::getCommentId();
         $comment['id']       = Helper::getCommentId();
         $comment['parentid'] = Helper::getPasteId();
         $comment['parentid'] = Helper::getPasteId();
         $this->assertEquals(
         $this->assertEquals(
-            array($comment['meta']['created'] => $comment),
+            [$comment['meta']['created'] => $comment],
             $this->_model->readComments(Helper::getPasteId())
             $this->_model->readComments(Helper::getPasteId())
         );
         );
 
 
@@ -67,7 +67,7 @@ class FilesystemTest extends TestCase
     public function testFileBasedAttachmentStoreWorks()
     public function testFileBasedAttachmentStoreWorks()
     {
     {
         $this->_model->delete(Helper::getPasteId());
         $this->_model->delete(Helper::getPasteId());
-        $original = $paste = Helper::getPaste(array('expire_date' => 1344803344));
+        $original = $paste = Helper::getPaste(['expire_date' => 1344803344]);
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
         $this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste');
         $this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste');
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
@@ -81,14 +81,14 @@ class FilesystemTest extends TestCase
     public function testPurge()
     public function testPurge()
     {
     {
         mkdir($this->_path . DIRECTORY_SEPARATOR . '00', 0777, true);
         mkdir($this->_path . DIRECTORY_SEPARATOR . '00', 0777, true);
-        $expired = Helper::getPaste(array('expire_date' => 1344803344));
-        $paste   = Helper::getPaste(array('expire_date' => time() + 3600));
-        $keys    = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z');
-        $ids     = array();
+        $expired = Helper::getPaste(['expire_date' => 1344803344]);
+        $paste   = Helper::getPaste(['expire_date' => time() + 3600]);
+        $keys    = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z'];
+        $ids     = [];
         foreach ($keys as $key) {
         foreach ($keys as $key) {
             $ids[$key] = hash('fnv164', $key);
             $ids[$key] = hash('fnv164', $key);
             $this->assertFalse($this->_model->exists($ids[$key]), "paste $key does not yet exist");
             $this->assertFalse($this->_model->exists($ids[$key]), "paste $key does not yet exist");
-            if (in_array($key, array('x', 'y', 'z'))) {
+            if (in_array($key, ['x', 'y', 'z'])) {
                 $this->assertTrue($this->_model->create($ids[$key], $paste), "store $key paste");
                 $this->assertTrue($this->_model->create($ids[$key], $paste), "store $key paste");
             } elseif ($key === 'x') {
             } elseif ($key === 'x') {
                 $data = Helper::getPaste();
                 $data = Helper::getPaste();
@@ -100,7 +100,7 @@ class FilesystemTest extends TestCase
         }
         }
         $this->_model->purge(10);
         $this->_model->purge(10);
         foreach ($ids as $key => $id) {
         foreach ($ids as $key => $id) {
-            if (in_array($key, array('x', 'y', 'z'))) {
+            if (in_array($key, ['x', 'y', 'z'])) {
                 $this->assertTrue($this->_model->exists($id), "paste $key exists after purge");
                 $this->assertTrue($this->_model->exists($id), "paste $key exists after purge");
                 $this->_model->delete($id);
                 $this->_model->delete($id);
             } else {
             } else {
@@ -113,7 +113,7 @@ class FilesystemTest extends TestCase
     {
     {
         $error_log_setting = ini_get('error_log');
         $error_log_setting = ini_get('error_log');
         $this->_model->delete(Helper::getPasteId());
         $this->_model->delete(Helper::getPasteId());
-        $paste = Helper::getPaste(array('expire' => "Invalid UTF-8 sequence: \xB1\x31"));
+        $paste = Helper::getPaste(['expire' => "Invalid UTF-8 sequence: \xB1\x31"]);
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
         ini_set('error_log', '/dev/null');
         ini_set('error_log', '/dev/null');
         $this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store broken paste');
         $this->assertFalse($this->_model->create(Helper::getPasteId(), $paste), 'unable to store broken paste');
@@ -127,7 +127,7 @@ class FilesystemTest extends TestCase
         $error_log_setting = ini_get('error_log');
         $error_log_setting = ini_get('error_log');
         $this->_model->delete(Helper::getPasteId());
         $this->_model->delete(Helper::getPasteId());
         $data    = Helper::getPaste();
         $data    = Helper::getPaste();
-        $comment = Helper::getComment(array('icon' => "Invalid UTF-8 sequence: \xB1\x31"));
+        $comment = Helper::getComment(['icon' => "Invalid UTF-8 sequence: \xB1\x31"]);
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
         $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->create(Helper::getPasteId(), $data), 'store new paste');
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
@@ -144,7 +144,7 @@ class FilesystemTest extends TestCase
         $paste     = Helper::getPaste();
         $paste     = Helper::getPaste();
         $comment   = Helper::getComment();
         $comment   = Helper::getComment();
         $commentid = Helper::getCommentId();
         $commentid = Helper::getCommentId();
-        $ids       = array();
+        $ids       = [];
         for ($i = 0, $max = 10; $i < $max; ++$i) {
         for ($i = 0, $max = 10; $i < $max; ++$i) {
             $dataid     = Helper::getRandomId();
             $dataid     = Helper::getRandomId();
             $storagedir = $this->_path . DIRECTORY_SEPARATOR . substr($dataid, 0, 2) .
             $storagedir = $this->_path . DIRECTORY_SEPARATOR . substr($dataid, 0, 2) .
@@ -178,16 +178,16 @@ class FilesystemTest extends TestCase
             $comment             = $comment;
             $comment             = $comment;
             $comment['id']       = $commentid;
             $comment['id']       = $commentid;
             $comment['parentid'] = $dataid;
             $comment['parentid'] = $dataid;
-            $this->assertEquals($this->_model->readComments($dataid), array($comment['meta']['created'] => $comment), "comment of $dataid wasn't modified in the conversion");
+            $this->assertEquals($this->_model->readComments($dataid), [$comment['meta']['created'] => $comment], "comment of $dataid wasn't modified in the conversion");
         }
         }
     }
     }
 
 
     public function testValueFileErrorHandling()
     public function testValueFileErrorHandling()
     {
     {
         define('VALID', 'valid content');
         define('VALID', 'valid content');
-        foreach (array('purge_limiter', 'salt', 'traffic_limiter') as $namespace) {
+        foreach (['purge_limiter', 'salt', 'traffic_limiter'] as $namespace) {
             file_put_contents($this->_invalidPath . DIRECTORY_SEPARATOR . $namespace . '.php', 'invalid content');
             file_put_contents($this->_invalidPath . DIRECTORY_SEPARATOR . $namespace . '.php', 'invalid content');
-            $model = new Filesystem(array('dir' => $this->_invalidPath));
+            $model = new Filesystem(['dir' => $this->_invalidPath]);
             ob_start(); // hide "invalid content", when file gets included
             ob_start(); // hide "invalid content", when file gets included
             $this->assertEquals($model->getValue($namespace), '', 'empty default value returned, invalid content ignored');
             $this->assertEquals($model->getValue($namespace), '', 'empty default value returned, invalid content ignored');
             ob_end_clean();
             ob_end_clean();

+ 14 - 14
tst/Data/GoogleCloudStorageTest.php

@@ -13,7 +13,7 @@ class GoogleCloudStorageTest extends TestCase
 
 
     public static function setUpBeforeClass(): void
     public static function setUpBeforeClass(): void
     {
     {
-        $httpClient = new Client(array('debug'=>false));
+        $httpClient = new Client(['debug'=>false]);
         $handler    = HttpHandlerFactory::build($httpClient);
         $handler    = HttpHandlerFactory::build($httpClient);
 
 
         $name     = 'pb-';
         $name     = 'pb-';
@@ -21,17 +21,17 @@ class GoogleCloudStorageTest extends TestCase
         for ($i = 0; $i < 29; ++$i) {
         for ($i = 0; $i < 29; ++$i) {
             $name .= $alphabet[rand(0, strlen($alphabet) - 1)];
             $name .= $alphabet[rand(0, strlen($alphabet) - 1)];
         }
         }
-        self::$_client = new StorageClientStub(array());
+        self::$_client = new StorageClientStub([]);
         self::$_bucket = self::$_client->createBucket($name);
         self::$_bucket = self::$_client->createBucket($name);
     }
     }
 
 
     public function setUp(): void
     public function setUp(): void
     {
     {
         ini_set('error_log', stream_get_meta_data(tmpfile())['uri']);
         ini_set('error_log', stream_get_meta_data(tmpfile())['uri']);
-        $this->_model = new GoogleCloudStorage(array(
+        $this->_model = new GoogleCloudStorage([
             'bucket' => self::$_bucket->name(),
             'bucket' => self::$_bucket->name(),
             'prefix' => 'pastes',
             'prefix' => 'pastes',
-        ));
+        ]);
     }
     }
 
 
     public function tearDown(): void
     public function tearDown(): void
@@ -51,7 +51,7 @@ class GoogleCloudStorageTest extends TestCase
         $this->_model->delete(Helper::getPasteId());
         $this->_model->delete(Helper::getPasteId());
 
 
         // storing pastes
         // storing pastes
-        $paste = Helper::getPaste(array('expire_date' => 1344803344));
+        $paste = Helper::getPaste(['expire_date' => 1344803344]);
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
         $this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste');
         $this->assertTrue($this->_model->create(Helper::getPasteId(), $paste), 'store new paste');
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
@@ -67,7 +67,7 @@ class GoogleCloudStorageTest extends TestCase
         $comment['id']       = Helper::getCommentId();
         $comment['id']       = Helper::getCommentId();
         $comment['parentid'] = Helper::getPasteId();
         $comment['parentid'] = Helper::getPasteId();
         $this->assertEquals(
         $this->assertEquals(
-            array($comment['meta']['created'] => $comment),
+            [$comment['meta']['created'] => $comment],
             $this->_model->readComments(Helper::getPasteId())
             $this->_model->readComments(Helper::getPasteId())
         );
         );
 
 
@@ -83,14 +83,14 @@ class GoogleCloudStorageTest extends TestCase
      */
      */
     public function testPurge()
     public function testPurge()
     {
     {
-        $expired = Helper::getPaste(array('expire_date' => 1344803344));
-        $paste   = Helper::getPaste(array('expire_date' => time() + 3600));
-        $keys    = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z');
-        $ids     = array();
+        $expired = Helper::getPaste(['expire_date' => 1344803344]);
+        $paste   = Helper::getPaste(['expire_date' => time() + 3600]);
+        $keys    = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'x', 'y', 'z'];
+        $ids     = [];
         foreach ($keys as $key) {
         foreach ($keys as $key) {
             $ids[$key] = hash('fnv164', $key);
             $ids[$key] = hash('fnv164', $key);
             $this->assertFalse($this->_model->exists($ids[$key]), "paste $key does not yet exist");
             $this->assertFalse($this->_model->exists($ids[$key]), "paste $key does not yet exist");
-            if (in_array($key, array('x', 'y', 'z'))) {
+            if (in_array($key, ['x', 'y', 'z'])) {
                 $this->assertTrue($this->_model->create($ids[$key], $paste), "store $key paste");
                 $this->assertTrue($this->_model->create($ids[$key], $paste), "store $key paste");
             } elseif ($key === 'x') {
             } elseif ($key === 'x') {
                 $data = Helper::getPaste();
                 $data = Helper::getPaste();
@@ -102,7 +102,7 @@ class GoogleCloudStorageTest extends TestCase
         }
         }
         $this->_model->purge(10);
         $this->_model->purge(10);
         foreach ($ids as $key => $id) {
         foreach ($ids as $key => $id) {
-            if (in_array($key, array('x', 'y', 'z'))) {
+            if (in_array($key, ['x', 'y', 'z'])) {
                 $this->assertTrue($this->_model->exists($id), "paste $key exists after purge");
                 $this->assertTrue($this->_model->exists($id), "paste $key exists after purge");
                 $this->_model->delete($id);
                 $this->_model->delete($id);
             } else {
             } else {
@@ -114,7 +114,7 @@ class GoogleCloudStorageTest extends TestCase
     public function testErrorDetection()
     public function testErrorDetection()
     {
     {
         $this->_model->delete(Helper::getPasteId());
         $this->_model->delete(Helper::getPasteId());
-        $paste = Helper::getPaste(array('expire' => "Invalid UTF-8 sequence: \xB1\x31"));
+        $paste = Helper::getPaste(['expire' => "Invalid UTF-8 sequence: \xB1\x31"]);
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
         $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->create(Helper::getPasteId(), $paste), 'unable to store broken paste');
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist');
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does still not exist');
@@ -124,7 +124,7 @@ class GoogleCloudStorageTest extends TestCase
     {
     {
         $this->_model->delete(Helper::getPasteId());
         $this->_model->delete(Helper::getPasteId());
         $data    = Helper::getPaste();
         $data    = Helper::getPaste();
-        $comment = Helper::getComment(array('icon' => "Invalid UTF-8 sequence: \xB1\x31"));
+        $comment = Helper::getComment(['icon' => "Invalid UTF-8 sequence: \xB1\x31"]);
         $this->assertFalse($this->_model->exists(Helper::getPasteId()), 'paste does not yet exist');
         $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->create(Helper::getPasteId(), $data), 'store new paste');
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists after storing it');

+ 37 - 0
tst/FormatV2Test.php

@@ -72,4 +72,41 @@ class FormatV2Test extends TestCase
         $paste = Helper::getPaste();
         $paste = Helper::getPaste();
         $this->assertFalse(FormatV2::isValid($paste), 'invalid meta key');
         $this->assertFalse(FormatV2::isValid($paste), 'invalid meta key');
     }
     }
+
+    public function testFormatV2ValidatorRejectsMalformedTypes()
+    {
+        // malformed input must yield "false" (Invalid data) rather than a
+        // fatal type error under strict_types
+        $paste          = Helper::getPastePost();
+        $paste['v']     = 'abc';
+        $this->assertFalse(FormatV2::isValid($paste), 'non-numeric version');
+
+        $paste          = Helper::getPastePost();
+        $paste['v']     = [];
+        $this->assertFalse(FormatV2::isValid($paste), 'array version');
+
+        $paste          = Helper::getPastePost();
+        $paste['ct']    = ['not', 'a', 'string'];
+        $this->assertFalse(FormatV2::isValid($paste), 'non-string ciphertext');
+
+        $paste          = Helper::getPastePost();
+        $paste['meta']  = 'not-an-array';
+        $this->assertFalse(FormatV2::isValid($paste), 'non-array meta');
+
+        $paste             = Helper::getPastePost();
+        $paste['adata'][0] = 'not-an-array';
+        $this->assertFalse(FormatV2::isValid($paste), 'non-array cipher parameters');
+
+        $paste             = Helper::getPastePost();
+        $paste['adata'][0] = [];
+        $this->assertFalse(FormatV2::isValid($paste), 'empty cipher parameters');
+
+        $paste                = Helper::getPastePost();
+        $paste['adata'][0][0] = [];
+        $this->assertFalse(FormatV2::isValid($paste), 'non-string iv');
+
+        $comment           = Helper::getCommentPost();
+        $comment['ct']     = 42;
+        $this->assertFalse(FormatV2::isValid($comment, true), 'non-string comment ciphertext');
+    }
 }
 }

+ 4 - 4
tst/I18nTest.php

@@ -8,7 +8,7 @@ class I18nMock extends I18n
 {
 {
     public static function resetAvailableLanguages()
     public static function resetAvailableLanguages()
     {
     {
-        self::$_availableLanguages = array();
+        self::$_availableLanguages = [];
     }
     }
 
 
     public static function resetPath($path = '')
     public static function resetPath($path = '')
@@ -24,7 +24,7 @@ class I18nMock extends I18n
 
 
 class I18nTest extends TestCase
 class I18nTest extends TestCase
 {
 {
-    private $_translations = array();
+    private $_translations = [];
 
 
     public function setUp(): void
     public function setUp(): void
     {
     {
@@ -248,8 +248,8 @@ class I18nTest extends TestCase
 
 
     public function testMessageIdsExistInAllLanguages()
     public function testMessageIdsExistInAllLanguages()
     {
     {
-        $messageIds = array();
-        $languages  = array();
+        $messageIds = [];
+        $languages  = [];
         foreach (new DirectoryIterator(PATH . 'i18n') as $file) {
         foreach (new DirectoryIterator(PATH . 'i18n') as $file) {
             $fileNameLength = strlen($file->getFilename());
             $fileNameLength = strlen($file->getFilename());
             if ($fileNameLength === 7) {       // xx.json
             if ($fileNameLength === 7) {       // xx.json

+ 18 - 18
tst/JsonApiTest.php

@@ -19,12 +19,12 @@ class JsonApiTest extends TestCase
         if (!is_dir($this->_path)) {
         if (!is_dir($this->_path)) {
             mkdir($this->_path);
             mkdir($this->_path);
         }
         }
-        $this->_model = new Filesystem(array('dir' => $this->_path));
+        $this->_model = new Filesystem(['dir' => $this->_path]);
         ServerSalt::setStore($this->_model);
         ServerSalt::setStore($this->_model);
 
 
-        $_POST   = array();
-        $_GET    = array();
-        $_SERVER = array();
+        $_POST   = [];
+        $_GET    = [];
+        $_SERVER = [];
         if ($this->_model->exists(Helper::getPasteId())) {
         if ($this->_model->exists(Helper::getPasteId())) {
             $this->_model->delete(Helper::getPasteId());
             $this->_model->delete(Helper::getPasteId());
         }
         }
@@ -119,9 +119,9 @@ class JsonApiTest extends TestCase
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data');
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data');
         $paste = $this->_model->read(Helper::getPasteId());
         $paste = $this->_model->read(Helper::getPasteId());
         $file  = Helper::createTempFile();
         $file  = Helper::createTempFile();
-        file_put_contents($file, json_encode(array(
+        file_put_contents($file, json_encode([
             'deletetoken' => hash_hmac('sha256', Helper::getPasteId(), $paste['meta']['salt']),
             'deletetoken' => hash_hmac('sha256', Helper::getPasteId(), $paste['meta']['salt']),
-        )));
+        ]));
         Request::setInputStream($file);
         Request::setInputStream($file);
         $_SERVER['QUERY_STRING']          = Helper::getPasteId();
         $_SERVER['QUERY_STRING']          = Helper::getPasteId();
         $_GET[Helper::getPasteId()]       = '';
         $_GET[Helper::getPasteId()]       = '';
@@ -147,10 +147,10 @@ class JsonApiTest extends TestCase
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data');
         $this->assertTrue($this->_model->exists(Helper::getPasteId()), 'paste exists before deleting data');
         $paste = $this->_model->read(Helper::getPasteId());
         $paste = $this->_model->read(Helper::getPasteId());
         $file  = Helper::createTempFile();
         $file  = Helper::createTempFile();
-        file_put_contents($file, json_encode(array(
+        file_put_contents($file, json_encode([
             'pasteid'     => Helper::getPasteId(),
             'pasteid'     => Helper::getPasteId(),
             'deletetoken' => hash_hmac('sha256', Helper::getPasteId(), $paste['meta']['salt']),
             'deletetoken' => hash_hmac('sha256', Helper::getPasteId(), $paste['meta']['salt']),
-        )));
+        ]));
         Request::setInputStream($file);
         Request::setInputStream($file);
         $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
         $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
         $_SERVER['REQUEST_METHOD']        = 'POST';
         $_SERVER['REQUEST_METHOD']        = 'POST';
@@ -397,20 +397,20 @@ class JsonApiTest extends TestCase
 
 
     public function baseUriProvider()
     public function baseUriProvider()
     {
     {
-        return array(
-            array('/path/shortenviayourls?'),
-            array('/path/index.php/shortenviayourls?'),
-            array('/path?shortenviayourls&'),
-        );
+        return [
+            ['/path/shortenviayourls?'],
+            ['/path/index.php/shortenviayourls?'],
+            ['/path?shortenviayourls&'],
+        ];
     }
     }
 
 
     public function baseShlinkUriProvider()
     public function baseShlinkUriProvider()
     {
     {
-        return array(
-            array('/path/shortenviashlink?'),
-            array('/path/index.php/shortenviashlink?'),
-            array('/path?shortenviashlink&'),
-        );
+        return [
+            ['/path/shortenviashlink?'],
+            ['/path/index.php/shortenviashlink?'],
+            ['/path?shortenviashlink&'],
+        ];
     }
     }
 
 
     /**
     /**

+ 5 - 5
tst/MigrateTest.php

@@ -34,15 +34,15 @@ class MigrateTest extends TestCase
         $this->_model_1                  = new Filesystem($options['model_options']);
         $this->_model_1                  = new Filesystem($options['model_options']);
         Helper::createIniFile($this->_path_instance_1 . DIRECTORY_SEPARATOR . 'cfg' . DIRECTORY_SEPARATOR . 'conf.php', $options);
         Helper::createIniFile($this->_path_instance_1 . DIRECTORY_SEPARATOR . 'cfg' . DIRECTORY_SEPARATOR . 'conf.php', $options);
 
 
-        $options['model']          = array(
+        $options['model']          = [
             'class' => 'Database',
             'class' => 'Database',
-        );
-        $options['model_options'] = array(
+        ];
+        $options['model_options'] = [
             'dsn' => 'sqlite:' . $this->_path_instance_2 . DIRECTORY_SEPARATOR . 'test.sq3',
             'dsn' => 'sqlite:' . $this->_path_instance_2 . DIRECTORY_SEPARATOR . 'test.sq3',
             'usr' => null,
             'usr' => null,
             'pwd' => null,
             'pwd' => null,
-            'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
-        );
+            'opt' => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION],
+        ];
         $this->_model_2 = new Database($options['model_options']);
         $this->_model_2 = new Database($options['model_options']);
         Helper::createIniFile($this->_path_instance_2 . DIRECTORY_SEPARATOR . 'cfg' . DIRECTORY_SEPARATOR . 'conf.php', $options);
         Helper::createIniFile($this->_path_instance_2 . DIRECTORY_SEPARATOR . 'cfg' . DIRECTORY_SEPARATOR . 'conf.php', $options);
     }
     }

+ 36 - 36
tst/ModelTest.php

@@ -28,15 +28,15 @@ class ModelTest extends TestCase
         }
         }
         $options                   = parse_ini_file(CONF_SAMPLE, true);
         $options                   = parse_ini_file(CONF_SAMPLE, true);
         $options['purge']['limit'] = 0;
         $options['purge']['limit'] = 0;
-        $options['model']          = array(
+        $options['model']          = [
             'class' => 'Database',
             'class' => 'Database',
-        );
-        $options['model_options'] = array(
+        ];
+        $options['model_options'] = [
             'dsn' => 'sqlite::memory:',
             'dsn' => 'sqlite::memory:',
             'usr' => null,
             'usr' => null,
             'pwd' => null,
             'pwd' => null,
-            'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
-        );
+            'opt' => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION],
+        ];
         Helper::confBackup();
         Helper::confBackup();
         Helper::createIniFile(CONF, $options);
         Helper::createIniFile(CONF, $options);
         ServerSalt::setStore(new Database($options['model_options']));
         ServerSalt::setStore(new Database($options['model_options']));
@@ -100,7 +100,7 @@ class ModelTest extends TestCase
         $this->_model->getPaste(Helper::getPasteId())->delete();
         $this->_model->getPaste(Helper::getPasteId())->delete();
         $paste = $this->_model->getPaste(Helper::getPasteId());
         $paste = $this->_model->getPaste(Helper::getPasteId());
         $this->assertFalse($paste->exists(), 'paste successfully deleted');
         $this->assertFalse($paste->exists(), 'paste successfully deleted');
-        $this->assertEquals(array(), $paste->getComments(), 'comment was deleted with paste');
+        $this->assertEquals([], $paste->getComments(), 'comment was deleted with paste');
     }
     }
 
 
     public function testCommentDefaults()
     public function testCommentDefaults()
@@ -141,15 +141,15 @@ class ModelTest extends TestCase
         }
         }
         $options                   = parse_ini_file(CONF_SAMPLE, true);
         $options                   = parse_ini_file(CONF_SAMPLE, true);
         $options['purge']['limit'] = 0;
         $options['purge']['limit'] = 0;
-        $options['model']          = array(
+        $options['model']          = [
             'class' => 'Database',
             'class' => 'Database',
-        );
-        $options['model_options'] = array(
+        ];
+        $options['model_options'] = [
             'dsn' => 'sqlite:' . $path,
             'dsn' => 'sqlite:' . $path,
             'usr' => null,
             'usr' => null,
             'pwd' => null,
             'pwd' => null,
-            'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
-        );
+            'opt' => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION],
+        ];
         Helper::createIniFile(CONF, $options);
         Helper::createIniFile(CONF, $options);
         $model = new Model(new Configuration);
         $model = new Model(new Configuration);
 
 
@@ -182,15 +182,15 @@ class ModelTest extends TestCase
         }
         }
         $options                   = parse_ini_file(CONF_SAMPLE, true);
         $options                   = parse_ini_file(CONF_SAMPLE, true);
         $options['purge']['limit'] = 0;
         $options['purge']['limit'] = 0;
-        $options['model']          = array(
+        $options['model']          = [
             'class' => 'Database',
             'class' => 'Database',
-        );
-        $options['model_options'] = array(
+        ];
+        $options['model_options'] = [
             'dsn' => 'sqlite:' . $path,
             'dsn' => 'sqlite:' . $path,
             'usr' => null,
             'usr' => null,
             'pwd' => null,
             'pwd' => null,
-            'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
-        );
+            'opt' => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION],
+        ];
         Helper::createIniFile(CONF, $options);
         Helper::createIniFile(CONF, $options);
         $model = new Model(new Configuration);
         $model = new Model(new Configuration);
 
 
@@ -257,14 +257,14 @@ class ModelTest extends TestCase
         $comment->get();
         $comment->get();
         $comment->store();
         $comment->store();
 
 
-        $identicon = new Identicon(array(
+        $identicon = new Identicon([
             'hash'  => TrafficLimiter::getHash(),
             'hash'  => TrafficLimiter::getHash(),
             'size'  => 16,
             'size'  => 16,
-            'style' => array(
+            'style' => [
                 'backgroundColor'   => '#fff0', // fully transparent, for dark mode
                 'backgroundColor'   => '#fff0', // fully transparent, for dark mode
                 'padding'           => 0,
                 'padding'           => 0,
-            ),
-        ));
+            ],
+        ]);
         $pngdata = $identicon->getImageDataUri('png');
         $pngdata = $identicon->getImageDataUri('png');
         $comment = current($this->_model->getPaste(Helper::getPasteId())->get()['comments']);
         $comment = current($this->_model->getPaste(Helper::getPasteId())->get()['comments']);
         $this->assertEquals($pngdata, $comment['meta']['icon'], 'icon gets set');
         $this->assertEquals($pngdata, $comment['meta']['icon'], 'icon gets set');
@@ -371,15 +371,15 @@ class ModelTest extends TestCase
         $conf  = new Configuration;
         $conf  = new Configuration;
         $store = new Database($conf->getSection('model_options'));
         $store = new Database($conf->getSection('model_options'));
         $store->delete(Helper::getPasteId());
         $store->delete(Helper::getPasteId());
-        $expired = Helper::getPaste(array('expire_date' => 1344803344));
-        $paste   = Helper::getPaste(array('expire_date' => time() + 3600));
-        $keys    = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'x', 'y', 'z');
-        $ids     = array();
+        $expired = Helper::getPaste(['expire_date' => 1344803344]);
+        $paste   = Helper::getPaste(['expire_date' => time() + 3600]);
+        $keys    = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'x', 'y', 'z'];
+        $ids     = [];
         foreach ($keys as $key) {
         foreach ($keys as $key) {
             $ids[$key] = hash('fnv164', $key);
             $ids[$key] = hash('fnv164', $key);
             $store->delete($ids[$key]);
             $store->delete($ids[$key]);
             $this->assertFalse($store->exists($ids[$key]), "paste $key does not yet exist");
             $this->assertFalse($store->exists($ids[$key]), "paste $key does not yet exist");
-            if (in_array($key, array('x', 'y', 'z'))) {
+            if (in_array($key, ['x', 'y', 'z'])) {
                 $this->assertTrue($store->create($ids[$key], $paste), "store $key paste");
                 $this->assertTrue($store->create($ids[$key], $paste), "store $key paste");
             } else {
             } else {
                 $this->assertTrue($store->create($ids[$key], $expired), "store $key paste");
                 $this->assertTrue($store->create($ids[$key], $expired), "store $key paste");
@@ -388,7 +388,7 @@ class ModelTest extends TestCase
         }
         }
         $this->_model->purge(10);
         $this->_model->purge(10);
         foreach ($ids as $key => $id) {
         foreach ($ids as $key => $id) {
-            if (in_array($key, array('x', 'y', 'z'))) {
+            if (in_array($key, ['x', 'y', 'z'])) {
                 $this->assertTrue($this->_model->getPaste($id)->exists(), "paste $key exists after purge");
                 $this->assertTrue($this->_model->getPaste($id)->exists(), "paste $key exists after purge");
                 $this->_model->getPaste($id)->delete();
                 $this->_model->getPaste($id)->delete();
             } else {
             } else {
@@ -402,15 +402,15 @@ class ModelTest extends TestCase
         $options                                  = parse_ini_file(CONF, true);
         $options                                  = parse_ini_file(CONF, true);
         $options['main']['discussiondatedisplay'] = 'false';
         $options['main']['discussiondatedisplay'] = 'false';
         $options['main']['icon']                  = 'none';
         $options['main']['icon']                  = 'none';
-        $options['model']                         = array(
+        $options['model']                         = [
             'class' => 'Database',
             'class' => 'Database',
-        );
-        $options['model_options']                 = array(
+        ];
+        $options['model_options']                 = [
             'dsn' => 'sqlite::memory:',
             'dsn' => 'sqlite::memory:',
             'usr' => null,
             'usr' => null,
             'pwd' => null,
             'pwd' => null,
-            'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
-        );
+            'opt' => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION],
+        ];
         Helper::createIniFile(CONF, $options);
         Helper::createIniFile(CONF, $options);
         $model = new Model(new Configuration);
         $model = new Model(new Configuration);
 
 
@@ -452,15 +452,15 @@ class ModelTest extends TestCase
     {
     {
         $options                 = parse_ini_file(CONF, true);
         $options                 = parse_ini_file(CONF, true);
         $options['main']['icon'] = 'vizhash';
         $options['main']['icon'] = 'vizhash';
-        $options['model']        = array(
+        $options['model']        = [
             'class' => 'Database',
             'class' => 'Database',
-        );
-        $options['model_options'] = array(
+        ];
+        $options['model_options'] = [
             'dsn' => 'sqlite::memory:',
             'dsn' => 'sqlite::memory:',
             'usr' => null,
             'usr' => null,
             'pwd' => null,
             'pwd' => null,
-            'opt' => array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION),
-        );
+            'opt' => [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION],
+        ];
         Helper::createIniFile(CONF, $options);
         Helper::createIniFile(CONF, $options);
         $model = new Model(new Configuration);
         $model = new Model(new Configuration);
 
 

+ 1 - 1
tst/Persistence/PurgeLimiterTest.php

@@ -16,7 +16,7 @@ class PurgeLimiterTest extends TestCase
             mkdir($this->_path);
             mkdir($this->_path);
         }
         }
         PurgeLimiter::setStore(
         PurgeLimiter::setStore(
-            new Filesystem(array('dir' => $this->_path))
+            new Filesystem(['dir' => $this->_path])
         );
         );
     }
     }
 
 

+ 9 - 9
tst/Persistence/ServerSaltTest.php

@@ -22,7 +22,7 @@ class ServerSaltTest extends TestCase
             mkdir($this->_path);
             mkdir($this->_path);
         }
         }
         ServerSalt::setStore(
         ServerSalt::setStore(
-            new Filesystem(array('dir' => $this->_path))
+            new Filesystem(['dir' => $this->_path])
         );
         );
 
 
         $this->_otherPath = $this->_path . DIRECTORY_SEPARATOR . 'foo';
         $this->_otherPath = $this->_path . DIRECTORY_SEPARATOR . 'foo';
@@ -45,17 +45,17 @@ class ServerSaltTest extends TestCase
     {
     {
         // generating new salt
         // generating new salt
         ServerSalt::setStore(
         ServerSalt::setStore(
-            new Filesystem(array('dir' => $this->_path))
+            new Filesystem(['dir' => $this->_path])
         );
         );
         $salt = ServerSalt::get();
         $salt = ServerSalt::get();
 
 
         // try setting a different path and resetting it
         // try setting a different path and resetting it
         ServerSalt::setStore(
         ServerSalt::setStore(
-            new Filesystem(array('dir' => $this->_otherPath))
+            new Filesystem(['dir' => $this->_otherPath])
         );
         );
         $this->assertNotEquals($salt, ServerSalt::get());
         $this->assertNotEquals($salt, ServerSalt::get());
         ServerSalt::setStore(
         ServerSalt::setStore(
-            new Filesystem(array('dir' => $this->_path))
+            new Filesystem(['dir' => $this->_path])
         );
         );
         $this->assertEquals($salt, ServerSalt::get());
         $this->assertEquals($salt, ServerSalt::get());
     }
     }
@@ -64,7 +64,7 @@ class ServerSaltTest extends TestCase
     {
     {
         // try setting an invalid path
         // try setting an invalid path
         chmod($this->_invalidPath, 0000);
         chmod($this->_invalidPath, 0000);
-        $store = new Filesystem(array('dir' => $this->_invalidPath));
+        $store = new Filesystem(['dir' => $this->_invalidPath]);
         ServerSalt::setStore($store);
         ServerSalt::setStore($store);
         $salt = ServerSalt::get();
         $salt = ServerSalt::get();
         ServerSalt::setStore($store);
         ServerSalt::setStore($store);
@@ -77,7 +77,7 @@ class ServerSaltTest extends TestCase
         chmod($this->_invalidPath, 0700);
         chmod($this->_invalidPath, 0700);
         file_put_contents($this->_invalidFile, '');
         file_put_contents($this->_invalidFile, '');
         chmod($this->_invalidFile, 0000);
         chmod($this->_invalidFile, 0000);
-        $store = new Filesystem(array('dir' => $this->_invalidPath));
+        $store = new Filesystem(['dir' => $this->_invalidPath]);
         ServerSalt::setStore($store);
         ServerSalt::setStore($store);
         $salt = ServerSalt::get();
         $salt = ServerSalt::get();
         ServerSalt::setStore($store);
         ServerSalt::setStore($store);
@@ -94,7 +94,7 @@ class ServerSaltTest extends TestCase
         }
         }
         file_put_contents($this->_invalidPath . DIRECTORY_SEPARATOR . '.htaccess', '');
         file_put_contents($this->_invalidPath . DIRECTORY_SEPARATOR . '.htaccess', '');
         chmod($this->_invalidPath, 0500);
         chmod($this->_invalidPath, 0500);
-        $store = new Filesystem(array('dir' => $this->_invalidPath));
+        $store = new Filesystem(['dir' => $this->_invalidPath]);
         ServerSalt::setStore($store);
         ServerSalt::setStore($store);
         $salt = ServerSalt::get();
         $salt = ServerSalt::get();
         ServerSalt::setStore($store);
         ServerSalt::setStore($store);
@@ -106,9 +106,9 @@ class ServerSaltTest extends TestCase
         // try creating an invalid path
         // try creating an invalid path
         chmod($this->_invalidPath, 0000);
         chmod($this->_invalidPath, 0000);
         ServerSalt::setStore(
         ServerSalt::setStore(
-            new Filesystem(array('dir' => $this->_invalidPath . DIRECTORY_SEPARATOR . 'baz'))
+            new Filesystem(['dir' => $this->_invalidPath . DIRECTORY_SEPARATOR . 'baz'])
         );
         );
-        $store = new Filesystem(array('dir' => $this->_invalidPath));
+        $store = new Filesystem(['dir' => $this->_invalidPath]);
         ServerSalt::setStore($store);
         ServerSalt::setStore($store);
         $salt = ServerSalt::get();
         $salt = ServerSalt::get();
         ServerSalt::setStore($store);
         ServerSalt::setStore($store);

+ 1 - 1
tst/Persistence/TrafficLimiterTest.php

@@ -13,7 +13,7 @@ class TrafficLimiterTest extends TestCase
     {
     {
         /* Setup Routine */
         /* Setup Routine */
         $this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'trafficlimit';
         $this->_path = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'trafficlimit';
-        $store       = new Filesystem(array('dir' => $this->_path));
+        $store       = new Filesystem(['dir' => $this->_path]);
         ServerSalt::setStore($store);
         ServerSalt::setStore($store);
         TrafficLimiter::setStore($store);
         TrafficLimiter::setStore($store);
     }
     }

+ 25 - 5
tst/RequestTest.php

@@ -7,9 +7,9 @@ class RequestTest extends TestCase
 {
 {
     public function reset()
     public function reset()
     {
     {
-        $_SERVER = array();
-        $_GET    = array();
-        $_POST   = array();
+        $_SERVER = [];
+        $_GET    = [];
+        $_POST   = [];
     }
     }
 
 
     /**
     /**
@@ -134,7 +134,7 @@ class RequestTest extends TestCase
         $_SERVER['REQUEST_METHOD']        = 'POST';
         $_SERVER['REQUEST_METHOD']        = 'POST';
         $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
         $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
         $_SERVER['QUERY_STRING']          = $id;
         $_SERVER['QUERY_STRING']          = $id;
-        $_GET                             = array($id => '');
+        $_GET                             = [$id => ''];
         $file                             = Helper::createTempFile();
         $file                             = Helper::createTempFile();
         file_put_contents($file, '{"deletetoken":"bar"}');
         file_put_contents($file, '{"deletetoken":"bar"}');
         Request::setInputStream($file);
         Request::setInputStream($file);
@@ -158,6 +158,26 @@ class RequestTest extends TestCase
         $this->assertEquals('create', $request->getOperation());
         $this->assertEquals('create', $request->getOperation());
     }
     }
 
 
+    public function testPostScalarJson()
+    {
+        // a valid JSON scalar body (number, boolean or quoted string) must not
+        // be treated as a set of parameters, so that it is rejected cleanly
+        // instead of triggering a type error further down
+        foreach (['1', '0.0', 'true', 'false', '"example"'] as $scalar) {
+            $this->reset();
+            $_SERVER['REQUEST_METHOD']        = 'POST';
+            $_SERVER['HTTP_X_REQUESTED_WITH'] = 'JSONHttpRequest';
+            $file                             = Helper::createTempFile();
+            file_put_contents($file, $scalar);
+            Request::setInputStream($file);
+            $request = new Request;
+            unlink($file);
+            $this->assertTrue($request->isJsonApiCall(), 'is JSON API call');
+            $this->assertEquals('create', $request->getOperation());
+            $this->assertEquals('', $request->getParam('ct'), "scalar body {$scalar} yields no parameters");
+        }
+    }
+
     public function testReadWithNegotiation()
     public function testReadWithNegotiation()
     {
     {
         $this->reset();
         $this->reset();
@@ -219,7 +239,7 @@ class RequestTest extends TestCase
         $this->reset();
         $this->reset();
         $id              = Helper::getRandomId();
         $id              = Helper::getRandomId();
         $path            = '/' . $this->getRandomQueryChars() . '/';
         $path            = '/' . $this->getRandomQueryChars() . '/';
-        $queryParams     = array($id);
+        $queryParams     = [$id];
         $queryParamCount = random_int(1, 5);
         $queryParamCount = random_int(1, 5);
         for ($i = 0; $i < $queryParamCount; ++$i) {
         for ($i = 0; $i < $queryParamCount; ++$i) {
             array_push($queryParams, $this->getRandomQueryChars());
             array_push($queryParams, $this->getRandomQueryChars());

+ 6 - 6
tst/ViewTest.php

@@ -12,25 +12,25 @@ class ViewTest extends TestCase
 
 
     private static $is_deleted = false;
     private static $is_deleted = false;
 
 
-    private static $formatters = array(
+    private static $formatters = [
         'plaintext'          => 'Plain Text',
         'plaintext'          => 'Plain Text',
         'syntaxhighlighting' => 'Source Code',
         'syntaxhighlighting' => 'Source Code',
         'markdown'           => 'Markdown',
         'markdown'           => 'Markdown',
-    );
+    ];
 
 
     private static $formatter_default = 'plaintext';
     private static $formatter_default = 'plaintext';
 
 
-    private static $expire = array(
+    private static $expire = [
         '5min'  => '5 minutes',
         '5min'  => '5 minutes',
         '1hour' => '1 hour',
         '1hour' => '1 hour',
         'never' => 'Never',
         'never' => 'Never',
-    );
+    ];
 
 
     private static $expire_default = '1hour';
     private static $expire_default = '1hour';
 
 
     private static $version = 'Version 1.2.3';
     private static $version = 'Version 1.2.3';
 
 
-    private $_content = array();
+    private $_content = [];
 
 
     public function setUp(): void
     public function setUp(): void
     {
     {
@@ -65,7 +65,7 @@ class ViewTest extends TestCase
         $page->assign('HTTPSLINK', 'https://example.com/');
         $page->assign('HTTPSLINK', 'https://example.com/');
         $page->assign('COMPRESSION', 'zlib');
         $page->assign('COMPRESSION', 'zlib');
         $page->assign('CSPHEADER', 'default-src \'none\'');
         $page->assign('CSPHEADER', 'default-src \'none\'');
-        $page->assign('SRI', array());
+        $page->assign('SRI', []);
 
 
         foreach (new DirectoryIterator(PATH . 'tpl') as $file) {
         foreach (new DirectoryIterator(PATH . 'tpl') as $file) {
             if ($file->getExtension() === 'php') {
             if ($file->getExtension() === 'php') {

+ 1 - 1
tst/Vizhash16x16Test.php

@@ -19,7 +19,7 @@ class Vizhash16x16Test extends TestCase
             mkdir($this->_path);
             mkdir($this->_path);
         }
         }
         $this->_file = $this->_path . DIRECTORY_SEPARATOR . 'vizhash.png';
         $this->_file = $this->_path . DIRECTORY_SEPARATOR . 'vizhash.png';
-        ServerSalt::setStore(new Filesystem(array('dir' => $this->_path)));
+        ServerSalt::setStore(new Filesystem(['dir' => $this->_path]));
     }
     }
 
 
     public function tearDown(): void
     public function tearDown(): void

+ 32 - 19
tst/YourlsProxyTest.php

@@ -73,16 +73,16 @@ class YourlsProxyTest extends TestCase
 
 
     public function providerInvalidUrl(): array
     public function providerInvalidUrl(): array
     {
     {
-        return array(
-            array(''),
-            array(' '),
-            array('foo'),
-            array('https://'),
-            array('https://example.com'), // missing path and query parameter,
-            array('https://example.com/'), // missing query parameter
-            array('https://example.com?paste=something'), // missing path parameter
-            array('https://example.com@foreign.malicious.example?foo#bar'), // missing path parameter
-        );
+        return [
+            [''],
+            [' '],
+            ['foo'],
+            ['https://'],
+            ['https://example.com'], // missing path and query parameter,
+            ['https://example.com/'], // missing query parameter
+            ['https://example.com?paste=something'], // missing path parameter
+            ['https://example.com@foreign.malicious.example?foo#bar'], // missing path parameter
+        ];
     }
     }
 
 
     /**
     /**
@@ -100,10 +100,10 @@ class YourlsProxyTest extends TestCase
 
 
     public function providerForeignUrlUsernameTrick(): array
     public function providerForeignUrlUsernameTrick(): array
     {
     {
-        return array(
-            array('https://example.com@foreign.malicious.example/?foo#bar'),
-            array('https://example.com/@foreign.malicious.example?foo#bar'),
-        );
+        return [
+            ['https://example.com@foreign.malicious.example/?foo#bar'],
+            ['https://example.com/@foreign.malicious.example?foo#bar'],
+        ];
     }
     }
 
 
     /**
     /**
@@ -118,11 +118,11 @@ class YourlsProxyTest extends TestCase
 
 
     public function providerForeignUrl(): array
     public function providerForeignUrl(): array
     {
     {
-        return array(
-            array('ftp://example.com/?n=np'), // wrong protocol
-            array('https://other.example.com/?foo#bar'), // wrong domain
-            array('https://other.example.com/?q=https://example.com/?foo#bar'), // domain included inside string
-        );
+        return [
+            ['ftp://example.com/?n=np'], // wrong protocol
+            ['https://other.example.com/?foo#bar'], // wrong domain
+            ['https://other.example.com/?q=https://example.com/?foo#bar'], // domain included inside string
+        ];
     }
     }
 
 
     public function testYourlsError()
     public function testYourlsError()
@@ -135,6 +135,19 @@ class YourlsProxyTest extends TestCase
         $this->assertEquals($yourls->getError(), 'Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.');
         $this->assertEquals($yourls->getError(), 'Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.');
     }
     }
 
 
+    public function testYourlsSuccessWithoutShortUrl()
+    {
+        // YOURLS may reply with statusCode 200 but without a shorturl field;
+        // this must be handled gracefully as an error instead of raising a
+        // TypeError (the method is declared to return ?string). YOURLS returns
+        // the status code as a string, so mirror that here.
+        file_put_contents($this->_mock_yourls_service, '{"statusCode":"200"}');
+
+        $yourls = new YourlsProxy($this->_conf, 'https://example.com/?foo#bar');
+        $this->assertTrue($yourls->isError());
+        $this->assertEquals($yourls->getError(), 'Proxy error: Error parsing proxy response. This can be a configuration issue, like wrong or missing config keys.');
+    }
+
     public function testServerError()
     public function testServerError()
     {
     {
         // simulate some other server error that results in a non-JSON reply
         // simulate some other server error that results in a non-JSON reply

+ 0 - 1
vendor/composer/autoload_classmap.php

@@ -74,7 +74,6 @@ return array(
     'PrivateBin\\Data\\Filesystem' => $baseDir . '/lib/Data/Filesystem.php',
     'PrivateBin\\Data\\Filesystem' => $baseDir . '/lib/Data/Filesystem.php',
     'PrivateBin\\Data\\GoogleCloudStorage' => $baseDir . '/lib/Data/GoogleCloudStorage.php',
     'PrivateBin\\Data\\GoogleCloudStorage' => $baseDir . '/lib/Data/GoogleCloudStorage.php',
     'PrivateBin\\Data\\S3Storage' => $baseDir . '/lib/Data/S3Storage.php',
     'PrivateBin\\Data\\S3Storage' => $baseDir . '/lib/Data/S3Storage.php',
-    'PrivateBin\\Exception\\JsonException' => $baseDir . '/lib/Exception/JsonException.php',
     'PrivateBin\\Exception\\TranslatedException' => $baseDir . '/lib/Exception/TranslatedException.php',
     'PrivateBin\\Exception\\TranslatedException' => $baseDir . '/lib/Exception/TranslatedException.php',
     'PrivateBin\\Filter' => $baseDir . '/lib/Filter.php',
     'PrivateBin\\Filter' => $baseDir . '/lib/Filter.php',
     'PrivateBin\\FormatV2' => $baseDir . '/lib/FormatV2.php',
     'PrivateBin\\FormatV2' => $baseDir . '/lib/FormatV2.php',

+ 0 - 1
vendor/composer/autoload_static.php

@@ -122,7 +122,6 @@ class ComposerStaticInitDontChange
         'PrivateBin\\Data\\Filesystem' => __DIR__ . '/../..' . '/lib/Data/Filesystem.php',
         'PrivateBin\\Data\\Filesystem' => __DIR__ . '/../..' . '/lib/Data/Filesystem.php',
         'PrivateBin\\Data\\GoogleCloudStorage' => __DIR__ . '/../..' . '/lib/Data/GoogleCloudStorage.php',
         'PrivateBin\\Data\\GoogleCloudStorage' => __DIR__ . '/../..' . '/lib/Data/GoogleCloudStorage.php',
         'PrivateBin\\Data\\S3Storage' => __DIR__ . '/../..' . '/lib/Data/S3Storage.php',
         'PrivateBin\\Data\\S3Storage' => __DIR__ . '/../..' . '/lib/Data/S3Storage.php',
-        'PrivateBin\\Exception\\JsonException' => __DIR__ . '/../..' . '/lib/Exception/JsonException.php',
         'PrivateBin\\Exception\\TranslatedException' => __DIR__ . '/../..' . '/lib/Exception/TranslatedException.php',
         'PrivateBin\\Exception\\TranslatedException' => __DIR__ . '/../..' . '/lib/Exception/TranslatedException.php',
         'PrivateBin\\Filter' => __DIR__ . '/../..' . '/lib/Filter.php',
         'PrivateBin\\Filter' => __DIR__ . '/../..' . '/lib/Filter.php',
         'PrivateBin\\FormatV2' => __DIR__ . '/../..' . '/lib/FormatV2.php',
         'PrivateBin\\FormatV2' => __DIR__ . '/../..' . '/lib/FormatV2.php',

+ 2 - 2
vendor/composer/installed.php

@@ -3,7 +3,7 @@
         'name' => 'privatebin/privatebin',
         'name' => 'privatebin/privatebin',
         'pretty_version' => 'dev-master',
         'pretty_version' => 'dev-master',
         'version' => 'dev-master',
         'version' => 'dev-master',
-        'reference' => '67baf8cca4b7aa1bc57e631b47ab561695c8ce2b',
+        'reference' => '8a77305838325d7be15b9a96e43415a6d2796489',
         'type' => 'project',
         'type' => 'project',
         'install_path' => __DIR__ . '/../../',
         'install_path' => __DIR__ . '/../../',
         'aliases' => array(),
         'aliases' => array(),
@@ -31,7 +31,7 @@
         'privatebin/privatebin' => array(
         'privatebin/privatebin' => array(
             'pretty_version' => 'dev-master',
             'pretty_version' => 'dev-master',
             'version' => 'dev-master',
             'version' => 'dev-master',
-            'reference' => '67baf8cca4b7aa1bc57e631b47ab561695c8ce2b',
+            'reference' => '8a77305838325d7be15b9a96e43415a6d2796489',
             'type' => 'project',
             'type' => 'project',
             'install_path' => __DIR__ . '/../../',
             'install_path' => __DIR__ . '/../../',
             'aliases' => array(),
             'aliases' => array(),

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