diff options
-rw-r--r-- | server/helpers/markdown.ts | 15 | ||||
-rw-r--r-- | server/lib/client-html.ts | 22 | ||||
-rw-r--r-- | server/tests/client.ts | 9 |
3 files changed, 28 insertions, 18 deletions
diff --git a/server/helpers/markdown.ts b/server/helpers/markdown.ts index c8fb31c8c..7c4a1a8b1 100644 --- a/server/helpers/markdown.ts +++ b/server/helpers/markdown.ts | |||
@@ -19,8 +19,21 @@ const toSafeHtml = text => { | |||
19 | return sanitizeHtml(html, SANITIZE_OPTIONS) | 19 | return sanitizeHtml(html, SANITIZE_OPTIONS) |
20 | } | 20 | } |
21 | 21 | ||
22 | const mdToPlainText = text => { | ||
23 | // Convert possible markdown (emojis, emphasis and lists) to html | ||
24 | const html = markdownIt.render(text) | ||
25 | |||
26 | // Convert to safe Html | ||
27 | const safeHtml = sanitizeHtml(html, SANITIZE_OPTIONS) | ||
28 | |||
29 | return safeHtml.replace(/<[^>]+>/g, '') | ||
30 | .replace(/\n$/, '') | ||
31 | .replace('\n', ', ') | ||
32 | } | ||
33 | |||
22 | // --------------------------------------------------------------------------- | 34 | // --------------------------------------------------------------------------- |
23 | 35 | ||
24 | export { | 36 | export { |
25 | toSafeHtml | 37 | toSafeHtml, |
38 | mdToPlainText | ||
26 | } | 39 | } |
diff --git a/server/lib/client-html.ts b/server/lib/client-html.ts index 5485376d3..203bd3893 100644 --- a/server/lib/client-html.ts +++ b/server/lib/client-html.ts | |||
@@ -24,7 +24,7 @@ import { VideoChannelModel } from '../models/video/video-channel' | |||
24 | import { getActivityStreamDuration } from '../models/video/video-format-utils' | 24 | import { getActivityStreamDuration } from '../models/video/video-format-utils' |
25 | import { VideoPlaylistModel } from '../models/video/video-playlist' | 25 | import { VideoPlaylistModel } from '../models/video/video-playlist' |
26 | import { MAccountActor, MChannelActor } from '../types/models' | 26 | import { MAccountActor, MChannelActor } from '../types/models' |
27 | import { toSafeHtml } from '../helpers/markdown' | 27 | import { mdToPlainText } from '../helpers/markdown' |
28 | 28 | ||
29 | type Tags = { | 29 | type Tags = { |
30 | ogType: string | 30 | ogType: string |
@@ -55,10 +55,6 @@ type Tags = { | |||
55 | } | 55 | } |
56 | } | 56 | } |
57 | 57 | ||
58 | const toPlainText = (content: string) => { | ||
59 | return toSafeHtml(content).replace(/<[^>]+>/g, '') | ||
60 | } | ||
61 | |||
62 | class ClientHtml { | 58 | class ClientHtml { |
63 | 59 | ||
64 | private static htmlCache: { [path: string]: string } = {} | 60 | private static htmlCache: { [path: string]: string } = {} |
@@ -99,13 +95,13 @@ class ClientHtml { | |||
99 | } | 95 | } |
100 | 96 | ||
101 | let customHtml = ClientHtml.addTitleTag(html, escapeHTML(video.name)) | 97 | let customHtml = ClientHtml.addTitleTag(html, escapeHTML(video.name)) |
102 | customHtml = ClientHtml.addDescriptionTag(customHtml, toPlainText(video.description)) | 98 | customHtml = ClientHtml.addDescriptionTag(customHtml, mdToPlainText(video.description)) |
103 | 99 | ||
104 | const url = WEBSERVER.URL + video.getWatchStaticPath() | 100 | const url = WEBSERVER.URL + video.getWatchStaticPath() |
105 | const originUrl = video.url | 101 | const originUrl = video.url |
106 | const title = escapeHTML(video.name) | 102 | const title = escapeHTML(video.name) |
107 | const siteName = escapeHTML(CONFIG.INSTANCE.NAME) | 103 | const siteName = escapeHTML(CONFIG.INSTANCE.NAME) |
108 | const description = toPlainText(video.description) | 104 | const description = mdToPlainText(video.description) |
109 | 105 | ||
110 | const image = { | 106 | const image = { |
111 | url: WEBSERVER.URL + video.getPreviewStaticPath() | 107 | url: WEBSERVER.URL + video.getPreviewStaticPath() |
@@ -157,13 +153,13 @@ class ClientHtml { | |||
157 | } | 153 | } |
158 | 154 | ||
159 | let customHtml = ClientHtml.addTitleTag(html, escapeHTML(videoPlaylist.name)) | 155 | let customHtml = ClientHtml.addTitleTag(html, escapeHTML(videoPlaylist.name)) |
160 | customHtml = ClientHtml.addDescriptionTag(customHtml, toPlainText(videoPlaylist.description)) | 156 | customHtml = ClientHtml.addDescriptionTag(customHtml, mdToPlainText(videoPlaylist.description)) |
161 | 157 | ||
162 | const url = videoPlaylist.getWatchUrl() | 158 | const url = videoPlaylist.getWatchUrl() |
163 | const originUrl = videoPlaylist.url | 159 | const originUrl = videoPlaylist.url |
164 | const title = escapeHTML(videoPlaylist.name) | 160 | const title = escapeHTML(videoPlaylist.name) |
165 | const siteName = escapeHTML(CONFIG.INSTANCE.NAME) | 161 | const siteName = escapeHTML(CONFIG.INSTANCE.NAME) |
166 | const description = toPlainText(videoPlaylist.description) | 162 | const description = mdToPlainText(videoPlaylist.description) |
167 | 163 | ||
168 | const image = { | 164 | const image = { |
169 | url: videoPlaylist.getThumbnailUrl() | 165 | url: videoPlaylist.getThumbnailUrl() |
@@ -241,13 +237,13 @@ class ClientHtml { | |||
241 | } | 237 | } |
242 | 238 | ||
243 | let customHtml = ClientHtml.addTitleTag(html, escapeHTML(entity.getDisplayName())) | 239 | let customHtml = ClientHtml.addTitleTag(html, escapeHTML(entity.getDisplayName())) |
244 | customHtml = ClientHtml.addDescriptionTag(customHtml, toPlainText(entity.description)) | 240 | customHtml = ClientHtml.addDescriptionTag(customHtml, mdToPlainText(entity.description)) |
245 | 241 | ||
246 | const url = entity.getLocalUrl() | 242 | const url = entity.getLocalUrl() |
247 | const originUrl = entity.Actor.url | 243 | const originUrl = entity.Actor.url |
248 | const siteName = escapeHTML(CONFIG.INSTANCE.NAME) | 244 | const siteName = escapeHTML(CONFIG.INSTANCE.NAME) |
249 | const title = escapeHTML(entity.getDisplayName()) | 245 | const title = escapeHTML(entity.getDisplayName()) |
250 | const description = toPlainText(entity.description) | 246 | const description = mdToPlainText(entity.description) |
251 | 247 | ||
252 | const image = { | 248 | const image = { |
253 | url: entity.Actor.getAvatarUrl(), | 249 | url: entity.Actor.getAvatarUrl(), |
@@ -383,7 +379,7 @@ class ClientHtml { | |||
383 | } | 379 | } |
384 | 380 | ||
385 | metaTags['og:url'] = tags.url | 381 | metaTags['og:url'] = tags.url |
386 | metaTags['og:description'] = tags.description | 382 | metaTags['og:description'] = mdToPlainText(tags.description) |
387 | 383 | ||
388 | if (tags.embed) { | 384 | if (tags.embed) { |
389 | metaTags['og:video:url'] = tags.embed.url | 385 | metaTags['og:video:url'] = tags.embed.url |
@@ -399,7 +395,7 @@ class ClientHtml { | |||
399 | private static generateStandardMetaTags (tags: Tags) { | 395 | private static generateStandardMetaTags (tags: Tags) { |
400 | return { | 396 | return { |
401 | name: tags.title, | 397 | name: tags.title, |
402 | description: tags.description, | 398 | description: mdToPlainText(tags.description), |
403 | image: tags.image.url | 399 | image: tags.image.url |
404 | } | 400 | } |
405 | } | 401 | } |
diff --git a/server/tests/client.ts b/server/tests/client.ts index d608764ee..3c99bcd1f 100644 --- a/server/tests/client.ts +++ b/server/tests/client.ts | |||
@@ -39,7 +39,8 @@ describe('Test a client controllers', function () { | |||
39 | let account: Account | 39 | let account: Account |
40 | 40 | ||
41 | const videoName = 'my super name for server 1' | 41 | const videoName = 'my super name for server 1' |
42 | const videoDescription = 'my super description for server 1' | 42 | const videoDescription = 'my<br> super __description__ for *server* 1<p></p>' |
43 | const videoDescriptionPlainText = 'my super description for server 1' | ||
43 | 44 | ||
44 | const playlistName = 'super playlist name' | 45 | const playlistName = 'super playlist name' |
45 | const playlistDescription = 'super playlist description' | 46 | const playlistDescription = 'super playlist description' |
@@ -169,7 +170,7 @@ describe('Test a client controllers', function () { | |||
169 | .expect(HttpStatusCode.OK_200) | 170 | .expect(HttpStatusCode.OK_200) |
170 | 171 | ||
171 | expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`) | 172 | expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`) |
172 | expect(res.text).to.contain(`<meta property="og:description" content="${videoDescription}" />`) | 173 | expect(res.text).to.contain(`<meta property="og:description" content="${videoDescriptionPlainText}" />`) |
173 | expect(res.text).to.contain('<meta property="og:type" content="video" />') | 174 | expect(res.text).to.contain('<meta property="og:type" content="video" />') |
174 | expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`) | 175 | expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`) |
175 | }) | 176 | }) |
@@ -181,7 +182,7 @@ describe('Test a client controllers', function () { | |||
181 | .expect(HttpStatusCode.OK_200) | 182 | .expect(HttpStatusCode.OK_200) |
182 | 183 | ||
183 | expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`) | 184 | expect(res.text).to.contain(`<meta property="og:title" content="${videoName}" />`) |
184 | expect(res.text).to.contain(`<meta property="og:description" content="${videoDescription}" />`) | 185 | expect(res.text).to.contain(`<meta property="og:description" content="${videoDescriptionPlainText}" />`) |
185 | expect(res.text).to.contain('<meta property="og:type" content="video" />') | 186 | expect(res.text).to.contain('<meta property="og:type" content="video" />') |
186 | expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`) | 187 | expect(res.text).to.contain(`<meta property="og:url" content="${servers[0].url}/videos/watch/${servers[0].video.uuid}" />`) |
187 | }) | 188 | }) |
@@ -210,7 +211,7 @@ describe('Test a client controllers', function () { | |||
210 | expect(res.text).to.contain('<meta property="twitter:card" content="summary_large_image" />') | 211 | expect(res.text).to.contain('<meta property="twitter:card" content="summary_large_image" />') |
211 | expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') | 212 | expect(res.text).to.contain('<meta property="twitter:site" content="@Chocobozzz" />') |
212 | expect(res.text).to.contain(`<meta property="twitter:title" content="${videoName}" />`) | 213 | expect(res.text).to.contain(`<meta property="twitter:title" content="${videoName}" />`) |
213 | expect(res.text).to.contain(`<meta property="twitter:description" content="${videoDescription}" />`) | 214 | expect(res.text).to.contain(`<meta property="twitter:description" content="${videoDescriptionPlainText}" />`) |
214 | }) | 215 | }) |
215 | 216 | ||
216 | it('Should have valid twitter card on the watch playlist page', async function () { | 217 | it('Should have valid twitter card on the watch playlist page', async function () { |