Merge commit from fork
* Rework frontend code interacting directly with DOM Rework frontend code that uses user-supplied data to render things like comments and notes. In places where using React's built-in sanitization is possible, the feature is used. In other places, where some markup might be necessary, DOMPurify is used to sanitize the HTML before rendering it. Solves: GHSA-rh3r-8pxm-hg4w * Remove test post DOM rework * fixup! Rework frontend code interacting directly with DOM
This commit is contained in:
Generated
+53
-4
@@ -18,6 +18,7 @@
|
||||
"clsx": "^2.1.1",
|
||||
"connected-react-router": "^6.9.3",
|
||||
"deepmerge": "^4.3.1",
|
||||
"dompurify": "^3.3.1",
|
||||
"history": "^4.10.1",
|
||||
"inflection": "^3.0.2",
|
||||
"jwt-decode": "^4.0.0",
|
||||
@@ -128,6 +129,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz",
|
||||
"integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.28.6",
|
||||
"@babel/generator": "^7.28.6",
|
||||
@@ -1742,6 +1744,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
@@ -1765,6 +1768,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
@@ -2572,6 +2576,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@jsonforms/core/-/core-2.5.2.tgz",
|
||||
"integrity": "sha512-tl64cLC2dUrGvu2nTHRDEA5Yv3RfwzMCIlVaoSUSq44LakKLGJdkPl8j/fb07llpFqz0a7gEAmy/8gLdmwgaLQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/json-schema": "^7.0.3",
|
||||
"ajv": "^6.10.2",
|
||||
@@ -2625,6 +2630,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@jsonforms/react/-/react-2.5.2.tgz",
|
||||
"integrity": "sha512-kZf2fq4urIBlFTCiBX95eKg8uojkyJj7FVDtIV739aVkJjE5+ihn1+kG1qLxYSxlGC7S24i12BZJzRetSRihBQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"lodash": "^4.17.15",
|
||||
"object-hash": "^2.0.0"
|
||||
@@ -2640,6 +2646,7 @@
|
||||
"integrity": "sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ==",
|
||||
"deprecated": "Material UI v4 doesn't receive active development since September 2021. See the guide https://mui.com/material-ui/migration/migration-v4/ to upgrade to v5.",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.4.4",
|
||||
"@material-ui/styles": "^4.11.5",
|
||||
@@ -2686,6 +2693,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@material-ui/icons/-/icons-4.11.3.tgz",
|
||||
"integrity": "sha512-IKHlyx6LDh8n19vzwH5RtHIOHl9Tu90aAAxcbWME6kp4dmvODM3UvOHJeMIDzUbd4muuJKHmlNoBN+mDY4XkBA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.4.4"
|
||||
},
|
||||
@@ -3409,6 +3417,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.7.tgz",
|
||||
"integrity": "sha512-PQTyIulDkIDro8P+IHbKCsw7U2xxBYflVzW/FgWdCAePD9xGSidgA76/GeJ6lBKoblyhf9pBY763gbrN+1dI8g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"hoist-non-react-statics": "^3.3.0"
|
||||
},
|
||||
@@ -3461,6 +3470,7 @@
|
||||
"integrity": "sha512-ne4A0IpG3+2ETuREInjPNhUGis1SFjv1d5asp8MzEAGtOZeTeHVDOYqOgqfhvseqg/iXty2hjBf1zAOb7RNiNw==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~7.16.0"
|
||||
}
|
||||
@@ -3482,6 +3492,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.90.tgz",
|
||||
"integrity": "sha512-P9beVR/x06U9rCJzSxtENnOr4BrbJ6VrsrDTc+73TtHv9XHhryXKbjGRB+6oooB2r0G/pQkD/S4dHo/7jUfwFw==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"@types/scheduler": "^0.16",
|
||||
@@ -3651,6 +3662,7 @@
|
||||
"integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==",
|
||||
"dev": true,
|
||||
"license": "BSD-2-Clause",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "6.21.0",
|
||||
"@typescript-eslint/types": "6.21.0",
|
||||
@@ -3982,6 +3994,7 @@
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@@ -4663,6 +4676,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"baseline-browser-mapping": "^2.9.0",
|
||||
"caniuse-lite": "^1.0.30001759",
|
||||
@@ -5038,6 +5052,7 @@
|
||||
"resolved": "https://registry.npmjs.org/connected-react-router/-/connected-react-router-6.9.3.tgz",
|
||||
"integrity": "sha512-4ThxysOiv/R2Dc4Cke1eJwjKwH1Y51VDwlOrOfs1LjpdYOVvCNjNkZDayo7+sx42EeGJPQUNchWkjAIJdXGIOQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"lodash.isequalwith": "^4.4.0",
|
||||
"prop-types": "^15.7.2"
|
||||
@@ -5502,10 +5517,13 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "2.5.8",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.8.tgz",
|
||||
"integrity": "sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==",
|
||||
"license": "(MPL-2.0 OR Apache-2.0)"
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz",
|
||||
"integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==",
|
||||
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||
"optionalDependencies": {
|
||||
"@types/trusted-types": "^2.0.7"
|
||||
}
|
||||
},
|
||||
"node_modules/dot-prop": {
|
||||
"version": "9.0.0",
|
||||
@@ -5919,6 +5937,7 @@
|
||||
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
@@ -6502,6 +6521,7 @@
|
||||
"resolved": "https://registry.npmjs.org/final-form/-/final-form-4.20.10.tgz",
|
||||
"integrity": "sha512-TL48Pi1oNHeMOHrKv1bCJUrWZDcD3DIG6AGYVNOnyZPr7Bd/pStN0pL+lfzF5BNoj/FclaoiaLenk4XUIFVYng==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.10.0"
|
||||
},
|
||||
@@ -6518,6 +6538,7 @@
|
||||
"resolved": "https://registry.npmjs.org/final-form-arrays/-/final-form-arrays-3.1.0.tgz",
|
||||
"integrity": "sha512-TWBvun+AopgBLw9zfTFHBllnKMVNEwCEyDawphPuBGGqNsuhGzhT7yewHys64KFFwzIs6KEteGLpKOwvTQEscQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"peerDependencies": {
|
||||
"final-form": "^4.20.8"
|
||||
}
|
||||
@@ -6932,6 +6953,7 @@
|
||||
"integrity": "sha512-hM9gltmtQLfmWPqoPreUtRdP3nZCSzQEw7l/JC+up5CxquDykhYFKzIzoFFeVev3AGFEULNvsbE8fpZPgxUYEQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/node": ">=20.0.0",
|
||||
"@types/whatwg-mimetype": "^3.0.2",
|
||||
@@ -7045,6 +7067,7 @@
|
||||
"resolved": "https://registry.npmjs.org/history/-/history-4.10.1.tgz",
|
||||
"integrity": "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.1.2",
|
||||
"loose-envify": "^1.2.0",
|
||||
@@ -8653,6 +8676,7 @@
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
|
||||
"integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
@@ -9372,6 +9396,7 @@
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.4.0",
|
||||
"object-assign": "^4.1.1",
|
||||
@@ -9463,6 +9488,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ra-core/-/ra-core-3.19.12.tgz",
|
||||
"integrity": "sha512-E0cM6OjEUtccaR+dR5mL1MLiVVYML0Yf7aPhpLEq4iue73X3+CKcLztInoBhWgeevPbFQwgAtsXhlpedeyrNNg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"classnames": "~2.3.1",
|
||||
"date-fns": "^1.29.0",
|
||||
@@ -9677,6 +9703,12 @@
|
||||
"integrity": "sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ra-ui-materialui/node_modules/dompurify": {
|
||||
"version": "2.5.8",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.8.tgz",
|
||||
"integrity": "sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==",
|
||||
"license": "(MPL-2.0 OR Apache-2.0)"
|
||||
},
|
||||
"node_modules/ra-ui-materialui/node_modules/inflection": {
|
||||
"version": "1.13.4",
|
||||
"resolved": "https://registry.npmjs.org/inflection/-/inflection-1.13.4.tgz",
|
||||
@@ -9852,6 +9884,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
|
||||
"integrity": "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1"
|
||||
@@ -9933,6 +9966,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
||||
"integrity": "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"object-assign": "^4.1.1",
|
||||
@@ -10005,6 +10039,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react-final-form/-/react-final-form-6.5.9.tgz",
|
||||
"integrity": "sha512-x3XYvozolECp3nIjly+4QqxdjSSWfcnpGEL5K8OBT6xmGrq5kBqbA6+/tOqoom9NwqIPPbxPNsOViFlbKgowbA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.15.4"
|
||||
},
|
||||
@@ -10022,6 +10057,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react-final-form-arrays/-/react-final-form-arrays-3.1.4.tgz",
|
||||
"integrity": "sha512-siVFAolUAe29rMR6u8VwepoysUcUdh6MLV2OWnCtKpsPRUdT9VUgECjAPaVMAH2GROZNiVB9On1H9MMrm9gdpg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.19.4"
|
||||
},
|
||||
@@ -10127,6 +10163,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz",
|
||||
"integrity": "sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.15.4",
|
||||
"@types/react-redux": "^7.1.20",
|
||||
@@ -10162,6 +10199,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-5.3.4.tgz",
|
||||
"integrity": "sha512-Ys9K+ppnJah3QuaRiLxk+jDWOR1MekYQrlytiXxC1RyfbdsZkS5pvKAzCCr031xHixZwpnsYNT5xysdFHQaYsA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.13",
|
||||
"history": "^4.9.0",
|
||||
@@ -10182,6 +10220,7 @@
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.4.tgz",
|
||||
"integrity": "sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.13",
|
||||
"history": "^4.9.0",
|
||||
@@ -10363,6 +10402,7 @@
|
||||
"resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz",
|
||||
"integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.9.2"
|
||||
}
|
||||
@@ -10372,6 +10412,7 @@
|
||||
"resolved": "https://registry.npmjs.org/redux-saga/-/redux-saga-1.4.2.tgz",
|
||||
"integrity": "sha512-QLIn/q+7MX/B+MkGJ/K6R3//60eJ4QNy65eqPsJrfGezbxdh1Jx+37VRKE2K4PsJnNET5JufJtgWdT30WBa+6w==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@redux-saga/core": "^1.4.2"
|
||||
}
|
||||
@@ -10625,6 +10666,7 @@
|
||||
"integrity": "sha512-oWKZLjYwTihnTeINcNenxIIDfeotkQ2GAjFJPe7aYsMONrwDwQQXcAl3Qv0qON7Hdc8RTsFomq22zotm/i6VVQ==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.8"
|
||||
},
|
||||
@@ -11585,6 +11627,7 @@
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -11806,6 +11849,7 @@
|
||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -12050,6 +12094,7 @@
|
||||
"integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"esbuild": "^0.27.0",
|
||||
"fdir": "^6.5.0",
|
||||
@@ -12174,6 +12219,7 @@
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -12187,6 +12233,7 @@
|
||||
"integrity": "sha512-FQMeF0DJdWY0iOnbv466n/0BudNdKj1l5jYgl5JVTwjSsZSlqyXFt/9+1sEyhR6CLowbZpV7O1sCHrzBhucKKg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vitest/expect": "4.0.17",
|
||||
"@vitest/mocker": "4.0.17",
|
||||
@@ -12703,6 +12750,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
|
||||
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"fast-uri": "^3.0.1",
|
||||
@@ -12790,6 +12838,7 @@
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
|
||||
"integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
"clsx": "^2.1.1",
|
||||
"connected-react-router": "^6.9.3",
|
||||
"deepmerge": "^4.3.1",
|
||||
"dompurify": "^3.3.1",
|
||||
"history": "^4.10.1",
|
||||
"inflection": "^3.0.2",
|
||||
"jwt-decode": "^4.0.0",
|
||||
|
||||
@@ -33,6 +33,7 @@ import {
|
||||
import config from '../config'
|
||||
import { formatFullDate, intersperse } from '../utils'
|
||||
import AlbumExternalLinks from './AlbumExternalLinks'
|
||||
import { SafeHTML } from '../common/SafeHTML'
|
||||
|
||||
const useStyles = makeStyles(
|
||||
(theme) => ({
|
||||
@@ -225,8 +226,7 @@ const AlbumDetails = (props) => {
|
||||
const [imageLoading, setImageLoading] = useState(false)
|
||||
const [imageError, setImageError] = useState(false)
|
||||
|
||||
let notes =
|
||||
albumInfo?.notes?.replace(new RegExp('<.*>', 'g'), '') || record.notes
|
||||
let notes = albumInfo?.notes || record.notes
|
||||
|
||||
if (notes) {
|
||||
notes += '..'
|
||||
@@ -351,7 +351,7 @@ const AlbumDetails = (props) => {
|
||||
variant={'body1'}
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
>
|
||||
<span dangerouslySetInnerHTML={{ __html: notes }} />
|
||||
<span><SafeHTML>{notes}</SafeHTML></span>
|
||||
</Typography>
|
||||
</Collapse>
|
||||
)}
|
||||
@@ -371,7 +371,7 @@ const AlbumDetails = (props) => {
|
||||
variant={'body1'}
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
>
|
||||
<span dangerouslySetInnerHTML={{ __html: notes }} />
|
||||
<span><SafeHTML>{notes}</SafeHTML></span>
|
||||
</Typography>
|
||||
</Collapse>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, createElement, useEffect } from 'react'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { useMediaQuery, withWidth } from '@material-ui/core'
|
||||
import {
|
||||
useShowController,
|
||||
@@ -53,9 +53,7 @@ const ArtistDetails = (props) => {
|
||||
const isDesktop = useMediaQuery((theme) => theme.breakpoints.up('sm'))
|
||||
const [artistInfo, setArtistInfo] = useState()
|
||||
|
||||
const biography =
|
||||
artistInfo?.biography?.replace(new RegExp('<.*>', 'g'), '') ||
|
||||
record.biography
|
||||
const biography = artistInfo?.biography || record.biography
|
||||
|
||||
useEffect(() => {
|
||||
subsonic
|
||||
@@ -72,16 +70,8 @@ const ArtistDetails = (props) => {
|
||||
})
|
||||
}, [record.id])
|
||||
|
||||
const component = isDesktop ? DesktopArtistDetails : MobileArtistDetails
|
||||
return (
|
||||
<>
|
||||
{createElement(component, {
|
||||
artistInfo,
|
||||
record,
|
||||
biography,
|
||||
})}
|
||||
</>
|
||||
)
|
||||
const Component = isDesktop ? DesktopArtistDetails : MobileArtistDetails
|
||||
return <Component artistInfo={artistInfo} record={record} biography={biography} />
|
||||
}
|
||||
|
||||
const ArtistShowLayout = (props) => {
|
||||
|
||||
@@ -11,6 +11,7 @@ import Lightbox from 'react-image-lightbox'
|
||||
import ExpandInfoDialog from '../dialogs/ExpandInfoDialog'
|
||||
import AlbumInfo from '../album/AlbumInfo'
|
||||
import subsonic from '../subsonic'
|
||||
import { SafeHTML } from '../common/SafeHTML'
|
||||
|
||||
const useStyles = makeStyles(
|
||||
(theme) => ({
|
||||
@@ -172,7 +173,7 @@ const DesktopArtistDetails = ({ artistInfo, record, biography }) => {
|
||||
variant={'body1'}
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
>
|
||||
<span dangerouslySetInnerHTML={{ __html: biography }} />
|
||||
<span><SafeHTML>{biography}</SafeHTML></span>
|
||||
</Typography>
|
||||
</Collapse>
|
||||
</CardContent>
|
||||
|
||||
@@ -7,6 +7,7 @@ import config from '../config'
|
||||
import { LoveButton, RatingField } from '../common'
|
||||
import Lightbox from 'react-image-lightbox'
|
||||
import subsonic from '../subsonic'
|
||||
import { SafeHTML } from '../common/SafeHTML'
|
||||
|
||||
const useStyles = makeStyles(
|
||||
(theme) => ({
|
||||
@@ -168,7 +169,7 @@ const MobileArtistDetails = ({ artistInfo, biography, record }) => {
|
||||
<div className={classes.biography}>
|
||||
<Collapse collapsedHeight={'1.5em'} in={expanded} timeout={'auto'}>
|
||||
<Typography variant={'body1'} onClick={() => setExpanded(!expanded)}>
|
||||
<span dangerouslySetInnerHTML={{ __html: biography }} />
|
||||
<span><SafeHTML>{biography}</SafeHTML></span>
|
||||
</Typography>
|
||||
</Collapse>
|
||||
</div>
|
||||
|
||||
@@ -53,12 +53,7 @@ const Linkify = ({ text, ...rest }) => {
|
||||
|
||||
// Push remaining text
|
||||
if (text.length > lastIndex) {
|
||||
elements.push(
|
||||
<span
|
||||
key={'last-span-key'}
|
||||
dangerouslySetInnerHTML={{ __html: text.substring(lastIndex) }}
|
||||
/>,
|
||||
)
|
||||
elements.push(text.substring(lastIndex))
|
||||
}
|
||||
|
||||
return elements.length === 1 ? elements[0] : elements
|
||||
|
||||
@@ -30,17 +30,7 @@ export const MultiLineTextField = memo(
|
||||
>
|
||||
{lines.length === 0 && emptyText
|
||||
? emptyText
|
||||
: lines.map((line, idx) =>
|
||||
line === '' ? (
|
||||
<br key={md5(line + idx)} />
|
||||
) : (
|
||||
<div
|
||||
data-testid={`${source}.${idx}`}
|
||||
key={md5(line + idx)}
|
||||
dangerouslySetInnerHTML={{ __html: line }}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
: lines}
|
||||
</Typography>
|
||||
)
|
||||
},
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
import * as React from 'react'
|
||||
import { render, cleanup, screen } from '@testing-library/react'
|
||||
import { MultiLineTextField } from './MultiLineTextField'
|
||||
|
||||
describe('<MultiLineTextField />', () => {
|
||||
afterEach(cleanup)
|
||||
|
||||
it('should render each line in a separated div', () => {
|
||||
const record = { comment: 'line1\nline2' }
|
||||
render(<MultiLineTextField record={record} source={'comment'} />)
|
||||
expect(screen.queryByTestId('comment.0').textContent).toBe('line1')
|
||||
expect(screen.queryByTestId('comment.1').textContent).toBe('line2')
|
||||
})
|
||||
|
||||
it.each([null, undefined])(
|
||||
'should render the emptyText when value is %s',
|
||||
(body) => {
|
||||
render(
|
||||
<MultiLineTextField
|
||||
record={{ id: 123, body }}
|
||||
emptyText="NA"
|
||||
source="body"
|
||||
/>,
|
||||
)
|
||||
expect(screen.getByText('NA')).toBeInTheDocument()
|
||||
},
|
||||
)
|
||||
})
|
||||
@@ -0,0 +1,29 @@
|
||||
import DOMPurify from 'dompurify'
|
||||
import { Fragment, useMemo } from 'react'
|
||||
|
||||
export const SafeHTML = ({
|
||||
children,
|
||||
}) => {
|
||||
const purified = useMemo(() => {
|
||||
const purify = DOMPurify()
|
||||
|
||||
purify.addHook('afterSanitizeElements', async (node) => {
|
||||
if (node instanceof HTMLElement) {
|
||||
// Set referrer-policy for elements with src
|
||||
switch (node.tagName.toLowerCase()) {
|
||||
case 'a':
|
||||
case 'area':
|
||||
case 'img':
|
||||
case 'video':
|
||||
case 'iframe':
|
||||
case 'script':
|
||||
node.setAttribute('referrer-policy', 'no-referrer')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return purify.sanitize(children, { ADD_ATTR: ['referrer-policy'] })
|
||||
}, [children])
|
||||
|
||||
return <Fragment dangerouslySetInnerHTML={{ __html: purified }} />
|
||||
}
|
||||
@@ -136,6 +136,8 @@ const FormLogin = ({ loading, handleSubmit, validate }) => {
|
||||
{config.welcomeMessage && (
|
||||
<div
|
||||
className={classes.welcome}
|
||||
// Use dangerouslySetInnerHTML to allow admins to configure
|
||||
// whatever content they want
|
||||
dangerouslySetInnerHTML={{ __html: config.welcomeMessage }}
|
||||
/>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user