refactor: 简化Markdown白名单构建
This commit is contained in:
parent
add0dc3a8c
commit
f74bd14c34
@ -24,6 +24,34 @@ const MARKDOWN_SOURCE_PATTERN =
|
|||||||
/<!--\s*kt-markdown-source:([A-Za-z0-9+/=]+)\s*-->/;
|
/<!--\s*kt-markdown-source:([A-Za-z0-9+/=]+)\s*-->/;
|
||||||
const CONTENT_CLASS_PATTERN =
|
const CONTENT_CLASS_PATTERN =
|
||||||
/^(kt-md-|wp-|align|size-|is-|has-|language-|attachment-)/;
|
/^(kt-md-|wp-|align|size-|is-|has-|language-|attachment-)/;
|
||||||
|
const CONTENT_CLASS_ATTRIBUTE = ['className', CONTENT_CLASS_PATTERN];
|
||||||
|
const EXTRA_TAG_NAMES = ['figcaption', 'figure'];
|
||||||
|
const CONTENT_CLASS_TAG_NAMES = [
|
||||||
|
'a',
|
||||||
|
'blockquote',
|
||||||
|
'code',
|
||||||
|
'div',
|
||||||
|
'figcaption',
|
||||||
|
'figure',
|
||||||
|
'h1',
|
||||||
|
'h2',
|
||||||
|
'h3',
|
||||||
|
'h4',
|
||||||
|
'h5',
|
||||||
|
'h6',
|
||||||
|
'li',
|
||||||
|
'ol',
|
||||||
|
'p',
|
||||||
|
'pre',
|
||||||
|
'span',
|
||||||
|
'table',
|
||||||
|
'tbody',
|
||||||
|
'td',
|
||||||
|
'th',
|
||||||
|
'thead',
|
||||||
|
'tr',
|
||||||
|
'ul',
|
||||||
|
];
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MarkdownService {
|
export class MarkdownService {
|
||||||
@ -185,49 +213,27 @@ export class MarkdownService {
|
|||||||
|
|
||||||
private createSanitizeSchema(defaultSchema: unknown) {
|
private createSanitizeSchema(defaultSchema: unknown) {
|
||||||
const schema = defaultSchema as Record<string, any>;
|
const schema = defaultSchema as Record<string, any>;
|
||||||
const attributes = schema.attributes || {};
|
const attributes = (schema.attributes || {}) as Record<string, any[]>;
|
||||||
const classNameAttribute = ['className', CONTENT_CLASS_PATTERN];
|
const classAttributes = Object.fromEntries(
|
||||||
|
CONTENT_CLASS_TAG_NAMES.map((tagName) => [
|
||||||
|
tagName,
|
||||||
|
[...(attributes[tagName] || []), CONTENT_CLASS_ATTRIBUTE],
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...schema,
|
...schema,
|
||||||
tagNames: [
|
tagNames: [
|
||||||
...new Set([
|
...new Set([
|
||||||
...(schema.tagNames || []),
|
...(schema.tagNames || []),
|
||||||
'figcaption',
|
...EXTRA_TAG_NAMES,
|
||||||
'figure',
|
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
attributes: {
|
attributes: {
|
||||||
...attributes,
|
...attributes,
|
||||||
a: [...(attributes.a || []), 'target', 'rel', classNameAttribute],
|
...classAttributes,
|
||||||
blockquote: [...(attributes.blockquote || []), classNameAttribute],
|
a: [...(attributes.a || []), 'target', 'rel', CONTENT_CLASS_ATTRIBUTE],
|
||||||
code: [...(attributes.code || []), classNameAttribute],
|
img: [...(attributes.img || []), 'loading', CONTENT_CLASS_ATTRIBUTE],
|
||||||
div: [...(attributes.div || []), classNameAttribute],
|
|
||||||
figcaption: [...(attributes.figcaption || []), classNameAttribute],
|
|
||||||
figure: [...(attributes.figure || []), classNameAttribute],
|
|
||||||
h1: [...(attributes.h1 || []), classNameAttribute],
|
|
||||||
h2: [...(attributes.h2 || []), classNameAttribute],
|
|
||||||
h3: [...(attributes.h3 || []), classNameAttribute],
|
|
||||||
h4: [...(attributes.h4 || []), classNameAttribute],
|
|
||||||
h5: [...(attributes.h5 || []), classNameAttribute],
|
|
||||||
h6: [...(attributes.h6 || []), classNameAttribute],
|
|
||||||
img: [
|
|
||||||
...(attributes.img || []),
|
|
||||||
'loading',
|
|
||||||
classNameAttribute,
|
|
||||||
],
|
|
||||||
li: [...(attributes.li || []), classNameAttribute],
|
|
||||||
ol: [...(attributes.ol || []), classNameAttribute],
|
|
||||||
p: [...(attributes.p || []), classNameAttribute],
|
|
||||||
pre: [...(attributes.pre || []), classNameAttribute],
|
|
||||||
span: [...(attributes.span || []), classNameAttribute],
|
|
||||||
table: [...(attributes.table || []), classNameAttribute],
|
|
||||||
tbody: [...(attributes.tbody || []), classNameAttribute],
|
|
||||||
td: [...(attributes.td || []), classNameAttribute],
|
|
||||||
th: [...(attributes.th || []), classNameAttribute],
|
|
||||||
thead: [...(attributes.thead || []), classNameAttribute],
|
|
||||||
tr: [...(attributes.tr || []), classNameAttribute],
|
|
||||||
ul: [...(attributes.ul || []), classNameAttribute],
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,4 +35,30 @@ describe('MarkdownService', () => {
|
|||||||
expect(html).not.toContain('onclick');
|
expect(html).not.toContain('onclick');
|
||||||
expect(html).not.toContain('<script>');
|
expect(html).not.toContain('<script>');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('builds sanitizer schema for content classes and image loading', () => {
|
||||||
|
const schema = (service as any).createSanitizeSchema({
|
||||||
|
attributes: {
|
||||||
|
a: ['href'],
|
||||||
|
img: ['src'],
|
||||||
|
},
|
||||||
|
tagNames: ['p'],
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(schema.tagNames).toEqual(['p', 'figcaption', 'figure']);
|
||||||
|
expect(schema.attributes.a).toEqual([
|
||||||
|
'href',
|
||||||
|
'target',
|
||||||
|
'rel',
|
||||||
|
['className', /^(kt-md-|wp-|align|size-|is-|has-|language-|attachment-)/],
|
||||||
|
]);
|
||||||
|
expect(schema.attributes.figure).toEqual([
|
||||||
|
['className', /^(kt-md-|wp-|align|size-|is-|has-|language-|attachment-)/],
|
||||||
|
]);
|
||||||
|
expect(schema.attributes.img).toEqual([
|
||||||
|
'src',
|
||||||
|
'loading',
|
||||||
|
['className', /^(kt-md-|wp-|align|size-|is-|has-|language-|attachment-)/],
|
||||||
|
]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user