From 214d306837bf076f79e01ab023e937a9fbbdde50 Mon Sep 17 00:00:00 2001 From: Basil Crow Date: Fri, 11 Oct 2024 14:04:18 -0700 Subject: [PATCH] [JENKINS-69651] CSP compatibility for `ScriptApproval` --- ...cated-approvedClasspaths-clear-btn-hide.js | 2 + ...cated-approvedClasspaths-clear-btn-show.js | 2 + .../scripts/ScriptApproval/index.jelly | 210 ++-------------- .../scripts/ScriptApproval/script-approval.js | 236 ++++++++++++++++++ 4 files changed, 259 insertions(+), 191 deletions(-) create mode 100644 src/main/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval/deprecated-approvedClasspaths-clear-btn-hide.js create mode 100644 src/main/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval/deprecated-approvedClasspaths-clear-btn-show.js create mode 100644 src/main/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval/script-approval.js diff --git a/src/main/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval/deprecated-approvedClasspaths-clear-btn-hide.js b/src/main/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval/deprecated-approvedClasspaths-clear-btn-hide.js new file mode 100644 index 000000000..777b5b8f6 --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval/deprecated-approvedClasspaths-clear-btn-hide.js @@ -0,0 +1,2 @@ +document.getElementById('deprecated-approvedClasspaths-clear-btn').style.display = 'none'; +document.getElementById('deprecated-approvedClasspaths-clear-spinner').style.display = ''; diff --git a/src/main/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval/deprecated-approvedClasspaths-clear-btn-show.js b/src/main/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval/deprecated-approvedClasspaths-clear-btn-show.js new file mode 100644 index 000000000..d7d39bd5c --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval/deprecated-approvedClasspaths-clear-btn-show.js @@ -0,0 +1,2 @@ +document.getElementById('deprecated-approvedClasspaths-clear-btn').style.display = ''; +document.getElementById('deprecated-approvedClasspaths-clear-spinner').style.display = 'none'; diff --git a/src/main/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval/index.jelly b/src/main/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval/index.jelly index cb2ca82a3..8c56b0e0d 100644 --- a/src/main/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval/index.jelly +++ b/src/main/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval/index.jelly @@ -27,176 +27,8 @@ THE SOFTWARE. - + +

@@ -207,7 +39,7 @@ THE SOFTWARE.

- / ${ps.language.displayName} script + / ${ps.language.displayName} script :

@@ -218,7 +50,7 @@ THE SOFTWARE.

You have script approvals with deprecated hashes: - +

Script approvals are stored in Jenkins as the hashed value of the script. Old approvals were hashed using SHA-1, which is deprecated. @@ -228,7 +60,7 @@ THE SOFTWARE.

You can also remove all previous script approvals: - +


@@ -240,12 +72,12 @@ THE SOFTWARE.
-

- / +

+ / - / + / - signature + signature : ${s.signature} @@ -274,13 +106,15 @@ THE SOFTWARE. ${line} -

+

You can also remove all previous signature approvals: - +

- Or you can just remove the dangerous ones: - +

+ Or you can just remove the dangerous ones: + +


@@ -299,7 +133,7 @@ THE SOFTWARE.

You have ${it.countDeprecatedApprovedClasspathHashes()} approved classpath entries with deprecated hashes: - + @@ -312,22 +146,16 @@ THE SOFTWARE.

- + - +

You can also remove all previous classpath entry approvals: - +

