Skip to content

Commit

Permalink
✨ Add dangerous html content to rss (ajnart#885)
Browse files Browse the repository at this point in the history
  • Loading branch information
manuel-rw authored May 24, 2023
1 parent 0a72921 commit 11659dd
Show file tree
Hide file tree
Showing 5 changed files with 354 additions and 403 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"sabnzbd-api": "^1.5.0",
"uuid": "^9.0.0",
"xml-js": "^1.6.11",
"xss": "^1.0.14",
"yarn": "^1.22.19",
"zod": "^3.21.4",
"zustand": "^4.3.7"
Expand Down
8 changes: 7 additions & 1 deletion public/locales/en/modules/rss.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@
},
"refreshInterval": {
"label": "Refresh interval (in minutes)"
},
"dangerousAllowSanitizedItemContent": {
"label": "Dangerous: Allow sanitized item content"
},
"settings.textLinesClamp": {
"label": "Text lines clamp"
}
},
"card": {
Expand All @@ -21,4 +27,4 @@
}
}
}
}
}
44 changes: 41 additions & 3 deletions src/pages/api/modules/rss/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import xss from 'xss';
import { NextApiRequest, NextApiResponse } from 'next';
import Consola from 'consola';
import { getCookie } from 'cookies-next';
import { decode } from 'html-entities';
import { decode, encode } from 'html-entities';
import Parser from 'rss-parser';
import { z } from 'zod';

Expand Down Expand Up @@ -58,10 +59,13 @@ export const Get = async (request: NextApiRequest, response: NextApiResponse) =>
const orderedFeed = {
...feed,
items: feed.items
.map((item: { title: any; content: any }) => ({
.map((item: { title: string; content: string; 'content:encoded': string }) => ({
...item,
title: item.title ? decode(item.title) : undefined,
content: decode(item.content),
content: processItemContent(
item['content:encoded'] ?? item.content,
rssWidget.properties.dangerousAllowSanitizedItemContent
),
enclosure: createEnclosure(item),
link: createLink(item),
}))
Expand All @@ -81,6 +85,40 @@ export const Get = async (request: NextApiRequest, response: NextApiResponse) =>
});
};

const processItemContent = (content: string, dangerousAllowSanitizedItemContent: boolean) => {
if (dangerousAllowSanitizedItemContent) {
return xss(content, {
allowList: {
p: [],
h1: [],
h2: [],
h3: [],
h4: [],
h5: [],
h6: [],
a: ['href'],
b: [],
strong: [],
i: [],
em: [],
img: ['src', 'width', 'height'],
br: [],
small: [],
ul: [],
li: [],
ol: [],
figure: [],
svg: [],
code: [],
mark: [],
blockquote: [],
},
});
}

return encode(content);
};

const createLink = (item: any) => {
if (item.link) {
return item.link;
Expand Down
49 changes: 42 additions & 7 deletions src/widgets/rss/RssWidgetTile.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import Link from 'next/link';
import {
ActionIcon,
Badge,
Expand All @@ -19,6 +18,7 @@ import { IconClock, IconRefresh, IconRss } from '@tabler/icons-react';
import { useQuery } from '@tanstack/react-query';
import dayjs from 'dayjs';
import { useTranslation } from 'next-i18next';
import Link from 'next/link';

import { defineWidget } from '../helper';
import { IWidget } from '../widgets';
Expand All @@ -38,6 +38,17 @@ const definition = defineWidget({
max: 300,
step: 15,
},
dangerousAllowSanitizedItemContent: {
type: 'switch',
defaultValue: false,
},
textLinesClamp: {
type: 'slider',
defaultValue: 5,
min: 1,
max: 50,
step: 1,
},
},
gridstack: {
minWidth: 2,
Expand Down Expand Up @@ -141,10 +152,10 @@ function RssTile({ widget }: RssTileProps) {
)}

<Flex gap="xs">
{item.enclosure && (
{item.enclosure && item.enclosure.url && (
<MediaQuery query="(max-width: 1200px)" styles={{ display: 'none' }}>
<Image
src={item.enclosure?.url ?? undefined}
src={item.enclosure.url ?? undefined}
width={140}
height={140}
radius="md"
Expand All @@ -162,9 +173,13 @@ function RssTile({ widget }: RssTileProps) {
)}

<Text lineClamp={2}>{item.title}</Text>
<Text color="dimmed" size="xs" lineClamp={3}>
{item.content}
</Text>
<Text
className={classes.itemContent}
color="dimmed"
size="xs"
lineClamp={widget.properties.textLinesClamp}
dangerouslySetInnerHTML={{ __html: item.content }}
/>

{item.pubDate && (
<InfoDisplay title={feed.feed.title} date={formatDate(item.pubDate)} />
Expand Down Expand Up @@ -210,7 +225,7 @@ const InfoDisplay = ({ date, title }: { date: string; title: string | undefined
</Group>
);

const useStyles = createStyles(({ colorScheme }) => ({
const useStyles = createStyles(({ colorScheme, colors, radius, spacing }) => ({
backgroundImage: {
position: 'absolute',
width: '100%',
Expand All @@ -225,6 +240,26 @@ const useStyles = createStyles(({ colorScheme }) => ({
filter: 'blur(40px) brightness(0.7)',
},
},
itemContent: {
img: {
height: 100,
width: 'auto',
borderRadius: radius.sm,
},
blockquote: {
marginLeft: 10,
marginRight: 10,
paddingLeft: spacing.xs,
paddingRight: spacing.xs,
paddingTop: 1,
paddingBottom: 1,
borderLeftWidth: 4,
borderLeftStyle: 'solid',
borderLeftColor: colors.red[5],
borderRadius: radius.sm,
backgroundColor: colorScheme === 'dark' ? colors.dark[4] : '',
},
},
}));

export default definition;
Loading

0 comments on commit 11659dd

Please sign in to comment.