Sfoglia il codice sorgente

fix(TopNav): tolerate missing discussion and password elements

Since the jQuery removal in 2.1.0, creating a document fails with "TypeError: can't access property "classList", openDiscussionOption is null" when `discussion = false` is set in the configuration, because the template omits the `#opendiscussionoption` element. The same applies to `#password` when `password = false`. The page then stays stuck on "Preparing document…".

Guard the three remaining unguarded accesses in TopNav.showCreateButtons(), TopNav.hideCreateButtons() and TopNav.resetInput(), consistent with the existing guards in the change handlers. Add unit tests covering the omitted elements and update the SRI hash of js/privatebin.js.
Upellift99 3 settimane fa
parent
commit
0250510c15
4 ha cambiato i file con 55 aggiunte e 6 eliminazioni
  1. 1 0
      CHANGELOG.md
  2. 13 5
      js/privatebin.js
  3. 40 0
      js/test/TopNav.js
  4. 1 1
      lib/Configuration.php

+ 1 - 0
CHANGELOG.md

@@ -1,6 +1,7 @@
 # PrivateBin version history
 
 ## 2.1.1 (not yet released)
+* FIXED: Creating a document failed with a JavaScript error when the `discussion` or `password` option is disabled, as the top navigation accessed the omitted elements
 
 ## 2.1.0 (2026-10-18)
 * ADDED: Added `shortenviachhoto` endpoint with an `chhoto` configuration section

+ 13 - 5
js/privatebin.js

@@ -4333,8 +4333,12 @@ window.PrivateBin = (function () {
             expiration.classList.remove('hidden');
             formatter.classList.remove('hidden');
             newButton.classList.remove('hidden');
-            openDiscussionOption.classList.remove('hidden');
-            password.classList.remove('hidden');
+            if (openDiscussionOption) {
+                openDiscussionOption.classList.remove('hidden');
+            }
+            if (password) {
+                password.classList.remove('hidden');
+            }
             sendButton.classList.remove('hidden');
 
             createButtonsDisplayed = true;
@@ -4356,8 +4360,12 @@ window.PrivateBin = (function () {
             expiration.classList.add('hidden');
             formatter.classList.add('hidden');
             burnAfterReadingOption.classList.add('hidden');
-            openDiscussionOption.classList.add('hidden');
-            password.classList.add('hidden');
+            if (openDiscussionOption) {
+                openDiscussionOption.classList.add('hidden');
+            }
+            if (password) {
+                password.classList.add('hidden');
+            }
             if (attach) {
                 attach.classList.add('hidden');
             }
@@ -4571,7 +4579,7 @@ window.PrivateBin = (function () {
             if (openDiscussion) {
                 openDiscussion.checked = openDiscussionDefault;
             }
-            if (openDiscussionDefault || !burnAfterReadingDefault) {
+            if (openDiscussionOption && (openDiscussionDefault || !burnAfterReadingDefault)) {
                 openDiscussionOption.classList.remove('buttondisabled');
             }
             if (burnAfterReadingDefault || !openDiscussionDefault) {

+ 40 - 0
js/test/TopNav.js

@@ -125,6 +125,31 @@ describe('TopNav', function () {
                 assert.ok(result);
             }
         );
+
+        it(
+            'tolerates missing optional elements (discussion & password disabled)',
+            function () {
+                // with discussion = false and password = false in the
+                // configuration, the template omits these elements entirely
+                document.documentElement.innerHTML =
+                    '<nav><div id="navbar"><ul><li><button id="newbutton" ' +
+                    'type="button" class="hidden">New</button></li><li><a ' +
+                    'id="expiration" href="#" class="hidden">Expiration</a>' +
+                    '</li><li><div id="burnafterreadingoption" class="hidden">' +
+                    'Burn after reading</div></li><li>' +
+                    '<a id="formatter" href="#" class="hidden">Format</a>' +
+                    '</li><li><button id="sendbutton" type="button" ' +
+                    'class="hidden">Create</button></li></ul></div></nav>';
+                PrivateBin.TopNav.init();
+                assert.doesNotThrow(() => PrivateBin.TopNav.showCreateButtons());
+                assert.ok(!query('#sendbutton').classList.contains('hidden'));
+                assert.ok(!query('#burnafterreadingoption').classList.contains('hidden'));
+                assert.doesNotThrow(() => PrivateBin.TopNav.hideCreateButtons());
+                assert.ok(query('#sendbutton').classList.contains('hidden'));
+                assert.ok(query('#burnafterreadingoption').classList.contains('hidden'));
+                cleanup();
+            }
+        );
     });
 
     describe('send shortcut', function () {
@@ -566,6 +591,21 @@ describe('TopNav', function () {
                 assert.ok(result);
             }
         );
+
+        it(
+            'tolerates a missing discussion option (discussion disabled)',
+            function () {
+                document.documentElement.innerHTML =
+                    '<nav><div id="navbar"><ul><li id="burnafterreadingoption" ' +
+                    'class="buttondisabled"><label><input type="checkbox" ' +
+                    'id="burnafterreading" name="burnafterreading" /> ' +
+                    'Burn after reading</label></li></ul></div></nav>';
+                PrivateBin.TopNav.init();
+                assert.doesNotThrow(() => PrivateBin.TopNav.resetInput());
+                assert.ok(!query('#burnafterreadingoption').classList.contains('buttondisabled'));
+                cleanup();
+            }
+        );
     });
 
     describe('getExpiration', function () {

+ 1 - 1
lib/Configuration.php

@@ -124,7 +124,7 @@ class Configuration
             'js/kjua-0.10.0.js'      => 'sha512-BYj4xggowR7QD150VLSTRlzH62YPfhpIM+b/1EUEr7RQpdWAGKulxWnOvjFx1FUlba4m6ihpNYuQab51H6XlYg==',
             'js/legacy.js'           => 'sha512-pRofxsrf5UItjiP22Dcjh3FAcBjF/n7h8U9/W5xqJk17U0N2U1oajhXypq/omo9jhwS1iVGOhWrRepoPeFns+w==',
             'js/prettify.js'         => 'sha512-puO0Ogy++IoA2Pb9IjSxV1n4+kQkKXYAEUtVzfZpQepyDPyXk8hokiYDS7ybMogYlyyEIwMLpZqVhCkARQWLMg==',
-            'js/privatebin.js'       => 'sha512-ECxau81icFK+pB7VsyYoxEMXrERcuE7ILhtTD6dedfsHZfL59+4f57SSvvpwIy/CZ665jyvtYZ9FBDZ1Lx3DAQ==',
+            'js/privatebin.js'       => 'sha512-n3OsnBiq2RnihXpDKdwrRJrF55DHJLyiD7oZtA47WYhVE3o46rma/g9VZQdTH6dy44s0nPtthuPU0nu0mSaRZQ==',
             'js/purify-3.4.17.js'    => 'sha512-udF2zPdEyVCAxIGeBbeSGFK1Fj5c4eHGi6NqOSsr8M75lGs39POzgUNxO3SFxOg4cHfAoZJgR2EaXdmDi6v6AQ==',
             'js/showdown-2.1.0.js'   => 'sha512-WYXZgkTR0u/Y9SVIA4nTTOih0kXMEd8RRV6MLFdL6YU8ymhR528NLlYQt1nlJQbYz4EW+ZsS0fx1awhiQJme1Q==',
             'js/zlib-1.3.2.js'       => 'sha512-RAhJgxg9siMIA8ky4c10Rc2zUgnK80olHB8Tt1IOYWY4Eh1WmrviQkDn+sgBlb38ZHq3tzufGC41kP360gmosQ==',