resolve content urls

This commit is contained in:
Nazar Kanaev 2020-08-14 22:36:53 +01:00
parent a3f62e9a56
commit 4ff7a538c6
2 changed files with 36 additions and 20 deletions

View File

@ -231,9 +231,7 @@
<time>{{ formatDate(itemSelectedDetails.date) }}</time>
</div>
<hr>
<div v-html="$sanitize(itemSelectedReadability)" v-if="itemSelectedReadability"></div>
<div v-html="$sanitize(itemSelectedDetails.content)" v-else-if="itemSelectedDetails.content"></div>
<div v-html="$sanitize(itemSelectedDetails.description)" v-else-if="itemSelectedDetails.description"></div>
<div v-html="itemSelectedContent"></div>
</div>
</div>
<b-modal id="settings-modal" hide-header hide-footer lazy>

View File

@ -10,22 +10,6 @@ var FONTS = [
"Verdana",
]
DOMPurify.addHook('afterSanitizeAttributes', function (node) {
// set all elements owning target to target=_blank
if ('target' in node) {
node.setAttribute('target', '_blank');
}
// set non-HTML/MathML links to xlink:show=new
if (
!node.hasAttribute('target') &&
(node.hasAttribute('xlink:href') || node.hasAttribute('href'))
) {
node.setAttribute('xlink:show', 'new');
}
});
Vue.prototype.$sanitize = DOMPurify.sanitize
var debounce = function(callback, wait) {
var timeout
return function() {
@ -37,6 +21,25 @@ var debounce = function(callback, wait) {
}
}
var sanitize = function(content, base) {
var sanitizer = new DOMPurify
sanitizer.addHook('afterSanitizeAttributes', function(node) {
// set all elements owning target to target=_blank
if ('target' in node)
node.setAttribute('target', '_blank')
// set non-HTML/MathML links to xlink:show=new
if (!node.hasAttribute('target') && (node.hasAttribute('xlink:href') || node.hasAttribute('href')))
node.setAttribute('xlink:show', 'new')
// set absolute urls
if (node.attributes.href && node.attributes.href.value)
node.href = new URL(node.attributes.href.value, base).toString()
if (node.attributes.src && node.attributes.src.value)
node.src = new URL(node.attributes.src.value, base).toString()
})
return sanitizer.sanitize(content)
}
Vue.directive('scroll', {
inserted: function(el, binding) {
el.addEventListener('scroll', debounce(function(event) {
@ -205,6 +208,20 @@ var vm = new Vue({
return acc
}, {unread: 0, starred: 0})
},
itemSelectedContent: function() {
if (!this.itemSelected) return ''
if (this.itemSelectedReadability)
return this.itemSelectedReadability
var content = ''
if (this.itemSelectedDetails.content)
content = this.itemSelectedDetails.content
else if (this.itemSelectedDetails.description)
content = this.itemSelectedDetails.description
return sanitize(content, this.feedsById[this.itemSelectedDetails.feed_id].link || this.itemSelectedDetails.link)
},
},
watch: {
'theme': {
@ -479,7 +496,8 @@ var vm = new Vue({
if (item.link) {
api.crawl(item.link).then(function(body) {
if (!body.length) return
var doc = new DOMParser().parseFromString(body, 'text/html')
var bodyClean = sanitize(body, vm.feedsById[item.feed_id].link || item.link)
var doc = new DOMParser().parseFromString(bodyClean, 'text/html')
var parsed = new Readability(doc).parse()
if (parsed && parsed.content) {
vm.itemSelectedReadability = parsed.content