Input Validation
Relevant source files
The following files were used as context for generating this wiki page:Input validation is a critical security and data integrity mechanism within gr8hopper. It ensures that all user-provided data, including route configurations, global settings, and API inputs, adheres to a strict set of rules. This prevents common vulnerabilities such as Cross-Site Scripting (XSS), CRLF injection, and Regular Expression Denial of Service (ReDoS), while also maintaining the stability and predictability of the redirect service.
Validation is implemented at multiple layers: on the client-side within the Admin UI for immediate feedback, and more comprehensively on the server-side for all API endpoints. The core validation logic is centralized in src/utils/validation.ts and is applied across the application, from handling admin API requests to initializing the server.
URL Validation
A primary function of the validation system is to ensure that all destination URLs (template) and fallback URLs are safe and well-formed. This is handled by the isValidUrlScheme and sanitizeUrl functions.
Sources: src/utils/validation.ts:101-137, SECURITY.md:37-39
URL Sanitization
Before any validation occurs, URLs are sanitized using the sanitizeUrl function. This function removes control characters (e.g., \x00-\x1F) to prevent security issues like CRLF injection.
Sources: src/utils/validation.ts:94-99
Scheme and Length Validation
The isValidUrlScheme function performs several checks on a sanitized URL:
- Length Check: Enforces a maximum URL length of 2048 characters.
- Dangerous Scheme Check: Blocks URLs that start with known dangerous schemes to prevent XSS and other attacks.
- Protocol-Relative URL Check: Blocks URLs starting with
//. - Allowed Scheme Check: If the URL is parsable, it ensures the protocol is either
http:orhttpshttps:.
The following diagram illustrates the URL validation flow.
Sources: src/utils/validation.ts:101-137
The lists of allowed and dangerous schemes are defined as constants.
| Type | Schemes | Source File |
|---|---|---|
| Allowed | http:, https:, | src/utils/validation.ts:8-9 |
| Dangerous | javascript:, data:, vbscript:, file:, about:, blob:, filesystem: | src/utils/validation.ts:14-17 |
Route Configuration Validation
When a route is created or updated via the Admin API, its configuration is rigorously validated by validateRouteConfigWithReason or validateRoutePatch.
Sources: src/utils/validation.ts:376-413, src/handlers/admin.ts:70, src/handlers/admin.ts:100
Validation Process
The following sequence diagram shows the validation process when a new route is created through the Admin UI.
Route Field Validation
| Field | Type | Validation Rules | Source |
|---|---|---|---|
template | string | Must be a non-empty string. Must pass sanitizeUrl and isValidUrlScheme validation. | [src/utils/validation.ts:385-399](https://github.com/dima6312/gr8hopper/blob/HEAD/src/utils/validation.ts#L385-L399) |
active | boolean | Must be a boolean. | [src/utils/validation.ts:389-391](https://github.com/dima6312/gr8hopper/blob/HEAD/src/utils/validation.ts#L389-L391) |
passthrough | boolean | Optional. If provided, must be a boolean. Defaults to false. | [src/utils/validation.ts:401-406](https://github.com/dima6312/gr8hopper/blob/HEAD/src/utils/validation.ts#L401-L406) |
Route ID / Pattern Validation
Route IDs can be simple strings or complex patterns for dynamic matching. The validateRouteIdPattern function ensures these patterns are syntactically correct.
Sources: src/utils/validation.ts:34-88, test/validation.test.ts
Validation Logic
The function performs the following checks:
- Required: The ID cannot be empty.
- Balanced Braces: Ensures every
{has a corresponding}and they are not nested. - Path Segment Validation: Splits the pattern into path segments and validates each one using
validatePathSegment. This checks for valid placeholder syntax ({param},{param?},{param=default},:param,:param?) and wildcards (*,**). - Query String Validation: If a
?is present, the query string portion is validated byvalidateQueryStringto ensure parameter specifications are correct.
This logic is tested in test/validation.test.ts, which provides examples of valid and invalid patterns.
| Status | Example Patterns | Source |
|---|---|---|
| Valid | shop/{id}, files/**, blog/:slug?, product/{id}?lang={lang} | [test/validation.test.ts:6-16](https://github.com/dima6312/gr8hopper/blob/HEAD/test/validation.test.ts#L6-L16) |
| Invalid | shop/{}, shop/{id, shop/{id}{slug}, product/{id}?lang={} | [test/validation.test.ts:22-32](https://github.com/dima6312/gr8hopper/blob/HEAD/test/validation.test.ts#L22-L32) |
Global Settings Validation
Global settings are validated on server startup and when updated via the Admin API using validateSettings or validateSettingsWithReason.
Sources: src/utils/validation.ts:444-480, src/server.ts:143-153
Settings Field Validation
| Field | Type | Validation Rules | Source |
|---|---|---|---|
fallback_url | string | Must be a string. If not empty, it is sanitized with sanitizeUrl and validated with isValidUrlScheme. | [src/utils/validation.ts:453-462](https://github.com/dima6312/gr8hopper/blob/HEAD/src/utils/validation.ts#L453-L462) |
cache_ttl | number | Must be a finite, non-negative number. | [src/utils/validation.ts:451-452](https://github.com/dima6312/gr8hopper/blob/HEAD/src/utils/validation.ts#L451-L452) |
route_param | string | Must be a non-empty string. It is trimmed, converted to lowercase, and stripped of non-alphanumeric characters. | [src/utils/validation.ts:464-467](https://github.com/dima6312/gr8hopper/blob/HEAD/src/utils/validation.ts#L464-L467) |
The Node.js server entrypoint ensures the storage is initialized, which involves loading and validating these settings from the JSON configuration file.
Sources: src/server.ts:143-153
Client-Side Validation
The Admin UI, defined in src/admin-html.ts, implements client-side validation to provide immediate user feedback and reduce invalid API requests.
Route ID Sanitization
The "Route ID / Path" input field has an event listener that sanitizes the input in real-time.
// from src/admin-html.ts
document.getElementById('route-id').addEventListener('input', (e) => {
const input = e.target;
input.value = input.value.toLowerCase().replace(/[^a-z0-9/{}.?&=:*-]/g, '');
});
This script ensures that only allowed characters for route IDs and patterns are entered.
Sources: src/admin-html.ts:1196-1199
Destination URL Sanitization
Similarly, the "Destination URL" input automatically strips the http:// or https:// prefix, as the system standardizes on prepending https:// on the backend.
// from src/admin-html.ts
document.getElementById('route-template').addEventListener('input', (e) => {
const input = e.target;
input.value = input.value.replace(/^https?:\\/\\//i, '');
});
Sources: src/admin-html.ts:1202-1205
Conclusion
The input validation system in gr8hopper is a comprehensive, multi-layered defense that is fundamental to the application's security and reliability. By centralizing validation logic and applying it at every data entry point—from the client-side UI to the server-side API and initial configuration loading—the system effectively prevents malformed data and protects against a range of potential security vulnerabilities. This strict validation of URLs, route configurations, and global settings ensures that the redirect engine operates on clean, predictable, and safe data.