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

Commit a93ee19

Browse files
committed
fixup! feat($compile): add support for arbitrary property and event bindings
1 parent d163243 commit a93ee19

File tree

2 files changed

+127
-6
lines changed

2 files changed

+127
-6
lines changed

Diff for: src/ng/compile.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -1623,6 +1623,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16231623
* - SecurityContext.* => SCE_CONTEXTS/$sce.*
16241624
* - STYLE => CSS
16251625
* - various URL => MEDIA_URL
1626+
* - *|formAction, form|action URL => RESOURCE_URL (like the attribute)
16261627
*/
16271628
(function registerNativePropertyContexts() {
16281629
function registerContext(ctx, values) {
@@ -1636,13 +1637,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16361637
]);
16371638
registerContext(SCE_CONTEXTS.CSS, ['*|style']);
16381639
registerContext(SCE_CONTEXTS.URL, [
1639-
'*|formAction',
16401640
'area|href', 'area|ping',
16411641
'a|href', 'a|ping',
16421642
'blockquote|cite',
16431643
'body|background',
16441644
'del|cite',
1645-
'form|action',
16461645
'input|src',
16471646
'ins|cite',
16481647
'q|cite'
@@ -1655,10 +1654,12 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
16551654
'video|src', 'video|poster'
16561655
]);
16571656
registerContext(SCE_CONTEXTS.RESOURCE_URL, [
1657+
'*|formAction',
16581658
'applet|code', 'applet|codebase',
16591659
'base|href',
16601660
'embed|src',
16611661
'frame|src',
1662+
'form|action',
16621663
'head|profile',
16631664
'html|manifest',
16641665
'iframe|src',

Diff for: test/ng/compileSpec.js

+124-4
Original file line numberDiff line numberDiff line change
@@ -11739,7 +11739,7 @@ describe('$compile', function() {
1173911739
}));
1174011740
});
1174111741

