Files
puaros/packages/guardian/src/infrastructure/strategies/ValuePatternMatcher.ts

194 lines
5.8 KiB
TypeScript

import { VALUE_PATTERN_TYPES } from "../../shared/constants/ast-node-types"
/**
* Pattern matcher for detecting specific value types
*
* Provides pattern matching for emails, IPs, paths, dates, UUIDs, versions, and other common hardcoded values
*/
export class ValuePatternMatcher {
private static readonly EMAIL_PATTERN = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/
private static readonly IP_V4_PATTERN = /^(\d{1,3}\.){3}\d{1,3}$/
private static readonly IP_V6_PATTERN =
/^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^::([0-9a-fA-F]{1,4}:){0,6}[0-9a-fA-F]{1,4}$/
private static readonly DATE_ISO_PATTERN = /^\d{4}-\d{2}-\d{2}$/
private static readonly URL_PATTERN = /^https?:\/\/|^mongodb:\/\/|^postgresql:\/\//
private static readonly UNIX_PATH_PATTERN = /^\/[a-zA-Z0-9/_-]+/
private static readonly WINDOWS_PATH_PATTERN = /^[a-zA-Z]:\\[a-zA-Z0-9\\/_-]+/
private static readonly API_KEY_PATTERN = /^(sk_|pk_|api_|key_)[a-zA-Z0-9_-]{20,}$/
private static readonly UUID_PATTERN =
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i
private static readonly SEMVER_PATTERN = /^\d+\.\d+\.\d+(-[\w.-]+)?(\+[\w.-]+)?$/
private static readonly HEX_COLOR_PATTERN = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/
private static readonly MAC_ADDRESS_PATTERN = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/
private static readonly BASE64_PATTERN =
/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/
private static readonly JWT_PATTERN = /^eyJ[A-Za-z0-9-_]+\.eyJ[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+$/
/**
* Checks if value is an email address
*/
public isEmail(value: string): boolean {
return ValuePatternMatcher.EMAIL_PATTERN.test(value)
}
/**
* Checks if value is an IP address (v4 or v6)
*/
public isIpAddress(value: string): boolean {
return (
ValuePatternMatcher.IP_V4_PATTERN.test(value) ||
ValuePatternMatcher.IP_V6_PATTERN.test(value)
)
}
/**
* Checks if value is a date in ISO format
*/
public isDate(value: string): boolean {
return ValuePatternMatcher.DATE_ISO_PATTERN.test(value)
}
/**
* Checks if value is a URL
*/
public isUrl(value: string): boolean {
return ValuePatternMatcher.URL_PATTERN.test(value)
}
/**
* Checks if value is a file path (Unix or Windows)
*/
public isFilePath(value: string): boolean {
return (
ValuePatternMatcher.UNIX_PATH_PATTERN.test(value) ||
ValuePatternMatcher.WINDOWS_PATH_PATTERN.test(value)
)
}
/**
* Checks if value looks like an API key
*/
public isApiKey(value: string): boolean {
return ValuePatternMatcher.API_KEY_PATTERN.test(value)
}
/**
* Checks if value is a UUID
*/
public isUuid(value: string): boolean {
return ValuePatternMatcher.UUID_PATTERN.test(value)
}
/**
* Checks if value is a semantic version
*/
public isSemver(value: string): boolean {
return ValuePatternMatcher.SEMVER_PATTERN.test(value)
}
/**
* Checks if value is a hex color
*/
public isHexColor(value: string): boolean {
return ValuePatternMatcher.HEX_COLOR_PATTERN.test(value)
}
/**
* Checks if value is a MAC address
*/
public isMacAddress(value: string): boolean {
return ValuePatternMatcher.MAC_ADDRESS_PATTERN.test(value)
}
/**
* Checks if value is Base64 encoded (min length 20 to avoid false positives)
*/
public isBase64(value: string): boolean {
return value.length >= 20 && ValuePatternMatcher.BASE64_PATTERN.test(value)
}
/**
* Checks if value is a JWT token
*/
public isJwt(value: string): boolean {
return ValuePatternMatcher.JWT_PATTERN.test(value)
}
/**
* Detects the type of value
*/
public detectType(
value: string,
):
| "email"
| "url"
| "ip_address"
| "file_path"
| "date"
| "api_key"
| "uuid"
| "version"
| "color"
| "mac_address"
| "base64"
| null {
if (this.isEmail(value)) {
return VALUE_PATTERN_TYPES.EMAIL
}
if (this.isJwt(value)) {
return VALUE_PATTERN_TYPES.API_KEY
}
if (this.isApiKey(value)) {
return VALUE_PATTERN_TYPES.API_KEY
}
if (this.isUrl(value)) {
return VALUE_PATTERN_TYPES.URL
}
if (this.isIpAddress(value)) {
return VALUE_PATTERN_TYPES.IP_ADDRESS
}
if (this.isFilePath(value)) {
return VALUE_PATTERN_TYPES.FILE_PATH
}
if (this.isDate(value)) {
return VALUE_PATTERN_TYPES.DATE
}
if (this.isUuid(value)) {
return VALUE_PATTERN_TYPES.UUID
}
if (this.isSemver(value)) {
return VALUE_PATTERN_TYPES.VERSION
}
if (this.isHexColor(value)) {
return "color"
}
if (this.isMacAddress(value)) {
return VALUE_PATTERN_TYPES.MAC_ADDRESS
}
if (this.isBase64(value)) {
return VALUE_PATTERN_TYPES.BASE64
}
return null
}
/**
* Checks if value should be detected as hardcoded
*/
public shouldDetect(value: string): boolean {
return (
this.isEmail(value) ||
this.isUrl(value) ||
this.isIpAddress(value) ||
this.isFilePath(value) ||
this.isDate(value) ||
this.isApiKey(value) ||
this.isUuid(value) ||
this.isSemver(value) ||
this.isHexColor(value) ||
this.isMacAddress(value) ||
this.isBase64(value) ||
this.isJwt(value)
)
}
}