Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kody/aws

src/redact.ts

50 lines · 1.8 KB · TypeScript
const ACCESS_KEY_PATTERN = /\b(A[KS]IA[A-Z0-9]{16})\b/g
const SECRET_KEY_PATTERN =
	/(?:aws_secret_access_key|secret[_-]?access[_-]?key|secretAccessKey)\s*[:=]\s*["']?[A-Za-z0-9/+=]{20,}["']?/gi
const PRIVATE_KEY_PATTERN =
	/-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g
const SESSION_TOKEN_PATTERN =
	/(?:aws_session_token|sessionToken|x-amz-security-token)\s*[:=]\s*["']?[A-Za-z0-9/+=]{20,}["']?/gi
const PLACEHOLDER_PATTERN = /\{\{secret:[A-Za-z0-9._-]+(?:\|[^}]*)?\}\}/g

export function looksLikeCredentialText(value: string): boolean {
	return (
		ACCESS_KEY_PATTERN.test(value) ||
		SECRET_KEY_PATTERN.test(value) ||
		PRIVATE_KEY_PATTERN.test(value) ||
		SESSION_TOKEN_PATTERN.test(value) ||
		PLACEHOLDER_PATTERN.test(value)
	)
}

export function redactSecrets(value: string): string {
	return value
		.replace(PRIVATE_KEY_PATTERN, '[redacted-private-key]')
		.replace(SECRET_KEY_PATTERN, '[redacted-secret-key]')
		.replace(SESSION_TOKEN_PATTERN, '[redacted-session-token]')
		.replace(ACCESS_KEY_PATTERN, '[redacted-access-key]')
		.replace(PLACEHOLDER_PATTERN, '{{secret:<name>}}')
}

export function redactUnknown(value: unknown, depth = 0): unknown {
	if (depth > 6) return '[truncated]'
	if (typeof value === 'string') {
		const trimmed = value.length > 4000 ? value.slice(0, 4000) + '…' : value
		return redactSecrets(trimmed)
	}
	if (Array.isArray(value)) {
		return value.slice(0, 50).map((item) => redactUnknown(item, depth + 1))
	}
	if (value && typeof value === 'object') {
		const out: Record<string, unknown> = {}
		for (const [key, item] of Object.entries(value)) {
			if (/secret|token|password|authorization|credential/i.test(key)) {
				out[key] = '[redacted]'
				continue
			}
			out[key] = redactUnknown(item, depth + 1)
		}
		return out
	}
	return value
}