Pārlūkot izejas kodu

Use DOMPurify instead of XSS.js

Remove exports-loader, which is therefore no longer necessary
JC Brand 4 gadi atpakaļ
vecāks
revīzija
2bcf01f5ab

+ 16 - 79
package-lock.json

@@ -13,6 +13,7 @@
 				"bootstrap": "^4.6.0",
 				"bootstrap.native": "^2.0.27",
 				"dayjs": "1.10.5",
+				"dompurify": "^2.3.0",
 				"favico.js-slevomat": "^0.3.11",
 				"filesize": "^7.0.0",
 				"jed": "1.1.1",
@@ -26,8 +27,7 @@
 				"sizzle": "^2.3.5",
 				"sprintf-js": "^1.1.2",
 				"strophe.js": "1.4.2",
-				"urijs": "^1.19.6",
-				"xss": "^1.0.9"
+				"urijs": "^1.19.6"
 			},
 			"devDependencies": {
 				"@babel/cli": "^7.14.5",
@@ -42,7 +42,6 @@
 				"copy-webpack-plugin": "^9.0.1",
 				"css-loader": "^3.5.3",
 				"eslint": "^7.3.0",
-				"exports-loader": "^0.7.0",
 				"fast-text-encoding": "^1.0.3",
 				"file-loader": "^6.2.0",
 				"html-webpack-plugin": "^5.3.2",
@@ -7166,7 +7165,8 @@
 		"node_modules/commander": {
 			"version": "2.20.3",
 			"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
-			"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
+			"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+			"dev": true
 		},
 		"node_modules/commondir": {
 			"version": "1.0.1",
@@ -7962,11 +7962,6 @@
 				"node": ">=4"
 			}
 		},
-		"node_modules/cssfilter": {
-			"version": "0.0.10",
-			"resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz",
-			"integrity": "sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4="
-		},
 		"node_modules/custom-event": {
 			"version": "1.0.1",
 			"resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz",
@@ -8392,6 +8387,11 @@
 				"url": "https://github.com/fb55/domhandler?sponsor=1"
 			}
 		},
+		"node_modules/dompurify": {
+			"version": "2.3.0",
+			"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.0.tgz",
+			"integrity": "sha512-VV5C6Kr53YVHGOBKO/F86OYX6/iLTw2yVSI721gKetxpHCK/V5TaLEf9ODjRgl1KLSWRMY6cUhAbv/c+IUnwQw=="
+		},
 		"node_modules/domutils": {
 			"version": "2.7.0",
 			"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz",
@@ -9210,28 +9210,6 @@
 				"node": ">=0.10.0"
 			}
 		},
-		"node_modules/exports-loader": {
-			"version": "0.7.0",
-			"resolved": "https://registry.npmjs.org/exports-loader/-/exports-loader-0.7.0.tgz",
-			"integrity": "sha512-RKwCrO4A6IiKm0pG3c9V46JxIHcDplwwGJn6+JJ1RcVnh/WSGJa0xkmk5cRVtgOPzCAtTMGj2F7nluh9L0vpSA==",
-			"dev": true,
-			"dependencies": {
-				"loader-utils": "^1.1.0",
-				"source-map": "0.5.0"
-			},
-			"engines": {
-				"node": ">= 4"
-			}
-		},
-		"node_modules/exports-loader/node_modules/source-map": {
-			"version": "0.5.0",
-			"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.0.tgz",
-			"integrity": "sha1-D+llA6yGpa213mP05BKuSHLNvoY=",
-			"dev": true,
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
 		"node_modules/express": {
 			"version": "4.17.1",
 			"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
@@ -23255,21 +23233,6 @@
 				"node": ">=10.0.0"
 			}
 		},
-		"node_modules/xss": {
-			"version": "1.0.9",
-			"resolved": "https://registry.npmjs.org/xss/-/xss-1.0.9.tgz",
-			"integrity": "sha512-2t7FahYnGJys6DpHLhajusId7R0Pm2yTmuL0GV9+mV0ZlaLSnb2toBmppATfg5sWIhZQGlsTLoecSzya+l4EAQ==",
-			"dependencies": {
-				"commander": "^2.20.3",
-				"cssfilter": "0.0.10"
-			},
-			"bin": {
-				"xss": "bin/xss"
-			},
-			"engines": {
-				"node": ">= 0.10.0"
-			}
-		},
 		"node_modules/xtend": {
 			"version": "4.0.2",
 			"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
@@ -28971,7 +28934,8 @@
 		"commander": {
 			"version": "2.20.3",
 			"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
-			"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
+			"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+			"dev": true
 		},
 		"commondir": {
 			"version": "1.0.1",
@@ -29579,11 +29543,6 @@
 			"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
 			"dev": true
 		},
-		"cssfilter": {
-			"version": "0.0.10",
-			"resolved": "https://registry.npmjs.org/cssfilter/-/cssfilter-0.0.10.tgz",
-			"integrity": "sha1-xtJnJjKi5cg+AT5oZKQs6N79IK4="
-		},
 		"custom-event": {
 			"version": "1.0.1",
 			"resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz",
@@ -29921,6 +29880,11 @@
 				"domelementtype": "^2.2.0"
 			}
 		},
