From c4e527bf8e23b2bb4898b14850daf4ba05e3139e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexis=20M=C3=A9taireau?= Date: Thu, 28 Mar 2024 17:02:11 +0100 Subject: [PATCH] [chore] move umap utils to a module Allow the tests to be run from inside a cli, without requiring a browser. --- package.json | 3 +- scripts/vendorsjs.sh | 2 +- umap/static/umap/js/modules/global.js | 2 +- umap/static/umap/js/modules/urls.js | 17 +- umap/static/umap/js/modules/utils.js | 283 +++++++++++++++ umap/static/umap/js/umap.autocomplete.js | 2 +- umap/static/umap/js/umap.controls.js | 14 +- umap/static/umap/js/umap.core.js | 321 +++--------------- .../umap/js/umap.datalayer.permissions.js | 2 +- umap/static/umap/js/umap.features.js | 19 +- umap/static/umap/js/umap.forms.js | 14 +- umap/static/umap/js/umap.icon.js | 15 +- umap/static/umap/js/umap.importer.js | 2 +- umap/static/umap/js/umap.js | 35 +- umap/static/umap/js/umap.layer.js | 44 +-- umap/static/umap/js/umap.permissions.js | 9 +- umap/static/umap/js/umap.popup.js | 8 +- umap/static/umap/js/umap.share.js | 8 +- umap/static/umap/test/index.html | 1 - umap/templates/umap/js.html | 1 - 20 files changed, 419 insertions(+), 383 deletions(-) diff --git a/package.json b/package.json index aa6b9da3..1440cd52 100644 --- a/package.json +++ b/package.json @@ -40,8 +40,9 @@ "@tmcw/togeojson": "^5.8.0", "colorbrewer": "^1.5.6", "csv2geojson": "5.1.1", - "dompurify": "^3.0.3", + "dompurify": "^3.0.11", "georsstogeojson": "^0.1.0", + "jsdom": "^24.0.0", "leaflet": "1.9.4", "leaflet-contextmenu": "^1.4.0", "leaflet-editable": "^1.2.0", diff --git a/scripts/vendorsjs.sh b/scripts/vendorsjs.sh index 39f8f097..a506a276 100755 --- a/scripts/vendorsjs.sh +++ b/scripts/vendorsjs.sh @@ -25,7 +25,7 @@ mkdir -p umap/static/umap/vendors/georsstogeojson/ && cp -r node_modules/georsst mkdir -p umap/static/umap/vendors/togpx/ && cp -r node_modules/togpx/togpx.js umap/static/umap/vendors/togpx/ mkdir -p umap/static/umap/vendors/tokml && cp -r node_modules/tokml/tokml.js umap/static/umap/vendors/tokml mkdir -p umap/static/umap/vendors/locatecontrol/ && cp -r node_modules/leaflet.locatecontrol/dist/L.Control.Locate.min.* umap/static/umap/vendors/locatecontrol/ -mkdir -p umap/static/umap/vendors/dompurify/ && cp -r node_modules/dompurify/dist/purify.min.* umap/static/umap/vendors/dompurify/ +mkdir -p umap/static/umap/vendors/dompurify/ && cp -r node_modules/dompurify/dist/*.mjs umap/static/umap/vendors/dompurify/ mkdir -p umap/static/umap/vendors/colorbrewer/ && cp node_modules/colorbrewer/index.js umap/static/umap/vendors/colorbrewer/colorbrewer.js mkdir -p umap/static/umap/vendors/simple-statistics/ && cp node_modules/simple-statistics/dist/simple-statistics.min.* umap/static/umap/vendors/simple-statistics/ mkdir -p umap/static/umap/vendors/iconlayers/ && cp node_modules/leaflet-iconlayers/dist/* umap/static/umap/vendors/iconlayers/ diff --git a/umap/static/umap/js/modules/global.js b/umap/static/umap/js/modules/global.js index 25ee3505..c432771e 100644 --- a/umap/static/umap/js/modules/global.js +++ b/umap/static/umap/js/modules/global.js @@ -1,7 +1,7 @@ import URLs from './urls.js' import Browser from './browser.js' import * as Utils from './utils.js' -import {SCHEMA} from './schema.js' +import { SCHEMA } from './schema.js' import { Request, ServerRequest, RequestError, HTTPError, NOKError } from './request.js' // Import modules and export them to the global scope. diff --git a/umap/static/umap/js/modules/urls.js b/umap/static/umap/js/modules/urls.js index bdf54363..ede3ac54 100644 --- a/umap/static/umap/js/modules/urls.js +++ b/umap/static/umap/js/modules/urls.js @@ -1,19 +1,4 @@ -// Vendorized from leaflet.utils -// https://github.com/Leaflet/Leaflet/blob/108c6717b70f57c63645498f9bd66b6677758786/src/core/Util.js#L132-L151 -var templateRe = /\{ *([\w_ -]+) *\}/g - -function template(str, data) { - return str.replace(templateRe, function (str, key) { - var value = data[key] - - if (value === undefined) { - throw new Error('No value provided for variable ' + str) - } else if (typeof value === 'function') { - value = value(data) - } - return value - }) -} +import { template } from "./utils.js" export default class URLs { constructor(serverUrls) { diff --git a/umap/static/umap/js/modules/utils.js b/umap/static/umap/js/modules/utils.js index a5116616..e6117c04 100644 --- a/umap/static/umap/js/modules/utils.js +++ b/umap/static/umap/js/modules/utils.js @@ -1,3 +1,5 @@ +import { default as DOMPurifyInitializer } from '../../vendors/dompurify/purify.es.mjs' + /** * Generate a pseudo-unique identifier (5 chars long, mixed-case alphanumeric) * @@ -22,3 +24,284 @@ export function checkId(string) { if (typeof string !== 'string') return false return /^[A-Za-z0-9]{5}$/.test(string) } + +/** + * Import DOM purify, and initialize it. + * + * If the context is a node server, uses jsdom to provide + * DOM APIs + */ +export default function getPurify() { + if (typeof window === 'undefined') { + return DOMPurifyInitializer(new global.JSDOM('').window) + } else { + return DOMPurifyInitializer(window) + } +} + +export function escapeHTML(s) { + s = s ? s.toString() : '' + s = getPurify().sanitize(s, { + USE_PROFILES: { html: true }, + ADD_TAGS: ['iframe'], + ALLOWED_TAGS: [ + 'h3', + 'h4', + 'h5', + 'hr', + 'strong', + 'em', + 'ul', + 'li', + 'a', + 'div', + 'iframe', + 'img', + 'br', + ], + ADD_ATTR: ['target', 'allow', 'allowfullscreen', 'frameborder', 'scrolling'], + ALLOWED_ATTR: ['href', 'src', 'width', 'height'], + // Added: `geo:` URL scheme as defined in RFC5870: + // https://www.rfc-editor.org/rfc/rfc5870.html + // The base RegExp comes from: + // https://github.com/cure53/DOMPurify/blob/main/src/regexp.js#L10 + ALLOWED_URI_REGEXP: + /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp|geo):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i, + }) + return s +} + +export function toHTML(r, options) { + if (!r) return '' + const target = (options && options.target) || 'blank' + let ii + + // detect newline format + const newline = r.indexOf('\r\n') != -1 ? '\r\n' : r.indexOf('\n') != -1 ? '\n' : '' + + // headings and hr + r = r.replace(/^### (.*)/gm, '
$1
') + r = r.replace(/^## (.*)/gm, '

$1

') + r = r.replace(/^# (.*)/gm, '

$1

') + r = r.replace(/^---/gm, '
') + + // bold, italics + r = r.replace(/\*\*(.*?)\*\*/g, '$1') + r = r.replace(/\*(.*?)\*/g, '$1') + + // unordered lists + r = r.replace(/^\*\* (.*)/gm, '') + r = r.replace(/^\* (.*)/gm, '') + for (ii = 0; ii < 3; ii++) + r = r.replace(new RegExp(`${newline}${newline}