[SECURITY] Prevent XSS in modal component
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Resources / Private / TypeScript / SecurityUtility.ts
1 /*
2  * This file is part of the TYPO3 CMS project.
3  *
4  * It is free software; you can redistribute it and/or modify it under
5  * the terms of the GNU General Public License, either version 2
6  * of the License, or any later version.
7  *
8  * For the full copyright and license information, please read the
9  * LICENSE.txt file that was distributed with this source code.
10  *
11  * The TYPO3 project - inspiring people to share!
12  */
13
14 /**
15  * Module: TYPO3/CMS/Core/SecurityUtility
16  * contains method to escape input to prevent XSS and other security related things
17  * @exports TYPO3/CMS/Core/SecurityUtility
18  */
19 class SecurityUtility {
20   private readonly documentRef: Document;
21
22   /**
23    * @param {Document} documentRef
24    */
25   constructor(documentRef: Document = document) {
26     this.documentRef = documentRef;
27   }
28
29   /**
30    * Encodes HTML to use according entities. Behavior is similar to PHP's
31    * htmlspecialchars. Input might contain XSS, output has it encoded.
32    *
33    * @param {string} value Input value to be encoded
34    * @param {boolean} doubleEncode (default `true`)
35    * @return {string}
36    */
37   public encodeHtml(value: string, doubleEncode: boolean = true): string {
38     let anvil: HTMLSpanElement = this.createAnvil();
39     if (!doubleEncode) {
40       // decode HTML entities step-by-step
41       // but NEVER(!) as a whole, since that would allow XSS
42       value = value.replace(/&[#A-Za-z0-9]+;/g, (html: string) => {
43         anvil.innerHTML = html;
44         return anvil.innerText;
45       });
46     }
47     // apply arbitrary data a text node
48     // thus browser is capable of properly encoding
49     anvil.innerText = value;
50     return anvil.innerHTML;
51   }
52
53   /**
54    * @param {string} value
55    */
56   public debug(value: string): void {
57     if (value !== this.encodeHtml(value)) {
58       console.warn('XSS?!', value);
59     }
60   }
61
62   /**
63    * @return {HTMLSpanElement}
64    */
65   private createAnvil(): HTMLSpanElement {
66     return this.documentRef.createElement('span');
67   }
68 }
69
70 export = SecurityUtility;