@@ -20,6 +20,7 @@ import { escape } from '../common/strings.js';
20
20
import { URI } from '../common/uri.js' ;
21
21
import * as DOM from './dom.js' ;
22
22
import * as domSanitize from './domSanitize.js' ;
23
+ import { convertTagToPlaintext } from './domSanitize.js' ;
23
24
import { DomEmitter } from './event.js' ;
24
25
import { FormattedTextRenderOptions } from './formattedTextRenderer.js' ;
25
26
import { StandardKeyboardEvent } from './keyboardEvent.js' ;
@@ -211,6 +212,20 @@ export function renderMarkdown(markdown: IMarkdownString, options: MarkdownRende
211
212
} ) ) ;
212
213
}
213
214
215
+ // Remove/disable inputs
216
+ for ( const e of element . getElementsByTagName ( 'input' ) ) {
217
+ if ( e . attributes . getNamedItem ( 'type' ) ?. value === 'checkbox' ) {
218
+ e . setAttribute ( 'disabled' , '' ) ;
219
+ } else {
220
+ if ( options . sanitizerConfig ?. replaceWithPlaintext ) {
221
+ const replacement = convertTagToPlaintext ( element ) ;
222
+ element . parentElement ?. replaceChild ( replacement , element ) ;
223
+ } else {
224
+ e . remove ( ) ;
225
+ }
226
+ }
227
+ }
228
+
214
229
return {
215
230
element,
216
231
dispose : ( ) => {
@@ -412,15 +427,12 @@ function resolveWithBaseUri(baseUri: URI, href: string): string {
412
427
}
413
428
}
414
429
415
-
416
- const selfClosingTags = [ 'area' , 'base' , 'br' , 'col' , 'command' , 'embed' , 'hr' , 'img' , 'input' , 'keygen' , 'link' , 'meta' , 'param' , 'source' , 'track' , 'wbr' ] ;
417
-
418
430
function sanitizeRenderedMarkdown (
419
431
renderedMarkdown : string ,
420
432
isTrusted : boolean | MarkdownStringTrustedOptions ,
421
433
options : MarkdownSanitizerConfig = { } ,
422
434
) : TrustedHTML {
423
- const sanitizerConfig = getSanitizerOptions ( isTrusted , options ) ;
435
+ const sanitizerConfig = getDomSanitizerConfig ( isTrusted , options ) ;
424
436
return domSanitize . sanitizeHtml ( renderedMarkdown , sanitizerConfig ) ;
425
437
}
426
438
@@ -462,7 +474,7 @@ export const allowedMarkdownHtmlAttributes = [
462
474
'class' ,
463
475
] ;
464
476
465
- function getSanitizerOptions ( isTrusted : boolean | MarkdownStringTrustedOptions , options : MarkdownSanitizerConfig ) : domSanitize . DomSanitizerConfig {
477
+ function getDomSanitizerConfig ( isTrusted : boolean | MarkdownStringTrustedOptions , options : MarkdownSanitizerConfig ) : domSanitize . DomSanitizerConfig {
466
478
const allowedLinkSchemes = [
467
479
Schemas . http ,
468
480
Schemas . https ,
@@ -507,6 +519,7 @@ function getSanitizerOptions(isTrusted: boolean | MarkdownStringTrustedOptions,
507
519
Schemas . vscodeRemoteResource ,
508
520
]
509
521
} ,
522
+ replaceWithPlaintext : options . replaceWithPlaintext ,
510
523
_do_not_use_hooks : {
511
524
uponSanitizeAttribute : ( element , e ) => {
512
525
if ( options . customAttrSanitizer ) {
@@ -545,61 +558,6 @@ function getSanitizerOptions(isTrusted: boolean | MarkdownStringTrustedOptions,
545
558
e . keepAttr = false ;
546
559
}
547
560
} ,
548
- uponSanitizeElement : ( element , e ) => {
549
- let wantsReplaceWithPlaintext = false ;
550
- if ( e . tagName === 'input' ) {
551
- if ( element . attributes . getNamedItem ( 'type' ) ?. value === 'checkbox' ) {
552
- element . setAttribute ( 'disabled' , '' ) ;
553
- } else if ( options . replaceWithPlaintext ) {
554
- wantsReplaceWithPlaintext = true ;
555
- } else {
556
- element . remove ( ) ;
557
- return ;
558
- }
559
- }
560
-
561
- if ( options . replaceWithPlaintext && ( wantsReplaceWithPlaintext || ( ! e . allowedTags [ e . tagName ] && e . tagName !== 'body' ) ) ) {
562
- if ( element . parentElement ) {
563
- let startTagText : string ;
564
- let endTagText : string | undefined ;
565
- if ( e . tagName === '#comment' ) {
566
- startTagText = `<!--${ element . textContent } -->` ;
567
- } else {
568
- const isSelfClosing = selfClosingTags . includes ( e . tagName ) ;
569
- const attrString = element . attributes . length ?
570
- ' ' + Array . from ( element . attributes )
571
- . map ( attr => `${ attr . name } ="${ attr . value } "` )
572
- . join ( ' ' )
573
- : '' ;
574
- startTagText = `<${ e . tagName } ${ attrString } >` ;
575
- if ( ! isSelfClosing ) {
576
- endTagText = `</${ e . tagName } >` ;
577
- }
578
- }
579
-
580
- const fragment = document . createDocumentFragment ( ) ;
581
- const textNode = element . parentElement . ownerDocument . createTextNode ( startTagText ) ;
582
- fragment . appendChild ( textNode ) ;
583
- const endTagTextNode = endTagText ? element . parentElement . ownerDocument . createTextNode ( endTagText ) : undefined ;
584
- while ( element . firstChild ) {
585
- fragment . appendChild ( element . firstChild ) ;
586
- }
587
-
588
- if ( endTagTextNode ) {
589
- fragment . appendChild ( endTagTextNode ) ;
590
- }
591
-
592
- if ( element . nodeType === Node . COMMENT_NODE ) {
593
- // Workaround for https://github.com/cure53/DOMPurify/issues/1005
594
- // The comment will be deleted in the next phase. However if we try to remove it now, it will cause
595
- // an exception. Instead we insert the text node before the comment.
596
- element . parentElement . insertBefore ( fragment , element ) ;
597
- } else {
598
- element . parentElement . replaceChild ( fragment , element ) ;
599
- }
600
- }
601
- }
602
- }
603
561
}
604
562
} ;
605
563
}
0 commit comments