Skip to content

Commit 5bdc85b

Browse files
authored
Core: Support passing nonce through jQuery.globalEval
Fixes jquerygh-4278 Closes jquerygh-4280 Ref jquerygh-3541 Ref jquerygh-4269
1 parent e4de8b4 commit 5bdc85b

File tree

8 files changed

+64
-17
lines changed

8 files changed

+64
-17
lines changed

src/core.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -238,8 +238,8 @@ jQuery.extend( {
238238
},
239239

240240
// Evaluates a script in a global context
241-
globalEval: function( code ) {
242-
DOMEval( code );
241+
globalEval: function( code, options ) {
242+
DOMEval( code, { nonce: options && options.nonce } );
243243
},
244244

245245
each: function( obj, callback ) {

src/core/DOMEval.js

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,29 @@ define( [
1010
noModule: true
1111
};
1212

13-
function DOMEval( code, doc, node ) {
13+
function DOMEval( code, node, doc ) {
1414
doc = doc || document;
1515

16-
var i,
16+
var i, val,
1717
script = doc.createElement( "script" );
1818

1919
script.text = code;
2020
if ( node ) {
2121
for ( i in preservedScriptAttributes ) {
22-
if ( node[ i ] ) {
23-
script[ i ] = node[ i ];
24-
} else if ( node.getAttribute( i ) ) {
2522

26-
// Support: Firefox 64+, Edge 18+
27-
// Some browsers don't support the "nonce" property on scripts.
28-
// On the other hand, just using `setAttribute` & `getAttribute`
29-
// is not enough as `nonce` is no longer exposed as an attribute
30-
// in the latest standard.
31-
// See https://github.com/whatwg/html/issues/2369
32-
script.setAttribute( i, node.getAttribute( i ) );
23+
// Support: Firefox 64+, Edge 18+
24+
// Some browsers don't support the "nonce" property on scripts.
25+
// On the other hand, just using `getAttribute` is not enough as
26+
// the `nonce` attribute is reset to an empty string whenever it
27+
// becomes browsing-context connected.
28+
// See https://github.com/whatwg/html/issues/2369
29+
// See https://html.spec.whatwg.org/#nonce-attributes
30+
// The `node.getAttribute` check was added for the sake of
31+
// `jQuery.globalEval` so that it can fake a nonce-containing node
32+
// via an object.
33+
val = node[ i ] || node.getAttribute && node.getAttribute( i );
34+
if ( val ) {
35+
script.setAttribute( i, val );
3336
}
3437
}
3538
}

src/manipulation.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ function domManip( collection, args, callback, ignored ) {
202202
jQuery._evalUrl( node.src );
203203
}
204204
} else {
205-
DOMEval( node.textContent.replace( rcleanScript, "" ), doc, node );
205+
DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc );
206206
}
207207
}
208208
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5+
<title>CSP nonce via jQuery.globalEval Test Page</title>
6+
<script nonce="jquery+hardcoded+nonce" src="../jquery.js"></script>
7+
<script nonce="jquery+hardcoded+nonce" src="iframeTest.js"></script>
8+
<script nonce="jquery+hardcoded+nonce" src="csp-nonce-globaleval.js"></script>
9+
</head>
10+
<body>
11+
<p>CSP nonce via jQuery.globalEval Test Page</p>
12+
</body>
13+
</html>

test/data/csp-nonce-globaleval.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/* global startIframeTest */
2+
3+
jQuery( function() {
4+
$.globalEval( "startIframeTest()", { nonce: "jquery+hardcoded+nonce" } );
5+
} );

test/data/mock.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,10 @@ protected function cspFrame( $req ) {
201201
protected function cspNonce( $req ) {
202202
// This is CSP only for browsers with "Content-Security-Policy" header support
203203
// i.e. no old WebKit or old Firefox
204+
$test = $req->query['test'] ? '-' . $req->query['test'] : '';
204205
header( "Content-Security-Policy: script-src 'nonce-jquery+hardcoded+nonce'; report-uri ./mock.php?action=cspLog" );
205206
header( 'Content-type: text/html' );
206-
echo file_get_contents( __DIR__ . '/csp-nonce.html' );
207+
echo file_get_contents( __DIR__ . '/csp-nonce' . $test . '.html' );
207208
}
208209

209210
protected function cspLog( $req ) {

test/middleware-mockserver.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,11 +208,13 @@ var mocks = {
208208
resp.end( body );
209209
},
210210
cspNonce: function( req, resp ) {
211+
var testParam = req.query.test ? "-" + req.query.test : "";
211212
resp.writeHead( 200, {
212213
"Content-Type": "text/html",
213214
"Content-Security-Policy": "script-src 'nonce-jquery+hardcoded+nonce'; report-uri /base/test/data/mock.php?action=cspLog"
214215
} );
215-
var body = fs.readFileSync( __dirname + "/data/csp-nonce.html" ).toString();
216+
var body = fs.readFileSync(
217+
__dirname + "/data/csp-nonce" + testParam + ".html" ).toString();
216218
resp.end( body );
217219
},
218220
cspLog: function( req, resp ) {

test/unit/manipulation.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2888,3 +2888,26 @@ testIframe(
28882888
// script-src restrictions completely.
28892889
QUnit[ /\bedge\/|iphone os [789]|android 4\./i.test( navigator.userAgent ) ? "skip" : "test" ]
28902890
);
2891+
2892+
testIframe(
2893+
"jQuery.globalEval supports nonce",
2894+
"mock.php?action=cspNonce&test=globaleval",
2895+
function( assert, jQuery, window, document ) {
2896+
var done = assert.async();
2897+
2898+
assert.expect( 1 );
2899+
2900+
supportjQuery.get( baseURL + "support/csp.log" ).done( function( data ) {
2901+
assert.equal( data, "", "No log request should be sent" );
2902+
supportjQuery.get( baseURL + "mock.php?action=cspClean" ).done( done );
2903+
} );
2904+
},
2905+
2906+
// Support: Edge 18+, iOS 7-9 only, Android 4.0-4.4 only
2907+
// Edge doesn't support nonce in non-inline scripts.
2908+
// See https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/13246371/
2909+
// Old iOS & Android Browser versions support script-src but not nonce, making this test
2910+
// impossible to run. Browsers not supporting CSP at all are not a problem as they'll skip
2911+
// script-src restrictions completely.
2912+
QUnit[ /\bedge\/|iphone os [789]|android 4\./i.test( navigator.userAgent ) ? "skip" : "test" ]
2913+
);

0 commit comments

Comments
 (0)