mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[I18n] Sanitize angular directive message before inserting it to DOM (#24830)
* [I18n] Sanitize message before inserting it to DOM * Add tests
This commit is contained in:
parent
f05bb942fa
commit
2fb2bda157
3 changed files with 107 additions and 9 deletions
|
@ -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>
|
||||
`;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
@ -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="dangerousAction()"></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="alert(1)">Press</span>' }"
|
||||
/>`
|
||||
);
|
||||
|
||||
compile(element)(scope);
|
||||
scope.$digest();
|
||||
|
||||
expect(element[0]).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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: {
|
||||
|
@ -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,
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue