@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ecency/render-helper",
3
- "version": "2.3.15",
3
+ "version": "2.3.17",
4
4
  "description": "Markdown+Html Render helper",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
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(permlink);
33
- const hasSpecialChars = /[?#]/.test(permlink);
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 && !hasSpecialChars;
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://img.3speakcontent.online/xrhjxocx/post.png?v2)](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.online/embed?v=wehmoen/xrhjxocx"><img class="no-replace video-thumbnail" itemprop="image" src="https://images.ecency.com/p/2ufhwNgM3qHKBGVeU2TMMqPBjdB17MRuf4Q7vGrmGMtTn6yFtvW3Lt9t5v1c3so7UFhWDYh9B.png?format=match&amp;mode=fit" loading="eager" fetchpriority="high" /><span class="markdown-video-play"></span></a></p>'
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&amp;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://img.3speakcontent.co/blnmdkjt/post.png)](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.co/embed?v=theycallmedan/blnmdkjt"><img class="no-replace video-thumbnail" itemprop="image" src="https://images.ecency.com/p/CQdwDW6BZfWWtctopKyTJuDRdBH4KXwm9ijE6sZXe5MveWF3nUu4zXXBFUau8NS.png?format=match&amp;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>'
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&amp;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\" class=\"markdown-post-link\">https://ecency.com/@ecency/faq?history</a></p>'
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\">https://ecency.com/@ecency/posts?q=games</a></p>'
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
  })
@@ -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.${e[1]}/embed?v=${e[3]}`
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 s = `${src}&autoplay=true`;
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