Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

fix($compile): sanitize special chars in directive name #16314

Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion src/ng/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -3637,7 +3637,7 @@ function SimpleChange(previous, current) {
SimpleChange.prototype.isFirstChange = function() { return this.previousValue === _UNINITIALIZED_VALUE; };


var PREFIX_REGEXP = /^((?:x|data)[:\-_])/i;
var PREFIX_REGEXP = /^((?:x|data)*[:\-_])/i;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The * is wrong. Use ? instead.

Copy link
Member

@gkalpak gkalpak Nov 2, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, PREFIX_REGEXP is used to process ng-attr- attributes (here) and this change affects that too.
IMO, this PR should restore the behavior of directiveNormalize() pre- 73050cd and not affect anything else.

var SPECIAL_CHARS_REGEXP = /[:\-_]+(.)/g;

/**
Expand Down
89 changes: 88 additions & 1 deletion test/ng/compileSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,26 @@ describe('$compile', function() {
inject(function($compile) {});
});

it('should omit special chars before processing directive name', function() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this applies only to directives with restrict: 'A', then the test description should reflect that. Maybe even link to this issue in a comment.

module(function() {
directive('t', function(log) {
return {
restrict: 'A',
link: {
pre: log.fn('pre'),
post: log.fn('post')
}
};
});
});
inject(function($compile, $rootScope, log) {
element = $compile('<div _t></div>')($rootScope);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The element = parts are redundant.

element = $compile('<div -t></div>')($rootScope);
element = $compile('<div :t></div>')($rootScope);
expect(log).toEqual('pre; post; pre; post; pre; post');
});
});

it('should throw an exception if the directive factory is not defined', function() {
module(function() {
expect(function() {
Expand Down Expand Up @@ -10638,7 +10658,10 @@ describe('$compile', function() {
template:
'<div class="a" ng-transclude="ng-transclude"></div>' +
'<div class="b" ng:transclude="ng:transclude"></div>' +
'<div class="c" data-ng-transclude="data-ng-transclude"></div>'
'<div class="c" data-ng-transclude="data-ng-transclude"></div>' +
'<div class="d" -ng-transclude="-ng-transclude"></div>' +
'<div class="e" _ng_transclude="_ng_transclude"></div>' +
'<div class="f" :ng:transclude=":ng:transclude"></div>'
};
});
});
Expand All @@ -10653,12 +10676,21 @@ describe('$compile', function() {
var a = element.children().eq(0);
var b = element.children().eq(1);
var c = element.children().eq(2);
var d = element.children().eq(3);
var e = element.children().eq(4);
var f = element.children().eq(5);
expect(a).toHaveClass('a');
expect(b).toHaveClass('b');
expect(c).toHaveClass('c');
expect(d).toHaveClass('d');
expect(e).toHaveClass('e');
expect(f).toHaveClass('f');
expect(a.text()).toEqual('stuartbobkevin');
expect(b.text()).toEqual('stuartbobkevin');
expect(c.text()).toEqual('stuartbobkevin');
expect(d.text()).toEqual('stuartbobkevin');
expect(e.text()).toEqual('stuartbobkevin');
expect(f.text()).toEqual('stuartbobkevin');
});
});

Expand Down Expand Up @@ -11710,6 +11742,18 @@ describe('$compile', function() {
expect(element.attr('dash-test4')).toBe('JamieMason');
}));

it('should work if they are prefixed with special chars', inject(function() {
$rootScope.name = 'JamieMason';
element = $compile('<span -ng-attr-dash-test2="{{name}}" _ng-attr-dash-test3="{{name}}" :ng:attr-dash-test4="{{name}}"></span>')($rootScope);
expect(element.attr('dash-test2')).toBeUndefined();
expect(element.attr('dash-test3')).toBeUndefined();
expect(element.attr('dash-test4')).toBeUndefined();
$rootScope.$digest();
expect(element.attr('dash-test2')).toBe('JamieMason');
expect(element.attr('dash-test3')).toBe('JamieMason');
expect(element.attr('dash-test4')).toBe('JamieMason');
}));

it('should keep attributes ending with -start single-element directives', function() {
module(function($compileProvider) {
$compileProvider.directive('dashStarter', function(log) {
Expand Down Expand Up @@ -11774,6 +11818,27 @@ describe('$compile', function() {
expect(element.find('feDiffuseLighting').attr('surfaceScale')).toBe('1');
expect(element.find('feSpecularLighting').attr('surfaceScale')).toBe('1');
}));

it('should work if they are prefixed with special chars', inject(function($compile, $rootScope) {
$rootScope.dimensions = '0 0 0 0';
$rootScope.number = 0.42;
$rootScope.scale = 1;

element = $compile('<svg -ng-attr-view_box="{{dimensions}}">' +
'<filter _ng-attr-filter_units="{{number}}">' +
'<feDiffuseLighting -ng:attr_surface_scale="{{scale}}"' +
':ng:attr_diffuse_constant="{{number}}"></feDiffuseLighting>' +
'<feSpecularLighting _ng:attr_surface_scale="{{scale}}"' +
':ng-attr_diffuse_constant="{{number}}"></feSpecularLighting>')($rootScope);
expect(element.attr('viewBox')).toBeUndefined();
$rootScope.$digest();
expect(element.attr('viewBox')).toBe('0 0 0 0');
expect(element.find('filter').attr('filterUnits')).toBe('0.42');
expect(element.find('feDiffuseLighting').attr('surfaceScale')).toBe('1');
expect(element.find('feDiffuseLighting').attr('diffuseConstant')).toBe('0.42');
expect(element.find('feSpecularLighting').attr('surfaceScale')).toBe('1');
expect(element.find('feSpecularLighting').attr('diffuseConstant')).toBe('0.42');
}));
});

describe('multi-element directive', function() {
Expand Down Expand Up @@ -12129,6 +12194,28 @@ describe('$compile', function() {
expect(spans.eq(2)).toBeHidden();
expect(spans.eq(3)).toBeHidden();
}));


it('should support special char prefix', inject(function($compile, $rootScope) {
$rootScope.show = false;
element = $compile(
'<div>' +
'<span -ng-show-start="show"></span>' +
'<span -ng-show-end></span>' +
'<span :ng-show-start="show"></span>' +
'<span :ng-show-end></span>' +
'<span _ng-show-start="show"></span>' +
'<span _ng-show-end></span>' +
'</div>')($rootScope);
$rootScope.$digest();
var spans = element.find('span');
expect(spans.eq(0)).toBeHidden();
expect(spans.eq(1)).toBeHidden();
expect(spans.eq(2)).toBeHidden();
expect(spans.eq(3)).toBeHidden();
expect(spans.eq(4)).toBeHidden();
expect(spans.eq(5)).toBeHidden();
}));
});

describe('$animate animation hooks', function() {
Expand Down