@@ -6,6 +6,61 @@ import { site, i18n } from 'astro:config/client';
66
77const blog = ( await getCollection ( 'blog' ) ) . sort ( ( a , b ) => b . data . pubDate . valueOf ( ) - a . data . pubDate . valueOf ( ) ) ;
88const parser = new MarkdownIt ( ) ;
9+ const wikiImagePattern = / ! \[ \[ ( [ ^ \] ] + ) \] \] / g;
10+ const iframePattern = / < i f r a m e [ ^ > ] * s r c = [ " ' ] ( [ ^ " ' ] + ) [ " ' ] [ ^ > ] * > .* ?< \/ i f r a m e > / gi;
11+
12+ function isFullyQualifiedUrl ( value ) {
13+ try {
14+ const parsed = new URL ( value ) ;
15+ return parsed . protocol === 'http:' || parsed . protocol === 'https:' ;
16+ }
17+ catch {
18+ return false ;
19+ }
20+ }
21+
22+ function normalizeRssContent ( markdown ) {
23+ const withWikiEmbedsHandled = markdown . replaceAll ( wikiImagePattern , ( _ , rawTarget ) => {
24+ const [ target ] = rawTarget . split ( '|' ) ;
25+ const cleanedTarget = target . trim ( ) ;
26+
27+ if ( ! isFullyQualifiedUrl ( cleanedTarget ) ) {
28+ return '[Embedded Image]' ;
29+ }
30+
31+ return `` ;
32+ } ) ;
33+
34+ return withWikiEmbedsHandled . replaceAll ( iframePattern , '[Note: Embedded content from $1]' ) ;
35+ }
36+
37+ function sanitizeRssHtml ( html ) {
38+ return sanitizeHtml ( html , {
39+ allowedTags : sanitizeHtml . defaults . allowedTags . concat ( 'img' ) ,
40+ allowedAttributes : {
41+ ...sanitizeHtml . defaults . allowedAttributes ,
42+ img : [ 'src' , 'alt' , 'title' ] ,
43+ } ,
44+ transformTags : {
45+ img : ( _ , attribs ) => {
46+ const src = attribs . src ?. trim ( ) ;
47+
48+ if ( ! src || ! isFullyQualifiedUrl ( src ) ) {
49+ return { tagName : 'span' , text : '[Embedded Image]' } ;
50+ }
51+
52+ return {
53+ tagName : 'img' ,
54+ attribs : {
55+ src,
56+ alt : attribs . alt || 'Embedded Image' ,
57+ ...( attribs . title ? { title : attribs . title } : { } ) ,
58+ } ,
59+ } ;
60+ } ,
61+ } ,
62+ } ) ;
63+ }
964
1065export async function GET ( context ) {
1166 return rss ( {
@@ -26,7 +81,7 @@ export async function GET(context) {
2681 description : post . data . description ,
2782 link : `/blog/${ post . slug } /` ,
2883 pubDate : post . data . pubDate ,
29- content : sanitizeHtml ( parser . render ( post . body . replaceAll ( / ! \[ \[ ( [ ^ \] ] + ) \] \] / g , '[Embedded Image]' ) . replaceAll ( / < i f r a m e [ ^ > ] * s r c = [ " ' ] ( [ ^ " ' ] + ) [ " ' ] [ ^ > ] * > . * ? < \/ i f r a m e > / gi , '[Note: Embedded content from $1]' ) ) ) ,
84+ content : sanitizeRssHtml ( parser . render ( normalizeRssContent ( post . body ) ) ) ,
3085 } ) ) ,
3186 } ) ;
32- }
87+ }
0 commit comments