Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions user/src/com/google/gwt/dom/client/StyleInjector.java
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,21 @@ public void setContents(StyleElement style, String contents) {

private StyleElement createElement(String contents) {
StyleElement style = Document.get().createStyleElement();
propagateNonceIfPossible(style);
style.setPropertyString("language", "text/css");
setContents(style, contents);
return style;
}

private static native void propagateNonceIfPossible(Element element) /*-{
var doc = element.ownerDocument;
if (doc.querySelector && doc.querySelector('script[nonce]')) {
var firstNoncedScript = doc.querySelector('script[nonce]');
var nonce = firstNoncedScript['nonce'] || firstNoncedScript.getAttribute('nonce');
element.setAttribute('nonce', nonce);
}
}-*/;

private HeadElement getHead() {
if (head == null) {
Element elt = Document.get().getElementsByTagName("head").getItem(0);
Expand Down
63 changes: 63 additions & 0 deletions user/test/com/google/gwt/dom/client/StyleInjectorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.google.gwt.dom.client;

import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.junit.client.GWTTestCase;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
Expand All @@ -31,6 +32,41 @@ public String getModuleName() {
return "com.google.gwt.dom.DOMTest";
}

@SuppressWarnings("deprecation")
public void testStyleInjectorCopiesNonceFromExistingScriptElement() {
final String nonce = "StyleInjectorNonce";
ScriptElement noncedScript = Document.get().createScriptElement();
noncedScript.setAttribute("nonce", nonce);
Document.get().getHead().insertBefore(noncedScript, Document.get().getHead().getFirstChild());

StyleElement style = null;
try {
style = StyleInjector.injectStylesheet(".styleInjectorNonceTest { color: red; }");
assertEquals(nonce, getNonce(style));
} finally {
if (style != null) {
style.removeFromParent();
}
noncedScript.removeFromParent();
}
}

@SuppressWarnings("deprecation")
public void testStyleInjectorDoesNotCreateNonceWithoutSource() {
JavaScriptObject savedNonces = removeScriptNonces();
StyleElement style = null;
try {
assertFalse(hasNoncedScript());
style = StyleInjector.injectStylesheet(".styleInjectorNoNonceTest { color: blue; }");
assertNull(getNonce(style));
} finally {
if (style != null) {
style.removeFromParent();
}
restoreScriptNonces(savedNonces);
}
}

@SuppressWarnings("deprecation")
public void testOldMethods() {
final DivElement elt = Document.get().createDivElement();
Expand Down Expand Up @@ -139,4 +175,31 @@ public void execute() {
delayTestFinish(TEST_DELAY);
}
}

private static native String getNonce(Element element) /*-{
return element['nonce'] || element.getAttribute('nonce') || null;
}-*/;

private static native boolean hasNoncedScript() /*-{
return !!$doc.querySelector('script[nonce]');
}-*/;

private static native JavaScriptObject removeScriptNonces() /*-{
var scripts = $doc.querySelectorAll('script[nonce]');
var savedNonces = [];
for (var i = 0; i < scripts.length; i++) {
savedNonces.push({
element: scripts[i],
nonce: scripts[i]['nonce'] || scripts[i].getAttribute('nonce')
});
scripts[i].removeAttribute('nonce');
}
return savedNonces;
}-*/;

private static native void restoreScriptNonces(JavaScriptObject savedNonces) /*-{
for (var i = 0; i < savedNonces.length; i++) {
savedNonces[i].element.setAttribute('nonce', savedNonces[i].nonce);
}
}-*/;
}