@ecency/render-helper 2.3.15 → 2.3.17
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/helper.d.ts +1 -0
- package/lib/helper.js +17 -5
- package/lib/helper.js.map +1 -1
- package/lib/methods/a.method.js +7 -7
- package/lib/methods/a.method.js.map +1 -1
- package/lib/methods/iframe.method.js +5 -1
- package/lib/methods/iframe.method.js.map +1 -1
- package/lib/methods/linkify.method.js +1 -1
- package/lib/methods/linkify.method.js.map +1 -1
- package/lib/methods/text.method.js +1 -1
- package/lib/methods/text.method.js.map +1 -1
- package/lib/render-helper.js +1 -1
- package/package.json +1 -1
- package/src/helper.ts +20 -4
- package/src/markdown-2-html.spec.ts +28 -4
- package/src/methods/a.method.ts +8 -8
- package/src/methods/iframe.method.ts +5 -1
- package/src/methods/linkify.method.ts +2 -2
- package/src/methods/text.method.ts +2 -2
package/package.json
CHANGED
package/src/helper.ts
CHANGED
|
@@ -27,13 +27,29 @@ export function extractYtStartTime(url:string):string {
|
|
|
27
27
|
return '';
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
+
export function sanitizePermlink(permlink: string): string {
|
|
31
|
+
if (!permlink || typeof permlink !== 'string') {
|
|
32
|
+
return ''
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const [withoutQuery] = permlink.split('?')
|
|
36
|
+
const [cleaned] = withoutQuery.split('#')
|
|
37
|
+
|
|
38
|
+
return cleaned
|
|
39
|
+
}
|
|
40
|
+
|
|
30
41
|
export function isValidPermlink(permlink: string): boolean {
|
|
42
|
+
const sanitized = sanitizePermlink(permlink)
|
|
43
|
+
|
|
44
|
+
if (!sanitized) {
|
|
45
|
+
return false
|
|
46
|
+
}
|
|
47
|
+
|
|
31
48
|
// Should not contain image extensions, query params, or fragments
|
|
32
|
-
const isImage = /\.(jpg|jpeg|png|webp|gif|svg)$/i.test(
|
|
33
|
-
const
|
|
34
|
-
const isCleanFormat = /^[a-z0-9-]+$/.test(permlink); // Hive standard
|
|
49
|
+
const isImage = /\.(jpg|jpeg|png|webp|gif|svg)$/i.test(sanitized)
|
|
50
|
+
const isCleanFormat = /^[a-z0-9-]+$/.test(sanitized) // Hive standard
|
|
35
51
|
|
|
36
|
-
return isCleanFormat && !isImage
|
|
52
|
+
return isCleanFormat && !isImage
|
|
37
53
|
}
|
|
38
54
|
|
|
39
55
|
// Reference: https://en.wikipedia.org/wiki/Domain_Name_System#Domain_name_syntax
|
|
@@ -424,7 +424,7 @@ describe('Markdown2Html', () => {
|
|
|
424
424
|
last_update: '2019-05-10T09:15:21',
|
|
425
425
|
body: '[](https://3speak.online/watch?v=wehmoen/xrhjxocx)'
|
|
426
426
|
}
|
|
427
|
-
const expected = '<p dir=\"auto\"><a class="markdown-video-link markdown-video-link-speak" data-embed-src="https://3speak.
|
|
427
|
+
const expected = '<p dir=\"auto\"><a class="markdown-video-link markdown-video-link-speak" data-embed-src="https://3speak.tv/embed?v=wehmoen/xrhjxocx"><img class="no-replace video-thumbnail" itemprop="image" src="https://images.ecency.com/p/2ufhwNgM3qHKBGVeU2TMMqPBjdB17MRuf4Q7vGrmGMtTn6yFtvW3Lt9t5v1c3so7UFhWDYh9B.png?format=match&mode=fit" loading="eager" fetchpriority="high" /><span class="markdown-video-play"></span></a></p>'
|
|
428
428
|
|
|
429
429
|
expect(markdown2Html(input)).toBe(expected)
|
|
430
430
|
})
|
|
@@ -436,7 +436,7 @@ describe('Markdown2Html', () => {
|
|
|
436
436
|
last_update: '2029-05-10T09:15:21',
|
|
437
437
|
body: '[](https://3speak.co/watch?v=theycallmedan/blnmdkjt) [Watch on 3Speak](https://3speak.co/watch?v=theycallmedan/blnmdkjt)'
|
|
438
438
|
}
|
|
439
|
-
const expected = '<p dir=\"auto\"><a class="markdown-video-link markdown-video-link-speak" data-embed-src="https://3speak.
|
|
439
|
+
const expected = '<p dir=\"auto\"><a class="markdown-video-link markdown-video-link-speak" data-embed-src="https://3speak.tv/embed?v=theycallmedan/blnmdkjt"><img class="no-replace video-thumbnail" itemprop="image" src="https://images.ecency.com/p/CQdwDW6BZfWWtctopKyTJuDRdBH4KXwm9ijE6sZXe5MveWF3nUu4zXXBFUau8NS.png?format=match&mode=fit" loading="eager" fetchpriority="high" /><span class="markdown-video-play"></span></a> <a class="markdown-external-link" data-href="https://3speak.co/watch?v=theycallmedan/blnmdkjt">Watch on 3Speak</a></p>'
|
|
440
440
|
|
|
441
441
|
expect(markdown2Html(input)).toBe(expected)
|
|
442
442
|
})
|
|
@@ -501,6 +501,30 @@ describe('Markdown2Html', () => {
|
|
|
501
501
|
expect(markdown2Html(input)).toBe(expected)
|
|
502
502
|
})
|
|
503
503
|
|
|
504
|
+
it('32c - Should handle whitelisted post links with referral parameters', () => {
|
|
505
|
+
const input = {
|
|
506
|
+
author: 'foo33437',
|
|
507
|
+
permlink: 'bar32437',
|
|
508
|
+
last_update: '2019-05-10T09:15:21',
|
|
509
|
+
body: 'Read related post: [Weekly Sacrament of Confession? | 3 Misconducts to Avoid!](https://ecency.com/hive-148441/@artgirl/weekly-sacrament-of-confession-or?referral=artgirl)'
|
|
510
|
+
}
|
|
511
|
+
const expected = '<p dir=\"auto\">Read related post: <a class=\"markdown-post-link\" data-href=\"https://ecency.com/hive-148441/@artgirl/weekly-sacrament-of-confession-or?referral=artgirl\" data-is-inline=\"true\" data-tag=\"hive-148441\" data-author=\"artgirl\" data-permlink=\"weekly-sacrament-of-confession-or\">Weekly Sacrament of Confession? | 3 Misconducts to Avoid!</a></p>'
|
|
512
|
+
|
|
513
|
+
expect(markdown2Html(input)).toBe(expected)
|
|
514
|
+
})
|
|
515
|
+
|
|
516
|
+
it('32b - Should treat titled Hive links as non-inline', () => {
|
|
517
|
+
const input = {
|
|
518
|
+
author: 'foo33436',
|
|
519
|
+
permlink: 'bar32436',
|
|
520
|
+
last_update: '2019-05-10T09:15:21',
|
|
521
|
+
body: '[Waves mobile app](https://ecency.com/hive-125125/@ecency/waves-mobile-app-update-explore "https://ecency.com/hive-125125/@ecency/waves-mobile-app-update-explore")'
|
|
522
|
+
}
|
|
523
|
+
const expected = '<p dir=\"auto\"><a title=\"https://ecency.com/hive-125125/@ecency/waves-mobile-app-update-explore\" class=\"markdown-post-link\" data-href=\"https://ecency.com/hive-125125/@ecency/waves-mobile-app-update-explore\" data-is-inline=\"false\" data-tag=\"hive-125125\" data-author=\"ecency\" data-permlink=\"waves-mobile-app-update-explore\">Waves mobile app</a></p>'
|
|
524
|
+
|
|
525
|
+
expect(markdown2Html(input)).toBe(expected)
|
|
526
|
+
})
|
|
527
|
+
|
|
504
528
|
it('33- Should handle whitelisted user links', () => {
|
|
505
529
|
const input = {
|
|
506
530
|
author: 'foo334352',
|
|
@@ -910,7 +934,7 @@ describe('Markdown2Html', () => {
|
|
|
910
934
|
last_update: '2019-05-10T09:15:21',
|
|
911
935
|
body: 'direct link https://ecency.com/@ecency/faq?history'
|
|
912
936
|
}
|
|
913
|
-
const expected = '<p dir=\"auto\">direct link <a href=\"https://ecency.com/@ecency/faq?history\"
|
|
937
|
+
const expected = '<p dir=\"auto\">direct link <a class=\"markdown-post-link\" data-href=\"https://ecency.com/@ecency/faq?history\" data-is-inline=\"false\" data-tag=\"post\" data-author=\"ecency\" data-permlink=\"faq\">@ecency/faq</a></p>'
|
|
914
938
|
|
|
915
939
|
expect(markdown2Html(input)).toBe(expected)
|
|
916
940
|
})
|
|
@@ -922,7 +946,7 @@ describe('Markdown2Html', () => {
|
|
|
922
946
|
last_update: '2019-05-10T09:15:21',
|
|
923
947
|
body: 'direct link https://ecency.com/@ecency/posts?q=games'
|
|
924
948
|
}
|
|
925
|
-
const expected = '<p dir=\"auto\">direct link <a href=\"https://ecency.com/@ecency/posts?q=games\" class=\"markdown-profile-link\"
|
|
949
|
+
const expected = '<p dir=\"auto\">direct link <a href=\"https://ecency.com/@ecency/posts?q=games\" class=\"markdown-profile-link\">@ecency/posts?q=games</a></p>'
|
|
926
950
|
|
|
927
951
|
expect(markdown2Html(input)).toBe(expected)
|
|
928
952
|
})
|
package/src/methods/a.method.ts
CHANGED
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
import { getSerializedInnerHTML } from './get-inner-html.method'
|
|
31
31
|
import { proxifyImageSrc } from '../proxify-image-src'
|
|
32
32
|
import { removeChildNodes } from './remove-child-nodes.method'
|
|
33
|
-
import { extractYtStartTime, isValidPermlink, isValidUsername } from '../helper'
|
|
33
|
+
import { extractYtStartTime, isValidPermlink, isValidUsername, sanitizePermlink } from '../helper'
|
|
34
34
|
import { createImageHTML } from "./img.method";
|
|
35
35
|
|
|
36
36
|
const normalizeValue = (value?: string | null): string => (value ? value.trim() : '')
|
|
@@ -124,7 +124,7 @@ export function a(el: HTMLElement | null, forApp: boolean, webp: boolean): void
|
|
|
124
124
|
|
|
125
125
|
const tag = postMatch[2]
|
|
126
126
|
const author = postMatch[3].replace('@', '')
|
|
127
|
-
const permlink = postMatch[4]
|
|
127
|
+
const permlink = sanitizePermlink(postMatch[4])
|
|
128
128
|
|
|
129
129
|
if (!isValidPermlink(permlink)) return;
|
|
130
130
|
|
|
@@ -212,7 +212,7 @@ export function a(el: HTMLElement | null, forApp: boolean, webp: boolean): void
|
|
|
212
212
|
|
|
213
213
|
el.setAttribute('class', 'markdown-post-link')
|
|
214
214
|
const author = tpostMatch[2].replace('@', '')
|
|
215
|
-
const permlink = tpostMatch[3]
|
|
215
|
+
const permlink = sanitizePermlink(tpostMatch[3])
|
|
216
216
|
|
|
217
217
|
if (!isValidPermlink(permlink)) return;
|
|
218
218
|
|
|
@@ -291,7 +291,7 @@ export function a(el: HTMLElement | null, forApp: boolean, webp: boolean): void
|
|
|
291
291
|
const tag = 'post'
|
|
292
292
|
|
|
293
293
|
const author = cpostMatch[1].replace('@', '')
|
|
294
|
-
const permlink = cpostMatch[2]
|
|
294
|
+
const permlink = sanitizePermlink(cpostMatch[2])
|
|
295
295
|
|
|
296
296
|
if (!isValidPermlink(permlink)) return;
|
|
297
297
|
|
|
@@ -397,7 +397,7 @@ export function a(el: HTMLElement | null, forApp: boolean, webp: boolean): void
|
|
|
397
397
|
|
|
398
398
|
const tag = 'ccc'
|
|
399
399
|
const author = cccMatch[2].replace('@', '')
|
|
400
|
-
const permlink = cccMatch[3]
|
|
400
|
+
const permlink = sanitizePermlink(cccMatch[3])
|
|
401
401
|
|
|
402
402
|
if (!isValidPermlink(permlink)) return;
|
|
403
403
|
|
|
@@ -690,9 +690,9 @@ export function a(el: HTMLElement | null, forApp: boolean, webp: boolean): void
|
|
|
690
690
|
const imgEls = el.getElementsByTagName('img')
|
|
691
691
|
if (imgEls.length === 1 || el.textContent.trim() === href) {
|
|
692
692
|
const e = SPEAK_REGEX.exec(href)
|
|
693
|
-
// e[1] = tld , e[3] = embed address
|
|
694
|
-
if (e[1] && e[3]) {
|
|
695
|
-
const videoHref = `https://3speak
|
|
693
|
+
// e[1] / e[2] = tld , e[3] = embed address
|
|
694
|
+
if ((e[1] || e[2]) && e[3]) {
|
|
695
|
+
const videoHref = `https://3speak.tv/embed?v=${e[3]}`
|
|
696
696
|
el.setAttribute('class', 'markdown-video-link markdown-video-link-speak')
|
|
697
697
|
el.removeAttribute('href')
|
|
698
698
|
el.setAttribute('data-embed-src', videoHref)
|
|
@@ -40,7 +40,11 @@ export function iframe(el: HTMLElement | null): void {
|
|
|
40
40
|
|
|
41
41
|
// 3Speak
|
|
42
42
|
if (src.match(SPEAK_EMBED_REGEX)) {
|
|
43
|
-
const
|
|
43
|
+
const normalizedSrc = src.replace(/3speak\.[a-z]+/i, '3speak.tv');
|
|
44
|
+
const hasAutoplay = /[?&]autoplay=/.test(normalizedSrc);
|
|
45
|
+
const s = hasAutoplay
|
|
46
|
+
? normalizedSrc
|
|
47
|
+
: `${normalizedSrc}${normalizedSrc.includes('?') ? '&' : '?'}autoplay=true`;
|
|
44
48
|
el.setAttribute('src', s);
|
|
45
49
|
return;
|
|
46
50
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IMG_REGEX, SECTION_LIST } from '../consts'
|
|
2
2
|
import { proxifyImageSrc } from '../proxify-image-src'
|
|
3
|
-
import { isValidPermlink, isValidUsername } from "../helper";
|
|
3
|
+
import { isValidPermlink, isValidUsername, sanitizePermlink } from "../helper";
|
|
4
4
|
import { createImageHTML } from "./img.method";
|
|
5
5
|
|
|
6
6
|
export function linkify(content: string, forApp: boolean, webp: boolean): string {
|
|
@@ -35,7 +35,7 @@ export function linkify(content: string, forApp: boolean, webp: boolean): string
|
|
|
35
35
|
content = content.replace(
|
|
36
36
|
/((^|\s)(\/|)@[\w.\d-]+)\/(\S+)/gi, (match, u, p1, p2, p3) => {
|
|
37
37
|
const uu = u.trim().toLowerCase().replace('/@', '').replace('@', '');
|
|
38
|
-
const permlink = p3;
|
|
38
|
+
const permlink = sanitizePermlink(p3);
|
|
39
39
|
if (!isValidPermlink(permlink)) return match;
|
|
40
40
|
|
|
41
41
|
if (SECTION_LIST.some(v => p3.includes(v))) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IMG_REGEX, YOUTUBE_REGEX, WHITE_LIST, DOMParser, POST_REGEX } from '../consts'
|
|
2
|
-
import { extractYtStartTime, isValidPermlink, isValidUsername } from '../helper'
|
|
2
|
+
import { extractYtStartTime, isValidPermlink, isValidUsername, sanitizePermlink } from '../helper'
|
|
3
3
|
import { proxifyImageSrc } from '../proxify-image-src'
|
|
4
4
|
import { linkify } from './linkify.method'
|
|
5
5
|
import {createImageHTML} from "./img.method";
|
|
@@ -62,7 +62,7 @@ export function text(node: HTMLElement | null, forApp: boolean, webp: boolean):
|
|
|
62
62
|
if (postMatch && WHITE_LIST.includes(postMatch[1].replace(/www./,''))) {
|
|
63
63
|
const tag = postMatch[2]
|
|
64
64
|
const author = postMatch[3].replace('@', '')
|
|
65
|
-
const permlink = postMatch[4]
|
|
65
|
+
const permlink = sanitizePermlink(postMatch[4])
|
|
66
66
|
|
|
67
67
|
if (!isValidUsername(author)) return
|
|
68
68
|
if (!isValidPermlink(permlink)) return
|