# How GeoLibre Implements Server-Side File Search and Remote Data Lookup

> Discover how GeoLibre implements secure server-side file search and remote data lookup using an edge worker to validate URLs, prevent proxy abuse, and ensure permissive CORS.

- Repository: [Open Geospatial Solutions/GeoLibre](https://github.com/opengeos/GeoLibre)
- Tags: how-to-guide
- Published: 2026-08-18

---

**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](https://github.com/opengeos/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`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/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

### OpenAerialMap Metadata Search

Search satellite imagery metadata by bounding box:

```typescript
// 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)](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:

```typescript
// 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)](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:

```typescript
// 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)](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:

```typescript
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)](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)](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)](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)](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)](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)](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`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/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`](https://github.com/opengeos/GeoLibre/blob/main/LayerPanelPlaceSearch.tsx) consumes 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)](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/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.