+		"dompurify": {
+			"version": "2.3.0",
+			"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.3.0.tgz",
+			"integrity": "sha512-VV5C6Kr53YVHGOBKO/F86OYX6/iLTw2yVSI721gKetxpHCK/V5TaLEf9ODjRgl1KLSWRMY6cUhAbv/c+IUnwQw=="
+		},
 		"domutils": {
 			"version": "2.7.0",
 			"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz",
@@ -30561,24 +30525,6 @@
 				}
 			}
 		},
-		"exports-loader": {
-			"version": "0.7.0",
-			"resolved": "https://registry.npmjs.org/exports-loader/-/exports-loader-0.7.0.tgz",
-			"integrity": "sha512-RKwCrO4A6IiKm0pG3c9V46JxIHcDplwwGJn6+JJ1RcVnh/WSGJa0xkmk5cRVtgOPzCAtTMGj2F7nluh9L0vpSA==",
-			"dev": true,
-			"requires": {
-				"loader-utils": "^1.1.0",
-				"source-map": "0.5.0"
-			},
-			"dependencies": {
-				"source-map": {
-					"version": "0.5.0",
-					"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.0.tgz",
-					"integrity": "sha1-D+llA6yGpa213mP05BKuSHLNvoY=",
-					"dev": true
-				}
-			}
-		},
 		"express": {
 			"version": "4.17.1",
 			"resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
@@ -41331,15 +41277,6 @@
 			"integrity": "sha512-Foaj5FXVzgn7xFzsKeNIde9g6aFBxTPi37iwsno8QvApmtg7KYrr+OPyRHcJF7dud2a5nGRBXK3n0dL62Gf7PA==",
 			"optional": true
 		},
-		"xss": {
-			"version": "1.0.9",
-			"resolved": "https://registry.npmjs.org/xss/-/xss-1.0.9.tgz",
-			"integrity": "sha512-2t7FahYnGJys6DpHLhajusId7R0Pm2yTmuL0GV9+mV0ZlaLSnb2toBmppATfg5sWIhZQGlsTLoecSzya+l4EAQ==",
-			"requires": {
-				"commander": "^2.20.3",
-				"cssfilter": "0.0.10"
-			}
-		},
 		"xtend": {
 			"version": "4.0.2",
 			"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",

+ 2 - 3
package.json

@@ -75,7 +75,6 @@
     "copy-webpack-plugin": "^9.0.1",
     "css-loader": "^3.5.3",
     "eslint": "^7.3.0",
-    "exports-loader": "^0.7.0",
     "fast-text-encoding": "^1.0.3",
     "file-loader": "^6.2.0",
     "html-webpack-plugin": "^5.3.2",
@@ -111,9 +110,9 @@
     "@fortawesome/fontawesome-free": "5.14.0",
     "bootstrap": "^4.6.0",
     "bootstrap.native": "^2.0.27",
+    "dompurify": "^2.3.0",
     "favico.js-slevomat": "^0.3.11",
     "jed": "1.1.1",
-    "lit": "^2.0.0-rc.2",
-    "xss": "^1.0.9"
+    "lit": "^2.0.0-rc.2"
   }
 }

+ 2 - 2
src/headless/shared/utils.js

@@ -1,8 +1,8 @@
+import DOMPurify from 'dompurify';
 import Storage from '@converse/skeletor/src/storage.js';
 import log from '@converse/headless/log';
 import { _converse, api } from '@converse/headless/core';
 import { getOpenPromise } from '@converse/openpromise';
