@snowcone-app/mockup-resolver
v1.0.3
Published
URL signing and verification Cloudflare Worker
Readme
Mockup Resolver
A Cloudflare Worker that resolves, authenticates, and redirects mockup requests. Signing/verifying URLs (HMAC-SHA256) is part of what it does.
Features
- Sign URLs with a truncated HMAC-SHA256 signature
- Verify URL signatures
- Secure implementation using Web Crypto API
- Timing-safe comparison for security against timing attacks
- Dual authentication methods:
- API Key authentication
- Client ID + Origin authentication
- Local KV storage for development
- Edge-optimized deployment through Cloudflare Workers
Development
# Install dependencies
pnpm install
# Seed the local KV store with test data
pnpm run seed:local
# Start local development server (default port 8102)
pnpm run dev:local
# Check if the service is running correctly
pnpm run check
# Run tests
pnpm run test
# Deploy to Cloudflare
pnpm deployDeployment to Cloudflare Edge Network
This service is deployed to Cloudflare Workers using a hybrid approach:
- Application code lives in
workers/mockup-resolver/ - Infrastructure code lives in
infra/cloudflare/ - Build scripts bridge the gap between application and infrastructure
Deployment Process
# Build the worker for deployment to Cloudflare
pnpm build:worker
# Update routes in the API router
pnpm update:routes
# Deploy just the mockup resolver worker to Cloudflare
pnpm deploy:worker
# Deploy the entire edge infrastructure including mockup resolver
pnpm deploy:worker:prodAutomatic Deployment
The mockup resolver worker is automatically deployed to Cloudflare when:
- Changes are pushed to the
mainbranch that affect:workers/mockup-resolver/**infra/cloudflare/**
- The GitHub workflow is manually triggered
File Structure
worker.js- Core worker implementation that gets packaged for Cloudflarecloudflare-routes.js- Route definitions for the mockup resolverscripts/build-worker.js- Script to build and copy the worker to infrastructurescripts/update-routes.js- Script to update routes in the API router
Accessing the Service
After deployment, the mockup resolver service is accessible at:
/v1/url-signer/sign- For signing URLs/v1/url-signer/verify- For verifying signed URLs
Mockup Resolver Routes
Example usage:
# Sign a URL
curl "https://api.snowcone.app/v1/url-signer/sign?url=https://example.com/resource.jpg"
# Verify a signed URL
curl "https://api.snowcone.app/v1/url-signer/verify?url=https://example.com/resource.jpg?signature=xxx&expires=123456789"Blank items (asset=default)
A reserved asset value renders a blank (un-printed) item, for every shop with
zero setup. Pass default in place of an artwork URL:
https://img.snowcone.app/{productCode}?asset=default&shop=...
https://img.snowcone.app/{productCode}?asset.front=default&shop=... # per-placementThe resolver substitutes the transparent /_blank.png this worker serves itself
(1×1, composites to nothing → a bare mockup). No hosting, no allowlist entry, no
per-shop setup.
Because the resolver injects this asset, it is exempt from the L2 asset-origin
allowlist by provenance (L2 only polices developer-supplied hosts). Omitting
artwork entirely still returns 400 — default is an explicit opt-in.
Future: a per-shop brand override could resolve default to the shop's own mark
instead of the transparent blank — the same URL, no caller change. Not built yet.
Configuration
The service is configured using wrangler.toml:
[dev]
port = 8102 # Local development port
[vars]
URL_SIGNING_SECRET = "your-secret-key" # Secret for signing URLs
[[kv_namespaces]]
binding = "API_KEYS" # KV namespace for API keys
id = "local" # Will be replaced in production
[[kv_namespaces]]
binding = "CLIENT_ORIGINS" # KV namespace for client origins
id = "local" # Will be replaced in productionAuthentication
The mockup resolver supports two authentication methods:
1. API Key Authentication
Use an API key in the x-api-key header:
curl -H "x-api-key: your-api-key" \
"http://localhost:8102/sign?url=https://example.com/image.jpg"API keys are stored in the API_KEYS KV namespace.
2. Client ID + Origin Authentication
For browser clients, use the clientId URL parameter:
curl -H "Origin: http://localhost:3000" \
"http://localhost:8102/sign?url=https://example.com/image.jpg&clientId=your_client_id"Allowed origins for each client are stored in the CLIENT_ORIGINS KV namespace.
API Endpoints
Sign a URL
GET /sign?url=https://example.com/pathHeaders (one of the following authentication methods is required):
x-api-key: your-api-keyOrigin: https://your-allowed-origin.com+ URL parameterclientId=your_client_id
Response:
{
"signature": "a1b2c3d4e5f6g7h8"
}Verify a URL signature
GET /verify?url=https://example.com/path&signature=a1b2c3d4e5f6g7h8Headers (one of the following authentication methods is required):
x-api-key: your-api-keyOrigin: https://your-allowed-origin.com+ URL parameterclientId=your_client_id
Response:
{
"valid": true
}KV Namespaces
The mockup resolver uses two KV namespaces:
API_KEYS
Stores API keys with the following format:
- Key:
api-key-value(e.g., "test-api-key-1") - Value: Client identifier (e.g., "client_1")
CLIENT_ORIGINS
Stores allowed origins for each client with the following format:
- Key: Client identifier (e.g., "client_1")
- Value: JSON array of allowed origins (e.g.,
["https://example.com", "https://app.example.com", "*.example.com"])
Origins can be specified in two ways:
- Exact match: e.g., "https://example.com"
- Wildcard pattern: e.g., "*.example.com" - matches any subdomain of example.com
Note: Wildcard patterns only match subdomains. For example, "*.example.com" will match "sub.example.com" but not "example.com" itself.
Testing
A comprehensive test suite is included in scripts/test-mockup-resolver.ts. Run the tests with:
pnpm run testThe test suite verifies:
- API key authentication
- Client ID + Origin authentication
- URL signing and verification
- Error handling
Security Notes
- Uses Web Crypto API for cryptographic operations
- Implements timing-safe comparison to prevent timing attacks
- Truncates signatures to 8 bytes (64 bits) for URL friendliness while maintaining security
- Validates origins to prevent cross-site request forgery
- Requires authentication for all operations
Production Deployment
When deploying to production:
- Create KV namespaces in your Cloudflare account
- Update the
wrangler.tomlfile with your KV namespace IDs - Set a strong
URL_SIGNING_SECRETenvironment variable - Seed your production KV namespaces with real API keys and client origins
- Deploy the worker with
pnpm deploy
