forked from MapComplete/MapComplete
		
	Refactoring: put all special visualisations into their own class, add their location into the documentation
This commit is contained in:
		
							parent
							
								
									c0e7c9e8fa
								
							
						
					
					
						commit
						ae5205f92d
					
				
					 29 changed files with 2270 additions and 2075 deletions
				
			
		|  | @ -7,21 +7,10 @@ import ThemeConfig from "../src/Models/ThemeConfig/ThemeConfig" | |||
| import xml2js from "xml2js" | ||||
| import ScriptUtils from "./ScriptUtils" | ||||
| import { Utils } from "../src/Utils" | ||||
| import SpecialVisualizations from "../src/UI/SpecialVisualizations" | ||||
| import Constants from "../src/Models/Constants" | ||||
| import { AvailableRasterLayers, RasterLayerPolygon } from "../src/Models/RasterLayers" | ||||
| import { ImmutableStore } from "../src/Logic/UIEventSource" | ||||
| import * as eli from "../public/assets/data/editor-layer-index.json" | ||||
| import * as layers_global from "../src/assets/global-raster-layers.json" | ||||
| import eli_global from "../src/assets/generated/editor-layer-index-global.json" | ||||
| import bing from "../src/assets/bing.json" | ||||
| 
 | ||||
| import ValidationUtils from "../src/Models/ThemeConfig/Conversion/ValidationUtils" | ||||
| import { LayerConfigJson } from "../src/Models/ThemeConfig/Json/LayerConfigJson" | ||||
| import { QuestionableTagRenderingConfigJson } from "../src/Models/ThemeConfig/Json/QuestionableTagRenderingConfigJson" | ||||
| import Script from "./Script" | ||||
| import crypto from "crypto" | ||||
| import { RasterLayerProperties } from "../src/Models/RasterLayerProperties" | ||||
| import { SourceOverview } from "./SourceOverview" | ||||
| 
 | ||||
| const sharp = require("sharp") | ||||
| 
 | ||||
