@ecency/render-helper 2.2.11 → 2.2.15
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 +1 -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 +72 -54
- 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 +1 -0
- package/src/consts/regexes.const.ts +2 -1
- package/src/helper.ts +11 -0
- package/src/markdown-2-html.spec.ts +39 -3
- package/src/methods/a.method.ts +40 -13
- 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
|
+
}
|
|
@@ -99,6 +99,30 @@ describe('Markdown2Html', () => {
|
|
|
99
99
|
expect(markdown2Html(input)).toBe(expected)
|
|
100
100
|
})
|
|
101
101
|
|
|
102
|
+
it('7.1- Should handle raw d.tube videos without thumbnail', () => {
|
|
103
|
+
const input = {
|
|
104
|
+
author: 'foo37.1',
|
|
105
|
+
permlink: 'bar37.1',
|
|
106
|
+
last_update: '2020-05-10T09:15:21',
|
|
107
|
+
body: 'https://d.tube/#!/v/techcoderx/QmVdEYicJwiTxSk2U9ER1Yc8Rumb1Nek4KynqAYGyQs7ga'
|
|
108
|
+
}
|
|
109
|
+
const expected = '<p><a class="markdown-video-link markdown-video-link-dtube" data-embed-src="https://emb.d.tube/#!/techcoderx/QmVdEYicJwiTxSk2U9ER1Yc8Rumb1Nek4KynqAYGyQs7ga"><span class="markdown-video-play"></span></a></p>'
|
|
110
|
+
|
|
111
|
+
expect(markdown2Html(input)).toBe(expected)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('7.2- Should handle raw d.tube videos different format', () => {
|
|
115
|
+
const input = {
|
|
116
|
+
author: 'foo37.2',
|
|
117
|
+
permlink: 'bar37.2',
|
|
118
|
+
last_update: '2020-05-10T09:15:21',
|
|
119
|
+
body: 'https://d.tube/v/techcoderx/QmVdEYicJwiTxSk2U9ER1Yc8Rumb1Nek4KynqAYGyQs7ga'
|
|
120
|
+
}
|
|
121
|
+
const expected = '<p><a class="markdown-video-link markdown-video-link-dtube" data-embed-src="https://emb.d.tube/#!/techcoderx/QmVdEYicJwiTxSk2U9ER1Yc8Rumb1Nek4KynqAYGyQs7ga"><span class="markdown-video-play"></span></a></p>'
|
|
122
|
+
|
|
123
|
+
expect(markdown2Html(input)).toBe(expected)
|
|
124
|
+
})
|
|
125
|
+
|
|
102
126
|
it('9- Should handle witnesses links', () => {
|
|
103
127
|
const input = {
|
|
104
128
|
author: 'foo39',
|
|
@@ -142,7 +166,7 @@ describe('Markdown2Html', () => {
|
|
|
142
166
|
last_update: '2019-05-10T09:15:21',
|
|
143
167
|
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
168
|
}
|
|
145
|
-
const expected = '<iframe src=\"https://www.youtube.com/embed/I3f9ixg59no\" allowfullscreen=\"allowfullscreen\"></iframe>'
|
|
169
|
+
const expected = '<iframe src=\"https://www.youtube.com/embed/I3f9ixg59no\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"></iframe>'
|
|
146
170
|
|
|
147
171
|
expect(markdown2Html(input)).toBe(expected)
|
|
148
172
|
})
|
|
@@ -445,9 +469,9 @@ describe('Markdown2Html', () => {
|
|
|
445
469
|
author: 'foo329',
|
|
446
470
|
permlink: 'bar329',
|
|
447
471
|
last_update: '2019-05-10T09:15:21',
|
|
448
|
-
body: 'https://youtu.be/
|
|
472
|
+
body: 'https://youtu.be/UuyS7YAkECA?t=295s'
|
|
449
473
|
}
|
|
450
|
-
const expected = '<p><a class="markdown-video-link markdown-video-link-youtube" data-embed-src="https://www.youtube.com/embed/
|
|
474
|
+
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
475
|
|
|
452
476
|
expect(markdown2Html(input)).toBe(expected)
|
|
453
477
|
})
|
|
@@ -877,6 +901,18 @@ describe('Markdown2Html', () => {
|
|
|
877
901
|
|
|
878
902
|
expect(markdown2Html(input, false)).toBe(expected)
|
|
879
903
|
})
|
|
904
|
+
|
|
905
|
+
it('65- Should handle youtube.com/embed videos', () => {
|
|
906
|
+
const input = {
|
|
907
|
+
author: 'foo329',
|
|
908
|
+
permlink: 'bar329',
|
|
909
|
+
last_update: '2019-05-10T09:15:21',
|
|
910
|
+
body: 'https://www.youtube.com/embed/UuyS7YAkECA?start=295&autoplay=1'
|
|
911
|
+
}
|
|
912
|
+
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>'
|
|
913
|
+
|
|
914
|
+
expect(markdown2Html(input)).toBe(expected)
|
|
915
|
+
})
|
|
880
916
|
})
|
|
881
917
|
|
|
882
918
|
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')
|
|
@@ -416,6 +417,12 @@ export function a(el: HTMLElement, forApp: boolean, webp: boolean): void {
|
|
|
416
417
|
el.setAttribute('data-embed-src', embedSrc);
|
|
417
418
|
el.setAttribute('data-youtube', vid);
|
|
418
419
|
|
|
420
|
+
//extract start time if available
|
|
421
|
+
const startTime = extractYtStartTime(href);
|
|
422
|
+
if(startTime){
|
|
423
|
+
el.setAttribute('data-start-time', startTime);
|
|
424
|
+
}
|
|
425
|
+
|
|
419
426
|
const thumbImg = el.ownerDocument.createElement('img')
|
|
420
427
|
thumbImg.setAttribute('class', 'no-replace video-thumbnail')
|
|
421
428
|
thumbImg.setAttribute('itemprop', 'thumbnailUrl')
|
|
@@ -532,37 +539,46 @@ export function a(el: HTMLElement, forApp: boolean, webp: boolean): void {
|
|
|
532
539
|
// If a d.tube video
|
|
533
540
|
match = href.match(D_TUBE_REGEX)
|
|
534
541
|
if (match) {
|
|
535
|
-
// Only d.tube links contains an image
|
|
536
|
-
const imgEls = el.getElementsByTagName('img')
|
|
537
542
|
|
|
538
|
-
|
|
543
|
+
// Only d.tube links contains an image
|
|
544
|
+
const imgEls = el.getElementsByTagName('img')
|
|
545
|
+
|
|
546
|
+
if (imgEls.length === 1 || el.textContent.trim() === href) {
|
|
539
547
|
const e = D_TUBE_REGEX.exec(href)
|
|
540
548
|
// e[2] = username, e[3] object id
|
|
541
549
|
if (e[2] && e[3]) {
|
|
542
550
|
el.setAttribute('class', 'markdown-video-link markdown-video-link-dtube')
|
|
543
551
|
el.removeAttribute('href')
|
|
552
|
+
|
|
544
553
|
|
|
545
|
-
const thumbnail = proxifyImageSrc(imgEls[0].getAttribute('src').replace(/\s+/g, ''), 0, 0, webp ? 'webp' : 'match')
|
|
546
554
|
const videoHref = `https://emb.d.tube/#!/${e[2]}/${e[3]}`
|
|
547
555
|
|
|
548
556
|
// el.setAttribute('data-video-href', videoHref)
|
|
549
557
|
el.setAttribute('data-embed-src', videoHref)
|
|
550
558
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
559
|
+
//process thumb img element
|
|
560
|
+
if (imgEls.length === 1) {
|
|
561
|
+
const thumbnail = proxifyImageSrc(imgEls[0].getAttribute('src').replace(/\s+/g, ''), 0, 0, webp ? 'webp' : 'match')
|
|
562
|
+
const thumbImg = el.ownerDocument.createElement('img')
|
|
563
|
+
|
|
564
|
+
thumbImg.setAttribute('class', 'no-replace video-thumbnail')
|
|
565
|
+
thumbImg.setAttribute('itemprop', 'thumbnailUrl')
|
|
566
|
+
|
|
567
|
+
thumbImg.setAttribute('src', thumbnail)
|
|
568
|
+
el.appendChild(thumbImg)
|
|
569
|
+
|
|
570
|
+
// Remove image.
|
|
571
|
+
el.removeChild(imgEls[0])
|
|
572
|
+
} else {
|
|
573
|
+
el.textContent = '';
|
|
574
|
+
}
|
|
556
575
|
|
|
557
576
|
const play = el.ownerDocument.createElement('span')
|
|
558
577
|
play.setAttribute('class', 'markdown-video-play')
|
|
559
578
|
|
|
560
|
-
|
|
579
|
+
|
|
561
580
|
el.appendChild(play)
|
|
562
581
|
|
|
563
|
-
// Remove image.
|
|
564
|
-
el.removeChild(imgEls[0])
|
|
565
|
-
|
|
566
582
|
return
|
|
567
583
|
}
|
|
568
584
|
}
|
|
@@ -574,6 +590,7 @@ export function a(el: HTMLElement, forApp: boolean, webp: boolean): void {
|
|
|
574
590
|
if (e[2] && e[3]) {
|
|
575
591
|
el.setAttribute('class', 'markdown-video-link markdown-video-link-dtube')
|
|
576
592
|
el.removeAttribute('href')
|
|
593
|
+
el.textContent = '';
|
|
577
594
|
|
|
578
595
|
const videoHref = `https://emb.d.tube/#!/${e[2]}/${e[3]}`
|
|
579
596
|
|
|
@@ -583,6 +600,7 @@ export function a(el: HTMLElement, forApp: boolean, webp: boolean): void {
|
|
|
583
600
|
play.setAttribute('class', 'markdown-video-play')
|
|
584
601
|
|
|
585
602
|
el.appendChild(play)
|
|
603
|
+
|
|
586
604
|
|
|
587
605
|
return
|
|
588
606
|
}
|
|
@@ -671,6 +689,12 @@ export function a(el: HTMLElement, forApp: boolean, webp: boolean): void {
|
|
|
671
689
|
if (e[1]) {
|
|
672
690
|
const vid = e[1]
|
|
673
691
|
el.setAttribute('data-youtube', vid);
|
|
692
|
+
|
|
693
|
+
//extract start time if available
|
|
694
|
+
const startTime = extractYtStartTime(href);
|
|
695
|
+
if(startTime){
|
|
696
|
+
el.setAttribute('data-start-time', startTime);
|
|
697
|
+
}
|
|
674
698
|
}
|
|
675
699
|
}
|
|
676
700
|
el.removeAttribute('href')
|
|
@@ -684,3 +708,6 @@ export function a(el: HTMLElement, forApp: boolean, webp: boolean): void {
|
|
|
684
708
|
}
|
|
685
709
|
}
|
|
686
710
|
}
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
|
|
@@ -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
|
}
|