-
Notifications
You must be signed in to change notification settings - Fork 111
Expand file tree
/
Copy pathconfig-mask.utils.ts
More file actions
84 lines (74 loc) · 2.5 KB
/
Copy pathconfig-mask.utils.ts
File metadata and controls
84 lines (74 loc) · 2.5 KB
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import { envConfig } from '../config';
/**
* Sensitive key patterns for config value masking.
*
* Config keys matching any of these patterns (case-insensitive substring match)
* will have their values redacted when logged. Add new patterns here when
* introducing config fields that contain secrets, keys, passwords, or tokens.
*
* Current sensitive patterns:
* - `SECRET` — matches APP_SECRET, GOOGLE_CLIENT_SECRET, CLOUDINARY_API_SECRET,
* PAYSTACK_SECRET_KEY
* - `KEY` — matches PAYSTACK_SECRET_KEY, PAYSTACK_PUBLIC_KEY,
* CLOUDINARY_API_KEY
* - `PASSWORD` — matches GMAIL_APP_PASSWORD
* - `TOKEN` — reserved for future token-based config values
* - `DATABASE_URL` — contains embedded credentials (user:password@host)
*/
const SENSITIVE_KEY_PATTERNS = [
/SECRET/i,
/KEY/i,
/PASSWORD/i,
/TOKEN/i,
];
const SENSITIVE_EXACT_KEYS = ['DATABASE_URL'];
function isKeySensitive(key: string): boolean {
if (SENSITIVE_EXACT_KEYS.includes(key)) return true;
return SENSITIVE_KEY_PATTERNS.some((pattern) => pattern.test(key));
}
function maskDatabaseUrl(url: string): string {
try {
const parsed = new URL(url);
if (parsed.password) {
parsed.password = '***';
}
if (parsed.username) {
parsed.username = parsed.username ? '***' : '';
}
return parsed.toString();
} catch {
return '***';
}
}
function maskValue(key: string, value: unknown): unknown {
if (!isKeySensitive(key)) return value;
if (typeof value === 'string') {
if (key === 'DATABASE_URL') {
return maskDatabaseUrl(value);
}
if (value.length > 8) {
return value.slice(0, 4) + '***' + value.slice(-4);
}
}
return '***';
}
/**
* Returns a copy of the envConfig object with sensitive values redacted.
*
* Non-sensitive config values are returned as-is. Sensitive values are
* partially masked (first 4 and last 4 characters preserved when the value
* is a string longer than 8 characters; otherwise fully replaced with `'***'`).
* DATABASE_URL has its embedded password redacted while preserving the rest of
* the connection string.
*
* @example
* import { maskSensitiveConfigValues } from './utils/config-mask.utils';
* logger.info(maskSensitiveConfigValues(), 'Startup configuration summary');
*/
export function maskSensitiveConfigValues(): Record<string, unknown> {
const masked: Record<string, unknown> = {};
for (const [key, value] of Object.entries(envConfig)) {
masked[key] = maskValue(key, value);
}
return masked;
}