|  | @ -36,8 +25,6 @@ class GenerateLayouts extends Script { | |||
|         .join("\n") | ||||
|     private readonly removeOtherLanguagesHash = | ||||
|         "sha256-" + crypto.createHash("sha256").update(this.removeOtherLanguages).digest("base64") | ||||
|     private previousSrc: Set<string> = new Set<string>() | ||||
|     private eliUrlsCached: string[] | ||||
|     private date = new Date().toISOString() | ||||
|     private branchName: string = undefined | ||||
|     private alreadyWritten: Set<string> = new Set<string>() | ||||
|  | @ -265,78 +252,7 @@ class GenerateLayouts extends Script { | |||
|         return values.join("\n") | ||||
|     } | ||||
| 
 | ||||
|     async eliUrls(): Promise<string[]> { | ||||
|         if (this.eliUrlsCached) { | ||||
|             return this.eliUrlsCached | ||||
|         } | ||||
|         const urls: string[] = [] | ||||
|         const regex = /{switch:([^}]+)}/ | ||||
|         const rasterLayers: { properties: RasterLayerProperties }[] = [ | ||||
|             AvailableRasterLayers.defaultBackgroundLayer, | ||||
|             ...eli.features, | ||||
|             bing, | ||||
|             ...eli_global.map((properties) => ({ properties })), | ||||
|             ...layers_global.layers.map((properties) => ({ properties })), | ||||
|         ] | ||||
|         for (const feature of rasterLayers) { | ||||
|             const f = <RasterLayerPolygon>feature | ||||
|             const url = f.properties.url | ||||
|             const match = url.match(regex) | ||||
|             if (match) { | ||||
|                 const domains = match[1].split(",") | ||||
|                 const subpart = match[0] | ||||
|                 urls.push(...domains.map((d) => url.replace(subpart, d))) | ||||
|             } else { | ||||
|                 urls.push(url) | ||||
|             } | ||||
| 
 | ||||
|             if (f.properties.type === "vector") { | ||||
|                 // We also need to whitelist eventual sources
 | ||||
|                 let url = f.properties.url | ||||
|                 urls.push(...(f.properties["connect-src"] ?? [])) | ||||
|                 if (url.startsWith("pmtiles://")) { | ||||
|                     url = url.substring("pmtiles://".length) | ||||
|                 } | ||||
|                 if (url.endsWith(".pmtiles")) { | ||||
|                     continue | ||||
|                 } | ||||
|                 try { | ||||
|                     console.log("Downloading ", url) | ||||
|                     const styleSpec = await Utils.downloadJsonCached(url, 1000 * 120, { | ||||
|                         Origin: "https://mapcomplete.org", | ||||
|                     }) | ||||
|                     for (const key of Object.keys(styleSpec?.["sources"] ?? {})) { | ||||
|                         const url = styleSpec["sources"][key].url | ||||
|                         if (!url) { | ||||
|                             continue | ||||
|                         } | ||||
|                         let urlClipped = url | ||||
|                         if (url.indexOf("?") > 0) { | ||||
|                             urlClipped = url?.substring(0, url.indexOf("?")) | ||||
|                         } | ||||
|                         console.log("Source url ", key, url) | ||||
|                         urls.push(url) | ||||
|                         if (urlClipped.endsWith(".json")) { | ||||
|                             const tileInfo = await Utils.downloadJsonCached(url, 1000 * 120, { | ||||
|                                 Origin: "https://mapcomplete.org", | ||||
|                             }) | ||||
|                             urls.push(tileInfo["tiles"] ?? []) | ||||
|                         } | ||||
|                     } | ||||
|                     urls.push(...(styleSpec["tiles"] ?? [])) | ||||
|                     urls.push(styleSpec["sprite"]) | ||||
|                     urls.push(styleSpec["glyphs"]) | ||||
|                 } catch (e) { | ||||
|                     console.error( | ||||
|                         "ERROR: could not download a resource, some sprites might not be whitelisted and thus not load" | ||||
|                     ) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         this.eliUrlsCached = urls | ||||
|         return Utils.NoNull(urls).sort() | ||||
|     } | ||||
| 
 | ||||
|     private readonly sourceOverview = new SourceOverview() | ||||
|     async generateCsp( | ||||
|         layout: ThemeConfig, | ||||
|         layoutJson: ThemeConfigJson, | ||||
|  | @ -344,66 +260,10 @@ class GenerateLayouts extends Script { | |||
|             scriptSrcs: string[] | ||||
|         } | ||||
|     ): Promise<string> { | ||||
|         const apiUrls: string[] = [ | ||||
|             ...Constants.allServers, | ||||
|             "https://www.openstreetmap.org", | ||||
|             "https://api.openstreetmap.org", | ||||
|             "https://pietervdvn.goatcounter.com", | ||||
|             "https://api.panoramax.xyz", | ||||
|             "https://panoramax.mapcomplete.org", | ||||
|             "https://data.velopark.be", | ||||
|             "https://data.mapcomplete.org", | ||||
|         ].concat(...(await this.eliUrls())) | ||||
| 
 | ||||
|         SpecialVisualizations.specialVisualizations.forEach((sv) => { | ||||
|             if (typeof sv.needsUrls === "function") { | ||||
|                 // Handled below
 | ||||
|                 return | ||||
|             } | ||||
|             apiUrls.push(...(sv.needsUrls ?? [])) | ||||
|         }) | ||||
| 
 | ||||
|         const usedSpecialVisualisations = [].concat( | ||||
|             ...layoutJson.layers.map((l) => | ||||
|                 ValidationUtils.getAllSpecialVisualisations( | ||||
|                     <QuestionableTagRenderingConfigJson[]>(<LayerConfigJson>l).tagRenderings ?? [] | ||||
|                 ) | ||||
|             ) | ||||
|         ) | ||||
|         for (const usedSpecialVisualisation of usedSpecialVisualisations) { | ||||
|             if (typeof usedSpecialVisualisation === "string") { | ||||
|                 continue | ||||
|             } | ||||
|             const neededUrls = usedSpecialVisualisation.func.needsUrls ?? [] | ||||
|             if (typeof neededUrls === "function") { | ||||
|                 let needed: string | string[] = neededUrls(usedSpecialVisualisation.args) | ||||
|                 if (typeof needed === "string") { | ||||
|                     needed = [needed] | ||||
|                 } | ||||
|                 apiUrls.push(...needed) | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         const geojsonSources: string[] = layout.layers.map((l) => l.source?.geojsonSource) | ||||
|         const urls = await this.sourceOverview.getOverview(layout, layoutJson, options) | ||||
|         const hosts = new Set<string>() | ||||
|         hosts.add("https://schema.org") | ||||
|         const eliLayers: RasterLayerPolygon[] = AvailableRasterLayers.layersAvailableAt( | ||||
|             new ImmutableStore({ lon: 0, lat: 0 }) | ||||
|         ).store.data | ||||
|         { | ||||
|             const vectorLayers = eliLayers.filter((l) => l.properties.type === "vector") | ||||
|             const vectorSources = vectorLayers.map((l) => l.properties.url) | ||||
|             vectorSources.push(...vectorLayers.map((l) => l.properties.style)) | ||||
|             apiUrls.push( | ||||
|                 ...vectorSources.map((url) => { | ||||
|                     if (url?.startsWith("pmtiles://")) { | ||||
|                         return url.substring("pmtiles://".length) | ||||
|                     } | ||||
|                     return url | ||||
|                 }) | ||||
|             ) | ||||
|         } | ||||
|         for (let connectSource of apiUrls.concat(geojsonSources)) { | ||||
| 
 | ||||
|         for (let connectSource of urls) { | ||||
|             if (!connectSource) { | ||||
|                 continue | ||||
|             } | ||||
|  | @ -425,17 +285,12 @@ class GenerateLayouts extends Script { | |||
|         } | ||||
| 
 | ||||
|         const connectSrc = Array.from(hosts).sort() | ||||
| 
 | ||||
|         const newSrcs = connectSrc.filter((newItem) => !this.previousSrc.has(newItem)) | ||||
| 
 | ||||
|         console.log( | ||||
|             "Got", | ||||
|             hosts.size, | ||||
|             "connect-src items for theme", | ||||
|             layout.id, | ||||
|             newSrcs.length > 0 ? "(extra sources: " + newSrcs.join(" ") + ")" : "" | ||||
|         ) | ||||
|         this.previousSrc = hosts | ||||
| 
 | ||||
|         const csp: Record<string, string> = { | ||||
|             "default-src": "'self'", | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue