forked from MapComplete/MapComplete
		
	Refactoring: make needed URLs explicit
This commit is contained in:
		
							parent
							
								
									7852829f1b
								
							
						
					
					
						commit
						4852888b41
					
				
					 51 changed files with 978 additions and 871 deletions
				
			
		|  | @ -8,6 +8,10 @@ import LayoutConfig from "../src/Models/ThemeConfig/LayoutConfig" | |||
| 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" | ||||
| 
 | ||||
| const sharp = require("sharp") | ||||
| const template = readFileSync("theme.html", "utf8") | ||||
|  | @ -195,29 +199,72 @@ function asLangSpan(t: Translation, tag = "span"): string { | |||
|         if (lang === "_context") { | ||||
|             continue | ||||
|         } | ||||
|         values.push(`<${tag} lang='${lang}'>${t.translations[lang]}</${tag}>`) | ||||
|         values.push(`<${tag} lang="${lang}">${t.translations[lang]}</${tag}>`) | ||||
|     } | ||||
|     return values.join("\n") | ||||
| } | ||||
| 
 | ||||
| let cspCached: string = undefined | ||||
| function generateCsp(): string { | ||||
|     if (cspCached !== undefined) { | ||||
|         return cspCached | ||||
| let previousSrc: Set<string> = new Set<string>() | ||||
| function generateCsp(layout: LayoutConfig): string { | ||||
|     const apiUrls: string[] = [ | ||||
|         "self", | ||||
|         ...Constants.defaultOverpassUrls, | ||||
|         Constants.countryCoderEndpoint, | ||||
|         "https://api.openstreetmap.org", | ||||
|         "https://pietervdvn.goatcounter.com", | ||||
|     ].concat(...SpecialVisualizations.specialVisualizations.map((sv) => sv.needsUrls)) | ||||
| 
 | ||||
|     const geojsonSources: string[] = layout.layers.map((l) => l.source?.geojsonSource) | ||||
|     const hosts = new Set<string>() | ||||
|     const eliLayers: RasterLayerPolygon[] = AvailableRasterLayers.layersAvailableAt( | ||||
|         new ImmutableStore({ lon: 0, lat: 0 }) | ||||
|     ).data | ||||
|     const vectorLayers = eliLayers.filter((l) => l.properties.type === "vector") | ||||
|     const vectorSources = vectorLayers.map((l) => l.properties.url) | ||||
|     apiUrls.push(...vectorSources) | ||||
|     for (const connectSource of apiUrls.concat(geojsonSources)) { | ||||
|         if (!connectSource) { | ||||
|             continue | ||||
|         } | ||||
|         try { | ||||
|             const url = new URL(connectSource) | ||||
|             hosts.add("https://" + url.host) | ||||
|         } catch (e) { | ||||
|             hosts.add(connectSource) | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     const connectSrc = Array.from(hosts).sort() | ||||
| 
 | ||||
|     const newSrcs = connectSrc.filter((newItem) => !previousSrc.has(newItem)) | ||||
| 
 | ||||
|     console.log( | ||||
|         "Got", | ||||
|         hosts.size, | ||||
|         "connect-src items for theme", | ||||
|         layout.id, | ||||
|         "(extra sources: ", | ||||
|         newSrcs.join(" ") + ")" | ||||
|     ) | ||||
|     previousSrc = hosts | ||||
| 
 | ||||
|     const csp = { | ||||
|         "default-src": "'self'", | ||||
|         "script-src": "'self'", | ||||
|         "img-src": "*", | ||||
|         "connect-src": "*", | ||||
|         "script-src": "'self' https://gc.zgo.at/count.js", | ||||
|         "img-src": "* data:", // maplibre depends on 'data:' to load
 | ||||
|         "connect-src": connectSrc.join(" "), | ||||
|         "report-to": "https://report.mapcomplete.org/csp", | ||||
|         "worker-src": "'self' blob:", // Vite somehow loads the worker via a 'blob'
 | ||||
|         "style-src": "'self' 'unsafe-inline'", // unsafe-inline is needed to change the default background pin colours
 | ||||
|     } | ||||
|     const content = Object.keys(csp) | ||||
|         .map((k) => k + ": " + csp[k]) | ||||
|         .map((k) => k + " " + csp[k]) | ||||
|         .join("; ") | ||||
| 
 | ||||
|     cspCached = `<meta http-equiv="Content-Security-Policy" content="${content}">` | ||||
|     return cspCached | ||||
|     return [ | ||||
|         `<meta http-equiv ="Report-To" content='{"group":"csp-endpoint", "max_age": 86400,"endpoints": [\{"url": "https://report.mapcomplete.org/csp"}], "include_subdomains": true}'>`, | ||||
|         `<meta http-equiv="Content-Security-Policy" content="${content}">`, | ||||
|     ].join("\n") | ||||
| } | ||||
| 
 | ||||
| async function createLandingPage(layout: LayoutConfig, manifest, whiteIcons, alreadyWritten) { | ||||
|  | @ -290,7 +337,7 @@ async function createLandingPage(layout: LayoutConfig, manifest, whiteIcons, alr | |||
|         ...apple_icons, | ||||
|     ].join("\n") | ||||
| 
 | ||||
|     const loadingText = Translations.t.general.loadingTheme.Subs({ theme: ogTitle }) | ||||
|     const loadingText = Translations.t.general.loadingTheme.Subs({ theme: layout.title }) | ||||
| 
 | ||||
|     let output = template | ||||
|         .replace("Loading MapComplete, hang on...", asLangSpan(loadingText, "h1")) | ||||
|  | @ -299,7 +346,7 @@ async function createLandingPage(layout: LayoutConfig, manifest, whiteIcons, alr | |||
|             Translations.t.general.poweredByOsm.textFor(targetLanguage) | ||||
|         ) | ||||
|         .replace(/<!-- THEME-SPECIFIC -->.*<!-- THEME-SPECIFIC-END-->/s, themeSpecific) | ||||
|         .replace(/<!-- CSP -->/, generateCsp()) | ||||
|         .replace(/<!-- CSP -->/, generateCsp(layout)) | ||||
|         .replace( | ||||
|             /<!-- DESCRIPTION START -->.*<!-- DESCRIPTION END -->/s, | ||||
|             asLangSpan(layout.shortDescription) | ||||
|  | @ -311,7 +358,7 @@ async function createLandingPage(layout: LayoutConfig, manifest, whiteIcons, alr | |||
| 
 | ||||
|         .replace( | ||||
|             '<script src="./src/index.ts" type="module"></script>', | ||||
|             `<script type="module" src='./index_${layout.id}.ts'></script>` | ||||
|             `<script type="module" src="./index_${layout.id}.ts"></script>` | ||||
|         ) | ||||
| 
 | ||||
|     return output | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue