mirror of
https://github.com/Cacti/cacti.git
synced 2026-11-03 02:27:13 +09:00
* security: harden browser history and dependency option merging Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * docs: record CodeQL triage decisions and follow-up scope Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: wait for history reload before inspecting browser storage Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * security: isolate HTMX history from the legacy navigation handler Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * ci: build CodeQL assets through controlled dependency installs Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * security: render form validation messages as plain text Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: verify drag rows and color input security boundaries Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: verify tree navigation rename and datetime input boundaries Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * security: harden menu rendering and complete CodeQL caller review Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * security: centralize menu rendering and stabilize certificate CI Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> * test: align certificate expectation with parallel web PR Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com> Co-authored-by: TheWitness <thewitness@cacti.net>
41 lines
1.4 KiB
JavaScript
41 lines
1.4 KiB
JavaScript
/* Copyright (C) 2026 The Cacti Group. SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
// One synchronous interface for legacy widgets that intentionally accept menu
|
|
// markup. Labels use text APIs instead. This policy is not a general-purpose
|
|
// template renderer: application attributes, IDs, styles and embeds are removed.
|
|
(() => {
|
|
'use strict';
|
|
|
|
function menuFragment(value) {
|
|
const content = typeof value === 'string' ? value : '';
|
|
if (!window.DOMPurify || !window.DOMPurify.isSupported) {
|
|
return document.createTextNode(content);
|
|
}
|
|
const fragment = window.DOMPurify.sanitize(content, {
|
|
ALLOWED_TAGS: ['h6', 'div', 'a', 'span', 'p', 'br', 'ul', 'ol', 'li', 'strong', 'em', 'b', 'i'],
|
|
ALLOWED_ATTR: ['href', 'title'],
|
|
ALLOW_DATA_ATTR: false,
|
|
ALLOW_ARIA_ATTR: false,
|
|
RETURN_DOM_FRAGMENT: true
|
|
});
|
|
fragment.querySelectorAll('a[href]').forEach(link => {
|
|
try {
|
|
const url = new URL(link.getAttribute('href'), document.baseURI);
|
|
if (!['http:', 'https:', 'mailto:', 'tel:'].includes(url.protocol)) {
|
|
link.removeAttribute('href');
|
|
}
|
|
} catch (error) {
|
|
link.removeAttribute('href');
|
|
}
|
|
});
|
|
return fragment;
|
|
}
|
|
|
|
// Legacy classic-script loaders need a shared synchronous interface. An own,
|
|
// immutable value also prevents HTML named properties from replacing it.
|
|
Object.defineProperty(window, 'CactiRenderer', {
|
|
value: Object.freeze({ menuFragment }),
|
|
configurable: true
|
|
});
|
|
})();
|