diff --git a/packages/ember-htmlbars/tests/attr_nodes/style_test.js b/packages/ember-htmlbars/tests/attr_nodes/style_test.js index 888172d07b2..c3a4d571363 100644 --- a/packages/ember-htmlbars/tests/attr_nodes/style_test.js +++ b/packages/ember-htmlbars/tests/attr_nodes/style_test.js @@ -1,50 +1,78 @@ +/* globals EmberDev */ + +import Ember from "ember-metal/core"; import EmberView from "ember-views/views/view"; import compile from "ember-template-compiler/system/compile"; import { SafeString } from "ember-htmlbars/utils/string"; import { runAppend, runDestroy } from "ember-runtime/tests/utils"; +import { styleWarning } from "ember-views/attr_nodes/attr_node"; -var view; +var view, originalWarn, warnings; QUnit.module("ember-htmlbars: style attribute", { + setup() { + warnings = []; + originalWarn = Ember.warn; + Ember.warn = function(message, test) { + if (!test) { + warnings.push(message); + } + }; + }, + teardown() { runDestroy(view); + Ember.warn = originalWarn; } }); if (Ember.FEATURES.isEnabled('ember-htmlbars-attribute-syntax')) { // jscs:disable validateIndentation -QUnit.test('specifying `
') - }); +if (!EmberDev.runningProdBuild) { + QUnit.test('specifying `
` generates a warning', function() { + view = EmberView.create({ + userValue: 'width: 42px', + template: compile('
') + }); - expectDeprecation(function() { runAppend(view); - }, /Dynamic content in the `style` attribute is not escaped and may pose a security risk. Please perform a security audit and once verified change from `
` to `
/); -}); -QUnit.test('specifying `
') + deepEqual(warnings, [styleWarning]); }); - expectNoDeprecation(function() { + QUnit.test('specifying `attributeBindings: ["style"]` generates a warning', function() { + view = EmberView.create({ + userValue: 'width: 42px', + template: compile('
') + }); + runAppend(view); + + deepEqual(warnings, [styleWarning]); }); -}); +} -QUnit.test('specifying `
') + userValue: 'width: 42px', + template: compile('
') }); - expectNoDeprecation(function() { - runAppend(view); + runAppend(view); + + deepEqual(warnings, [ ]); +}); + +QUnit.test('specifying `
` works properly with a SafeString', function() { + view = EmberView.create({ + userValue: new SafeString('width: 42px'), + template: compile('
') }); + + runAppend(view); + + deepEqual(warnings, [ ]); }); // jscs:enable validateIndentation diff --git a/packages/ember-htmlbars/tests/helpers/bind_attr_test.js b/packages/ember-htmlbars/tests/helpers/bind_attr_test.js index 56e951700d3..cdb16513bc3 100644 --- a/packages/ember-htmlbars/tests/helpers/bind_attr_test.js +++ b/packages/ember-htmlbars/tests/helpers/bind_attr_test.js @@ -1,4 +1,6 @@ +/*globals EmberDev */ /*jshint newcap:false*/ + import Ember from "ember-metal/core"; // Ember.lookup import run from "ember-metal/run_loop"; import Namespace from "ember-runtime/system/namespace"; @@ -11,13 +13,15 @@ import { observersFor } from "ember-metal/observer"; import { Registry } from "ember-runtime/system/container"; import { set } from "ember-metal/property_set"; import { runAppend, runDestroy } from "ember-runtime/tests/utils"; +import { styleWarning } from "ember-views/attr_nodes/attr_node"; +import { SafeString } from "ember-htmlbars/utils/string"; import helpers from "ember-htmlbars/helpers"; import compile from "ember-template-compiler/system/compile"; var view; var originalLookup = Ember.lookup; -var TemplateTests, registry, container, lookup; +var TemplateTests, registry, container, lookup, warnings, originalWarn; /** This module specifically tests integration with Handlebars and Ember-specific @@ -35,6 +39,14 @@ QUnit.module("ember-htmlbars: {{bind-attr}}", { registry.optionsForType('template', { instantiate: false }); registry.register('view:default', _MetamorphView); registry.register('view:toplevel', EmberView.extend()); + + warnings = []; + originalWarn = Ember.warn; + Ember.warn = function(message, test) { + if (!test) { + warnings.push(message); + } + }; }, teardown() { @@ -43,6 +55,7 @@ QUnit.module("ember-htmlbars: {{bind-attr}}", { registry = container = view = null; Ember.lookup = lookup = originalLookup; + Ember.warn = originalWarn; TemplateTests = null; } }); @@ -600,24 +613,27 @@ QUnit.test("src attribute bound to null is not present", function() { ok(!view.element.firstChild.hasAttribute('src'), "src attribute not present"); }); -QUnit.test('specifying `
` is [DEPRECATED]', function() { - view = EmberView.create({ - userValue: '42', - template: compile('
') - }); +if (!EmberDev.runningProdBuild) { + + QUnit.test('specifying `
` triggers a warning', function() { + view = EmberView.create({ + userValue: '42', + template: compile('
') + }); - expectDeprecation(function() { runAppend(view); - }, /Dynamic content in the `style` attribute is not escaped and may pose a security risk. Please perform a security audit and once verified change from `
` to `
/); -}); -QUnit.test('specifying `
` works properly', function() { - view = EmberView.create({ - userValue: '42', - template: compile('
') + deepEqual(warnings, [styleWarning]); }); +} - expectNoDeprecation(function() { - runAppend(view); +QUnit.test('specifying `
` works properly with a SafeString', function() { + view = EmberView.create({ + userValue: new SafeString('42'), + template: compile('
') }); + + runAppend(view); + + deepEqual(warnings, [ ]); }); diff --git a/packages/ember-views/lib/attr_nodes/attr_node.js b/packages/ember-views/lib/attr_nodes/attr_node.js index dd1ad181107..3c7836fbe49 100644 --- a/packages/ember-views/lib/attr_nodes/attr_node.js +++ b/packages/ember-views/lib/attr_nodes/attr_node.js @@ -15,6 +15,11 @@ export default function AttrNode(attrName, attrValue) { this.init(attrName, attrValue); } +export var styleWarning = 'Binding style attributes may introduce cross-site scripting vulnerabilities; ' + + 'please ensure that values being bound are properly escaped. For more information, ' + + 'including how to disable this warning, see ' + + 'http://emberjs.com/deprecations/v1.x/#toc_warning-when-binding-style-attributes.'; + AttrNode.prototype.init = function init(attrName, simpleAttrValue) { this.isView = true; @@ -27,8 +32,6 @@ AttrNode.prototype.init = function init(attrName, simpleAttrValue) { this.isDestroying = false; this.lastValue = null; this.hasRenderedInitially = false; - this._dynamicStyleDeprecationMessage = '`
` to ' + - '`
`.'; subscribe(this.attrValue, this.rerender, this); }; @@ -76,16 +79,19 @@ AttrNode.prototype.render = function render(buffer) { }; AttrNode.prototype._deprecateEscapedStyle = function AttrNode_deprecateEscapedStyle(value) { - Ember.deprecate( - 'Dynamic content in the `style` attribute is not escaped and may pose a security risk. ' + - 'Please perform a security audit and once verified change from ' + - this._dynamicStyleDeprecationMessage, + Ember.warn( + styleWarning, (function(name, value, escaped) { // SafeString if (value && value.toHTML) { return true; } - return name !== 'style' || !escaped; + + if (name !== 'style') { + return true; + } + + return !escaped; }(this.attrName, value, this._morph.escaped)) ); }; diff --git a/packages/ember-views/lib/attr_nodes/legacy_bind.js b/packages/ember-views/lib/attr_nodes/legacy_bind.js index cda3fe51176..7ad2343eb31 100644 --- a/packages/ember-views/lib/attr_nodes/legacy_bind.js +++ b/packages/ember-views/lib/attr_nodes/legacy_bind.js @@ -11,9 +11,6 @@ import o_create from "ember-metal/platform/create"; function LegacyBindAttrNode(attrName, attrValue) { this.init(attrName, attrValue); - - this._dynamicStyleDeprecationMessage = '`
` to ' + - '`
`.'; } LegacyBindAttrNode.prototype = o_create(AttrNode.prototype); @@ -34,7 +31,7 @@ LegacyBindAttrNode.prototype.render = function render(buffer) { } Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [value]), - value === null || value === undefined || typeOf(value) === 'number' || typeOf(value) === 'string' || typeOf(value) === 'boolean'); + value === null || value === undefined || typeOf(value) === 'number' || typeOf(value) === 'string' || typeOf(value) === 'boolean' || !!(value && value.toHTML)); if (this.lastValue !== null || value !== null) { this._deprecateEscapedStyle(value);