File size: 944 Bytes
9e93b10
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import { REXPRO_BASE_URL } from '$lib/constants';

const PLACEHOLDER_IMAGE = '/favicon.png';

/**
 * Validates an image URL against an allowlist of safe patterns and returns
 * the URL if trusted, or a placeholder otherwise.
 *
 * Allowed patterns:
 *   - Relative paths (starting with '/')
 *   - data:image/* URIs
 *   - Same-origin URLs (starting with REXPRO_BASE_URL)
 *   - Gravatar URLs (https://www.gravatar.com/avatar/)
 *
 * All other URLs (including arbitrary http(s):// origins) are rejected to
 * prevent client-side IP/UA/Referer leaks to attacker-controlled servers.
 */
export function safeImageUrl(url: string): string {
	if (!url || url === '') {
		return `${REXPRO_BASE_URL}${PLACEHOLDER_IMAGE}`;
	}

	if (
		url.startsWith(REXPRO_BASE_URL) ||
		url.startsWith('https://www.gravatar.com/avatar/') ||
		url.startsWith('data:') ||
		url.startsWith('/')
	) {
		return url;
	}

	return `${REXPRO_BASE_URL}${PLACEHOLDER_IMAGE}`;
}