Fix managed fonts and quoted styles in slide previews
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile, web, pulse-signage-web) (push) Successful in 1m20s
Publish Docker Image / build-and-push-existing-registry (./build/Dockerfile.player, player, pulse-signage-player) (push) Successful in 35s

This commit is contained in:
lzstealth committed 2026-10-26 01:52:55 +00:00
1 parent 5b5af1a7b9
commit ccd3535e7c
4 files changed
+61 -2

No files matched your search

+51
View File
@@ -35,6 +35,57 @@ function loadEditorTimeDateModule() {
return modules.get('time-date');
}
test('preview sanitizers preserve entity-quoted font families without double escaping', () => {
const entities = { apos: "'", quot: '"', amp: '&', lt: '<', gt: '>' };
const sandbox = {
window: {},
document: {
createElement(tag) {
assert.equal(tag, 'textarea');
return {
set innerHTML(value) {
this.value = value.replace(/&(#x[\da-f]+|#\d+|apos|quot|amp|lt|gt);/gi, (_match, entity) => {
if (entity[0] !== '#') return entities[entity];
return String.fromCodePoint(entity[1].toLowerCase() === 'x' ? parseInt(entity.slice(2), 16) : Number(entity.slice(1)));
});
}
};
}
}
};
vm.runInNewContext(fs.readFileSync(require.resolve('../src/web/public/js/regions/region-utils'), 'utf8'), sandbox);
for (const sanitize of [sandbox.window.pulseRegionUtils.sanitizePreviewHtml, sandbox.window.pulseRegionUtils.sanitizeRichText]) {
for (const quotes of ["'Ubuntu Regular'", '&#39;Ubuntu Regular&#39;', '&quot;Ubuntu Regular&quot;']) {
const markup = sanitize('<span style="font-family: ' + quotes + ';">Player</span>');
assert.doesNotMatch(markup, /&amp;#39;|&amp;quot;/);
assert.equal(sanitize(markup), markup);
assert.match(markup, /font-family: (?:&#39;Ubuntu Regular&#39;|&quot;Ubuntu Regular&quot;);/);
}
const unsafe = sanitize('<a href="java&#115;cript:alert(1)" style="background:u&#114;l(test)">Player</a>');
assert.doesNotMatch(unsafe, /href=|style=/);
}
});
test('page route wiring preserves the configured media directory for popup font stylesheets', () => {
let pageDependencies;
const sandbox = {
module: { exports: {} },
require(name) {
if (name === '#src/rbac') return { PERMISSIONS: [], normalizePermissionKeys: value => value };
return function (_app, dependencies) {
if (name === '#src/web/routes/admin/pages') pageDependencies = dependencies;
};
}
};
vm.runInNewContext(fs.readFileSync(require.resolve('../src/web/routes/register'), 'utf8'), sandbox);
sandbox.module.exports.registerRoutes({}, {
mediaDir: '/configured/signage-media',
playerActionService: {}
});
assert.equal(pageDependencies.mediaDir, '/configured/signage-media');
});
test('thumbnail payload passes saved region geometry and content to the popup renderer', () => {
const payload = buildThumbnailPreviewPayload({
template: {