diff --git a/package-lock.json b/package-lock.json
index 154610c..9cf1c9c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -51,6 +51,7 @@
"react-dom": "^18.3.1",
"react-hook-form": "^7.52.1",
"react-router-dom": "^6.26.1",
+ "sanitize-html": "^2.14.0",
"short-uuid": "^5.2.0",
"sonner": "^1.7.4",
"tailwind": "^4.0.0",
@@ -65,6 +66,7 @@
"@types/node": "^20.11.20",
"@types/react": "^18.2.57",
"@types/react-dom": "^18.2.19",
+ "@types/sanitize-html": "^2.13.0",
"@types/uuid": "^10.0.0",
"@typescript-eslint/eslint-plugin": "^7.1.1",
"@typescript-eslint/parser": "^7.1.1",
@@ -1252,9 +1254,9 @@
}
},
"node_modules/@next/env": {
- "version": "14.2.17",
- "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.17.tgz",
- "integrity": "sha512-MCgO7VHxXo8sYR/0z+sk9fGyJJU636JyRmkjc7ZJY8Hurl8df35qG5hoAh5KMs75FLjhlEo9bb2LGe89Y/scDA==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.24.tgz",
+ "integrity": "sha512-LAm0Is2KHTNT6IT16lxT+suD0u+VVfYNQqM+EJTKuFRRuY2z+zj01kueWXPCxbMBDt0B5vONYzabHGUNbZYAhA==",
"license": "MIT"
},
"node_modules/@next/eslint-plugin-next": {
@@ -1268,12 +1270,13 @@
}
},
"node_modules/@next/swc-darwin-arm64": {
- "version": "14.2.17",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.17.tgz",
- "integrity": "sha512-WiOf5nElPknrhRMTipXYTJcUz7+8IAjOYw3vXzj3BYRcVY0hRHKWgTgQ5439EvzQyHEko77XK+yN9x9OJ0oOog==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.24.tgz",
+ "integrity": "sha512-7Tdi13aojnAZGpapVU6meVSpNzgrFwZ8joDcNS8cJVNuP3zqqrLqeory9Xec5TJZR/stsGJdfwo8KeyloT3+rQ==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -1283,12 +1286,13 @@
}
},
"node_modules/@next/swc-darwin-x64": {
- "version": "14.2.17",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.17.tgz",
- "integrity": "sha512-29y425wYnL17cvtxrDQWC3CkXe/oRrdt8ie61S03VrpwpPRI0XsnTvtKO06XCisK4alaMnZlf8riwZIbJTaSHQ==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.24.tgz",
+ "integrity": "sha512-lXR2WQqUtu69l5JMdTwSvQUkdqAhEWOqJEYUQ21QczQsAlNOW2kWZCucA6b3EXmPbcvmHB1kSZDua/713d52xg==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"darwin"
@@ -1298,12 +1302,13 @@
}
},
"node_modules/@next/swc-linux-arm64-gnu": {
- "version": "14.2.17",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.17.tgz",
- "integrity": "sha512-SSHLZls3ZwNEHsc+d0ynKS+7Af0Nr8+KTUBAy9pm6xz9SHkJ/TeuEg6W3cbbcMSh6j4ITvrjv3Oi8n27VR+IPw==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.24.tgz",
+ "integrity": "sha512-nxvJgWOpSNmzidYvvGDfXwxkijb6hL9+cjZx1PVG6urr2h2jUqBALkKjT7kpfurRWicK6hFOvarmaWsINT1hnA==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -1313,12 +1318,13 @@
}
},
"node_modules/@next/swc-linux-arm64-musl": {
- "version": "14.2.17",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.17.tgz",
- "integrity": "sha512-VFge37us5LNPatB4F7iYeuGs9Dprqe4ZkW7lOEJM91r+Wf8EIdViWHLpIwfdDXinvCdLl6b4VyLpEBwpkctJHA==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.24.tgz",
+ "integrity": "sha512-PaBgOPhqa4Abxa3y/P92F3kklNPsiFjcjldQGT7kFmiY5nuFn8ClBEoX8GIpqU1ODP2y8P6hio6vTomx2Vy0UQ==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -1328,12 +1334,13 @@
}
},
"node_modules/@next/swc-linux-x64-gnu": {
- "version": "14.2.17",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.17.tgz",
- "integrity": "sha512-aaQlpxUVb9RZ41adlTYVQ3xvYEfBPUC8+6rDgmQ/0l7SvK8S1YNJzPmDPX6a4t0jLtIoNk7j+nroS/pB4nx7vQ==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.24.tgz",
+ "integrity": "sha512-vEbyadiRI7GOr94hd2AB15LFVgcJZQWu7Cdi9cWjCMeCiUsHWA0U5BkGPuoYRnTxTn0HacuMb9NeAmStfBCLoQ==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -1343,12 +1350,13 @@
}
},
"node_modules/@next/swc-linux-x64-musl": {
- "version": "14.2.17",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.17.tgz",
- "integrity": "sha512-HSyEiFaEY3ay5iATDqEup5WAfrhMATNJm8dYx3ZxL+e9eKv10XKZCwtZByDoLST7CyBmyDz+OFJL1wigyXeaoA==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.24.tgz",
+ "integrity": "sha512-df0FC9ptaYsd8nQCINCzFtDWtko8PNRTAU0/+d7hy47E0oC17tI54U/0NdGk7l/76jz1J377dvRjmt6IUdkpzQ==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"linux"
@@ -1358,12 +1366,13 @@
}
},
"node_modules/@next/swc-win32-arm64-msvc": {
- "version": "14.2.17",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.17.tgz",
- "integrity": "sha512-h5qM9Btqv87eYH8ArrnLoAHLyi79oPTP2vlGNSg4CDvUiXgi7l0+5KuEGp5pJoMhjuv9ChRdm7mRlUUACeBt4w==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.24.tgz",
+ "integrity": "sha512-ZEntbLjeYAJ286eAqbxpZHhDFYpYjArotQ+/TW9j7UROh0DUmX7wYDGtsTPpfCV8V+UoqHBPU7q9D4nDNH014Q==",
"cpu": [
"arm64"
],
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -1373,12 +1382,13 @@
}
},
"node_modules/@next/swc-win32-ia32-msvc": {
- "version": "14.2.17",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.17.tgz",
- "integrity": "sha512-BD/G++GKSLexQjdyoEUgyo5nClU7er5rK0sE+HlEqnldJSm96CIr/+YOTT063LVTT/dUOeQsNgp5DXr86/K7/A==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.24.tgz",
+ "integrity": "sha512-9KuS+XUXM3T6v7leeWU0erpJ6NsFIwiTFD5nzNg8J5uo/DMIPvCp3L1Ao5HjbHX0gkWPB1VrKoo/Il4F0cGK2Q==",
"cpu": [
"ia32"
],
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -1388,12 +1398,13 @@
}
},
"node_modules/@next/swc-win32-x64-msvc": {
- "version": "14.2.17",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.17.tgz",
- "integrity": "sha512-vkQfN1+4V4KqDibkW2q0sJ6CxQuXq5l2ma3z0BRcfIqkAMZiiW67T9yCpwqJKP68QghBtPEFjPAlaqe38O6frw==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.24.tgz",
+ "integrity": "sha512-cXcJ2+x0fXQ2CntaE00d7uUH+u1Bfp/E0HsNQH79YiLaZE5Rbm7dZzyAYccn3uICM7mw+DxoMqEfGXZtF4Fgaw==",
"cpu": [
"x64"
],
+ "license": "MIT",
"optional": true,
"os": [
"win32"
@@ -2346,6 +2357,16 @@
"form-data": "^2.5.0"
}
},
+ "node_modules/@types/sanitize-html": {
+ "version": "2.13.0",
+ "resolved": "https://registry.npmjs.org/@types/sanitize-html/-/sanitize-html-2.13.0.tgz",
+ "integrity": "sha512-X31WxbvW9TjIhZZNyNBZ/p5ax4ti7qsNDBDEnH4zAgmEh35YnFD1UiS6z9Cd34kKm0LslFW0KPmTQzu/oGtsqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "htmlparser2": "^8.0.0"
+ }
+ },
"node_modules/@types/send": {
"version": "0.17.4",
"license": "MIT",
@@ -3647,6 +3668,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/deepmerge": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/define-data-property": {
"version": "1.1.4",
"license": "MIT",
@@ -3752,6 +3782,61 @@
"node": ">=6.0.0"
}
},
+ "node_modules/dom-serializer": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
+ "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.2",
+ "entities": "^4.2.0"
+ },
+ "funding": {
+ "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
+ }
+ },
+ "node_modules/domelementtype": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
+ "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "BSD-2-Clause"
+ },
+ "node_modules/domhandler": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
+ "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "domelementtype": "^2.3.0"
+ },
+ "engines": {
+ "node": ">= 4"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domhandler?sponsor=1"
+ }
+ },
+ "node_modules/domutils": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
+ "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "dom-serializer": "^2.0.0",
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/domutils?sponsor=1"
+ }
+ },
"node_modules/dotenv": {
"version": "16.4.5",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz",
@@ -3898,6 +3983,18 @@
"node": ">=10.13.0"
}
},
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
"node_modules/es-abstract": {
"version": "1.23.3",
"license": "MIT",
@@ -4061,7 +4158,6 @@
},
"node_modules/escape-string-regexp": {
"version": "4.0.0",
- "dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
@@ -5482,6 +5578,25 @@
"license": "MIT",
"optional": true
},
+ "node_modules/htmlparser2": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
+ "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
+ "funding": [
+ "https://github.com/fb55/htmlparser2?sponsor=1",
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/fb55"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "domelementtype": "^2.3.0",
+ "domhandler": "^5.0.3",
+ "domutils": "^3.0.1",
+ "entities": "^4.4.0"
+ }
+ },
"node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
@@ -5852,6 +5967,15 @@
"node": ">=8"
}
},
+ "node_modules/is-plain-object": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
+ "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/is-regex": {
"version": "1.1.4",
"license": "MIT",
@@ -6174,9 +6298,9 @@
}
},
"node_modules/katex": {
- "version": "0.16.11",
- "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.11.tgz",
- "integrity": "sha512-RQrI8rlHY92OLf3rho/Ts8i/XvjgguEjOkO1BEXcU3N8BqPpSzBNwV/G0Ukr+P/l3ivvJUE/Fa/CwbS6HesGNQ==",
+ "version": "0.16.21",
+ "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.21.tgz",
+ "integrity": "sha512-XvqR7FgOHtWupfMiigNzmh+MgUVmDGU2kXZm899ZkPfcuoPuFxyHmXsgATDpFZDAXCI8tvinaVcDo8PIIJSo4A==",
"funding": [
"https://opencollective.com/katex",
"https://github.com/sponsors/katex"
@@ -6562,12 +6686,12 @@
}
},
"node_modules/next": {
- "version": "14.2.17",
- "resolved": "https://registry.npmjs.org/next/-/next-14.2.17.tgz",
- "integrity": "sha512-hNo/Zy701DDO3nzKkPmsLRlDfNCtb1OJxFUvjGEl04u7SFa3zwC6hqsOUzMajcaEOEV8ey1GjvByvrg0Qr5AiQ==",
+ "version": "14.2.24",
+ "resolved": "https://registry.npmjs.org/next/-/next-14.2.24.tgz",
+ "integrity": "sha512-En8VEexSJ0Py2FfVnRRh8gtERwDRaJGNvsvad47ShkC2Yi8AXQPXEA2vKoDJlGFSj5WE5SyF21zNi4M5gyi+SQ==",
"license": "MIT",
"dependencies": {
- "@next/env": "14.2.17",
+ "@next/env": "14.2.24",
"@swc/helpers": "0.5.5",
"busboy": "1.6.0",
"caniuse-lite": "^1.0.30001579",
@@ -6582,15 +6706,15 @@
"node": ">=18.17.0"
},
"optionalDependencies": {
- "@next/swc-darwin-arm64": "14.2.17",
- "@next/swc-darwin-x64": "14.2.17",
- "@next/swc-linux-arm64-gnu": "14.2.17",
- "@next/swc-linux-arm64-musl": "14.2.17",
- "@next/swc-linux-x64-gnu": "14.2.17",
- "@next/swc-linux-x64-musl": "14.2.17",
- "@next/swc-win32-arm64-msvc": "14.2.17",
- "@next/swc-win32-ia32-msvc": "14.2.17",
- "@next/swc-win32-x64-msvc": "14.2.17"
+ "@next/swc-darwin-arm64": "14.2.24",
+ "@next/swc-darwin-x64": "14.2.24",
+ "@next/swc-linux-arm64-gnu": "14.2.24",
+ "@next/swc-linux-arm64-musl": "14.2.24",
+ "@next/swc-linux-x64-gnu": "14.2.24",
+ "@next/swc-linux-x64-musl": "14.2.24",
+ "@next/swc-win32-arm64-msvc": "14.2.24",
+ "@next/swc-win32-ia32-msvc": "14.2.24",
+ "@next/swc-win32-x64-msvc": "14.2.24"
},
"peerDependencies": {
"@opentelemetry/api": "^1.1.0",
@@ -6909,6 +7033,12 @@
"node": ">=6"
}
},
+ "node_modules/parse-srcset": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz",
+ "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==",
+ "license": "MIT"
+ },
"node_modules/parseurl": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
@@ -7811,6 +7941,20 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"license": "MIT"
},
+ "node_modules/sanitize-html": {
+ "version": "2.14.0",
+ "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.14.0.tgz",
+ "integrity": "sha512-CafX+IUPxZshXqqRaG9ZClSlfPVjSxI0td7n07hk8QO2oO+9JDnlcL8iM8TWeOXOIBFgIOx6zioTzM53AOMn3g==",
+ "license": "MIT",
+ "dependencies": {
+ "deepmerge": "^4.2.2",
+ "escape-string-regexp": "^4.0.0",
+ "htmlparser2": "^8.0.0",
+ "is-plain-object": "^5.0.0",
+ "parse-srcset": "^1.0.2",
+ "postcss": "^8.3.11"
+ }
+ },
"node_modules/scheduler": {
"version": "0.23.2",
"license": "MIT",
diff --git a/package.json b/package.json
index 986a142..8803899 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,8 @@
"build": "next build",
"dev": "next dev",
"lint": "next lint",
- "start": "next start"
+ "start": "next start",
+ "emulate": "firebase emulators:start --import emulator --export-on-exit"
},
"dependencies": {
"@editorjs/attaches": "^1.3.0",
@@ -53,6 +54,7 @@
"react-dom": "^18.3.1",
"react-hook-form": "^7.52.1",
"react-router-dom": "^6.26.1",
+ "sanitize-html": "^2.14.0",
"short-uuid": "^5.2.0",
"sonner": "^1.7.4",
"tailwind": "^4.0.0",
@@ -67,6 +69,7 @@
"@types/node": "^20.11.20",
"@types/react": "^18.2.57",
"@types/react-dom": "^18.2.19",
+ "@types/sanitize-html": "^2.13.0",
"@types/uuid": "^10.0.0",
"@typescript-eslint/eslint-plugin": "^7.1.1",
"@typescript-eslint/parser": "^7.1.1",
diff --git a/src/components/article-creator/Renderer.tsx b/src/components/article-creator/Renderer.tsx
index 97fd154..3132692 100644
--- a/src/components/article-creator/Renderer.tsx
+++ b/src/components/article-creator/Renderer.tsx
@@ -9,6 +9,7 @@ import { createRoot, type Root } from "react-dom/client";
import { QuestionsOutput } from "./custom_questions/QuestionInstance";
import type { QuestionFormat } from "@/types/questions";
import "@/styles/katexStyling.css";
+import sanitizeHtml from "sanitize-html";
import { Config } from "editorjs-parser";
// derived from advancedtextbox
@@ -252,11 +253,67 @@ const Renderer = (props: { content: OutputData }) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
const markup = parser.parse(props.content);
+ // XSS Prevention
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment
+ const sanitizedMarkup = sanitizeHtml(markup, {
+ allowedTags: [
+ "p",
+ "div",
+ "span",
+ "h1",
+ "h2",
+ "h3",
+ "h4",
+ "h5",
+ "h6",
+ "ul",
+ "ol",
+ "li",
+ "a",
+ "img",
+ "code",
+ "pre",
+ "blockquote",
+ "table",
+ "thead",
+ "tbody",
+ "tr",
+ "th",
+ "td",
+ "hr",
+ "br",
+ "cite",
+ "figure",
+ "figcaption",
+ "iframe",
+ "math",
+ ],
+ allowedAttributes: {
+ "*": ["class", "id", "style"],
+ a: ["href", "target", "rel"],
+ img: ["src", "alt", "class"],
+ iframe: [
+ "src",
+ "height",
+ "width",
+ "frameborder",
+ "allowtransparency",
+ "scrolling",
+ ],
+ },
+ allowedClasses: {
+ "*": [/^.*$/], // Might want to restrict this later (if there are any xss attacks via css)
+ },
+ });
+
return (
);
};
diff --git a/src/components/article-creator/custom_questions/QuestionsInputInterface.tsx b/src/components/article-creator/custom_questions/QuestionsInputInterface.tsx
index 9820324..e32169d 100644
--- a/src/components/article-creator/custom_questions/QuestionsInputInterface.tsx
+++ b/src/components/article-creator/custom_questions/QuestionsInputInterface.tsx
@@ -150,17 +150,28 @@ const QuestionsInputInterface: React.FC = ({
setUnsavedChanges?.(true);
};
+ // Filters out different keyboard numbers
+ const normalizeAnswer = (answer: string): string => {
+ // Normalize the string and remove any special characters or different encodings
+ return answer
+ .normalize("NFKD") // Normalize to decomposed form
+ .replace(/[\u0300-\u036f]/g, "") // Remove diacritics
+ .replace(/[^\d,]/g, ""); // Keep only digits and commas
+ };
+
const validateCorrectAnswer = (
value: string,
type: "mcq" | "multi-answer",
) => {
+ const normalizedValue = normalizeAnswer(value);
let errorMessage = "";
+
if (type === "mcq") {
- if (!/^\d$/.test(value)) {
+ if (!/^\d$/.test(normalizedValue)) {
errorMessage = "Only a single number is allowed for MCQ. (e.g. 1)";
}
} else {
- if (!/^\d(,\d){0,7}$/.test(value) || value.length > 8) {
+ if (!/^\d(,\d){0,7}$/.test(normalizedValue) || normalizedValue.length > 8) {
errorMessage =
"Only numbers separated by commas are allowed, max correct questions is 4. (e.g. 1,2,4)";
}
diff --git a/src/components/questions/utils/normalizeAnswer.tsx b/src/components/questions/utils/normalizeAnswer.tsx
new file mode 100644
index 0000000..f095125
--- /dev/null
+++ b/src/components/questions/utils/normalizeAnswer.tsx
@@ -0,0 +1,22 @@
+export const normalizeAnswer = (input: string | number): string => {
+ // Convert to string if number
+ const str = input.toString();
+
+ // Normalize the string to remove any special characters or different encodings
+ const normalized = str
+ .normalize("NFKD") // Normalize to decomposed form
+ .replace(/[\u0300-\u036f]/g, "") // Remove diacritics
+ .replace(/[^\d,]/g, ""); // Keep only digits and commas
+
+ // Sort numbers for consistent comparison if multiple answers
+ if (normalized.includes(",")) {
+ return normalized
+ .split(",")
+ .map((n) => parseInt(n, 10))
+ .filter((n) => !isNaN(n)) // Filter out invalid numbers
+ .sort((a, b) => a - b)
+ .join(",");
+ }
+
+ return normalized;
+};