diff --git a/src/main/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval/script-approval.js b/src/main/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval/script-approval.js new file mode 100644 index 000000000..71837764b --- /dev/null +++ b/src/main/resources/org/jenkinsci/plugins/scriptsecurity/scripts/ScriptApproval/script-approval.js @@ -0,0 +1,236 @@ +function hideScript(hash) { + document.getElementById('ps-' + hash).remove(); +} +function approveScript(hash) { + mgr.approveScript(hash); + hideScript(hash); +} +function denyScript(hash) { + mgr.denyScript(hash); + hideScript(hash); +} +function hideSignature(hash) { + document.getElementById('s-' + hash).style.display = 'none'; +} +function updateApprovedSignatures(r) { + var both = r.responseObject(); + document.getElementById('approvedSignatures').value = both[0].join('\n'); + document.getElementById('aclApprovedSignatures').value = both[1].join('\n'); + if (document.getElementById('dangerousApprovedSignatures')) { + document.getElementById('dangerousApprovedSignatures').value = both[2].join('\n'); + } +} +function approveSignature(signature, hash) { + mgr.approveSignature(signature, function(r) { + updateApprovedSignatures(r); + }); + hideSignature(hash); +} +function aclApproveSignature(signature, hash) { + mgr.aclApproveSignature(signature, function(r) { + updateApprovedSignatures(r); + }); + hideSignature(hash); +} +function denySignature(signature, hash) { + mgr.denySignature(signature); + hideSignature(hash); +} +function clearApprovedSignatures() { + mgr.clearApprovedSignatures(function(r) { + updateApprovedSignatures(r); + }); +} +function clearDangerousApprovedSignatures() { + mgr.clearDangerousApprovedSignatures(function(r) { + updateApprovedSignatures(r); + }); +} + +function renderPendingClasspathEntries(pendingClasspathEntries) { + if (pendingClasspathEntries.length == 0) { + document.getElementById('pendingClasspathEntries-none').style.display = ''; + Array.from(document.getElementById('pendingClasspathEntries').children).forEach(function(e){e.remove()}); + document.getElementById('pendingClasspathEntries').style.display = 'none'; + } else { + document.getElementById('pendingClasspathEntries-none').style.display = 'none'; + Array.from(document.getElementById('pendingClasspathEntries').children).forEach(function(e){e.remove()}); + pendingClasspathEntries.forEach(function(e) { + var block = document.createElement('p'); + block.setAttribute('id', 'pcp-' + e.hash); + var approveButton = document.createElement('button'); + approveButton.setAttribute('class', 'approve'); + approveButton.setAttribute('hash', e.hash); + approveButton.textContent = 'Approve'; + approveButton.addEventListener('click', function() { + approveClasspathEntry(this.getAttribute('hash')); + }); + var denyButton = document.createElement('button'); + denyButton.setAttribute('class', 'deny'); + denyButton.setAttribute('hash', e.hash); + denyButton.textContent = 'Deny'; + denyButton.addEventListener('click', function() { + denyClasspathEntry(this.getAttribute('hash')); + }); + block.appendChild(approveButton); + block.appendChild(denyButton); + var code = document.createElement('code'); + code.setAttribute('title', e.hash); + code.textContent = e.path; + block.appendChild(code); + + document.getElementById('pendingClasspathEntries').appendChild(block); + }); + document.getElementById('pendingClasspathEntries').style.display = ''; + } +} + +function renderApprovedClasspathEntries(approvedClasspathEntries) { + if (approvedClasspathEntries.length == 0) { + document.getElementById('approvedClasspathEntries-none').style.display = ''; + Array.from(document.getElementById('approvedClasspathEntries').children).forEach(function(e){e.remove()}); + document.getElementById('approvedClasspathEntries').style.display = 'none'; + document.getElementById('approvedClasspathEntries-clear').style.display = 'none'; + } else { + document.getElementById('approvedClasspathEntries-none').style.display = 'none'; + Array.from(document.getElementById('approvedClasspathEntries').children).forEach(function(e){e.remove()}); + approvedClasspathEntries.forEach(function(e) { + var block = document.createElement('p'); + block.setAttribute('id', 'acp-' + e.hash); + var deleteButton = document.createElement('button'); + deleteButton.setAttribute('class', 'delete'); + deleteButton.setAttribute('hash', e.hash); + deleteButton.textContent = 'Delete'; + deleteButton.addEventListener('click', function() { + if (confirm('Really delete this approved classpath entry? Any existing scripts using it will need to be rerun and the entry reapproved.')) { + denyApprovedClasspathEntry(this.getAttribute('hash')); + } + }); + block.appendChild(deleteButton); + var code = document.createElement('code'); + code.setAttribute('title', e.hash); + code.textContent = e.path; + block.appendChild(code); + + document.getElementById('approvedClasspathEntries').appendChild(block); + }); + document.getElementById('approvedClasspathEntries').style.display = ''; + document.getElementById('approvedClasspathEntries-clear').style.display = ''; + } +} + +function renderClasspaths(r) { + renderPendingClasspathEntries(r.responseObject()[0]); + renderApprovedClasspathEntries(r.responseObject()[1]); +} + +function approveClasspathEntry(hash) { + mgr.approveClasspathEntry(hash, function(r) { + renderClasspaths(r); + }); +} +function denyClasspathEntry(hash) { + mgr.denyClasspathEntry(hash, function(r) { + renderClasspaths(r); + }); +} +function denyApprovedClasspathEntry(hash) { + mgr.denyApprovedClasspathEntry(hash, function(r) { + renderClasspaths(r); + }); +} +function clearApprovedClasspathEntries() { + mgr.clearApprovedClasspathEntries(function(r) { + renderClasspaths(r); + }); +} + +document.addEventListener('DOMContentLoaded', function() { + mgr.getClasspathRenderInfo(function(r) { + renderClasspaths(r); + }); + + const approveScriptButtons = document.querySelectorAll('.ps-context button.approve'); + approveScriptButtons.forEach(function (button) { + button.addEventListener('click', function () { + approveScript(button.dataset.hash); + }); + }); + + const denyScriptButtons = document.querySelectorAll('.ps-context button.deny'); + denyScriptButtons.forEach(function (button) { + button.addEventListener('click', function () { + denyScript(button.dataset.hash); + }); + }); + + const deprecatedApprovedScriptsClearButton = document.querySelector('#deprecated-approvedScripts-clear button'); + if (deprecatedApprovedScriptsClearButton) { + deprecatedApprovedScriptsClearButton.addEventListener('click', function () { + if (confirm('Really delete all deprecated approvals? Any existing scripts will need to be requeued and reapproved.')) { + mgr.clearDeprecatedApprovedScripts(); + document.getElementById('deprecated-approvedScripts-clear').style.display = 'none'; + } + }); + } + + const approvedScriptsClearButton = document.querySelector('#approvedScripts-clear button'); + approvedScriptsClearButton.addEventListener('click', function () { + if (confirm('Really delete all approvals? Any existing scripts will need to be requeued and reapproved.')) { + mgr.clearApprovedScripts(); + } + }); + + const approveSignatureButtons = document.querySelectorAll('.s-context button.approve'); + approveSignatureButtons.forEach(function (button) { + button.addEventListener('click', function () { + approveSignature(button.dataset.signature, button.dataset.hash); + }); + }); + + const aclApproveSignatureButtons = document.querySelectorAll('.s-context button.acl-approve'); + aclApproveSignatureButtons.forEach(function (button) { + button.addEventListener('click', function () { + aclApproveSignature(button.dataset.signature, button.dataset.hash); + }); + }); + + const denySignatureButtons = document.querySelectorAll('.s-context button.deny'); + denySignatureButtons.forEach(function (button) { + button.addEventListener('click', function () { + denySignature(button.dataset.signature, button.dataset.hash); + }); + }); + + const approvedSignaturesClearButton = document.querySelector('#approvedSignatures-clear button'); + approvedSignaturesClearButton.addEventListener('click', function () { + if (confirm('Really delete all approvals? Any existing scripts will need to be rerun and signatures reapproved.')) { + clearApprovedSignatures(); + } + }); + + const dangerousApprovedSignaturesClearButton = document.querySelector('#dangerousApprovedSignatures-clear button'); + if (dangerousApprovedSignaturesClearButton) { + dangerousApprovedSignaturesClearButton.addEventListener('click', function () { + clearDangerousApprovedSignatures(); + }); + } + + const deprecatedApprovedClasspathsClearButton = document.querySelector('#deprecated-approvedClasspaths-clear-btn button'); + if (deprecatedApprovedClasspathsClearButton) { + deprecatedApprovedClasspathsClearButton.addEventListener('click', function () { + if (confirm('This will be scheduled on a background thread. You can follow the progress in the system log')) { + mgr.convertDeprecatedApprovedClasspathEntries(); + document.getElementById('deprecated-approvedClasspaths-clear-btn').style.display = 'none'; + document.getElementById('deprecated-approvedClasspaths-clear-spinner').style.display = ''; + } + }); + } + + const approvedClasspathEntriesClearButton = document.querySelector('#approvedClasspathEntries-clear button'); + approvedClasspathEntriesClearButton.addEventListener('click', function () { + if (confirm('Really delete all approvals? Any existing scripts using a classpath will need to be rerun and entries reapproved.')) { + clearApprovedClasspathEntries(); + } + }); +});