diff --git a/package.json b/package.json index aff33e56..02bc7bcd 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,8 @@ "cookie-parser": "^1.4.4", "cors": "^2.8.5", "cross-env": "^7.0.0", - "dayjs": "^1.8.19", + "dayjs": "^1.8.20", + "dompurify": "^2.0.8", "element-ui": "^2.13.0", "email-templates": "^7.0.2", "express": "^4.17.1", @@ -73,6 +74,7 @@ "http-signature": "^1.3.1", "ics": "^2.16.0", "inquirer": "^7.0.4", + "jsdom": "^16.1.0", "jsonwebtoken": "^8.5.1", "less": "^3.10.3", "lodash": "^4.17.14", @@ -83,8 +85,7 @@ "nuxt": "^2.11.0", "nuxt-express-module": "^0.0.11", "pg": "^7.18.1", - "sanitize-html": "^1.21.1", - "sequelize": "^5.21.3", + "sequelize": "^5.21.4", "sequelize-cli": "^5.5.1", "sharp": "^0.24.0", "sqlite3": "^4.1.1", @@ -105,7 +106,7 @@ "eslint-config-standard": ">=14.1.0", "eslint-loader": "^3.0.3", "eslint-plugin-import": ">=2.20.1", - "eslint-plugin-jest": ">=23.6.0", + "eslint-plugin-jest": ">=23.7.0", "eslint-plugin-node": ">=11.0.0", "eslint-plugin-nuxt": ">=0.5.0", "eslint-plugin-prettier": "^3.1.2", diff --git a/server/api/controller/event.js b/server/api/controller/event.js index bb3cea39..a59454f5 100644 --- a/server/api/controller/event.js +++ b/server/api/controller/event.js @@ -5,6 +5,8 @@ const config = require('config') const fs = require('fs') const { Op } = require('sequelize') const _ = require('lodash') +const helpers = require('../../helpers') + const { event: Event, resource: Resource, @@ -15,7 +17,6 @@ const { } = require('../models') const Sequelize = require('sequelize') const exportController = require('./export') -const sanitizeHtml = require('sanitize-html') const debug = require('debug')('controller:event') @@ -301,7 +302,7 @@ const eventController = { body.image_path = req.file.filename } - body.description = sanitizeHtml(body.description) + body.description = helpers.sanitizeHTML(body.description) await event.update(body) let place diff --git a/server/federation/resources.js b/server/federation/resources.js index 2e44a9f0..25d7d6af 100644 --- a/server/federation/resources.js +++ b/server/federation/resources.js @@ -1,6 +1,7 @@ const { event: Event, resource: Resource, ap_user: APUser } = require('../api/models') const debug = require('debug')('fediverse:resource') -const sanitize = require('sanitize-html') +const helpers = require('../helpers') + module.exports = { // create a resource from AP Note @@ -30,7 +31,7 @@ module.exports = { // TODO should probably map links here // clean resource - body.object.content = sanitize(body.object.content, { + body.object.content = helpers.sanitizeHTML(body.object.content, { nonTextTags: ['style', 'script', 'textarea', 'noscript'] }) diff --git a/server/helpers.js b/server/helpers.js index e17728bb..7def7283 100644 --- a/server/helpers.js +++ b/server/helpers.js @@ -4,7 +4,40 @@ const moment = require('moment-timezone') const config = require('config') const pkg = require('../package.json') +const DOMPurify = require('dompurify') +const { JSDOM } = require('jsdom') +const { window } = new JSDOM('') +const domPurify = DOMPurify(window) +const URL = require('url') + +domPurify.addHook('beforeSanitizeElements', node => { + if (node.hasAttribute && node.hasAttribute('href')) { + const href = node.getAttribute('href') + const text = node.textContent + if (href.includes('fbclid=')) { + try { + const url = new URL.URL(href) + url.searchParams.delete('fbclid') + node.setAttribute('href', url.href) + if (text.includes('fbclid=')) { + node.textContent = url.href + } + } catch (e) { + return node + } + } + } + return node +}) + module.exports = { + sanitizeHTML (html) { + return domPurify.sanitize(html, { + ALLOWED_TAGS: ['p', 'h1', 'h2', 'h3', 'h4', 'h5', + 'h6', 'b', 'a', 'li', 'ul', 'ol', 'code', 'blockquote', 'u', 's', 'strong'], + ALLOWED_ATTR: ['href'] + }) + }, async initSettings (req, res, next) { await settingsController.load() diff --git a/yarn.lock b/yarn.lock index 45b87730..53a34015 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1128,16 +1128,16 @@ consola "^2.11.1" defu "^0.0.3" -"@nuxtjs/axios@^5.9.3": - version "5.9.3" - resolved "https://registry.yarnpkg.com/@nuxtjs/axios/-/axios-5.9.3.tgz#9d99b10f752b49b42aaa3e2e5ca9484372ce86e9" - integrity sha512-+P1BK7MxMRL4q1WeYM9vyfocJrRoskbuD2TztKU8ryunK8JgpkIvqCzQxTI2BLUbOPd7qvjPLwzA0QBdzqYlaA== +"@nuxtjs/axios@^5.9.5": + version "5.9.5" + resolved "https://registry.yarnpkg.com/@nuxtjs/axios/-/axios-5.9.5.tgz#5adc0acc4deb7e1d67ab7240c741a401a6c01823" + integrity sha512-5sMsl5PbNSbAOou75wN2ztDAfGi6pU12zZQvfkDBz3s9KnKST/Azfc1FLw2Y8TR4UaDv074vt20oxK+z7AnH1A== dependencies: "@nuxtjs/proxy" "^1.3.3" - axios "^0.19.1" + axios "^0.19.2" axios-retry "^3.1.2" consola "^2.11.3" - defu "^0.0.4" + defu "^1.0.0" "@nuxtjs/eslint-config@^2.0.0": version "2.0.0" @@ -1740,11 +1740,6 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array-uniq@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - array-unique@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" @@ -1877,13 +1872,6 @@ axios@^0.19.0: follow-redirects "1.5.10" is-buffer "^2.0.2" -axios@^0.19.1: - version "0.19.1" - resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.1.tgz#8a6a04eed23dfe72747e1dd43c604b8f1677b5aa" - integrity sha512-Yl+7nfreYKaLRvAvjNPkvfjnQHJM1yLBY3zhqAwcJSwR/6ETkanUgylgtIvkvz0xJ+p/vZuNw8X7Hnb7Whsbpw== - dependencies: - follow-redirects "1.5.10" - axios@^0.19.2: version "0.19.2" resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27" @@ -3498,10 +3486,10 @@ defu@^0.0.3: resolved "https://registry.yarnpkg.com/defu/-/defu-0.0.3.tgz#bdc3ea1e1ab2120d4d4a129147f3ba9b7f9fe103" integrity sha512-u/fe4fBwrD0KACvI0sYWTWFzooqONZq8ywPnK0ZkAgLNwaDTKpSWvMiiU4QmzhrQCXu8Y0+HIWP8amE18lsL4A== -defu@^0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/defu/-/defu-0.0.4.tgz#9294753fff9a88217635ed387e4a451f1738e6ff" - integrity sha512-rgzSYjB7bq5P6uPTPOlFYy/hw4SR/Ml+SM/ZlRx1BEcgUmcTA8yqnzByRiA4npIuJPb1uRJo6ROx++Xs5QooqQ== +defu@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defu/-/defu-1.0.0.tgz#43acb09dfcf81866fa3b0fc047ece18e5c30df71" + integrity sha512-1Y1KRFxiiq+LYsZ3iP7xYSR8bHfmHFOUpDunZCN1ld1fGfDJWJIvkUBtjl3apnBwPuJtL/H7cwwlLYX8xPkraQ== delayed-stream@~1.0.0: version "1.0.0" @@ -3655,6 +3643,11 @@ domhandler@^3.0.0: dependencies: domelementtype "^2.0.1" +dompurify@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.0.8.tgz#6ef89d2d227d041af139c7b01d9f67ed59c2eb3c" + integrity sha512-vIOSyOXkMx81ghEalh4MLBtDHMx1bhKlaqHDMqM2yeitJ996SLOk5mGdDpI9ifJAgokred8Rmu219fX4OltqXw== + domutils@1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" @@ -4048,10 +4041,10 @@ eslint-plugin-es@^3.0.0: eslint-utils "^2.0.0" regexpp "^3.0.0" -eslint-plugin-import@>=2.20.0: - version "2.20.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.0.tgz#d749a7263fb6c29980def8e960d380a6aa6aecaa" - integrity sha512-NK42oA0mUc8Ngn4kONOPsPB1XhbUvNHqF+g307dPV28aknPoiNnKLFd9em4nkswwepdF5ouieqv5Th/63U7YJQ== +eslint-plugin-import@>=2.20.1: + version "2.20.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.1.tgz#802423196dcb11d9ce8435a5fc02a6d3b46939b3" + integrity sha512-qQHgFOTjguR+LnYRoToeZWT62XM55MBVXObHM6SKFd1VzDcX/vqT1kAz8ssqigh5eMj8qXcRoXXGZpPP6RfdCw== dependencies: array-includes "^3.0.3" array.prototype.flat "^1.2.1" @@ -5328,7 +5321,7 @@ html-webpack-plugin@^3.2.0: toposort "^1.0.0" util.promisify "1.0.0" -htmlparser2@^3.10.0, htmlparser2@^3.10.1, htmlparser2@^3.3.0, htmlparser2@^3.9.1: +htmlparser2@^3.10.1, htmlparser2@^3.3.0, htmlparser2@^3.9.1: version "3.10.1" resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== @@ -6412,11 +6405,6 @@ lodash.camelcase@^4.3.0: resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= -lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= - lodash.defaults@^4.0.1: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" @@ -6427,11 +6415,6 @@ lodash.defaultsdeep@^4.6.1: resolved "https://registry.yarnpkg.com/lodash.defaultsdeep/-/lodash.defaultsdeep-4.6.1.tgz#512e9bd721d272d94e3d3a63653fa17516741ca6" integrity sha512-3j8wdDzYuWO3lM3Reg03MuQR957t287Rpcxp1njpEa8oDrikb+FwGdW3n+FELh/A6qib6yPit0j/pv9G/yeAqA== -lodash.escaperegexp@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347" - integrity sha1-ZHYsSGGAglGKw99Mz11YhtriA0c= - lodash.filter@^4.4.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace" @@ -6502,11 +6485,6 @@ lodash.merge@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash.mergewith@^4.6.1: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55" - integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ== - lodash.once@^4.0.0: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" @@ -9699,22 +9677,6 @@ safe-regex@^2.1.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sanitize-html@^1.21.1: - version "1.21.1" - resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-1.21.1.tgz#1647d15c0c672901aa41eac1b86d0c38146d30ce" - integrity sha512-W6enXSVphVaVbmVbzVngBthR5f5sMmhq3EfPfBlzBzp2WnX8Rnk7NGpP7KmHUc0Y3MVk9tv/+CbpdHchX9ai7g== - dependencies: - chalk "^2.4.1" - htmlparser2 "^3.10.0" - lodash.clonedeep "^4.5.0" - lodash.escaperegexp "^4.1.2" - lodash.isplainobject "^4.0.6" - lodash.isstring "^4.0.1" - lodash.mergewith "^4.6.1" - postcss "^7.0.5" - srcset "^1.0.0" - xtend "^4.0.1" - sax@^1.2.4, sax@~1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" @@ -10150,14 +10112,6 @@ sqlite3@^4.1.1: node-pre-gyp "^0.11.0" request "^2.87.0" -srcset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/srcset/-/srcset-1.0.0.tgz#a5669de12b42f3b1d5e83ed03c71046fc48f41ef" - integrity sha1-pWad4StC87HV6D7QPHEEb8SPQe8= - dependencies: - array-uniq "^1.0.2" - number-is-nan "^1.0.0" - sshpk@^1.14.1, sshpk@^1.7.0: version "1.16.1" resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" @@ -11673,7 +11627,7 @@ xdg-basedir@^3.0.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4" integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ= -xtend@^4.0.0, xtend@^4.0.1, xtend@^4.0.2, xtend@~4.0.1: +xtend@^4.0.0, xtend@^4.0.2, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==