Hi @Alex,
I'm writing about the v7 port of the University of Cádiz mapping tool (tool_leaflet_special_tools
in v6), which we have named tool_uca_maps in v7. First, what has been done and where, so you
can review it. Then, the three features that do not fully work yet. All three depend on core
pieces we would rather not touch without your judgement.
The tool is implemented and we have validated it by hand, feature by feature. It attaches to
component_geolocation (its only affected_models) and adds to the map a toolbar with one button
and one panel per feature:
- object console (measurements, elevation, Geoman editing, centroid, uncertainty, hierarchy,
properties with PDF export, styles and associated images);
- object viewer;
- 1x1 reference point;
- XYZ basemaps;
- WMS services;
- Catastro parcels;
- IGN administrative units;
- upload of vector files (KML, GeoJSON, Shapefile) and georeferenceable images;
- map download as an image;
- place search (Nominatim);
- browser geolocation;
- manual legend;
- historical Roman Empire data (Pleiades, Pelagios and DARE);
- scale bar.
All of the tool's code lives in tools/tool_uca_maps/**, so the change can be reviewed in one
place and does not collide with your work when we rebase:
| Path | What it is |
tools/tool_uca_maps/register.json, img/icon.svg | The tool's registration and its icon |
tools/tool_uca_maps/server/ (19 TS modules) | The tool's actions (server/index.ts), each with its declared permission. They reach public services (Nominatim, Catastro, IGN, open-elevation, Pleiades, DARE) through fetchGuardedText. GDAL, ImageMagick and Poppler run through runBinary from src/core/media/engine/spawn.ts. Uploaded images enter as Images records (rsc170) through the normal ingest path. |
tools/tool_uca_maps/js/ (38 modules) | The client: one logic file and one render file per feature, plus the shared toolbar (js/toolbar.js) |
tools/tool_uca_maps/js/lib/ | Two third-party libraries, copied in: dom-to-image-more and Leaflet.ImageOverlay.Rotated. We know engineering/VENDORING.md sends them to package.json, as was done with tool_qr; that will go in a separate message. |
tools/tool_uca_maps/css/ | The .less sheet and its compiled .css |
tools/tool_uca_maps/gazetteers/provision.ts | A maintenance script that downloads the Pleiades and Pelagios data (20 MB) into a directory the installation chooses. The data does not go into the repository. |
Outside that folder there are only tests, because the engine only runs them from there:
test/unit/tool_uca_maps_*.test.ts — 18 files, one per server action (215 tests). All of them
use the generic test TLD and build their own situation.
client/dedalo/test/client/js/test_tool_uca_maps.js — the client suite (251 tests).
client/dedalo/test/client/js/test_registry.js — a single line, to register that suite.
We have not touched anything under src/core/, client/dedalo/core/, engineering/ or docs/.
After today's rebase, typecheck and test:client pass. The tripwires still red are due to tool
contracts that have just landed and to shared counters. I'll cover those separately, since they
do not affect what follows.
My questions:
1. Third-party tiles: the CSP blocks them on screen and in the export
This is the underlying problem, and a single decision could close both sides.
On screen (img-src). src/core/api/static_asset.ts:207 allows a fixed list of five tile
domains. Several features exist precisely to load tiles from other servers:
- WMS (any server the user types in);
- XYZ basemaps (any server outside that list);
- Catastro (
ovc.catastro.meh.es);
- administrative units (
www.ign.es).
We have checked it in the browser with IGN and Catastro. The server-side request works, the
layers are listed and the parcels and polygons are created, but the browser blocks every
GetMap tile and the map shows the container's blue background. In v6 the IGN administrative
units layer does show, with its zones and names. No fixed list can cover "whatever server the
user chooses".
In the export (connect-src). Downloading the map as an image uses dom-to-image-more. To
avoid leaving the canvas tainted, that library downloads every <img> again over XHR and
inlines it as a data URL, and that download is governed by connect-src (static_asset.ts:210),
not img-src. The result: the exported image never has a basemap, even with the five allowed
domains. Polygons (inline SVG) and uploaded images (same origin) do come out. It also fails
silently: when blocked, the library throws no error, sets src = null, and the download
"succeeds" empty.
The options we see:
- (a) Let each installation add trusted domains through configuration (a key read with
readEnv). It fixes the screen, but not the export. Putting third-party domains in
connect-src goes against what static_asset.ts itself argues about that directive, so we do
not propose it.
- (b) Serve the tiles through our own server. It closes both sides at once, because
img-src 'self' and connect-src 'self' already cover them, and it stops depending on lists.
For the export no new HTTP route is needed: dom-to-image-more accepts a
requestInterceptor (which may return a promise), and a tool action that returns the bytes is
enough.
This is where we need your judgement. A tile is bytes, and none of the three outbound doors in
engineering/OUTBOUND_SPEC.md fits today:
fetchGuardedText always decodes to text (src/core/security/ssrf_guard.ts:1145), which
destroys a PNG.
harvestFetch returns bytes, but enforces at least 3 s between requests to the same origin
(src/core/harvest/pacing.ts, MIN_INTERVAL_MS). A map view asks for dozens of tiles at once.
- Copying the guard into the tool is explicitly forbidden, and rightly so (CARRY-14).
2. Google Maps: domain outside img-src, and an unofficial endpoint
v6 ships "Google Maps" among its built-in basemaps, and we have kept it as is. Its tiles come from
mt1.google.com, which is not in img-src, so it shows blue on every installation. There is
also a nuance: that endpoint is not Google's official API (maps.googleapis.com). It is an
undocumented use that v6 already made, and we don't know whether Dédalo wants to inherit it.
3. Where a tool keeps its own data
Three features store configuration: the added XYZ and WMS layers, and the legend. In v6 they were
written to a server-side file per section_tipo, so they were shared by every record of that
section and by all users. In v7 today they only last for the session: they are lost on reload
or when switching records.
We expected that declaring "ontology" in register.json would make the engine create the tool's
section, but src/core/tools/register.ts:201-202 only stores that array in the dd1334 column of
matrix_tools, and nothing in the core reads it to create nodes. The only precedent we found,
dd1781 from tool_export, is a section that already existed.
The three features share the same mechanism, so a single solution works for all three.
Thanks in advance. Whatever you decide on these three points, we will implement it ourselves
inside the tool. If any solution involves touching the core, we would rather you define that change.
Sergio