|
1 | 1 | const MAX_OCI_ERROR_FIELD_LENGTH = 1024 |
| 2 | +const MAX_OCI_ERROR_INPUT_LENGTH = 8192 |
| 3 | +const MAX_NESTED_JSON_DEPTH = 3 |
| 4 | +const SENSITIVE_JSON_FIELDS = new Set([ |
| 5 | + 'authorization', |
| 6 | + 'passphrase', |
| 7 | + 'privatekey', |
| 8 | + 'proxyauthorization', |
| 9 | + 'signingstring', |
| 10 | +]) |
| 11 | + |
| 12 | +function flattenJsonDiagnostic(value: unknown, depth = 0): string | undefined { |
| 13 | + if (depth > MAX_NESTED_JSON_DEPTH || value === null) return undefined |
| 14 | + if (typeof value === 'string') return value |
| 15 | + if (typeof value === 'number' || typeof value === 'boolean') return String(value) |
| 16 | + if (Array.isArray(value)) { |
| 17 | + return value |
| 18 | + .map((entry) => flattenJsonDiagnostic(entry, depth + 1)) |
| 19 | + .filter((entry): entry is string => entry !== undefined) |
| 20 | + .join(' ') |
| 21 | + } |
| 22 | + if (typeof value !== 'object') return undefined |
| 23 | + return Object.entries(value) |
| 24 | + .map(([key, entry]) => { |
| 25 | + const normalizedKey = key.replace(/[^a-z]/gi, '').toLowerCase() |
| 26 | + if (SENSITIVE_JSON_FIELDS.has(normalizedKey)) return `${key}: [redacted]` |
| 27 | + const flattened = flattenJsonDiagnostic(entry, depth + 1) |
| 28 | + return flattened === undefined ? undefined : `${key}: ${flattened}` |
| 29 | + }) |
| 30 | + .filter((entry): entry is string => entry !== undefined) |
| 31 | + .join(' ') |
| 32 | +} |
| 33 | + |
| 34 | +function decodeNestedJsonDiagnostic(value: string): string { |
| 35 | + let decoded = value.slice(0, MAX_OCI_ERROR_INPUT_LENGTH) |
| 36 | + for (let depth = 0; depth < MAX_NESTED_JSON_DEPTH; depth += 1) { |
| 37 | + let parsed: unknown |
| 38 | + try { |
| 39 | + parsed = JSON.parse(decoded) |
| 40 | + } catch { |
| 41 | + break |
| 42 | + } |
| 43 | + const flattened = flattenJsonDiagnostic(parsed) |
| 44 | + if (flattened === undefined || flattened === decoded) break |
| 45 | + decoded = flattened.slice(0, MAX_OCI_ERROR_INPUT_LENGTH) |
| 46 | + } |
| 47 | + return decoded |
| 48 | +} |
2 | 49 |
|
3 | 50 | function sanitizeOciErrorField( |
4 | 51 | value: unknown, |
5 | 52 | sensitiveValues: readonly string[] = [] |
6 | 53 | ): string | undefined { |
7 | 54 | if (typeof value !== 'string') return undefined |
8 | | - let sanitized = value |
| 55 | + let sanitized = decodeNestedJsonDiagnostic(value) |
9 | 56 | .replace(/-----BEGIN[\s\S]*/gi, '[redacted-key]') |
10 | 57 | .replace(/https?:\/\/[^\s"']+/gi, '[redacted-url]') |
11 | 58 | .replace(/Signature\s+version="1",[^\r\n]*/gi, '[redacted-authorization]') |
|
0 commit comments