@ecency/render-helper 2.2.10 → 2.2.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/catch-post-image.js +7 -7
- package/lib/catch-post-image.js.map +1 -1
- package/lib/consts/allowed-attributes.const.js +2 -0
- package/lib/consts/allowed-attributes.const.js.map +1 -1
- package/lib/consts/regexes.const.d.ts +1 -0
- package/lib/consts/regexes.const.js +3 -2
- package/lib/consts/regexes.const.js.map +1 -1
- package/lib/helper.d.ts +1 -0
- package/lib/helper.js +14 -2
- package/lib/helper.js.map +1 -1
- package/lib/markdown-2-html.js +7 -7
- package/lib/markdown-2-html.js.map +1 -1
- package/lib/methods/a.method.js +66 -46
- package/lib/methods/a.method.js.map +1 -1
- package/lib/methods/clean-reply.method.js +2 -2
- package/lib/methods/iframe.method.js +5 -5
- package/lib/methods/iframe.method.js.map +1 -1
- package/lib/methods/img.method.js +1 -1
- package/lib/methods/img.method.js.map +1 -1
- package/lib/methods/linkify.method.js +10 -10
- package/lib/methods/linkify.method.js.map +1 -1
- package/lib/methods/markdown-to-html.method.js +5 -5
- package/lib/methods/markdown-to-html.method.js.map +1 -1
- package/lib/methods/sanitize-html.method.js +1 -1
- package/lib/methods/sanitize-html.method.js.map +1 -1
- package/lib/methods/text.method.js +16 -10
- package/lib/methods/text.method.js.map +1 -1
- package/lib/methods/traverse.method.js +4 -4
- package/lib/methods/traverse.method.js.map +1 -1
- package/lib/post-body-summary.js +6 -5
- package/lib/post-body-summary.js.map +1 -1
- package/lib/proxify-image-src.js +12 -8
- package/lib/proxify-image-src.js.map +1 -1
- package/lib/render-helper.js +1 -1
- package/package.json +1 -1
- package/src/consts/allowed-attributes.const.ts +2 -0
- package/src/consts/regexes.const.ts +2 -1
- package/src/helper.ts +11 -0
- package/src/markdown-2-html.spec.ts +16 -4
- package/src/methods/a.method.ts +27 -2
- package/src/methods/clean-reply.method.ts +2 -2
- package/src/methods/markdown-to-html.method.ts +2 -2
- package/src/methods/text.method.ts +7 -1
- package/src/post-body-summary.ts +3 -1
- package/src/test/data/legacy/23.json +1 -1
- package/src/test/data/legacy/27.JSON +1 -1
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@ export const INTERNAL_TOPIC_REGEX = /^\/(trending|hot|created|promoted|muted|pay
|
|
|
11
11
|
export const INTERNAL_POST_TAG_REGEX = /\/(.*)\/(@[\w.\d-]+)\/(.*)/i
|
|
12
12
|
export const INTERNAL_POST_REGEX = /^\/(@[\w.\d-]+)\/(.*)$/i
|
|
13
13
|
export const CUSTOM_COMMUNITY_REGEX = /^https?:\/\/(.*)\/c\/(hive-\d+)(.*)/i
|
|
14
|
-
export const YOUTUBE_REGEX = /(?:
|
|
14
|
+
export const YOUTUBE_REGEX = /(?:youtube.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu.be\/)([^"&?\/\s]{11})/g
|
|
15
15
|
export const YOUTUBE_EMBED_REGEX = /^(https?:)?\/\/www.youtube.com\/(embed|shorts)\/.*/i
|
|
16
16
|
export const VIMEO_REGEX = /(https?:\/\/)?(www\.)?(?:vimeo)\.com.*(?:videos|video|channels|)\/([\d]+)/i
|
|
17
17
|
export const VIMEO_EMBED_REGEX = /https:\/\/player\.vimeo\.com\/video\/([0-9]+)/
|
|
@@ -39,3 +39,4 @@ export const BRAND_NEW_TUBE_REGEX = /^https:\/\/brandnewtube\.com\/embed\/[a-z0-
|
|
|
39
39
|
export const LOOM_REGEX = /^(https?:)?\/\/www.loom.com\/share\/(.*)/i
|
|
40
40
|
export const LOOM_EMBED_REGEX = /^(https?:)?\/\/www.loom.com\/embed\/(.*)/i
|
|
41
41
|
export const AUREAL_EMBED_REGEX = /^(https?:\/\/)?(www\.)?(?:aureal-embed)\.web\.app\/([0-9]+)/i
|
|
42
|
+
export const ENTITY_REGEX = /&([a-z0-9]+|#[0-9]{1,6}|#x[0-9a-fA-F]{1,6});/ig;
|
package/src/helper.ts
CHANGED
|
@@ -14,3 +14,14 @@ export function makeEntryCacheKey(entry: any): string {
|
|
|
14
14
|
return `${entry.author}-${entry.permlink}-${entry.last_update}`
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
export function extractYtStartTime(url:string):string {
|
|
18
|
+
const urlObj = new URL(url);
|
|
19
|
+
const params = new URLSearchParams(urlObj.search);
|
|
20
|
+
if(params.has('t')){
|
|
21
|
+
return '' + parseInt(params.get('t')); //parsing is important as sometimes t is famated '123s';
|
|
22
|
+
}else if (params.has('start')){
|
|
23
|
+
return params.get('start');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return '';
|
|
27
|
+
}
|
|
@@ -70,7 +70,7 @@ describe('Markdown2Html', () => {
|
|
|
70
70
|
last_update: '2019-05-10T09:15:21',
|
|
71
71
|
body: 'https://www.youtube.com/watch?v=qK3d1eoH-Qs'
|
|
72
72
|
}
|
|
73
|
-
const expected = '<p><a class="markdown-video-link markdown-video-link-youtube" data-embed-src="https://www.youtube.com/embed/qK3d1eoH-Qs?autoplay=1"><img class="no-replace video-thumbnail" src="https://images.ecency.com/p/S5Eokt4BcQdk7EHeT1aYjzebg2hC7hkthT45eMZRVYW6mkGBWKemLWWzXbRhNG7Z3h1qjGS.png?format=match&mode=fit" /><span class="markdown-video-play"></span></a></p>'
|
|
73
|
+
const expected = '<p><a class="markdown-video-link markdown-video-link-youtube" data-embed-src="https://www.youtube.com/embed/qK3d1eoH-Qs?autoplay=1" data-youtube="qK3d1eoH-Qs"><img class="no-replace video-thumbnail" src="https://images.ecency.com/p/S5Eokt4BcQdk7EHeT1aYjzebg2hC7hkthT45eMZRVYW6mkGBWKemLWWzXbRhNG7Z3h1qjGS.png?format=match&mode=fit" /><span class="markdown-video-play"></span></a></p>'
|
|
74
74
|
|
|
75
75
|
expect(markdown2Html(input)).toBe(expected)
|
|
76
76
|
})
|
|
@@ -142,7 +142,7 @@ describe('Markdown2Html', () => {
|
|
|
142
142
|
last_update: '2019-05-10T09:15:21',
|
|
143
143
|
body: '<iframe width="560" height="315" src="https://www.youtube.com/embed/I3f9ixg59no?foo=bar&baz=000" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>'
|
|
144
144
|
}
|
|
145
|
-
const expected = '<iframe src=\"https://www.youtube.com/embed/I3f9ixg59no\" allowfullscreen=\"allowfullscreen\"></iframe>'
|
|
145
|
+
const expected = '<iframe src=\"https://www.youtube.com/embed/I3f9ixg59no\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"></iframe>'
|
|
146
146
|
|
|
147
147
|
expect(markdown2Html(input)).toBe(expected)
|
|
148
148
|
})
|
|
@@ -445,9 +445,9 @@ describe('Markdown2Html', () => {
|
|
|
445
445
|
author: 'foo329',
|
|
446
446
|
permlink: 'bar329',
|
|
447
447
|
last_update: '2019-05-10T09:15:21',
|
|
448
|
-
body: 'https://youtu.be/
|
|
448
|
+
body: 'https://youtu.be/UuyS7YAkECA?t=295s'
|
|
449
449
|
}
|
|
450
|
-
const expected = '<p><a class="markdown-video-link markdown-video-link-youtube" data-embed-src="https://www.youtube.com/embed/
|
|
450
|
+
const expected = '<p><a class="markdown-video-link markdown-video-link-youtube" data-embed-src="https://www.youtube.com/embed/UuyS7YAkECA?autoplay=1" data-youtube="UuyS7YAkECA" data-start-time="295"><img class="no-replace video-thumbnail" src="https://images.ecency.com/p/S5Eokt4BcQdk7EHeT1aYjzebg2hC7hkthT45eAMp88bZ44hfAQDm6BtJw2H53aq1Tpn1cu4.png?format=match&mode=fit" /><span class="markdown-video-play"></span></a></p>'
|
|
451
451
|
|
|
452
452
|
expect(markdown2Html(input)).toBe(expected)
|
|
453
453
|
})
|
|
@@ -877,6 +877,18 @@ describe('Markdown2Html', () => {
|
|
|
877
877
|
|
|
878
878
|
expect(markdown2Html(input, false)).toBe(expected)
|
|
879
879
|
})
|
|
880
|
+
|
|
881
|
+
it('65- Should handle youtube.com/embed videos', () => {
|
|
882
|
+
const input = {
|
|
883
|
+
author: 'foo329',
|
|
884
|
+
permlink: 'bar329',
|
|
885
|
+
last_update: '2019-05-10T09:15:21',
|
|
886
|
+
body: 'https://www.youtube.com/embed/UuyS7YAkECA?start=295&autoplay=1'
|
|
887
|
+
}
|
|
888
|
+
const expected = '<p><a class="markdown-video-link markdown-video-link-youtube" data-embed-src="https://www.youtube.com/embed/UuyS7YAkECA?autoplay=1" data-youtube="UuyS7YAkECA" data-start-time="295"><img class="no-replace video-thumbnail" src="https://images.ecency.com/p/S5Eokt4BcQdk7EHeT1aYjzebg2hC7hkthT45eAMp88bZ44hfAQDm6BtJw2H53aq1Tpn1cu4.png?format=match&mode=fit" /><span class="markdown-video-play"></span></a></p>'
|
|
889
|
+
|
|
890
|
+
expect(markdown2Html(input)).toBe(expected)
|
|
891
|
+
})
|
|
880
892
|
})
|
|
881
893
|
|
|
882
894
|
describe("Rumble support", () => {
|
package/src/methods/a.method.ts
CHANGED
|
@@ -28,6 +28,7 @@ import {
|
|
|
28
28
|
import { getSerializedInnerHTML } from './get-inner-html.method'
|
|
29
29
|
import { proxifyImageSrc } from '../proxify-image-src'
|
|
30
30
|
import { removeChildNodes } from './remove-child-nodes.method'
|
|
31
|
+
import { extractYtStartTime } from '../helper'
|
|
31
32
|
|
|
32
33
|
export function a(el: HTMLElement, forApp: boolean, webp: boolean): void {
|
|
33
34
|
let href = el.getAttribute('href')
|
|
@@ -412,8 +413,15 @@ export function a(el: HTMLElement, forApp: boolean, webp: boolean): void {
|
|
|
412
413
|
const embedSrc = `https://www.youtube.com/embed/${vid}?autoplay=1`
|
|
413
414
|
|
|
414
415
|
el.textContent = ''
|
|
415
|
-
|
|
416
|
-
el.setAttribute('data-embed-src', embedSrc)
|
|
416
|
+
|
|
417
|
+
el.setAttribute('data-embed-src', embedSrc);
|
|
418
|
+
el.setAttribute('data-youtube', vid);
|
|
419
|
+
|
|
420
|
+
//extract start time if available
|
|
421
|
+
const startTime = extractYtStartTime(href);
|
|
422
|
+
if(startTime){
|
|
423
|
+
el.setAttribute('data-start-time', startTime);
|
|
424
|
+
}
|
|
417
425
|
|
|
418
426
|
const thumbImg = el.ownerDocument.createElement('img')
|
|
419
427
|
thumbImg.setAttribute('class', 'no-replace video-thumbnail')
|
|
@@ -664,6 +672,20 @@ export function a(el: HTMLElement, forApp: boolean, webp: boolean): void {
|
|
|
664
672
|
|
|
665
673
|
if (forApp) {
|
|
666
674
|
el.setAttribute('data-href', href)
|
|
675
|
+
const match = href.match(YOUTUBE_REGEX)
|
|
676
|
+
if (match) {
|
|
677
|
+
const e = YOUTUBE_REGEX.exec(href)
|
|
678
|
+
if (e[1]) {
|
|
679
|
+
const vid = e[1]
|
|
680
|
+
el.setAttribute('data-youtube', vid);
|
|
681
|
+
|
|
682
|
+
//extract start time if available
|
|
683
|
+
const startTime = extractYtStartTime(href);
|
|
684
|
+
if(startTime){
|
|
685
|
+
el.setAttribute('data-start-time', startTime);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}
|
|
667
689
|
el.removeAttribute('href')
|
|
668
690
|
} else {
|
|
669
691
|
const externalRegex =/(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
|
|
@@ -675,3 +697,6 @@ export function a(el: HTMLElement, forApp: boolean, webp: boolean): void {
|
|
|
675
697
|
}
|
|
676
698
|
}
|
|
677
699
|
}
|
|
700
|
+
|
|
701
|
+
|
|
702
|
+
|
|
@@ -18,8 +18,8 @@ export function cleanReply(s: string): string {
|
|
|
18
18
|
.filter(item => item.toLowerCase().includes('read this post on travelfeed.io for the best experience') === false)
|
|
19
19
|
.filter(item => item.toLowerCase().includes('posted via <a href="https://www.dporn.co/"') === false)
|
|
20
20
|
.filter(item => item.toLowerCase().includes('▶️ [watch on 3speak](https://3speak') === false)
|
|
21
|
-
.filter(item => item.toLowerCase().includes('<sup><sub>
|
|
22
|
-
.filter(item => item.toLowerCase().includes('view this post on [
|
|
21
|
+
.filter(item => item.toLowerCase().includes('<sup><sub>posted via [inji.com]') === false)
|
|
22
|
+
.filter(item => item.toLowerCase().includes('view this post on [liketu]') === false)
|
|
23
23
|
.join('\n') : '')
|
|
24
24
|
.replace('Posted via <a href="https://d.buzz" data-link="promote-link">D.Buzz</a>', '')
|
|
25
25
|
.replace('<div class="pull-right"><a href="/@hive.engage"></a></div>', '')
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { traverse } from './traverse.method'
|
|
2
2
|
import { sanitizeHtml } from './sanitize-html.method'
|
|
3
|
-
import { DOMParser } from '../consts'
|
|
3
|
+
import { DOMParser, ENTITY_REGEX } from '../consts'
|
|
4
4
|
import xmldom from 'xmldom'
|
|
5
5
|
|
|
6
6
|
const lolight = require('lolight')
|
|
@@ -47,7 +47,7 @@ export function markdownToHTML(input: string, forApp: boolean, webp: boolean): s
|
|
|
47
47
|
let output = '';
|
|
48
48
|
|
|
49
49
|
//encrypt entities
|
|
50
|
-
const entities = input.match(
|
|
50
|
+
const entities = input.match(ENTITY_REGEX);
|
|
51
51
|
const encEntities:string[] = [];
|
|
52
52
|
|
|
53
53
|
try{
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { IMG_REGEX, YOUTUBE_REGEX, WHITE_LIST, DOMParser, POST_REGEX, } from '../consts'
|
|
2
|
+
import { extractYtStartTime } from '../helper'
|
|
2
3
|
import { proxifyImageSrc } from '../proxify-image-src'
|
|
3
4
|
import { linkify } from './linkify.method'
|
|
4
5
|
|
|
@@ -34,7 +35,12 @@ export function text(node: HTMLElement, forApp: boolean, webp: boolean): void {
|
|
|
34
35
|
const thumbnail = proxifyImageSrc(`https://img.youtube.com/vi/${vid.split('?')[0]}/hqdefault.jpg`, 0, 0, webp ? 'webp' : 'match')
|
|
35
36
|
const embedSrc = `https://www.youtube.com/embed/${vid}?autoplay=1`
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
let attrs = `class="markdown-video-link markdown-video-link-youtube" data-embed-src="${embedSrc}" data-youtube="${vid}"`
|
|
39
|
+
//extract start time if available
|
|
40
|
+
const startTime = extractYtStartTime(node.nodeValue);
|
|
41
|
+
if(startTime){
|
|
42
|
+
attrs = attrs.concat(` data-start-time="${startTime}"`);
|
|
43
|
+
}
|
|
38
44
|
|
|
39
45
|
const thumbImg = node.ownerDocument.createElement('img')
|
|
40
46
|
thumbImg.setAttribute('class', 'no-replace video-thumbnail')
|
package/src/post-body-summary.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { makeEntryCacheKey } from './helper'
|
|
|
3
3
|
import { cacheGet, cacheSet } from './cache'
|
|
4
4
|
import { Entry } from './types'
|
|
5
5
|
import { cleanReply } from './methods'
|
|
6
|
+
import { ENTITY_REGEX } from './consts'
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
const { Remarkable } = require('remarkable')
|
|
8
10
|
const { linkify } = require('remarkable/linkify')
|
|
@@ -58,7 +60,7 @@ function postBodySummary(entryBody: string, length?: number, platform:'ios'|'and
|
|
|
58
60
|
]);
|
|
59
61
|
|
|
60
62
|
//encrypt entities
|
|
61
|
-
const entities = entryBody.match(
|
|
63
|
+
const entities = entryBody.match(ENTITY_REGEX);
|
|
62
64
|
const encEntities:string[] = [];
|
|
63
65
|
if(entities && platform !== 'web'){
|
|
64
66
|
entities.forEach((entity)=>{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": 23,
|
|
3
3
|
"input": "<IMG SRC=/ onerror=\"alert(String.fromCharCode(88,83,83))\"></img> <img src=x onerror=\"javascript:alert('XSS')\"> <IMG SRC=javascript:alert('XSS')> <IMG SRC=javascript:alert('XSS')> <IMG SRC=\"  javascript:alert('XSS');\">",
|
|
4
|
-
"result": "<p><IMG SRC=/ onerror=\"alert(String.fromCharCode(88,83,83))\"> <img src=\"https://images.ecency.com/p/35.png?format=match&mode=fit\"
|
|
4
|
+
"result": "<p><IMG SRC=/ onerror=\"alert(String.fromCharCode(88,83,83))\"> <img src=\"https://images.ecency.com/p/35.png?format=match&mode=fit\" /> <IMG SRC=javascript:alert('XSS')> <img /> <img /></p>"
|
|
5
5
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": 27,
|
|
3
3
|
"input": "<BR SIZE=\"&{alert('XSS')}\"> <LINK REL=\"stylesheet\" HREF=\"javascript:alert('XSS');\"> <STYLE>body{}</STYLE> <META HTTP-EQUIV=\"Link\" Content=\"<http://xss.rocks/xss.css>; REL=stylesheet\"> <IFRAME SRC=\"javascript:alert('XSS');\"></IFRAME> foo <IFRAME SRC=# onmouseover=\"alert(document.cookie)\"></IFRAME> bar <FRAMESET><FRAME SRC=\"javascript:alert('XSS');\"></FRAMESET> baz ",
|
|
4
|
-
"result": "<p><br
|
|
4
|
+
"result": "<p><br /> foo bar baz\n</p>"
|
|
5
5
|
}
|