Issue
In a custom element, I try to replace an item’s body text with HTML for line breaks and links. It was working when I just handled line breaks (nl2br()), but no longer when handling links (linkify()).
get formattedBody {
if (item.isEmpty) return 'Loading...';
return "${InputFormatter.nl2br(InputFormatter.linkify(item['body']))}";
}
itemChanged() {
// Trick to respect line breaks.
HtmlElement body = $['body'];
body.innerHtml = formattedBody;
}
I get a warm and safe security message e.g.:
Removing disallowed attribute <A href="http://miamiherald.typepad.com/the-starting-gate/2014/09/news-.html">
I also tried setInnerHtml()
, to no avail.
Ideas? Thank you!
Solution
I’ve got a <safe-html>
element working. Verified on Chrome and even post-dart2js on Safari. Vote up this answer if you’d like me to turn it into a lib available on pub.dartlang.org.
Usage:
<safe-html validator="{{nodeValidator}}">{{someHtml}}</safe-html>
(Passing in your own validator
is optional. Without it, we’ll use a default.)
safe_html.html:
<link rel="import" href="../../../../../../../packages/polymer/polymer.html">
<polymer-element name="safe-html">
<template>
<div id="container"></div>
</template>
<script type="application/dart" src='safe_html.dart'></script>
</polymer-element>
safe_html.dart:
library safe_html;
import 'dart:async';
import "dart:html";
import "package:polymer/polymer.dart";
@CustomTag("safe-html")
class SafeHtml extends PolymerElement {
@published NodeValidator validator = new NodeValidatorBuilder()
..allowHtml5(uriPolicy: new DefaultUriPolicy());
SafeHtml.created() : super.created();
addFragment() {
DivElement container = $['container'];
String fragment = this.text;
container.setInnerHtml(fragment, // Set the fragment in a safe way.
validator: validator);
this.text = ""; // Clear the original fragment passed to the element.
}
attached() {
addFragment();
}
}
class DefaultUriPolicy implements UriPolicy {
DefaultUriPolicy();
// Allow all external, absolute URLs.
RegExp regex = new RegExp(r'(?:http://|https://|//)?.*');
bool allowsUri(String uri) {
return regex.hasMatch(uri);
}
}
If you choose to pass your own NodeValidator
, do it by specifying a getter in the parent element that uses <safe-html>
:
NodeValidator get nodeValidator => new NodeValidatorBuilder()
..allowHtml5(uriPolicy: new ItemUrlPolicy());
As you can see I reference a UriPolicy
which I keep in a separate file like uri_policy.dart:
import 'dart:html';
class ItemUrlPolicy implements UriPolicy {
ItemUrlPolicy();
RegExp regex = new RegExp(r'(?:http://|https://|//)?.*');
bool allowsUri(String uri) {
return regex.hasMatch(uri);
}
}
With lots of help from Günter Zöchbauer and the authors of other helpful posts on SO.
Answered By – David Notik
Answer Checked By – Mary Flores (FlutterFixes Volunteer)