Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.
Closed
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
22 changes: 19 additions & 3 deletions src/core/services/theming/theming.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@ angular.module('material.core.theming', ['material.core.theming.palette'])
* @description Provider to configure the `$mdTheming` service.
*/

/**
* @ngdoc method
* @name $mdThemingProvider#setNonce
* @param {string} nonceValue The nonce to be added as an attribute to the theme style tags.
* Setting a value allows the use CSP policy without using the unsafe-inline directive.
*/

/**
* @ngdoc method
* @name $mdThemingProvider#setDefaultTheme
Expand Down Expand Up @@ -125,6 +132,9 @@ var VALID_HUE_VALUES = [
// Whether or not themes are to be generated on-demand (vs. eagerly).
var generateOnDemand = false;

// Nonce to be added as an attribute to the generated themes style tags.
var nonce = null;

function ThemingProvider($mdColorPalette) {
PALETTES = { };
THEMES = { };
Expand All @@ -143,6 +153,9 @@ function ThemingProvider($mdColorPalette) {
extendPalette: extendPalette,
theme: registerTheme,

setNonce: function(nonceValue) {
nonce = nonceValue;
},
setDefaultTheme: function(theme) {
defaultTheme = theme;
},
Expand Down Expand Up @@ -355,7 +368,7 @@ function ThemingProvider($mdColorPalette) {
applyTheme.THEMES = angular.extend({}, THEMES);
applyTheme.defaultTheme = function() { return defaultTheme; };
applyTheme.registered = registered;
applyTheme.generateTheme = generateTheme;
applyTheme.generateTheme = function(name) { generateTheme(name, nonce); };

return applyTheme;

Expand Down Expand Up @@ -516,7 +529,7 @@ function generateAllThemes($injector) {

angular.forEach(THEMES, function(theme) {
if (!GENERATED[theme.name]) {
generateTheme(theme.name);
generateTheme(theme.name, nonce);
}
});

Expand Down Expand Up @@ -581,7 +594,7 @@ function generateAllThemes($injector) {
}
}

function generateTheme(name) {
function generateTheme(name, nonce) {
var theme = THEMES[name];
var head = document.head;
var firstChild = head ? head.firstElementChild : null;
Expand All @@ -596,6 +609,9 @@ function generateTheme(name) {
if (styleContent) {
var style = document.createElement('style');
style.setAttribute('md-theme-style', '');
if (nonce) {
style.setAttribute('nonce', nonce);
}
style.appendChild(document.createTextNode(styleContent));
head.insertBefore(style, firstChild);
}
Expand Down
62 changes: 62 additions & 0 deletions src/core/services/theming/theming.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,68 @@ describe('$mdThemeProvider with on-demand generation', function() {
});
});

describe('$mdThemeProvider with nonce', function() {
beforeEach(function() {

module('material.core', function($provide) {
/**
* material-mocks.js clears the $MD_THEME_CSS for Karma testing performance
* performance optimizations. Here inject some length into our theme_css so that
* palettes are parsed/generated
*/
$provide.constant('$MD_THEME_CSS', '/**/');
});
});

describe('and auto-generated themes', function() {
beforeEach(function() {
module('material.core', function($mdThemingProvider) {
$mdThemingProvider.generateThemesOnDemand(false);

$mdThemingProvider.theme('auto-nonce')
.primaryPalette('light-blue')
.accentPalette('yellow');

$mdThemingProvider.setNonce('1');
});
inject();
});

it('should add a nonce', function() {
var styles = document.head.querySelectorAll('style[nonce="1"]');
expect(styles.length).toBe(4);
});
});

describe('and on-demand generated themes', function() {
var $mdTheming;

beforeEach(function() {
module('material.core', function($mdThemingProvider) {
$mdThemingProvider.generateThemesOnDemand(true);

$mdThemingProvider.theme('nonce')
.primaryPalette('light-blue')
.accentPalette('yellow');

$mdThemingProvider.setNonce('2');
});
inject(function(_$mdTheming_) {
$mdTheming = _$mdTheming_;
});
});

it('should add a nonce', function() {
var styles = document.head.querySelectorAll('style[nonce="2"]');
expect(styles.length).toBe(0);

$mdTheming.generateTheme('nonce');
styles = document.head.querySelectorAll('style[nonce="2"]');
expect(styles.length).toBe(4);
});
});
});

describe('$mdTheming service', function() {
var $mdThemingProvider;
beforeEach(module('material.core', function(_$mdThemingProvider_) {
Expand Down