UNPKG

@ogcio/o11y-sdk-react

Version:

Opentelemetry standard instrumentation SDK for React based project

97 lines (87 loc) 2.68 kB
import { faro, TransportItemType } from "@grafana/faro-web-sdk"; const EMAIL_REGEX = /[a-zA-Z0-9._%+-]+@([a-zA-Z0-9.-]+\.[a-z]{2,})/gi; /** * Redacts all email addresses in the input string and collects metadata. * * @param {string} value The input string potentially containing email addresses. * @returns {{ * redacted: string, * count: number, * domains: Record<string, number> * }} * * An object containing: * - `redacted`: the string with email addresses replaced by `[REDACTED EMAIL]` * - `count`: total number of email addresses redacted * - `domains`: a map of domain names to the number of times they were redacted */ function _redactEmails(value: string): { redacted: string; count: number; domains: Record<string, number>; } { let count = 0; const domains: Record<string, number> = {}; const redacted = value.replace(EMAIL_REGEX, (_, domain) => { count++; domains[domain] = (domains[domain] || 0) + 1; return "[REDACTED EMAIL]"; }); return { redacted, count, domains }; } /** * Checks whether a string contains URI-encoded components. * * @param {string} value - The string to inspect. * @returns {boolean} `true` if the string is encoded, `false` otherwise. */ function _containsEncodedComponents(value: string) { try { return decodeURI(value) !== decodeURIComponent(value); } catch { return false; } } /** * Cleans a string by redacting email addresses and emitting metrics for PII. * * If the string is URL-encoded, it will be decoded before redaction. * Metrics are emitted for each domain found in redacted email addresses. * * @param {string} value - The input string to sanitize. * @param {TransportItemType} source - The source context of the input. * @returns {string} The cleaned string with any email addresses replaced by `[REDACTED EMAIL]`. */ export function _cleanStringPII( value: string, source: TransportItemType, ): string { let kind: "string" | "url" = "string"; let decodedValue = value; if (_containsEncodedComponents(value)) { decodedValue = decodeURIComponent(value); kind = "url"; } const { redacted, count, domains } = _redactEmails(decodedValue); if (count > 0) { for (const [domain, domainCount] of Object.entries(domains)) { faro.api.pushMeasurement( { type: "faro_o11y_pii_redaction", values: { redacted: domainCount, }, }, { context: { pii_type: "email", redaction_source: source, pii_email_domain: domain, pii_format: kind, }, }, ); } } return redacted; }