Skip to content

Commit

Permalink
[bugfix] Use CSSOM for style manipulations
Browse files Browse the repository at this point in the history
Currently we assign the style property directly when manipulating CSS.
This is an XSS vector, and prevents security conscious users from using
a CSP that prevents this type of manipulation. We can avoid it by
assigning style properties directly on the `element.style` object, which
filters the text safely (as per CSSOM).

fixes #566
  • Loading branch information
pzuraq committed Jul 31, 2018
1 parent 9a36ddb commit f19477e
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 80 deletions.
47 changes: 47 additions & 0 deletions addon/components/-private/base-table-cell.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import Component from '@ember/component';
import { equal } from '@ember/object/computed';
import { observer } from '@ember/object';
import { scheduleOnce } from '@ember/runloop';

export default Component.extend({
// Provided by subclasses
columnMeta: null,

classNameBindings: ['isFirstColumn', 'isFixedLeft', 'isFixedRight'],

isFirstColumn: equal('columnMeta.index', 0),
isFixedLeft: equal('columnMeta.isFixed', 'left'),
isFixedRight: equal('columnMeta.isFixed', 'right'),

// eslint-disable-next-line
scheduleUpdateStyles: observer(
'columnMeta.{width,offsetLeft,offsetRight}',
'isFixedLeft',
'isFixedRight',

function() {
scheduleOnce('actions', this, 'updateStyles');
}
),

updateStyles() {
if (typeof FastBoot === 'undefined' && this.element) {
let width = `${this.get('columnMeta.width')}px`;

this.element.style.width = width;
this.element.style.minWidth = width;
this.element.style.maxWidth = width;

if (this.get('isFixedLeft')) {
this.element.style.left = `${Math.round(this.get('columnMeta.offsetLeft'))}px`;
} else if (this.get('isFixedRight')) {
this.element.style.right = `${Math.round(this.get('columnMeta.offsetRight'))}px`;
}
}
},

didInsertElement() {
this._super(...arguments);
this.updateStyles();
},
});
6 changes: 3 additions & 3 deletions addon/components/-private/row-wrapper.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ class CellWrapper extends EmberObject {
}
}

const layout = hbs`{{yield api}}`;

@tagName('')
export default class RowWrapper extends Component {
layout = hbs`
{{yield api}}
`;
layout = layout;

@argument rowValue;
@argument columns;
Expand Down
43 changes: 4 additions & 39 deletions addon/components/ember-td/component.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import Component from '@ember/component';
import { htmlSafe } from '@ember/string';
import BaseTableCell from '../-private/base-table-cell';

import { action, computed } from '@ember-decorators/object';
import { alias, readOnly, equal } from '@ember-decorators/object/computed';
import { tagName, attribute, className } from '@ember-decorators/component';
import { alias, readOnly } from '@ember-decorators/object/computed';
import { tagName } from '@ember-decorators/component';
import { argument } from '@ember-decorators/argument';
import { type, optional } from '@ember-decorators/argument/type';
import { Action } from '@ember-decorators/argument/types';
Expand Down Expand Up @@ -39,7 +38,7 @@ import { SELECT_MODE } from '../../-private/collapse-tree';
@yield {object} rowMeta - The meta object associated with the row
*/
@tagName('td')
export default class EmberTd extends Component {
export default class EmberTd extends BaseTableCell {
layout = layout;

/**
Expand Down Expand Up @@ -80,18 +79,6 @@ export default class EmberTd extends Component {
@readOnly('unwrappedApi.rowSelectionMode') rowSelectionMode;
@readOnly('unwrappedApi.checkboxSelectionMode') checkboxSelectionMode;

@className
@equal('columnMeta.index', 0)
isFirstColumn;

@className
@equal('columnMeta.isFixed', 'left')
isFixedLeft;

@className
@equal('columnMeta.isFixed', 'right')
isFixedRight;

@readOnly('rowMeta.canCollapse') canCollapse;

@computed('rowMeta.depth')
Expand Down Expand Up @@ -120,28 +107,6 @@ export default class EmberTd extends Component {
);
}

@attribute
@computed('columnMeta.{width,offsetLeft,offsetRight}', 'isFixed')
get style() {
let width = this.get('columnMeta.width');

let style = `width: ${width}px; min-width: ${width}px; max-width: ${width}px;`;

if (this.get('isFixedLeft')) {
style += `left: ${Math.round(this.get('columnMeta.offsetLeft'))}px;`;
} else if (this.get('isFixedRight')) {
style += `right: ${Math.round(this.get('columnMeta.offsetRight'))}px;`;
}

if (typeof FastBoot === 'undefined' && this.element) {
// Keep any styling added by the Sticky polyfill
style += `position: ${this.element.style.position};`;
style += `top: ${this.element.style.top};`;
}

return htmlSafe(style);
}

@action
onSelectionToggled(event) {
let rowMeta = this.get('rowMeta');
Expand Down
42 changes: 4 additions & 38 deletions addon/components/ember-th/component.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
/* global Hammer */
import Component from '@ember/component';
import { htmlSafe } from '@ember/string';
import BaseTableCell from '../-private/base-table-cell';
import { next } from '@ember/runloop';

import { action, computed } from '@ember-decorators/object';
import { readOnly, equal } from '@ember-decorators/object/computed';
import { action } from '@ember-decorators/object';
import { readOnly } from '@ember-decorators/object/computed';
import { attribute, className, tagName } from '@ember-decorators/component';
import { argument } from '@ember-decorators/argument';
import { required } from '@ember-decorators/argument/validation';
Expand Down Expand Up @@ -40,7 +39,7 @@ const COLUMN_REORDERING = 2;
@yield {object} columnMeta - The meta object associated with this column
*/
@tagName('th')
export default class EmberTh extends Component {
export default class EmberTh extends BaseTableCell {
layout = layout;

/**
Expand Down Expand Up @@ -86,39 +85,6 @@ export default class EmberTh extends Component {
@readOnly('columnMeta.isMultiSorted') isMultiSorted;
@readOnly('columnMeta.isSortedAsc') isSortedAsc;

@equal('columnMeta.index', 0)
isFirstColumn;

@className
@equal('columnMeta.isFixed', 'left')
isFixedLeft;

@className
@equal('columnMeta.isFixed', 'right')
isFixedRight;

@attribute
@computed('columnMeta.{width,offsetLeft,offsetRight}', 'isFixed')
get style() {
let width = this.get('columnMeta.width');

let style = `width: ${width}px; min-width: ${width}px; max-width: ${width}px;`;

if (this.get('isFixedLeft')) {
style += `left: ${this.get('columnMeta.offsetLeft')}px;`;
} else if (this.get('isFixedRight')) {
style += `right: ${this.get('columnMeta.offsetRight')}px;`;
}

if (typeof FastBoot === 'undefined' && this.element) {
// Keep any styling added by the Sticky polyfill
style += `position: ${this.element.style.position};`;
style += `top: ${this.element.style.top};`;
}

return htmlSafe(style);
}

@attribute('colspan')
@readOnly('columnMeta.columnSpan')
columnSpan;
Expand Down

0 comments on commit f19477e

Please sign in to comment.