-import xss from 'xss/dist/xss';
 
 export function getDefaultStore () {
     if (_converse.config.get('trusted')) {
@@ -55,7 +55,7 @@ const element = document.createElement('div');
 
 export function decodeHTMLEntities (str) {
     if (str && typeof str === 'string') {
-        element.innerHTML = xss.filterXSS(str);
+        element.innerHTML = DOMPurify.sanitize(str);
         str = element.textContent;
         element.textContent = '';
     }

+ 2 - 4
src/modals/templates/muc-details.js

@@ -2,15 +2,13 @@ import { __ } from '../../i18n';
 import { html } from "lit";
 import { modal_close_button, modal_header_close_button } from "./buttons.js"
 import { unsafeHTML } from 'lit/directives/unsafe-html.js';
-import xss from "xss/dist/xss";
-
 
 const subject = (o) => {
     const i18n_topic = __('Topic');
     const i18n_topic_author = __('Topic author');
     return html`
-        <p class="room-info"><strong>${i18n_topic}</strong>: ${unsafeHTML(xss.filterXSS(o.subject.text, {'whiteList': {}}))}</p>
-            <p class="room-info"><strong>${i18n_topic_author}</strong>: ${o.subject && o.subject.author}</p>
+        <p class="room-info"><strong>${i18n_topic}</strong>: ${o.subject.text}</p>
+        <p class="room-info"><strong>${i18n_topic_author}</strong>: ${o.subject && o.subject.author}</p>
     `;
 }
 

+ 3 - 3
src/modals/templates/user-settings.js

@@ -1,4 +1,4 @@
-import xss from "xss/dist/xss";
+import DOMPurify from 'dompurify';
 import { __ } from '../../i18n';
 import { api } from "@converse/headless/core";
 import { html } from "lit";
@@ -58,8 +58,8 @@ export default (o) => {
                         <div class="container">
                             <h6 class="brand-heading">Converse</h6>
                             <p class="brand-subtitle">${o.version_name}</p>
-                            <p class="brand-subtitle">${unsafeHTML(xss.filterXSS(first_subtitle, {'whiteList': {'a': []}}))}</p>
-                            <p class="brand-subtitle">${unsafeHTML(xss.filterXSS(second_subtitle, {'whiteList': {'a': []}}))}</p>
+                            <p class="brand-subtitle">${unsafeHTML(DOMPurify.sanitize(first_subtitle))}</p>
+                            <p class="brand-subtitle">${unsafeHTML(DOMPurify.sanitize(second_subtitle))}</p>
                         </div>
                     </div>
 

+ 2 - 2
src/plugins/muc-views/templates/add-muc.js

@@ -1,4 +1,4 @@
-import xss from "xss/dist/xss";
+import DOMPurify from 'dompurify';
 import { __ } from 'i18n';
 import { html } from "lit";
 import { modal_header_close_button } from "modals/templates/buttons.js"
@@ -35,7 +35,7 @@ export default (o) => {
                             ${ (o.muc_roomid_policy_error_msg) ? html`<label class="roomid-policy-error">${o.muc_roomid_policy_error_msg}</label>` : '' }
                             <input type="text" required="required" name="chatroom" class="form-control roomjid-input" placeholder="${o.chatroom_placeholder}"/>
                         </div>
-                        ${ o.muc_roomid_policy_hint ?  html`<div class="form-group">${unsafeHTML(xss.filterXSS(o.muc_roomid_policy_hint, {'whiteList': {b: [], br: [], em: []}}))}</div>` : '' }
+                        ${ o.muc_roomid_policy_hint ?  html`<div class="form-group">${unsafeHTML(DOMPurify.sanitize(o.muc_roomid_policy_hint, {'ALLOWED_TAGS': ['b', 'br', 'em']}))}</div>` : '' }
                         ${ !o._converse.locked_muc_nickname ? nickname_input(o) : '' }
                         <input type="submit" class="btn btn-primary" name="join" value="${i18n_join || ''}" ?disabled=${o.muc_roomid_policy_error_msg}>
                     </form>

+ 2 - 2
src/shared/chat/help-messages.js

@@ -1,5 +1,5 @@
 import 'shared/components/icons.js';
-import xss from 'xss/dist/xss';
+import DOMPurify from 'dompurify';
 import { CustomElement } from 'shared/components/element.js';
 import { api } from '@converse/headless/core';
 import { html } from 'lit';
@@ -26,7 +26,7 @@ export default class ChatHelp extends CustomElement {
                     size="1em"></converse-icon>`,
             ...this.messages.map(m => this.renderHelpMessage({
                 isodate,
-                'markup': xss.filterXSS(m, {'whiteList': {'strong': []}})
+                'markup': DOMPurify.sanitize(m, {'ALLOWED_TAGS': ['strong']})
             }))
         ];
     }

+ 1 - 1
webpack.common.js

@@ -24,7 +24,7 @@ module.exports = {
         rules: [
         {
             test: path.resolve(__dirname, "node_modules/xss/dist/xss"),
-            use: "exports-loader?filterXSS,filterCSS"
+            use: "exports-loader?filterXSS"
         }, {
             test: /LC_MESSAGES\/converse.po$/,
             type: "json",