UNPKG

@ogcio/o11y-sdk-react

Version:

Opentelemetry standard instrumentation SDK for React based project

79 lines (78 loc) 2.61 kB
import { faro } 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) { let count = 0; const domains = {}; 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) { 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, source) { let kind = "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; }