@ecency/render-helper 2.2.5 → 2.2.9
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/methods/a.method.js +5 -5
- package/lib/methods/a.method.js.map +1 -1
- package/lib/methods/linkify.method.js +8 -2
- package/lib/methods/linkify.method.js.map +1 -1
- package/lib/methods/markdown-to-html.method.js +22 -1
- package/lib/methods/markdown-to-html.method.js.map +1 -1
- package/lib/post-body-summary.d.ts +1 -1
- package/lib/post-body-summary.js +26 -4
- package/lib/post-body-summary.js.map +1 -1
- package/lib/render-helper.js +1 -1
- package/package.json +2 -1
- package/src/markdown-2-html.spec.ts +17 -5
- package/src/methods/a.method.ts +5 -5
- package/src/methods/linkify.method.ts +7 -2
- package/src/methods/markdown-to-html.method.ts +24 -1
- package/src/post-body-summary.spec.ts +7 -0
- package/src/post-body-summary.ts +29 -4
- package/src/test/data/legacy/22.json +1 -1
- package/src/test/data/legacy/23.json +1 -1
- package/src/test/data/legacy/27.JSON +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ecency/render-helper",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.9",
|
|
4
4
|
"description": "Markdown+Html Render helper",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -63,6 +63,7 @@
|
|
|
63
63
|
"multihashes": "0.4.13",
|
|
64
64
|
"path": "^0.12.7",
|
|
65
65
|
"querystring": "^0.2.0",
|
|
66
|
+
"react-native-crypto-js": "^1.0.0",
|
|
66
67
|
"remarkable": "^2.0.1",
|
|
67
68
|
"url": "^0.11.0",
|
|
68
69
|
"xmldom": "^0.5.0",
|
|
@@ -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
|
|
145
|
+
const expected = '<iframe src=\"https://www.youtube.com/embed/I3f9ixg59no\" allowfullscreen=\"allowfullscreen\"></iframe>'
|
|
146
146
|
|
|
147
147
|
expect(markdown2Html(input)).toBe(expected)
|
|
148
148
|
})
|
|
@@ -476,14 +476,14 @@ describe('Markdown2Html', () => {
|
|
|
476
476
|
expect(markdown2Html(input)).toBe(expected)
|
|
477
477
|
})
|
|
478
478
|
|
|
479
|
-
it('32- Should handle whitelisted post links', () => {
|
|
479
|
+
it('32 - Should handle whitelisted post links', () => {
|
|
480
480
|
const input = {
|
|
481
481
|
author: 'foo33435',
|
|
482
482
|
permlink: 'bar32435',
|
|
483
483
|
last_update: '2019-05-10T09:15:21',
|
|
484
484
|
body: 'https://peakd.com/tag/@demo/tests and https://steemit.com/test/@demo/post'
|
|
485
485
|
}
|
|
486
|
-
const expected = '<p><a class
|
|
486
|
+
const expected = '<p><a class=\"markdown-post-link\" data-tag=\"tag\" data-author=\"demo\" data-permlink=\"tests\">@demo/tests</a> and <a class=\"markdown-post-link\" data-tag=\"test\" data-author=\"demo\" data-permlink=\"post\">@demo/post</a></p>'
|
|
487
487
|
|
|
488
488
|
expect(markdown2Html(input)).toBe(expected)
|
|
489
489
|
})
|
|
@@ -644,14 +644,14 @@ describe('Markdown2Html', () => {
|
|
|
644
644
|
expect(markdown2Html(input)).toBe(expected)
|
|
645
645
|
})
|
|
646
646
|
|
|
647
|
-
it('45- Should handle collection linking', () => {
|
|
647
|
+
it('45 - Should handle collection linking', () => {
|
|
648
648
|
const input = {
|
|
649
649
|
author: 'foo345',
|
|
650
650
|
permlink: 'bar345',
|
|
651
651
|
last_update: '2019-05-10T09:15:21',
|
|
652
652
|
body: 'this is link https://peakd.com/ccc/jarvie/one-week-roadtrip-to-all-5-utah-national-parks-and-more'
|
|
653
653
|
}
|
|
654
|
-
const expected = '<p>this is link <a class=\"markdown-post-link\" data-tag=\"ccc\" data-author=\"jarvie\" data-permlink=\"one-week-roadtrip-to-all-5-utah-national-parks-and-more\"
|
|
654
|
+
const expected = '<p>this is link <a class=\"markdown-post-link\" data-tag=\"ccc\" data-author=\"jarvie\" data-permlink=\"one-week-roadtrip-to-all-5-utah-national-parks-and-more\">@jarvie/one-week-roadtrip-to-all-5-utah-national-parks-and-more</a></p>'
|
|
655
655
|
|
|
656
656
|
expect(markdown2Html(input)).toBe(expected)
|
|
657
657
|
})
|
|
@@ -865,6 +865,18 @@ describe('Markdown2Html', () => {
|
|
|
865
865
|
|
|
866
866
|
expect(markdown2Html(input)).toBe(expected)
|
|
867
867
|
})
|
|
868
|
+
|
|
869
|
+
it('64 - Should username with section link', () => {
|
|
870
|
+
const input = {
|
|
871
|
+
author: 'foo364',
|
|
872
|
+
permlink: 'bar364',
|
|
873
|
+
last_update: '2021-10-23T09:15:21',
|
|
874
|
+
body: '@demo/wallet for internal'
|
|
875
|
+
}
|
|
876
|
+
const expected = '<p><span> <a class=\"markdown-profile-link\" href=\"/@demo/wallet\">@demo/wallet</a> for internal</span></p>'
|
|
877
|
+
|
|
878
|
+
expect(markdown2Html(input, false)).toBe(expected)
|
|
879
|
+
})
|
|
868
880
|
})
|
|
869
881
|
|
|
870
882
|
describe("Rumble support", () => {
|
package/src/methods/a.method.ts
CHANGED
|
@@ -99,7 +99,7 @@ export function a(el: HTMLElement, forApp: boolean, webp: boolean): void {
|
|
|
99
99
|
const author = postMatch[3].replace('@', '')
|
|
100
100
|
const permlink = postMatch[4]
|
|
101
101
|
if (el.textContent === href) {
|
|
102
|
-
el.textContent =
|
|
102
|
+
el.textContent = `@${author}/${permlink}`
|
|
103
103
|
}
|
|
104
104
|
if (forApp) {
|
|
105
105
|
el.removeAttribute('href')
|
|
@@ -152,7 +152,7 @@ export function a(el: HTMLElement, forApp: boolean, webp: boolean): void {
|
|
|
152
152
|
const ha = `https://ecency.com/@${author}/${section}`
|
|
153
153
|
el.setAttribute('href', ha)
|
|
154
154
|
} else {
|
|
155
|
-
const h =
|
|
155
|
+
const h = `/@${author}/${section}`
|
|
156
156
|
el.setAttribute('href', h)
|
|
157
157
|
}
|
|
158
158
|
return
|
|
@@ -215,7 +215,7 @@ export function a(el: HTMLElement, forApp: boolean, webp: boolean): void {
|
|
|
215
215
|
const section = cpostMatch[2]
|
|
216
216
|
|
|
217
217
|
if (el.textContent === href) {
|
|
218
|
-
el.textContent =
|
|
218
|
+
el.textContent = `@${author}/${section}`
|
|
219
219
|
}
|
|
220
220
|
if (forApp) {
|
|
221
221
|
const ha = `https://ecency.com/@${author}/${section}`
|
|
@@ -233,7 +233,7 @@ export function a(el: HTMLElement, forApp: boolean, webp: boolean): void {
|
|
|
233
233
|
const author = cpostMatch[1].replace('@', '')
|
|
234
234
|
const permlink = cpostMatch[2]
|
|
235
235
|
if (el.textContent === href) {
|
|
236
|
-
el.textContent =
|
|
236
|
+
el.textContent = `@${author}/${permlink}`
|
|
237
237
|
}
|
|
238
238
|
if (forApp) {
|
|
239
239
|
el.removeAttribute('href')
|
|
@@ -329,7 +329,7 @@ export function a(el: HTMLElement, forApp: boolean, webp: boolean): void {
|
|
|
329
329
|
const author = cccMatch[2].replace('@', '')
|
|
330
330
|
const permlink = cccMatch[3]
|
|
331
331
|
if (el.textContent === href) {
|
|
332
|
-
el.textContent =
|
|
332
|
+
el.textContent = `@${author}/${permlink}`
|
|
333
333
|
}
|
|
334
334
|
if (forApp) {
|
|
335
335
|
el.removeAttribute('href')
|
|
@@ -34,8 +34,13 @@ export function linkify(content: string, forApp: boolean, webp: boolean): string
|
|
|
34
34
|
/((^|\s)(\/|)@[\w.\d-]+)\/(\S+)/gi, (match, u, p1, p2, p3) => {
|
|
35
35
|
const uu = u.trim().toLowerCase().replace('/@','').replace('@','');
|
|
36
36
|
const perm = p3;
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
if (['wallet', 'feed', 'followers', 'following', 'points', 'communities', 'posts', 'blog', 'comments', 'replies', 'settings', 'engine'].includes(p3)) {
|
|
38
|
+
const attrs = forApp ? `https://ecency.com/@${uu}/${perm}` : `href="/@${uu}/${perm}"`
|
|
39
|
+
return ` <a class="markdown-profile-link" ${attrs}>@${uu}/${perm}</a>`
|
|
40
|
+
} else {
|
|
41
|
+
const attrs = forApp ? `data-author="${uu}" data-tag="post" data-permlink="${perm}"` : `href="/post/@${uu}/${perm}"`
|
|
42
|
+
return ` <a class="markdown-post-link" ${attrs}>@${uu}/${perm}</a>`
|
|
43
|
+
}
|
|
39
44
|
}
|
|
40
45
|
)
|
|
41
46
|
|
|
@@ -44,7 +44,20 @@ export function markdownToHTML(input: string, forApp: boolean, webp: boolean): s
|
|
|
44
44
|
return ''
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
let output
|
|
47
|
+
let output = '';
|
|
48
|
+
|
|
49
|
+
//encrypt entities
|
|
50
|
+
const entities = input.match(/&(.*?);/g);
|
|
51
|
+
const encEntities:string[] = [];
|
|
52
|
+
if(entities && forApp){
|
|
53
|
+
entities.forEach((entity)=>{
|
|
54
|
+
const CryptoJS = require("react-native-crypto-js");
|
|
55
|
+
const encData = CryptoJS.AES.encrypt(entity, 'key').toString();
|
|
56
|
+
const encyptedEntity = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(encData));
|
|
57
|
+
encEntities.push(encyptedEntity);
|
|
58
|
+
input = input.replace(entity, encyptedEntity);
|
|
59
|
+
})
|
|
60
|
+
}
|
|
48
61
|
|
|
49
62
|
try {
|
|
50
63
|
output = md.render(input)
|
|
@@ -57,6 +70,16 @@ export function markdownToHTML(input: string, forApp: boolean, webp: boolean): s
|
|
|
57
70
|
output = ''
|
|
58
71
|
}
|
|
59
72
|
|
|
73
|
+
//decrypt and put back entiteis
|
|
74
|
+
if(forApp && output){
|
|
75
|
+
encEntities.forEach((encEntity)=>{
|
|
76
|
+
const CryptoJS = require("react-native-crypto-js");
|
|
77
|
+
const decData = CryptoJS.enc.Base64.parse(encEntity).toString(CryptoJS.enc.Utf8);
|
|
78
|
+
const entity = CryptoJS.AES.decrypt(decData, 'key').toString(CryptoJS.enc.Utf8);
|
|
79
|
+
output = output.replace(encEntity, entity);
|
|
80
|
+
})
|
|
81
|
+
}
|
|
82
|
+
|
|
60
83
|
output = output.replace(/ xmlns="http:\/\/www.w3.org\/1999\/xhtml"/g, '')
|
|
61
84
|
.replace('<body id="root">', '')
|
|
62
85
|
.replace('</body>', '')
|
|
@@ -140,4 +140,11 @@ So, how can you qualify to get one?`
|
|
|
140
140
|
const expected = 'Lorem Ipsum Dolor'
|
|
141
141
|
expect(getPostBodySummary(input)).toBe(expected)
|
|
142
142
|
})
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
it('12- Test entity parsing', () => {
|
|
146
|
+
const input = 'http://lorem.com Lorem < Ipsum & Dolor € '
|
|
147
|
+
const expected = 'Lorem < Ipsum & Dolor €'
|
|
148
|
+
expect(getPostBodySummary(input)).toBe(expected)
|
|
149
|
+
})
|
|
143
150
|
})
|
package/src/post-body-summary.ts
CHANGED
|
@@ -31,7 +31,7 @@ const joint = (arr: string[], limit = 200) => {
|
|
|
31
31
|
return result.trim();
|
|
32
32
|
};
|
|
33
33
|
|
|
34
|
-
function postBodySummary(entryBody: string, length?: number): string {
|
|
34
|
+
function postBodySummary(entryBody: string, length?: number, platform:'ios'|'android'|'web' = 'web'): string {
|
|
35
35
|
if (!entryBody) {
|
|
36
36
|
return ''
|
|
37
37
|
}
|
|
@@ -57,6 +57,19 @@ function postBodySummary(entryBody: string, length?: number): string {
|
|
|
57
57
|
'sup'
|
|
58
58
|
]);
|
|
59
59
|
|
|
60
|
+
//encrypt entities
|
|
61
|
+
const entities = entryBody.match(/&(.*?);/g);
|
|
62
|
+
const encEntities:string[] = [];
|
|
63
|
+
if(entities && platform !== 'web'){
|
|
64
|
+
entities.forEach((entity)=>{
|
|
65
|
+
var CryptoJS = require("react-native-crypto-js");
|
|
66
|
+
const encData = CryptoJS.AES.encrypt(entity, 'key').toString();
|
|
67
|
+
let encyptedEntity = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(encData));
|
|
68
|
+
encEntities.push(encyptedEntity);
|
|
69
|
+
entryBody = entryBody.replace(entity, encyptedEntity);
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
60
73
|
// Convert markdown to html
|
|
61
74
|
let text = '';
|
|
62
75
|
try {
|
|
@@ -65,6 +78,18 @@ function postBodySummary(entryBody: string, length?: number): string {
|
|
|
65
78
|
console.log(err)
|
|
66
79
|
}
|
|
67
80
|
|
|
81
|
+
|
|
82
|
+
//decrypt and put back entiteis
|
|
83
|
+
if(platform !== 'web'){
|
|
84
|
+
encEntities.forEach((encEntity)=>{
|
|
85
|
+
var CryptoJS = require("react-native-crypto-js");
|
|
86
|
+
let decData = CryptoJS.enc.Base64.parse(encEntity).toString(CryptoJS.enc.Utf8);
|
|
87
|
+
let entity = CryptoJS.AES.decrypt(decData, 'key').toString(CryptoJS.enc.Utf8);
|
|
88
|
+
text = text.replace(encEntity, entity);
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
|
|
68
93
|
text = text
|
|
69
94
|
.replace(/(<([^>]+)>)/gi, '') // Remove html tags
|
|
70
95
|
.replace(/\r?\n|\r/g, ' ') // Remove new lines
|
|
@@ -84,9 +109,9 @@ function postBodySummary(entryBody: string, length?: number): string {
|
|
|
84
109
|
return text
|
|
85
110
|
}
|
|
86
111
|
|
|
87
|
-
export function getPostBodySummary(obj: Entry | string, length?: number): any {
|
|
112
|
+
export function getPostBodySummary(obj: Entry | string, length?: number, platform?:'ios'|'android'|'web'): any {
|
|
88
113
|
if (typeof obj === 'string') {
|
|
89
|
-
return postBodySummary(obj as string, length)
|
|
114
|
+
return postBodySummary(obj as string, length, platform)
|
|
90
115
|
}
|
|
91
116
|
|
|
92
117
|
const key = `${makeEntryCacheKey(obj)}-sum-${length}`
|
|
@@ -96,7 +121,7 @@ export function getPostBodySummary(obj: Entry | string, length?: number): any {
|
|
|
96
121
|
return item
|
|
97
122
|
}
|
|
98
123
|
|
|
99
|
-
const res = postBodySummary(obj.body, length)
|
|
124
|
+
const res = postBodySummary(obj.body, length, platform)
|
|
100
125
|
cacheSet(key, res)
|
|
101
126
|
|
|
102
127
|
return res
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": 22,
|
|
3
3
|
"input": "<IMG SRC=JaVaScRiPt:alert('XSS')> <IMG SRC=javascript:alert("XSS")>\n<IMG SRC=`javascript:alert(\"RSnake says, 'XSS'\")`>\n<a onmouseover=\"alert(document.cookie)\">xxs link</a><a onmouseover=alert(document.cookie)>xxs link</a>\n<IMG \"\"\"><SCRIPT>alert(\"XSS\")</SCRIPT>\"><IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>\n <IMG SRC= onmouseover=\"alert('xxs')\">",
|
|
4
|
-
"result": "<p><IMG SRC=JaVaScRiPt:alert('XSS')>
|
|
4
|
+
"result": "<p><IMG SRC=JaVaScRiPt:alert('XSS')> <IMG SRC=javascript:alert("XSS")><br />\n<IMG SRC=<code>javascript:alert(\"RSnake says, 'XSS'\")</code>><br />\n<a>xxs link</a><a>xxs link</a><br />\n<IMG \"\"\">alert("XSS")\"><img /><br />\n<IMG SRC= onmouseover=\"alert('xxs')\"></p>"
|
|
5
5
|
}
|
|
@@ -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> <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
|
}
|