11742-
describe('iframe[src]', function() {
11742+
describe('iframe[src] attribute', function() {
1174311743
it('should pass through src attributes for the same domain', inject(function($compile, $rootScope, $sce) {
1174411744
element = $compile('<iframe src="{{testUrl}}"></iframe>')($rootScope);
1174511745
$rootScope.testUrl = 'different_page';
@@ -11782,7 +11782,7 @@ describe('$compile', function() {
1178211782
}));
1178311783
});
1178411784

11785-
describe('base[href]', function() {
11785+
describe('base[href] attribute', function() {
1178611786
it('should be a RESOURCE_URL context', inject(function($compile, $rootScope, $sce) {
1178711787
element = $compile('<base href="{{testUrl}}"/>')($rootScope);
1178811788

@@ -11798,7 +11798,7 @@ describe('$compile', function() {
1179811798
}));
1179911799
});
1180011800

11801-
describe('form[action]', function() {
11801+
describe('form[action] attribute', function() {
1180211802
it('should pass through action attribute for the same domain', inject(function($compile, $rootScope, $sce) {
1180311803
element = $compile('<form action="{{testUrl}}"></form>')($rootScope);
1180411804
$rootScope.testUrl = 'different_page';
@@ -11842,7 +11842,7 @@ describe('$compile', function() {
1184211842
}));
1184311843
});
1184411844

11845-
describe('link[href]', function() {
11845+
describe('link[href] attribute', function() {
1184611846
it('should reject invalid RESOURCE_URLs', inject(function($compile, $rootScope) {
1184711847
element = $compile('<link href="{{testUrl}}" rel="stylesheet" />')($rootScope);
1184811848
$rootScope.testUrl = 'https://evil.example.org/css.css';
@@ -12722,6 +12722,126 @@ describe('$compile', function() {
1272212722
}));
1272312723
});
1272412724

12725+
describe('iframe[src]', function() {
12726+
it('should pass through src properties for the same domain', inject(function($compile, $rootScope, $sce) {
12727+
element = $compile('<iframe ng-prop-src="testUrl"></iframe>')($rootScope);
12728+
$rootScope.testUrl = 'different_page';
12729+
$rootScope.$apply();
12730+
expect(element.prop('src')).toMatch(/\/different_page$/);
12731+
}));
12732+
12733+
it('should clear out src properties for a different domain', inject(function($compile, $rootScope, $sce) {
12734+
element = $compile('<iframe ng-prop-src="testUrl"></iframe>')($rootScope);
12735+
$rootScope.testUrl = 'http://a.different.domain.example.com';
12736+
expect(function() { $rootScope.$apply(); }).toThrowMinErr(
12737+
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy.' +
12738+
' URL: http://a.different.domain.example.com');
12739+
}));
12740+
12741+
it('should clear out JS src properties', inject(function($compile, $rootScope, $sce) {
12742+
element = $compile('<iframe ng-prop-src="testUrl"></iframe>')($rootScope);
12743+
$rootScope.testUrl = 'javascript:alert(1);';
12744+
expect(function() { $rootScope.$apply(); }).toThrowMinErr(
12745+
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy.' +
12746+
' URL: javascript:alert(1);');
12747+
}));
12748+
12749+
it('should clear out non-resource_url src properties', inject(function($compile, $rootScope, $sce) {
12750+
element = $compile('<iframe ng-prop-src="testUrl"></iframe>')($rootScope);
12751+
$rootScope.testUrl = $sce.trustAsUrl('javascript:doTrustedStuff()');
12752+
expect(function() { $rootScope.$apply(); }).toThrowMinErr(
12753+
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy.' +
12754+
' URL: javascript:doTrustedStuff()');
12755+
}));
12756+
12757+
it('should pass through $sce.trustAs() values in src properties', inject(function($compile, $rootScope, $sce) {
12758+
element = $compile('<iframe ng-prop-src="testUrl"></iframe>')($rootScope);
12759+
$rootScope.testUrl = $sce.trustAsResourceUrl('javascript:doTrustedStuff()');
12760+
$rootScope.$apply();
12761+
12762+
expect(element.prop('src')).toEqual('javascript:doTrustedStuff()');
12763+
}));
12764+
});
12765+
12766+
describe('base[href]', function() {
12767+
it('should be a RESOURCE_URL context', inject(function($compile, $rootScope, $sce) {
12768+
element = $compile('<base ng-prop-href="testUrl"/>')($rootScope);
12769+
12770+
$rootScope.testUrl = $sce.trustAsResourceUrl('https://example.com/');
12771+
$rootScope.$apply();
12772+
expect(element.prop('href')).toContain('https://example.com/');
12773+
12774+
$rootScope.testUrl = 'https://not.example.com/';
12775+
expect(function() { $rootScope.$apply(); }).toThrowMinErr(
12776+
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy.' +
12777+
' URL: https://not.example.com/');
12778+
}));
12779+
});
12780+
12781+
describe('form[action]', function() {
12782+
it('should pass through action property for the same domain', inject(function($compile, $rootScope, $sce) {
12783+
element = $compile('<form ng-prop-action="testUrl"></form>')($rootScope);
12784+
$rootScope.testUrl = 'different_page';
12785+
$rootScope.$apply();
12786+
expect(element.prop('action')).toMatch(/\/different_page$/);
12787+
}));
12788+
12789+
it('should clear out action property for a different domain', inject(function($compile, $rootScope, $sce) {
12790+
element = $compile('<form ng-prop-action="testUrl"></form>')($rootScope);
12791+
$rootScope.testUrl = 'http://a.different.domain.example.com';
12792+
expect(function() { $rootScope.$apply(); }).toThrowMinErr(
12793+
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy.' +
12794+
' URL: http://a.different.domain.example.com');
12795+
}));
12796+
12797+
it('should clear out JS action property', inject(function($compile, $rootScope, $sce) {
12798+
element = $compile('<form ng-prop-action="testUrl"></form>')($rootScope);
12799+
$rootScope.testUrl = 'javascript:alert(1);';
12800+
expect(function() { $rootScope.$apply(); }).toThrowMinErr(
12801+
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy.' +
12802+
' URL: javascript:alert(1);');
12803+
}));
12804+
12805+
it('should clear out non-resource_url action property', inject(function($compile, $rootScope, $sce) {
12806+
element = $compile('<form ng-prop-action="testUrl"></form>')($rootScope);
12807+
$rootScope.testUrl = $sce.trustAsUrl('javascript:doTrustedStuff()');
12808+
expect(function() { $rootScope.$apply(); }).toThrowMinErr(
12809+
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy.' +
12810+
' URL: javascript:doTrustedStuff()');
12811+
}));
12812+
12813+
12814+
it('should pass through $sce.trustAs() values in action property', inject(function($compile, $rootScope, $sce) {
12815+
element = $compile('<form ng-prop-action="testUrl"></form>')($rootScope);
12816+
$rootScope.testUrl = $sce.trustAsResourceUrl('javascript:doTrustedStuff()');
12817+
$rootScope.$apply();
12818+
12819+
expect(element.prop('action')).toEqual('javascript:doTrustedStuff()');
12820+
}));
12821+
});
12822+
12823+
describe('link[href]', function() {
12824+
it('should reject invalid RESOURCE_URLs', inject(function($compile, $rootScope) {
12825+
element = $compile('<link ng-prop-href="testUrl" rel="stylesheet" />')($rootScope);
12826+
$rootScope.testUrl = 'https://evil.example.org/css.css';
12827+
expect(function() { $rootScope.$apply(); }).toThrowMinErr(
12828+
'$sce', 'insecurl', 'Blocked loading resource from url not allowed by $sceDelegate policy.' +
12829+
' URL: https://evil.example.org/css.css');
12830+
}));
12831+
12832+
it('should accept valid RESOURCE_URLs', inject(function($compile, $rootScope, $sce) {
12833+
element = $compile('<link ng-prop-href="testUrl" rel="stylesheet" />')($rootScope);
12834+
12835+
$rootScope.testUrl = './css1.css';
12836+
$rootScope.$apply();
12837+
expect(element.prop('href')).toContain('css1.css');
12838+
12839+
$rootScope.testUrl = $sce.trustAsResourceUrl('https://elsewhere.example.org/css2.css');
12840+
$rootScope.$apply();
12841+
expect(element.prop('href')).toContain('https://elsewhere.example.org/css2.css');
12842+
}));
12843+
});
12844+
1272512845
describe('*[innerHTML]', function() {
1272612846
describe('SCE disabled', function() {
1272712847
beforeEach(function() {

0 commit comments

Comments
 (0)