[I18n] Compile html in angular directive#23684
[I18n] Compile html in angular directive#23684LeanidShutau wants to merge 10 commits intoelastic:masterfrom
Conversation
There was a problem hiding this comment.
@azasypkin I believe now it is safe to compile html because:
- we have agreed not to use tags in
defaultMessage. - even if some vendor pass any tags, scripts or directive in
defaultMessagefor some language, before insertingdefaultMessageto DOM we check passed string using$sanitizeangular service which removes all unsafe tags likescriptand directives.
For example we have such text indefaultMessage:
<span>hello</span>world
<im-dangerous-directive>I will destroy something</im-dangerous-directive>
<script>document.write('ha-ha')</script>after using $sanitize service we will get:
<span>hello</span>world|
@azasypkin this merge request is necessary for us to be able to pass angular directives via values. Now we also can pass directives but they do not work because they need to be compiled. To check that all works as expected you can: with this code: <p>
<span i18n-id="test.test"
i18n-default-message="I just check {justToCheck}"
i18n-values="{ justToCheck: '<strong ng-click="checkDirectivesAreCompiled()">click me!</strong>' }">
</span>
</p>and in file open dashboard page. |
💚 Build Succeeded |
|
ack: Looking into this one at the monent |
pavel06081991
left a comment
There was a problem hiding this comment.
LGTM. Checked it works as expected.
2bc299e to
6486b93
Compare
💔 Build Failed |
|
retest |
💔 Build Failed |
…tml-in-i18n-directive
💚 Build Succeeded |
…tml-in-i18n-directive
💔 Build Failed |
…tml-in-i18n-directive
💔 Build Failed |
|
retest |
💔 Build Failed |
…tml-in-i18n-directive
💚 Build Succeeded |
💔 Build Failed |
💔 Build Failed |
|
retest |
💔 Build Failed |
…tml-in-i18n-directive
💚 Build Succeeded |
| $scope.$watchCollection('values', () => { | ||
| setHtmlContent($element, $scope, i18n); | ||
| setHtmlContent($element, $scope, $sanitize, i18n); | ||
| $compile($element.contents() as any)($scope.$parent); |
There was a problem hiding this comment.
issue: I'm still afraid of this "global" compile.... with this even $sanitize'ed variable without usafe_ can be pretty harmful, imagine the case that looks like this (help link that is displayed somewhere else on this page will lead user to the attacker site):
<span i18n-id="kbn.management.someId"
i18n-default-message="Some text that seems safe: {val}"
i18n-values="{ val: '\{\{controller.helpLink=\'http://attacker-site/\';\'value\'\}\}' }">
</span>Is there any way we can compile just unsafe_ pieces? Can you paste a couple of real use cases? If it's only about directives (e.g. <a ng-href\ng-click), we can probably mark all these elements with directive with some custom data-unsafe-i18n data attribute or class and then query only these things and compile.
I know it's becoming complex, but I feel uncomfortable with how it's currently. Basically we have 3 cases (sorted by popularity):
- Simple default message + simple values, in this case we should just use
element.text(i18n.translate(...))-textwill escape everything for us. - Simple default message + values with HTML (
html_prefix) - in this case we have to useelement.html, so we shouldescapedefault message (let's trylodash.escapeinstead of manual solution, we have severallodash.*packages in Kibana already anyway) + escape ordinary values (withouthtml_prefix) +$sanitizehtml_values - Simple default message + unsafe values (
unsafe_prefix_) - in this case we also have to useelement.html, so again we shouldescapedefault message + escape ordinary values +$sanitizehtml_values. And once we inserted them into DOM, we should call$compilefor nodes withdata-unsafe-i18n(or something like this).
Am I over-engineering this (or missing something) @spalger @LeanidShutau?
There was a problem hiding this comment.
Is there any way we can compile just unsafe_ pieces? Can you paste a couple of real use cases? If it's only about directives (e.g. <a ng-href\ng-click), we can probably mark all these elements with directive with some custom data-unsafe-i18n data attribute or class and then query only these things and compile.
Good point. I believe we can do it. It looks like in this case we do not need to use unsafe_ prefix for values' property names.
There was a problem hiding this comment.
I have to be honest, I don't have enough context to say if this is over-engineering or a comprehensive solution. Since I've been asked to review this and it seems like the overall direction is still in flux I'd really like to chat about what's going on here and how/why we're doing things this way. The PR description and the linked issue have basically no details and I just don't know enough to review this...
| values: $scope.values, | ||
| defaultMessage: $scope.defaultMessage, | ||
| values, | ||
| defaultMessage: ($scope.defaultMessage || '').replace(/\</g, '<').replace(/\>/g, '>'), |
There was a problem hiding this comment.
question: why do we need || ''? I believe we shouldn't ever have empty default message?
|
We don't need angular directive compiling any more. $sanitize part was implemented in separate PR: #24830 Issue has been solved by refactoring: <p class="kuiText kuiVerticalRhythm">
<span
i18n-id="kbn.dashboard.addVisualizationDescription1"
i18n-default-message="Click the "
i18n-context="Part of composite label kbn.dashboard.addVisualizationDescription1 + {link} + kbn.dashboard.addVisualizationDescription2"
>
</span>
<a
i18n-id="kbn.dashboard.addVisualizationLink"
i18n-default-message="Add"
kbn-accessible-click class="kuiButton kuiButton--primary kuiButton--small"
ng-click="showAddPanel()"
aria-label="{{ 'kbn.dashboard.addVisualizationLinkAria...' | i18n: { defaultMessage: 'Add visualization' }}"
data-test-subj="emptyDashboardAddPanelButton">
</a>
<span
i18n-id="kbn.dashboard.addVisualizationDescription2"
i18n-default-message=" button in the menu bar above to add a visualization to the dashboard. {br}If you haven't set up any visualizations yet, {visitVisualizeAppLink} to create your first visualization."
i18n-values="{
br: '<br/>',
visitVisualizeAppLink: '<a class=\'kuiLink\' href=\'#/visualize\'>' + visitVisualizeAppLinkText + '</a>'}"
i18n-context="Part of composite label kbn.dashboard.addVisualizationDescription1 + {link} + kbn.dashboard.addVisualizationDescription2"
>
</span>
</p>This PR can be reopened in the future, if needed |
Resolves #23359
We need to compile html in i18n directive to be able to pass html with angular directive via values, for example
It's not secure, so we need to sanitize or escape html in
defeultMessageor in values, that are not supposed to contain potentially dangerous html code. One of the solutions is to useunsafe_prefix in some values keys and sanitize/escape html indefaultMessageand all other values.