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 against TILES_ALLOWED_URL_PREFIXES and 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:

  1. Open proxy prevention — Upstream URLs must match exact prefix allow-lists
  2. Redirect hijacking — Redirect chains are validated at every hop; any deviation aborts the request
  3. 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

  1. Front-end request — The UI issues a fetch to a worker route, e.g. https://tiles.geolibre.app/ckan/search?q=earth&rows=20

  2. Route handling — index.ts matches the path against CKAN_SEARCH_PATH and extracts allowed query parameters (rejecting any unexpected keys)

  3. Upstream validation — fetchAllowlistedUpstream() checks that the constructed target URL satisfies TILES_ALLOWED_URL_PREFIXES

  4. 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

  5. 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

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.

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:

  1. Define upstream prefix — Add the base HTTPS URL to TILES_ALLOWED_URL_PREFIXES in the worker environment

  2. Create route handler — In index.ts, add a path constant (e.g., NEW_SOURCE_PATH = '/new-source/search') and parameter allow-list

  3. Implement fetch logic — Use fetchAllowlistedUpstream() with appropriate cache settings

  4. Add CORS headers — The helper automatically wraps responses; no additional work needed

  5. Update front-end — Modify LayerPanelPlaceSearch.tsx to 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() in allowlisted-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.tsx consumes these endpoints to populate the layer picker with remote datasets

Frequently Asked Questions

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →