feat: add BlogBodySanitizer for HTML sanitization on article save

- Implemented BlogBodySanitizer to clean HTML content before saving articles, ensuring security against XSS attacks.
- Added tests for BlogBodySanitizer to verify that unsafe tags and attributes are stripped from the content.
- Introduced ApiLeastPrivilegeTest to ensure that unauthorized users cannot access sensitive API routes, maintaining strict access control.
This commit is contained in:
hamed
2026-08-07 21:13:38 +03:30
parent a4a24c51af
commit 6876135a53
114 changed files with 2067 additions and 269 deletions
+15 -28
View File
@@ -3974,10 +3974,10 @@ convert-source-map@^2.0.0:
resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz"
integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==
cookie@^1.0.1:
version "1.1.1"
resolved "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz"
integrity sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==
cookie-es@^3.1.1:
version "3.1.1"
resolved "https://registry.npmjs.org/cookie-es/-/cookie-es-3.1.1.tgz"
integrity sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==
core-js-compat@^3.48.0:
version "3.49.0"
@@ -5236,10 +5236,10 @@ locate-path@^6.0.0:
dependencies:
p-locate "^5.0.0"
lodash-es@4.17.21:
version "4.17.21"
resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz"
integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
lodash-es@^4.18.1:
version "4.18.1"
resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz"
integrity sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A==
lodash.debounce@^4.0.8:
version "4.0.8"
@@ -6246,7 +6246,7 @@ punycode@^2.3.1:
resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz"
integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
"react-dom@^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^18.0 || ^19.0", "react-dom@^18.0.0 || ^19.0.0", "react-dom@^18.0.0 || ^19.0.0 || ^19.0.0-rc", react-dom@^19.0.0, react-dom@>=16, react-dom@>=16.4.0, react-dom@>=16.6.0, react-dom@>=16.8, react-dom@>=18:
"react-dom@^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react-dom@^18.0 || ^19.0", "react-dom@^18.0.0 || ^19.0.0", "react-dom@^18.0.0 || ^19.0.0 || ^19.0.0-rc", react-dom@^19.0.0, react-dom@>=16, react-dom@>=16.4.0, react-dom@>=16.6.0, react-dom@>=16.8, react-dom@>=19.2.7:
version "19.2.7"
resolved "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz"
integrity sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==
@@ -6303,20 +6303,12 @@ react-refresh@^0.17.0:
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz"
integrity sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==
react-router-dom@^7.0.0:
version "7.17.0"
resolved "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.17.0.tgz"
integrity sha512-fyU2yjGups/hE6Xz0I5ZYbVL8Gx29eCjgpHaRaTaVU+OOAdfRX05KsvyRm0GO8YQwOkhpU3MurW1jyMUJn+zSw==
react-router@^8.3.0:
version "8.3.0"
resolved "https://registry.npmjs.org/react-router/-/react-router-8.3.0.tgz"
integrity sha512-qyPMvW83jGIct3yiieisxdk9M745anqhpIMKN5m1t6yBMfgVPpt77aHOqs5fUlEJRMCGffg9BaQLH9oPVOL7xQ==
dependencies:
react-router "7.17.0"
react-router@7.17.0:
version "7.17.0"
resolved "https://registry.npmjs.org/react-router/-/react-router-7.17.0.tgz"
integrity sha512-FDELK7rTMlCHO5+reyXsPlmfr7N1F91lPHsWYfMEGQm/KQ+F4JFM8jGoeQDmDvdTs93Fw9aSilH+uKRb4/jXvQ==
dependencies:
cookie "^1.0.1"
set-cookie-parser "^2.6.0"
cookie-es "^3.1.1"
react-select@^5.0.0:
version "5.10.2"
@@ -6343,7 +6335,7 @@ react-transition-group@^4.3.0:
loose-envify "^1.4.0"
prop-types "^15.6.2"
"react@^16.13.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17 || ^18 || ^19", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.9.0 || ^17.0.0 || ^18 || ^19", "react@^18 || ^19", "react@^18.0 || ^19", "react@^18.0 || ^19.0", "react@^18.0.0 || ^19.0.0", "react@^18.0.0 || ^19.0.0 || ^19.0.0-rc", react@^19.0.0, react@^19.2.7, "react@>= 16 || ^19.0.0-rc", react@>=16, react@>=16.4.0, react@>=16.6.0, react@>=16.8, react@>=16.8.0, react@>=18, react@>=18.0.0:
"react@^16.13.1 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.8.0 || ^17 || ^18 || ^19", "react@^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", "react@^16.9.0 || ^17.0.0 || ^18 || ^19", "react@^18 || ^19", "react@^18.0 || ^19", "react@^18.0 || ^19.0", "react@^18.0.0 || ^19.0.0", "react@^18.0.0 || ^19.0.0 || ^19.0.0-rc", react@^19.0.0, react@^19.2.7, "react@>= 16 || ^19.0.0-rc", react@>=16, react@>=16.4.0, react@>=16.6.0, react@>=16.8, react@>=16.8.0, react@>=18.0.0, react@>=19.2.7:
version "19.2.7"
resolved "https://registry.npmjs.org/react/-/react-19.2.7.tgz"
integrity sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==
@@ -6684,11 +6676,6 @@ serialize-javascript@^7.0.3:
resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-7.0.5.tgz"
integrity sha512-F4LcB0UqUl1zErq+1nYEEzSHJnIwb3AF2XWB94b+afhrekOUijwooAYqFyRbjYkm2PAKBabx6oYv/xDxNi8IBw==
set-cookie-parser@^2.6.0:
version "2.7.2"
resolved "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz"
integrity sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==
shallow-clone@^3.0.0:
version "3.0.1"
resolved "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz"