diff --git a/client/src/app/core/renderer/html-renderer.service.ts b/client/src/app/core/renderer/html-renderer.service.ts index 302d92ed9..1fe91b96b 100644 --- a/client/src/app/core/renderer/html-renderer.service.ts +++ b/client/src/app/core/renderer/html-renderer.service.ts @@ -1,5 +1,6 @@ import { Injectable } from '@angular/core' import { LinkifierService } from './linkifier.service' +import { SANITIZE_OPTIONS } from '@shared/core-utils/renderer/html' @Injectable() export class HtmlRendererService { @@ -25,27 +26,7 @@ export class HtmlRendererService { // Convert possible markdown to html const html = this.linkifier.linkify(text) - return this.sanitizeHtml(html, { - allowedTags: [ 'a', 'p', 'span', 'br', 'strong', 'em', 'ul', 'ol', 'li' ], - allowedSchemes: [ 'http', 'https' ], - allowedAttributes: { - 'a': [ 'href', 'class', 'target', 'rel' ] - }, - transformTags: { - a: (tagName, attribs) => { - let rel = 'noopener noreferrer' - if (attribs.rel === 'me') rel += ' me' - - return { - tagName, - attribs: Object.assign(attribs, { - target: '_blank', - rel - }) - } - } - } - }) + return this.sanitizeHtml(html, SANITIZE_OPTIONS) } private async loadSanitizeHtml () { diff --git a/client/src/app/core/renderer/markdown.service.ts b/client/src/app/core/renderer/markdown.service.ts index 0e5c2ed75..0fde3f99d 100644 --- a/client/src/app/core/renderer/markdown.service.ts +++ b/client/src/app/core/renderer/markdown.service.ts @@ -1,6 +1,13 @@ import * as MarkdownIt from 'markdown-it' import { buildVideoLink } from 'src/assets/player/utils' import { Injectable } from '@angular/core' +import { + COMPLETE_RULES, + ENHANCED_RULES, + ENHANCED_WITH_HTML_RULES, + TEXT_RULES, + TEXT_WITH_HTML_RULES +} from '@shared/core-utils/renderer/markdown' import { HtmlRendererService } from './html-renderer.service' type MarkdownParsers = { @@ -25,21 +32,6 @@ type MarkdownParserConfigs = { @Injectable() export class MarkdownService { - static TEXT_RULES = [ - 'linkify', - 'autolink', - 'emphasis', - 'link', - 'newline', - 'list' - ] - static TEXT_WITH_HTML_RULES = MarkdownService.TEXT_RULES.concat([ 'html_inline', 'html_block' ]) - - static ENHANCED_RULES = MarkdownService.TEXT_RULES.concat([ 'image' ]) - static ENHANCED_WITH_HTML_RULES = MarkdownService.TEXT_WITH_HTML_RULES.concat([ 'image' ]) - - static COMPLETE_RULES = MarkdownService.ENHANCED_WITH_HTML_RULES.concat([ 'block', 'inline', 'heading', 'paragraph' ]) - private markdownParsers: MarkdownParsers = { textMarkdownIt: null, textWithHTMLMarkdownIt: null, @@ -48,13 +40,13 @@ export class MarkdownService { completeMarkdownIt: null } private parsersConfig: MarkdownParserConfigs = { - textMarkdownIt: { rules: MarkdownService.TEXT_RULES, html: false }, - textWithHTMLMarkdownIt: { rules: MarkdownService.TEXT_WITH_HTML_RULES, html: true, escape: true }, + textMarkdownIt: { rules: TEXT_RULES, html: false }, + textWithHTMLMarkdownIt: { rules: TEXT_WITH_HTML_RULES, html: true, escape: true }, - enhancedMarkdownIt: { rules: MarkdownService.ENHANCED_RULES, html: false }, - enhancedWithHTMLMarkdownIt: { rules: MarkdownService.ENHANCED_WITH_HTML_RULES, html: true, escape: true }, + enhancedMarkdownIt: { rules: ENHANCED_RULES, html: false }, + enhancedWithHTMLMarkdownIt: { rules: ENHANCED_WITH_HTML_RULES, html: true, escape: true }, - completeMarkdownIt: { rules: MarkdownService.COMPLETE_RULES, html: true } + completeMarkdownIt: { rules: COMPLETE_RULES, html: true } } constructor (private htmlRenderer: HtmlRendererService) {} diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts index 40f278608..650a3c090 100644 --- a/server/lib/emailer.ts +++ b/server/lib/emailer.ts @@ -5,6 +5,7 @@ import { join } from 'path' import { VideoChannelModel } from '@server/models/video/video-channel' import { MVideoBlacklistLightVideo, MVideoBlacklistVideo } from '@server/types/models/video/video-blacklist' import { MVideoImport, MVideoImportVideo } from '@server/types/models/video/video-import' +import { SANITIZE_OPTIONS, TEXT_WITH_HTML_RULES } from '@shared/core-utils' import { AbuseState, EmailPayload, UserAbuse } from '@shared/models' import { SendEmailOptions } from '../../shared/models/server/emailer.model' import { isTestInstance, root } from '../helpers/core-utils' @@ -20,14 +21,7 @@ const markdownItEmoji = require('markdown-it-emoji/light') const MarkdownItClass = require('markdown-it') const markdownIt = new MarkdownItClass('default', { linkify: true, breaks: true, html: true }) -markdownIt.enable([ - 'linkify', - 'autolink', - 'emphasis', - 'link', - 'newline', - 'list' -]) +markdownIt.enable(TEXT_WITH_HTML_RULES) markdownIt.use(markdownItEmoji) @@ -39,27 +33,7 @@ const toSafeHtml = text => { const html = markdownIt.render(textWithLineFeed) // Convert to safe Html - return sanitizeHtml(html, { - allowedTags: [ 'a', 'p', 'span', 'br', 'strong', 'em', 'ul', 'ol', 'li' ], - allowedSchemes: [ 'http', 'https' ], - allowedAttributes: { - a: [ 'href', 'class', 'target', 'rel' ] - }, - transformTags: { - a: (tagName, attribs) => { - let rel = 'noopener noreferrer' - if (attribs.rel === 'me') rel += ' me' - - return { - tagName, - attribs: Object.assign(attribs, { - target: '_blank', - rel - }) - } - } - } - }) + return sanitizeHtml(html, SANITIZE_OPTIONS) } const Email = require('email-templates') diff --git a/shared/core-utils/index.ts b/shared/core-utils/index.ts index 54e233522..42d7cab1d 100644 --- a/shared/core-utils/index.ts +++ b/shared/core-utils/index.ts @@ -1,3 +1,7 @@ +export * from './abuse' +export * from './i18n' export * from './logs' export * from './miscs' export * from './plugins' +export * from './renderer' +export * from './users' diff --git a/shared/core-utils/renderer/html.ts b/shared/core-utils/renderer/html.ts new file mode 100644 index 000000000..37ae5147c --- /dev/null +++ b/shared/core-utils/renderer/html.ts @@ -0,0 +1,21 @@ +export const SANITIZE_OPTIONS = { + allowedTags: [ 'a', 'p', 'span', 'br', 'strong', 'em', 'ul', 'ol', 'li' ], + allowedSchemes: [ 'http', 'https' ], + allowedAttributes: { + a: [ 'href', 'class', 'target', 'rel' ] + }, + transformTags: { + a: (tagName, attribs) => { + let rel = 'noopener noreferrer' + if (attribs.rel === 'me') rel += ' me' + + return { + tagName, + attribs: Object.assign(attribs, { + target: '_blank', + rel + }) + } + } + } +} diff --git a/shared/core-utils/renderer/index.ts b/shared/core-utils/renderer/index.ts new file mode 100644 index 000000000..0ad29d782 --- /dev/null +++ b/shared/core-utils/renderer/index.ts @@ -0,0 +1,2 @@ +export * from './markdown' +export * from './html' diff --git a/shared/core-utils/renderer/markdown.ts b/shared/core-utils/renderer/markdown.ts new file mode 100644 index 000000000..dff746d87 --- /dev/null +++ b/shared/core-utils/renderer/markdown.ts @@ -0,0 +1,23 @@ +export const TEXT_RULES = [ + 'linkify', + 'autolink', + 'emphasis', + 'link', + 'newline', + 'list' +] + +export const TEXT_WITH_HTML_RULES = TEXT_RULES.concat([ + 'html_inline', + 'html_block' +]) + +export const ENHANCED_RULES = TEXT_RULES.concat([ 'image' ]) +export const ENHANCED_WITH_HTML_RULES = TEXT_WITH_HTML_RULES.concat([ 'image' ]) + +export const COMPLETE_RULES = ENHANCED_WITH_HTML_RULES.concat([ + 'block', + 'inline', + 'heading', + 'paragraph' +])