Skip to content

Commit

Permalink
[I18n] Sanitize angular directive message before inserting it to DOM (e…
Browse files Browse the repository at this point in the history
…lastic#24830) (elastic#24969)

* [I18n] Sanitize message before inserting it to DOM

* Add tests
  • Loading branch information
LeanidShutau authored Nov 1, 2018
1 parent 11429c8 commit c26a6d6
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 9 deletions.
42 changes: 42 additions & 0 deletions packages/kbn-i18n/src/angular/__snapshots__/directive.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,45 @@
exports[`i18nDirective inserts correct translation html content with values 1`] = `"default-message word"`;

exports[`i18nDirective inserts correct translation html content with values 2`] = `"default-message anotherWord"`;

exports[`i18nDirective sanitizes message before inserting it to DOM 1`] = `
<div
class="ng-scope ng-isolate-scope"
i18n-default-message="Default message, {value}"
i18n-id="id"
i18n-values="{ value: '<div ng-click=\\"dangerousAction()\\"></div>' }"
>
Default message,
<div />
</div>
`;

exports[`i18nDirective sanitizes onclick attribute 1`] = `
<div
class="ng-scope ng-isolate-scope"
i18n-default-message="Default {one} onclick=alert(1) {two} message"
i18n-id="id"
i18n-values="{ one: '<span', two: '>Press</span>' }"
>
Default
<span>
Press
</span>
message
</div>
`;

exports[`i18nDirective sanitizes onmouseover attribute 1`] = `
<div
class="ng-scope ng-isolate-scope"
i18n-default-message="Default {value} message"
i18n-id="id"
i18n-values="{ value: '<span onmouseover=\\"alert(1)\\">Press</span>' }"
>
Default
<span>
Press
</span>
message
</div>
`;
48 changes: 47 additions & 1 deletion packages/kbn-i18n/src/angular/directive.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@

import angular from 'angular';
import 'angular-mocks';
import 'angular-sanitize';

import { i18nDirective } from './directive';
import { I18nProvider } from './provider';

angular
.module('app', [])
.module('app', ['ngSanitize'])
.provider('i18n', I18nProvider)
.directive('i18nId', i18nDirective);

Expand Down Expand Up @@ -82,4 +83,49 @@ describe('i18nDirective', () => {

expect(element.html()).toMatchSnapshot();
});

test('sanitizes message before inserting it to DOM', () => {
const element = angular.element(
`<div
i18n-id="id"
i18n-default-message="Default message, {value}"
i18n-values="{ value: '<div ng-click=&quot;dangerousAction()&quot;></div>' }"
/>`
);

compile(element)(scope);
scope.$digest();

expect(element[0]).toMatchSnapshot();
});

test('sanitizes onclick attribute', () => {
const element = angular.element(
`<div
i18n-id="id"
i18n-default-message="Default {one} onclick=alert(1) {two} message"
i18n-values="{ one: '<span', two: '>Press</span>' }"
/>`
);

compile(element)(scope);
scope.$digest();

expect(element[0]).toMatchSnapshot();
});

test('sanitizes onmouseover attribute', () => {
const element = angular.element(
`<div
i18n-id="id"
i18n-default-message="Default {value} message"
i18n-values="{ value: '<span onmouseover=&quot;alert(1)&quot;>Press</span>' }"
/>`
);

compile(element)(scope);
scope.$digest();

expect(element[0]).toMatchSnapshot();
});
});
26 changes: 18 additions & 8 deletions packages/kbn-i18n/src/angular/directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@ interface I18nScope extends IScope {
id: string;
}

export function i18nDirective(i18n: I18nServiceType): IDirective<I18nScope> {
export function i18nDirective(
i18n: I18nServiceType,
$sanitize: (html: string) => string
): IDirective<I18nScope> {
return {
restrict: 'A',
scope: {
Expand All @@ -38,20 +41,27 @@ export function i18nDirective(i18n: I18nServiceType): IDirective<I18nScope> {
link($scope, $element) {
if ($scope.values) {
$scope.$watchCollection('values', () => {
setHtmlContent($element, $scope, i18n);
setHtmlContent($element, $scope, $sanitize, i18n);
});
} else {
setHtmlContent($element, $scope, i18n);
setHtmlContent($element, $scope, $sanitize, i18n);
}
},
};
}

function setHtmlContent($element: IRootElementService, $scope: I18nScope, i18n: I18nServiceType) {
function setHtmlContent(
$element: IRootElementService,
$scope: I18nScope,
$sanitize: (html: string) => string,
i18n: I18nServiceType
) {
$element.html(
i18n($scope.id, {
values: $scope.values,
defaultMessage: $scope.defaultMessage,
})
$sanitize(
i18n($scope.id, {
values: $scope.values,
defaultMessage: $scope.defaultMessage,
})
)
);
}

0 comments on commit c26a6d6

Please sign in to comment.