How GeoLibre Implements Server-Side File Search and Remote Data Lookup
GeoLibre routes all file-search and remote-data requests through a secure, allow-listed edge worker in workers/tiles/src/ that validates upstream URLs, prevents open-proxy abuse, and re-emits responses with permissive CORS headers.
The GeoLibre file search functionality provides a safe intermediary layer between the front-end UI and external geospatial data sources. Rather than exposing an open proxy that could be exploited, the tiles worker forwards only pre-approved requests to trusted services like OpenAerialMap, HDX CKAN, Source Cooperative, and GitHub raw files. This architecture keeps sensitive upstream API keys and credentials server-side while giving browser clients seamless access to heterogeneous datasets.
Architecture of the File Search System
The search implementation divides cleanly between route definitions and security enforcement. All traffic flows through a Cloudflare edge worker with strict validation at every hop.
Core Components
-
workers/tiles/src/index.ts— Edge-caching worker that exposes named routes for searching remote datasets. Routes are tightly allow-listed; only defined URL patterns are forwarded to upstream services. -
workers/tiles/src/allowlisted-fetch.ts— Helper module that validates upstream URLs againstTILES_ALLOWED_URL_PREFIXESand follows redirects only while staying inside the allow-listed HTTPS prefix. Prevents open-proxy abuse with a hard redirect limit (TILES_MAX_REDIRECT_HOPS). -
Search Routes
/oam/meta— OpenAerialMap metadata search/ckan/search— HDX CKAN catalogue search/source-coop/...— Source Cooperative product metadata/github-raw/...— Raw file fetch from GitHub
-
CORS Layer — The worker fetches data server-side (bypassing browser CORS restrictions) and re-emits responses with
Access-Control-Allow-Origin: *. -
Edge Caching — Responses are cached at the Cloudflare edge using cache-control headers like
OAM_CACHE_CONTROL = "public, max-age=120"to reduce latency and upstream load.
Security Model
The file search architecture eliminates three common vulnerability classes:
- Open proxy prevention — Upstream URLs must match exact prefix allow-lists
- Redirect hijacking — Redirect chains are validated at every hop; any deviation aborts the request
- Information leakage — API keys and service credentials never reach the browser
How the Search Flow Works
Understanding the request lifecycle clarifies how GeoLibre balances flexibility with security.
Step-by-Step Request Processing
-
Front-end request — The UI issues a fetch to a worker route, e.g.
https://tiles.geolibre.app/ckan/search?q=earth&rows=20 -
Route handling —
index.tsmatches the path againstCKAN_SEARCH_PATHand extracts allowed query parameters (rejecting any unexpected keys) -
Upstream validation —
fetchAllowlistedUpstream()checks that the constructed target URL satisfiesTILES_ALLOWED_URL_PREFIXES -
Redirect safety — If the upstream returns a redirect (301–308), the helper follows only if the new location also matches the allow-list; otherwise it aborts with an error
-
CORS-wrapped response — The worker returns upstream JSON or binary data with
Access-Control-Allow-Origin: *, enabling cross-origin consumption regardless of upstream CORS policy
This five-stage pipeline ensures that even if a malicious client crafts requests, the allow-listed fetch layer blocks unauthorized destinations before any outbound connection opens.
Code Examples for File Search Endpoints
OpenAerialMap Metadata Search
Search satellite imagery metadata by bounding box:
// GET https://tiles.geolibre.app/oam/meta?bbox=-180,0,180,90&limit=10
const url = new URL('https://tiles.geolibre.app/oam/meta');
url.searchParams.set('bbox', '-180,0,180,90');
url.searchParams.set('limit', '10');
fetch(url.toString())
.then(r => r.json())
.then(data => console.log('OAM metadata:', data.results));
Route defined in [workers/tiles/src/index.ts](https://github.com/opengeos/GeoLibre/blob/main/workers/tiles/src/index.ts) — search for OAM_META_PATH and OAM_META_PARAMS.
HDX CKAN Catalogue Search
Query the Humanitarian Data Exchange for datasets:
// GET https://tiles.geolibre.app/ckan/search?q=water&rows=25
fetch('https://tiles.geolibre.app/ckan/search?q=water&rows=25')
.then(r => r.json())
.then(data => {
console.log(`Found ${data.count} datasets`);
data.results.forEach(r => console.log(r.title));
});
Upstream target configured via HDX_CKAN_SEARCH_UPSTREAM constant in [workers/tiles/src/index.ts](https://github.com/opengeos/GeoLibre/blob/main/workers/tiles/src/index.ts).
GitHub Raw File Fetch
Retrieve GeoJSON or other spatial files directly from repositories:
// GET https://tiles.geolibre.app/github-raw/owner/repo/raw/main/data.geojson
const owner = 'opengeos';
const repo = 'datasets';
const path = 'boundaries/countries.geojson';
fetch(`https://tiles.geolibre.app/github-raw/${owner}/${repo}/raw/main/${path}`)
.then(r => r.json())
.then(geojson => map.addLayer(geojson));
Path pattern defined in GITHUB_RAW_PATH and GITHUB_RAW_REPOSITORY_PATH within [workers/tiles/src/index.ts](https://github.com/opengeos/GeoLibre/blob/main/workers/tiles/src/index.ts).
Internal Allow-Listed Fetch
For adding new data sources, reuse the validation helper:
import { fetchAllowlistedUpstream } from './allowlisted-fetch';
const response = await fetchAllowlistedUpstream(
'https://source.coop/api/v1/products/xyz',
{
cf: { cacheTtl: 300 }, // Cache for 5 minutes at edge
}
);
Validation logic implemented in [workers/tiles/src/allowlisted-fetch.ts](https://github.com/opengeos/GeoLibre/blob/main/workers/tiles/src/allowlisted-fetch.ts).
Where the File Search Code Lives
| File | Purpose |
|---|---|
[workers/tiles/src/index.ts](https://github.com/opengeos/GeoLibre/blob/main/workers/tiles/src/index.ts) |
Route definitions for /oam/meta, /ckan/search, /source-coop/*, and /github-raw/* |
[workers/tiles/src/allowlisted-fetch.ts](https://github.com/opengeos/GeoLibre/blob/main/workers/tiles/src/allowlisted-fetch.ts) |
URL allow-list enforcement and safe redirect handling |
[workers/tiles/src/reproject.ts](https://github.com/opengeos/GeoLibre/blob/main/workers/tiles/src/reproject.ts) |
Tile reprojection logic supporting the/wms/* route |
[apps/geolibre-desktop/src/components/panels/LayerPanelPlaceSearch.tsx](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/components/panels/LayerPanelPlaceSearch.tsx) |
UI component invoking worker search endpoints |
[apps/geolibre-desktop/src/components/panels/LayerPanel.tsx](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/components/panels/LayerPanel.tsx) |
Layer picker integration for search results |
Adding New Search Sources
To extend the file search system with additional data providers:
-
Define upstream prefix — Add the base HTTPS URL to
TILES_ALLOWED_URL_PREFIXESin the worker environment -
Create route handler — In
index.ts, add a path constant (e.g.,NEW_SOURCE_PATH = '/new-source/search') and parameter allow-list -
Implement fetch logic — Use
fetchAllowlistedUpstream()with appropriate cache settings -
Add CORS headers — The helper automatically wraps responses; no additional work needed
-
Update front-end — Modify
LayerPanelPlaceSearch.tsxto render new result formats
This pattern maintains security invariants while rapidly onboarding new geospatial catalogs.
Performance Characteristics
| Aspect | Behavior |
|---|---|
| Cache hit latency | Sub-50ms from Cloudflare edge |
| Cache TTL | 120 seconds for OAM metadata (configurable per route) |
| Redirect limit | TILES_MAX_REDIRECT_HOPS prevents infinite chains |
| Payload size | Unrestricted for JSON; streaming for large binaries |
The edge-caching strategy is particularly effective for catalogue metadata that changes infrequently relative to tile requests.
Summary
-
GeoLibre's file search functionality lives in the
workers/tiles/src/directory as an edge-deployed worker -
Security is enforced by
fetchAllowlistedUpstream()inallowlisted-fetch.ts, which validates URLs against strict prefix lists and bounds redirect chains -
Four primary routes cover OpenAerialMap, HDX CKAN, Source Cooperative, and GitHub raw files—each with tailored parameter filtering
-
CORS and caching are handled transparently, returning permissive headers and edge-cached responses regardless of upstream policy
-
The front-end integration in
LayerPanelPlaceSearch.tsxconsumes these endpoints to populate the layer picker with remote datasets
Frequently Asked Questions
How does GeoLibre prevent open-proxy abuse in its file search?
GeoLibre prevents open-proxy abuse through prefix-based allow-listing in fetchAllowlistedUpstream(). Every upstream URL must match an entry in TILES_ALLOWED_URL_PREFIXES before any network request initiates. If a redirect occurs, the new location is re-validated against the same allow-list, and the TILES_MAX_REDIRECT_HOPS limit bounds traversal depth.
Can I use the file search worker for arbitrary URLs?
No. The worker only forwards requests to explicitly configured upstream services with known-good domains. Adding new sources requires deploying an updated worker with additional entries in TILES_ALLOWED_URL_PREFIXES. This design intentionally prevents abuse where attackers might attempt to scan internal networks or exfiltrate data through the worker.
What CORS headers does the file search worker return?
The worker returns Access-Control-Allow-Origin: * on all successful responses, enabling any origin to consume results. This is safe because the worker acts as a server-side intermediary—browser JavaScript never directly contacts upstream services, so their CORS policies become irrelevant.
Where is the search UI implemented in GeoLibre?
The search interface resides in [apps/geolibre-desktop/src/components/panels/LayerPanelPlaceSearch.tsx](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/components/panels/LayerPanelPlaceSearch.tsx). This component constructs fetch requests to worker endpoints, parses responses, and renders result lists. The parent [LayerPanel.tsx](https://github.com/opengeos/GeoLibre/blob/main/apps/geolibre-desktop/src/components/panels/LayerPanel.tsx) integrates selected results into the active map layers.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →