mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
fix(maps): backport attribution sanitizer fix without dropping WebGL1
This commit is contained in:
+5
-3
@@ -5,7 +5,7 @@
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"prebuild": "node scripts/generate-icons.mjs",
|
||||
"prebuild": "node scripts/patch-maplibre.mjs && node scripts/generate-icons.mjs",
|
||||
"build": "vite build",
|
||||
"build:analyze": "vite build --mode analyze",
|
||||
"preview": "vite preview",
|
||||
@@ -26,7 +26,9 @@
|
||||
"shots:promote": "node e2e/screenshots/promote.mjs",
|
||||
"e2e:report": "playwright show-report",
|
||||
"format": "prettier --write \"src/**/*.tsx\" \"src/**/*.css\"",
|
||||
"format:check": "prettier --check \"src/**/*.tsx\" \"src/**/*.css\""
|
||||
"format:check": "prettier --check \"src/**/*.tsx\" \"src/**/*.css\"",
|
||||
"postinstall": "node scripts/patch-maplibre.mjs",
|
||||
"predev": "node scripts/patch-maplibre.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/bebas-neue": "^5.3.0",
|
||||
@@ -49,7 +51,7 @@
|
||||
"leaflet": "^1.9.4",
|
||||
"lucide-react": "^0.344.0",
|
||||
"mapbox-gl": "^3.22.0",
|
||||
"maplibre-gl": "^5.24.0",
|
||||
"maplibre-gl": "5.24.0",
|
||||
"marked": "^18.0.0",
|
||||
"plyr": "^3.8.4",
|
||||
"react": "^19.2.6",
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import { readFileSync, writeFileSync } from 'node:fs'
|
||||
import { createRequire } from 'node:module'
|
||||
import { dirname, join } from 'node:path'
|
||||
|
||||
const require = createRequire(import.meta.url)
|
||||
const packagePath = require.resolve('maplibre-gl/package.json')
|
||||
const { version } = JSON.parse(readFileSync(packagePath, 'utf8'))
|
||||
|
||||
if (version !== '5.24.0') throw new Error('Recheck the MapLibre sanitizer backport before changing its version')
|
||||
|
||||
// Backport maplibre-gl-js#8189 without removing WebGL1 support in version 6.
|
||||
const loops = [
|
||||
['of elem.attributes)', 'of Array.from(elem.attributes))'],
|
||||
['of e.attributes)', 'of Array.from(e.attributes))'],
|
||||
]
|
||||
|
||||
for (const filename of [
|
||||
'src/util/dom.ts',
|
||||
'dist/maplibre-gl.js',
|
||||
'dist/maplibre-gl-dev.js',
|
||||
'dist/maplibre-gl-csp.js',
|
||||
'dist/maplibre-gl-csp-dev.js',
|
||||
]) {
|
||||
const target = join(dirname(packagePath), filename)
|
||||
const code = readFileSync(target, 'utf8')
|
||||
const loop = loops.find(([before, after]) => code.includes(before) || code.includes(after))
|
||||
if (!loop) throw new Error(`MapLibre sanitizer loop not found in ${filename}`)
|
||||
const [before, after] = loop
|
||||
if (code.split(before).length === 1 && code.split(after).length === 2) continue
|
||||
if (code.split(before).length !== 2 || code.includes(after)) {
|
||||
throw new Error(`Unexpected MapLibre sanitizer in ${filename}`)
|
||||
}
|
||||
writeFileSync(target, code.replace(before, after))
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import maplibregl from 'maplibre-gl'
|
||||
|
||||
function attribution(html: string, fromSource = false) {
|
||||
const control = new maplibregl.AttributionControl({
|
||||
compact: false,
|
||||
customAttribution: fromSource ? undefined : html,
|
||||
})
|
||||
const map = {
|
||||
style: {
|
||||
tileManagers: fromSource
|
||||
? { tiles: { used: true, getSource: () => ({ attribution: html }) } }
|
||||
: {},
|
||||
},
|
||||
_getUIString: () => 'Toggle attribution',
|
||||
on: () => {},
|
||||
off: () => {},
|
||||
getCanvasContainer: () => document.createElement('div'),
|
||||
} as unknown as maplibregl.Map
|
||||
return control.onAdd(map)
|
||||
}
|
||||
|
||||
describe('MapLibre attribution sanitizer backport', () => {
|
||||
it.each([false, true])('removes adjacent event handlers (source: %s)', fromSource => {
|
||||
const container = attribution('<details open onload="1" ontoggle="alert(1)">Credit</details>', fromSource)
|
||||
const details = container.querySelector('.maplibregl-ctrl-attrib-inner details')!
|
||||
expect(details.hasAttribute('onload')).toBe(false)
|
||||
expect(details.hasAttribute('ontoggle')).toBe(false)
|
||||
expect(details.textContent).toBe('Credit')
|
||||
})
|
||||
|
||||
it('removes consecutive dangerous URLs and handlers in nested markup', () => {
|
||||
const container = attribution('<span><a href="javascript:alert(1)" onclick="alert(2)" onfocus="alert(3)">Credit</a></span>')
|
||||
const link = container.querySelector('.maplibregl-ctrl-attrib-inner a')!
|
||||
expect(link.attributes.length).toBe(0)
|
||||
})
|
||||
|
||||
it('preserves provider credit and safe links', () => {
|
||||
const container = attribution('<a href="https://www.openstreetmap.org/copyright" target="_blank" rel="noopener">OpenStreetMap</a>')
|
||||
const link = container.querySelector('.maplibregl-ctrl-attrib-inner a')!
|
||||
expect(link.getAttribute('href')).toBe('https://www.openstreetmap.org/copyright')
|
||||
expect(link.getAttribute('rel')).toBe('noopener')
|
||||
expect(link.textContent).toBe('OpenStreetMap')
|
||||
})
|
||||
})
|
||||
Generated
+3
-2
@@ -47,7 +47,7 @@
|
||||
"leaflet": "^1.9.4",
|
||||
"lucide-react": "^0.344.0",
|
||||
"mapbox-gl": "^3.22.0",
|
||||
"maplibre-gl": "^5.24.0",
|
||||
"maplibre-gl": "5.24.0",
|
||||
"marked": "^18.0.0",
|
||||
"plyr": "^3.8.4",
|
||||
"react": "^19.2.6",
|
||||
@@ -99,7 +99,8 @@
|
||||
"vite": "8.1.0",
|
||||
"vite-plugin-pwa": "^1.3.0",
|
||||
"vitest": "^4.1.11"
|
||||
}
|
||||
},
|
||||
"hasInstallScript": true
|
||||
},
|
||||
"client/node_modules/cookie": {
|
||||
"version": "1.1.1",
|
||||
|
||||
Reference in New Issue
Block a user