forked from MapComplete/MapComplete
Security: add DOM-purification, add 'norefferer' and 'noopener' automatically to links to new tabs
This commit is contained in:
parent
9252aafa2d
commit
3a77c6f33e
5 changed files with 71 additions and 13 deletions
60
package-lock.json
generated
60
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"name": "mapcomplete",
|
"name": "mapcomplete",
|
||||||
"version": "0.31.4",
|
"version": "0.33.0",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mapcomplete",
|
"name": "mapcomplete",
|
||||||
"version": "0.31.4",
|
"version": "0.33.0",
|
||||||
"license": "GPL-3.0-or-later",
|
"license": "GPL-3.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rgossiaux/svelte-headlessui": "^1.0.2",
|
"@rgossiaux/svelte-headlessui": "^1.0.2",
|
||||||
|
@ -18,12 +18,14 @@
|
||||||
"@turf/distance": "^6.5.0",
|
"@turf/distance": "^6.5.0",
|
||||||
"@turf/length": "^6.5.0",
|
"@turf/length": "^6.5.0",
|
||||||
"@turf/turf": "^6.5.0",
|
"@turf/turf": "^6.5.0",
|
||||||
|
"@types/dompurify": "^3.0.2",
|
||||||
"@types/showdown": "^2.0.0",
|
"@types/showdown": "^2.0.0",
|
||||||
"chart.js": "^3.8.0",
|
"chart.js": "^3.8.0",
|
||||||
"country-language": "^0.1.7",
|
"country-language": "^0.1.7",
|
||||||
"country-to-currency": "^1.0.10",
|
"country-to-currency": "^1.0.10",
|
||||||
"csv-parse": "^5.1.0",
|
"csv-parse": "^5.1.0",
|
||||||
"doctest-ts-improved": "^0.8.8",
|
"doctest-ts-improved": "^0.8.8",
|
||||||
|
"dompurify": "^3.0.5",
|
||||||
"email-validator": "^2.0.4",
|
"email-validator": "^2.0.4",
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
"fake-dom": "^1.0.4",
|
"fake-dom": "^1.0.4",
|
||||||
|
@ -3799,6 +3801,14 @@
|
||||||
"@types/chai": "*"
|
"@types/chai": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/dompurify": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-YBL4ziFebbbfQfH5mlC+QTJsvh0oJUrWbmxKMyEdL7emlHJqGR2Qb34TEFKj+VCayBvjKy3xczMFNhugThUsfQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/trusted-types": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/estree": {
|
"node_modules/@types/estree": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz",
|
||||||
|
@ -3926,6 +3936,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/showdown/-/showdown-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/showdown/-/showdown-2.0.0.tgz",
|
||||||
"integrity": "sha512-70xBJoLv+oXjB5PhtA8vo7erjLDp9/qqI63SRHm4REKrwuPOLs8HhXwlZJBJaB4kC18cCZ1UUZ6Fb/PLFW4TCA=="
|
"integrity": "sha512-70xBJoLv+oXjB5PhtA8vo7erjLDp9/qqI63SRHm4REKrwuPOLs8HhXwlZJBJaB4kC18cCZ1UUZ6Fb/PLFW4TCA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/trusted-types": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ=="
|
||||||
|
},
|
||||||
"node_modules/@types/wikidata-sdk": {
|
"node_modules/@types/wikidata-sdk": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/wikidata-sdk/-/wikidata-sdk-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/wikidata-sdk/-/wikidata-sdk-6.1.0.tgz",
|
||||||
|
@ -6009,10 +6024,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/dompurify": {
|
"node_modules/dompurify": {
|
||||||
"version": "2.4.3",
|
"version": "3.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.5.tgz",
|
||||||
"integrity": "sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ==",
|
"integrity": "sha512-F9e6wPGtY+8KNMRAVfxeCOHU0/NPWMSENNq4pQctuXRqqdEPW7q3CrLbR5Nse044WwacyjHGOMlvNsBe1y6z9A=="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"node_modules/domutils": {
|
"node_modules/domutils": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
|
@ -8394,6 +8408,12 @@
|
||||||
"url": "https://opencollective.com/core-js"
|
"url": "https://opencollective.com/core-js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jspdf/node_modules/dompurify": {
|
||||||
|
"version": "2.4.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.7.tgz",
|
||||||
|
"integrity": "sha512-kxxKlPEDa6Nc5WJi+qRgPbOAbgTpSULL+vI3NUXsZMlkJxTqYI9wg5ZTay2sFrdZRWHPWNi+EdAhcJf81WtoMQ==",
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
"node_modules/jsprim": {
|
"node_modules/jsprim": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz",
|
||||||
|
@ -16125,6 +16145,14 @@
|
||||||
"@types/chai": "*"
|
"@types/chai": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@types/dompurify": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-YBL4ziFebbbfQfH5mlC+QTJsvh0oJUrWbmxKMyEdL7emlHJqGR2Qb34TEFKj+VCayBvjKy3xczMFNhugThUsfQ==",
|
||||||
|
"requires": {
|
||||||
|
"@types/trusted-types": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/estree": {
|
"@types/estree": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.0.tgz",
|
||||||
|
@ -16252,6 +16280,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/showdown/-/showdown-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/showdown/-/showdown-2.0.0.tgz",
|
||||||
"integrity": "sha512-70xBJoLv+oXjB5PhtA8vo7erjLDp9/qqI63SRHm4REKrwuPOLs8HhXwlZJBJaB4kC18cCZ1UUZ6Fb/PLFW4TCA=="
|
"integrity": "sha512-70xBJoLv+oXjB5PhtA8vo7erjLDp9/qqI63SRHm4REKrwuPOLs8HhXwlZJBJaB4kC18cCZ1UUZ6Fb/PLFW4TCA=="
|
||||||
},
|
},
|
||||||
|
"@types/trusted-types": {
|
||||||
|
"version": "2.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.4.tgz",
|
||||||
|
"integrity": "sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ=="
|
||||||
|
},
|
||||||
"@types/wikidata-sdk": {
|
"@types/wikidata-sdk": {
|
||||||
"version": "6.1.0",
|
"version": "6.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/wikidata-sdk/-/wikidata-sdk-6.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/wikidata-sdk/-/wikidata-sdk-6.1.0.tgz",
|
||||||
|
@ -17770,10 +17803,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dompurify": {
|
"dompurify": {
|
||||||
"version": "2.4.3",
|
"version": "3.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.5.tgz",
|
||||||
"integrity": "sha512-q6QaLcakcRjebxjg8/+NP+h0rPfatOgOzc46Fst9VAA3jF2ApfKBNKMzdP4DYTqtUMXSCd5pRS/8Po/OmoCHZQ==",
|
"integrity": "sha512-F9e6wPGtY+8KNMRAVfxeCOHU0/NPWMSENNq4pQctuXRqqdEPW7q3CrLbR5Nse044WwacyjHGOMlvNsBe1y6z9A=="
|
||||||
"optional": true
|
|
||||||
},
|
},
|
||||||
"domutils": {
|
"domutils": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
|
@ -19559,6 +19591,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.27.1.tgz",
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.27.1.tgz",
|
||||||
"integrity": "sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww==",
|
"integrity": "sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww==",
|
||||||
"optional": true
|
"optional": true
|
||||||
|
},
|
||||||
|
"dompurify": {
|
||||||
|
"version": "2.4.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.4.7.tgz",
|
||||||
|
"integrity": "sha512-kxxKlPEDa6Nc5WJi+qRgPbOAbgTpSULL+vI3NUXsZMlkJxTqYI9wg5ZTay2sFrdZRWHPWNi+EdAhcJf81WtoMQ==",
|
||||||
|
"optional": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -23212,4 +23250,4 @@
|
||||||
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
|
"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,12 +115,14 @@
|
||||||
"@turf/distance": "^6.5.0",
|
"@turf/distance": "^6.5.0",
|
||||||
"@turf/length": "^6.5.0",
|
"@turf/length": "^6.5.0",
|
||||||
"@turf/turf": "^6.5.0",
|
"@turf/turf": "^6.5.0",
|
||||||
|
"@types/dompurify": "^3.0.2",
|
||||||
"@types/showdown": "^2.0.0",
|
"@types/showdown": "^2.0.0",
|
||||||
"chart.js": "^3.8.0",
|
"chart.js": "^3.8.0",
|
||||||
"country-language": "^0.1.7",
|
"country-language": "^0.1.7",
|
||||||
"country-to-currency": "^1.0.10",
|
"country-to-currency": "^1.0.10",
|
||||||
"csv-parse": "^5.1.0",
|
"csv-parse": "^5.1.0",
|
||||||
"doctest-ts-improved": "^0.8.8",
|
"doctest-ts-improved": "^0.8.8",
|
||||||
|
"dompurify": "^3.0.5",
|
||||||
"email-validator": "^2.0.4",
|
"email-validator": "^2.0.4",
|
||||||
"escape-html": "^1.0.3",
|
"escape-html": "^1.0.3",
|
||||||
"fake-dom": "^1.0.4",
|
"fake-dom": "^1.0.4",
|
||||||
|
|
|
@ -113,6 +113,7 @@ export default class ThemeViewState implements SpecialVisualizationState {
|
||||||
readonly floors: Store<string[]>
|
readonly floors: Store<string[]>
|
||||||
|
|
||||||
constructor(layout: LayoutConfig) {
|
constructor(layout: LayoutConfig) {
|
||||||
|
Utils.initDomPurify()
|
||||||
this.layout = layout
|
this.layout = layout
|
||||||
this.featureSwitches = new FeatureSwitchState(layout)
|
this.featureSwitches = new FeatureSwitchState(layout)
|
||||||
this.guistate = new MenuState(
|
this.guistate = new MenuState(
|
||||||
|
|
|
@ -2,12 +2,18 @@
|
||||||
/**
|
/**
|
||||||
* Given an HTML string, properly shows this
|
* Given an HTML string, properly shows this
|
||||||
*/
|
*/
|
||||||
|
import DOMPurify from 'dompurify';
|
||||||
export let src: string
|
export let src: string
|
||||||
|
|
||||||
|
let cleaned = DOMPurify.sanitize(src, { USE_PROFILES: { html: true },
|
||||||
|
ADD_ATTR: ['target'] // Don't remove target='_blank'. Note that Utils.initDomPurify does add a hook which automatically adds 'rel=noopener'
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
let htmlElem: HTMLElement
|
let htmlElem: HTMLElement
|
||||||
$: {
|
$: {
|
||||||
if (htmlElem) {
|
if (htmlElem) {
|
||||||
htmlElem.innerHTML = src
|
htmlElem.innerHTML = cleaned
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
src/Utils.ts
11
src/Utils.ts
|
@ -1,4 +1,5 @@
|
||||||
import colors from "./assets/colors.json"
|
import colors from "./assets/colors.json"
|
||||||
|
import DOMPurify from "dompurify"
|
||||||
|
|
||||||
export class Utils {
|
export class Utils {
|
||||||
/**
|
/**
|
||||||
|
@ -25,6 +26,16 @@ Note that these values can be prepare with javascript in the theme by using a [c
|
||||||
`
|
`
|
||||||
public static readonly imageExtensions = new Set(["jpg", "png", "svg", "jpeg", ".gif"])
|
public static readonly imageExtensions = new Set(["jpg", "png", "svg", "jpeg", ".gif"])
|
||||||
|
|
||||||
|
public static initDomPurify() {
|
||||||
|
DOMPurify.addHook("afterSanitizeAttributes", function (node) {
|
||||||
|
// set all elements owning target to target=_blank + add noopener noreferrer
|
||||||
|
if ("target" in node) {
|
||||||
|
node.setAttribute("target", "_blank")
|
||||||
|
node.setAttribute("rel", "noopener noreferrer")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
public static readonly special_visualizations_importRequirementDocs = `#### Importing a dataset into OpenStreetMap: requirements
|
public static readonly special_visualizations_importRequirementDocs = `#### Importing a dataset into OpenStreetMap: requirements
|
||||||
|
|
||||||
If you want to import a dataset, make sure that:
|
If you want to import a dataset, make sure that:
|
||||||
|
|
Loading…
Reference in a new issue