From 5a4667b4afc4bea61b617a839fec61ccf2071a40 Mon Sep 17 00:00:00 2001 From: Robert Jackson Date: Thu, 9 Apr 2015 07:17:29 -0400 Subject: [PATCH] [SECURITY CVE-2015-1866] Escape Ember.Select option label contents. (cherry picked from commit 29703251a3d36ff972753985aa23f4e6bf2cf24e) (cherry picked from commit 3368489926d95cc0c9960e31c7ca904b9b092300) --- .../lib/templates/select-option.hbs | 1 + packages/ember-views/lib/views/select.js | 16 +------- .../ember-views/tests/views/select_test.js | 39 +++++++++++++++++++ 3 files changed, 41 insertions(+), 15 deletions(-) create mode 100644 packages/ember-htmlbars/lib/templates/select-option.hbs diff --git a/packages/ember-htmlbars/lib/templates/select-option.hbs b/packages/ember-htmlbars/lib/templates/select-option.hbs new file mode 100644 index 00000000000..6471e4e9467 --- /dev/null +++ b/packages/ember-htmlbars/lib/templates/select-option.hbs @@ -0,0 +1 @@ +{{~view.label~}} diff --git a/packages/ember-views/lib/views/select.js b/packages/ember-views/lib/views/select.js index f5de69dd801..191e813ab48 100644 --- a/packages/ember-views/lib/views/select.js +++ b/packages/ember-views/lib/views/select.js @@ -21,26 +21,12 @@ import { computed } from "ember-metal/computed"; import { A as emberA } from "ember-runtime/system/native_array"; import { observer } from "ember-metal/mixin"; import { defineProperty } from "ember-metal/properties"; -import run from "ember-metal/run_loop"; import htmlbarsTemplate from "ember-htmlbars/templates/select"; +import selectOptionDefaultTemplate from "ember-htmlbars/templates/select-option"; var defaultTemplate = htmlbarsTemplate; -var selectOptionDefaultTemplate = { - isHTMLBars: true, - revision: 'Ember@VERSION_STRING_PLACEHOLDER', - render(context, env, contextualElement) { - var lazyValue = context.getStream('view.label'); - - lazyValue.subscribe(context._wrapAsScheduled(function() { - run.scheduleOnce('render', context, 'rerender'); - })); - - return lazyValue.value(); - } -}; - var SelectOption = View.extend({ instrumentDisplay: 'Ember.SelectOption', diff --git a/packages/ember-views/tests/views/select_test.js b/packages/ember-views/tests/views/select_test.js index d9fb5000af1..af509339cd0 100644 --- a/packages/ember-views/tests/views/select_test.js +++ b/packages/ember-views/tests/views/select_test.js @@ -4,6 +4,7 @@ import run from "ember-metal/run_loop"; import jQuery from "ember-views/system/jquery"; import { map } from "ember-metal/enumerable_utils"; import EventDispatcher from "ember-views/system/event_dispatcher"; +import SafeString from 'htmlbars-util/safe-string'; var trim = jQuery.trim; @@ -133,6 +134,44 @@ QUnit.test("can specify the property path for an option's label and value", func deepEqual(map(select.$('option').toArray(), function(el) { return jQuery(el).attr('value'); }), ["1", "2"], "Options should have values"); }); +QUnit.test("XSS: does not escape label value when it is a SafeString", function() { + select.set('content', Ember.A([ + { id: 1, firstName: new SafeString('

Yehuda

') }, + { id: 2, firstName: new SafeString('

Tom

') } + ])); + + select.set('optionLabelPath', 'content.firstName'); + select.set('optionValuePath', 'content.id'); + + append(); + + equal(select.$('option').length, 2, "Should have two options"); + equal(select.$('option[value=1] b').length, 1, "Should have child elements"); + + // IE 8 adds whitespace + equal(trim(select.$().text()), "YehudaTom", "Options should have content"); + deepEqual(map(select.$('option').toArray(), function(el) { return jQuery(el).attr('value'); }), ["1", "2"], "Options should have values"); +}); + +QUnit.test("XSS: escapes label value content", function() { + select.set('content', Ember.A([ + { id: 1, firstName: '

Yehuda

' }, + { id: 2, firstName: '

Tom

' } + ])); + + select.set('optionLabelPath', 'content.firstName'); + select.set('optionValuePath', 'content.id'); + + append(); + + equal(select.$('option').length, 2, "Should have two options"); + equal(select.$('option[value=1] b').length, 0, "Should have no child elements"); + + // IE 8 adds whitespace + equal(trim(select.$().text()), "

Yehuda

Tom

", "Options should have content"); + deepEqual(map(select.$('option').toArray(), function(el) { return jQuery(el).attr('value'); }), ["1", "2"], "Options should have values"); +}); + QUnit.test("can retrieve the current selected option when multiple=false", function() { var yehuda = { id: 1, firstName: 'Yehuda' }; var tom = { id: 2, firstName: 'Tom' };