Commit graph

3 commits

Author SHA1 Message Date
11cadd9ac4 Escape the two popup URLs and the packet photo URL
RegionCountryMap builds its map popup by concatenation and escaped every value
in it -- the name, the religion, the description, the image, both button labels
-- except the two URLs:

    <a class="cm-popup__btn" href="${profileUrl}">

Both come from joinBase(props.researchUrl, p.slug), and joinBase says plainly
that it only normalises slashes. So two untrusted values reached an HTML
attribute raw: the slug, which is API data, and the base URL, which is an
attribute set by whoever embeds the element. With a slug of
`x" onerror=alert(1) data-x="` the rendered tag is

    <a href="https://doxa.life/research/x" onerror=alert(1) data-x="">

out of the attribute and into new ones. esc() was already imported in that file.

The same omission in library/packet/packet-render.js, found by sweeping for the
class rather than assuming it was one site: the people-group card writes
src="${src}" where src is photos.get(slug), and usePosterPrints builds that Map
directly from the API's image_url. esc(g.name) sits two lines below it.

Neither could be caught by review or by template analysis -- both are inside
template literals -- and the popup had never once rendered, because the Regions
map was grey. So the gate: no href= or src= in built HTML takes a raw
interpolation. Data URLs, blob URLs, encodeURIComponent and safeUrl() are
recognised as safe, each verified at its call site rather than assumed from the
name; anything else needs an href-escaped-ok: reason in the four lines above.

Two such reasons are recorded, for the two sites the check cannot see the safety
of: useMapAttribution's hrefs are module constants selected by engine type, and
export-public builds its rel entirely from encodeURIComponent one line earlier.

The sweep also cleared seven sites it first flagged -- three blob: URLs from
createObjectURL, two data: URLs from readAsDataURL, safeUrl(), and the
encodeURIComponent pair -- so the check now recognises those shapes instead of
reporting them.

Mutation-tested: reverting either fix alone turns the gate red. 6 self-tests
carry the founding bug and the safe shapes. gates:pre 65/66, the one red being
check:poster-action-print waiting on gospel's GiTree fix.
2026-09-29 05:26:27 +00:00
Doxa Maps
54df0de2a8 The map credit names the basemap that was actually drawn: OpenFreeMap / OpenMapTiles under MapLibre
addMapAttribution always credited "Mapbox · © OpenStreetMap". Under MapLibre the tiles are OpenFreeMap's
(OpenMapTiles on OpenStreetMap), so cities-internet, key-cities and gospel-resources credited Mapbox,
which served nothing, and omitted the OpenMapTiles credit (rega, row 28 at ccc2b1bb). The basemap credit
is now read from the map INSTANCE (instanceof maplibregl.Map, as setProjectionOn does): OpenFreeMap +
© OpenMapTiles + © OpenStreetMap contributors under MapLibre, Mapbox + © OpenStreetMap under Mapbox.
attributionText(provider) gives the print/PDF text per engine; ATTRIBUTION_TEXT is unchanged for
existing importers. check:map-attribution (headless, gates:post): 7 cases.
2026-09-26 08:51:38 +00:00
doxa-maps
d5ba21fa76 doxa-maps — portable bundler for embeddable JAMstack maps
Standalone repo that builds embeddable JAMstack map bundles (web components),
composes them into a lazy-loaded SPA via layouts/, and optionally wraps a
Capacitor Android/iOS app — one build, choose your output/CDN. Diátaxis docs.

History reset to a single clean commit; no PII, IPs, or internal terms.
2026-09-10 01:53:07 +00:00