From ceb0c119a6bb54a447406e078d084d15a5916f1f Mon Sep 17 00:00:00 2001 From: Andrei Vorobev <738482+vorobey@users.noreply.github.com> Date: Thu, 23 Jul 2026 15:49:38 +0300 Subject: [PATCH 1/2] ASPNet: template compiler csp feature detection --- packages/devextreme/js/aspnet.js | 511 +++++++++++++++++++------------ 1 file changed, 315 insertions(+), 196 deletions(-) diff --git a/packages/devextreme/js/aspnet.js b/packages/devextreme/js/aspnet.js index da464425f726..fface0793b01 100644 --- a/packages/devextreme/js/aspnet.js +++ b/packages/devextreme/js/aspnet.js @@ -5,14 +5,15 @@ define(function(require, exports, module) { module.exports = factory( require('jquery'), - require('./core/templates/template_engine_registry').setTemplateEngine, + require('./core/templates/template_engine_registry') + .setTemplateEngine, require('./core/templates/template_base').renderedCallbacks, require('./core/guid'), require('./ui/validation_engine'), require('./core/utils/iterator'), require('./core/utils/dom').extractTemplateMarkup, require('./core/utils/string').encodeHtml, - require('./core/utils/ajax') + require('./core/utils/ajax'), ); }); } else { @@ -25,238 +26,356 @@ DevExpress.utils.iterator, DevExpress.utils.dom.extractTemplateMarkup, DevExpress.utils.string.encodeHtml, - DevExpress.utils.ajax + DevExpress.utils.ajax, ); } -})(function($, setTemplateEngine, templateRendered, Guid, validationEngine, iteratorUtils, extractTemplateMarkup, encodeHtml, ajax) { - var templateCompiler = createTemplateCompiler(); - var pendingCreateComponentRoutines = [ ]; +})( + function( + $, + setTemplateEngine, + templateRendered, + Guid, + validationEngine, + iteratorUtils, + extractTemplateMarkup, + encodeHtml, + ajax, + ) { + var templateCompiler = createTemplateCompiler(); - function createTemplateCompiler() { - var ENCODE_QUALIFIER = '-', - INTERPOLATE_QUALIFIER = '='; + function readCspDirective(csp, name) { + var directives = csp.split(';'); + for(var i = 0; i < directives.length; i++) { + var parts = directives[i].trim().split(/\s+/); + if(parts.length && parts[0].toLowerCase() === name) { + return parts.slice(1).join(' ').toLowerCase(); + } + } + return null; + } + + function detectCspRestricted() { + var doc = window.document; + var scripts = doc.getElementsByTagName('script'); + for(var i = 0; i < scripts.length; i++) { + if(scripts[i].nonce || scripts[i].getAttribute('nonce')) { + return true; + } + } + var meta = doc.querySelectorAll( + 'meta[http-equiv=\'Content-Security-Policy\' i]', + ); + for(var j = 0; j < meta.length; j++) { + var content = meta[j].getAttribute('content') || ''; + var directive = readCspDirective(content, 'script-src'); + if(null === directive) { + directive = readCspDirective(content, 'default-src'); + } + if( + null !== directive && + -1 === directive.indexOf('\'unsafe-eval\'') + ) { + return true; + } + } + return false; + } - var EXTENDED_OPEN_TAG = /[<[]%/g, - EXTENDED_CLOSE_TAG = /%[>\]]/g; + var cspRestricted = null; - function acceptText(bag, text) { - if(text) { - bag.push('_.push(', JSON.stringify(text), ');'); + function isCspRestricted() { + if(null === cspRestricted) { + cspRestricted = detectCspRestricted(); } + return cspRestricted; } - function acceptCode(bag, code) { - var encode = code.charAt(0) === ENCODE_QUALIFIER, - value = code.substr(1), - interpolate = code.charAt(0) === INTERPOLATE_QUALIFIER; - - if(encode || interpolate) { - bag.push('_.push('); - var expression = value; - if(encode) { - expression = 'encodeHtml((' + value + ' !== null && ' + value + ' !== undefined) ? ' + value + ' : "")'; - if(/^\s*$/.test(value)) { - expression = 'encodeHtml(' + value + ')'; - } - } - bag.push(expression); - bag.push(');'); - } else { - bag.push(code + '\n'); + function compileViaScript(src, code) { + if(!src || 'SCRIPT' !== src.tagName || !src.id) { + return null; } + if(isCspRestricted() && !src.nonce) { + // eslint-disable-next-line no-console + console.warn( + 'DevExtreme: template