fix: decode HTML entities in feed titles to prevent literal display

Feedparser passes through HTML entities (“, ’, etc.) as
literal strings in item titles. Nunjucks auto-escaping then double-encodes
them, causing entities to render literally in the reader UI.

Apply sanitizeHtml with no allowed tags to decode entities in title fields
across RSS/Atom, JSON Feed, and feed metadata normalizers.
This commit is contained in:
Ricardo
2026-02-24 14:20:55 +01:00
parent 114998bf03
commit b4d2b7418d
2 changed files with 13 additions and 5 deletions
+12 -4
View File
@@ -150,7 +150,9 @@ export function normalizeItem(item, feedUrl, feedType) {
type: "entry", type: "entry",
uid, uid,
url, url,
name: item.title || undefined, name: item.title
? sanitizeHtml(item.title, { allowedTags: [] }).trim()
: undefined,
published: toISOStringSafe(item.pubdate), published: toISOStringSafe(item.pubdate),
updated: toISOStringSafe(item.date), updated: toISOStringSafe(item.date),
_source: { _source: {
@@ -241,7 +243,9 @@ export function normalizeItem(item, feedUrl, feedType) {
*/ */
export function normalizeFeedMeta(meta, feedUrl) { export function normalizeFeedMeta(meta, feedUrl) {
const normalized = { const normalized = {
name: meta.title || feedUrl, name: meta.title
? sanitizeHtml(meta.title, { allowedTags: [] }).trim()
: feedUrl,
}; };
if (meta.description) { if (meta.description) {
@@ -303,7 +307,9 @@ export function normalizeJsonFeedItem(item, feedUrl) {
type: "entry", type: "entry",
uid, uid,
url, url,
name: item.title || undefined, name: item.title
? sanitizeHtml(item.title, { allowedTags: [] }).trim()
: undefined,
published: item.date_published published: item.date_published
? new Date(item.date_published).toISOString() ? new Date(item.date_published).toISOString()
: undefined, : undefined,
@@ -400,7 +406,9 @@ export function normalizeJsonFeedItem(item, feedUrl) {
*/ */
export function normalizeJsonFeedMeta(feed, feedUrl) { export function normalizeJsonFeedMeta(feed, feedUrl) {
const normalized = { const normalized = {
name: feed.title || feedUrl, name: feed.title
? sanitizeHtml(feed.title, { allowedTags: [] }).trim()
: feedUrl,
}; };
if (feed.description) { if (feed.description) {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@rmdes/indiekit-endpoint-microsub", "name": "@rmdes/indiekit-endpoint-microsub",
"version": "1.0.33", "version": "1.0.34",
"description": "Microsub endpoint for Indiekit. Enables subscribing to feeds and reading content using the Microsub protocol.", "description": "Microsub endpoint for Indiekit. Enables subscribing to feeds and reading content using the Microsub protocol.",
"keywords": [ "keywords": [
"indiekit", "indiekit",