mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-19 13:36:48 +00:00
c8607ba234
image_url and website were bare strings in the contract, and the create/update bodies are open records, so the Zod pipe never looked at either. Both leave the database for something that treats them as a URL: the thumbnail is interpolated into hand-built marker HTML, and the homepage is handed to window.open, where a javascript: value would run in this origin rather than opening a page. Both are allow-listed on the way in now, next to hexColorSchema and checked in the handler the way validateRouteColor already is, on all three write surfaces so REST, the plugin RPC and MCP agree on what they accept. The entity schemas stay open: rows written before this still have to round-trip. safeHttpUrl covers the read side for exactly those rows, the same split safeHexColor uses, and the window.open calls it guards pick up noopener,noreferrer while they are being touched.
19 lines
914 B
TypeScript
19 lines
914 B
TypeScript
import { placeWebsiteSchema } from '@trek/shared'
|
|
|
|
/**
|
|
* Allow-list a URL before handing it to window.open.
|
|
*
|
|
* A place's website is a plain string in the older contracts, and it reaches
|
|
* window.open from the inspector, both sidebar context menus and the mobile
|
|
* place sheet. `window.open('javascript:…')` does not open a page — it evaluates
|
|
* the script in a fresh document that inherits this origin, so a co-traveller
|
|
* with place_edit could plant one and wait for someone to click Website.
|
|
*
|
|
* Server-side validation closes the write path. This closes the read path, which
|
|
* is what covers rows written before that validation existed and instances that
|
|
* have not updated yet — the same split as safeHexColor.
|
|
*/
|
|
export function safeHttpUrl(value: string | null | undefined): string | null {
|
|
return typeof value === 'string' && placeWebsiteSchema.safeParse(value).success ? value : null
|
|
}
|