mirror of
https://github.com/formbricks/formbricks.git
synced 2026-04-21 11:30:27 -05:00
84294f9df2
Co-authored-by: Matthias Nannt <mail@matthiasnannt.com>
122 lines
2.9 KiB
TypeScript
122 lines
2.9 KiB
TypeScript
import { isStringUrl } from "@/lib/utils/url";
|
|
|
|
const SENSITIVE_KEYS = [
|
|
"email",
|
|
"name",
|
|
"password",
|
|
"access_token",
|
|
"refresh_token",
|
|
"id_token",
|
|
"twofactorsecret",
|
|
"backupcodes",
|
|
"session_state",
|
|
"provideraccountid",
|
|
"imageurl",
|
|
"identityprovideraccountid",
|
|
"locale",
|
|
"token",
|
|
"key",
|
|
"secret",
|
|
"code",
|
|
"address",
|
|
"phone",
|
|
"hashedkey",
|
|
"apikey",
|
|
"createdby",
|
|
"lastusedat",
|
|
"expiresat",
|
|
"acceptorid",
|
|
"creatorid",
|
|
"firstname",
|
|
"lastname",
|
|
"userid",
|
|
"attributes",
|
|
"pin",
|
|
"image",
|
|
"stripeCustomerId",
|
|
"fileName",
|
|
"state",
|
|
];
|
|
|
|
const URL_SENSITIVE_KEYS = ["token", "code", "state"];
|
|
|
|
/**
|
|
* Redacts sensitive data from the object by replacing the sensitive keys with "********".
|
|
* @param obj - The object to redact.
|
|
* @returns The object with the sensitive data redacted.
|
|
*/
|
|
export const redactPII = (obj: any, seen: WeakSet<any> = new WeakSet()): any => {
|
|
if (obj instanceof Date) {
|
|
return obj.toISOString();
|
|
}
|
|
|
|
if (typeof obj === "string" && isStringUrl(obj)) {
|
|
return sanitizeUrlForLogging(obj);
|
|
}
|
|
|
|
if (obj && typeof obj === "object") {
|
|
if (seen.has(obj)) return "[Circular]";
|
|
seen.add(obj);
|
|
}
|
|
if (Array.isArray(obj)) {
|
|
return obj.map((v) => redactPII(v, seen));
|
|
}
|
|
if (obj && typeof obj === "object") {
|
|
return Object.fromEntries(
|
|
Object.entries(obj).map(([key, value]) => {
|
|
if (SENSITIVE_KEYS.some((sensitiveKey) => key.toLowerCase() === sensitiveKey)) {
|
|
return [key, "********"];
|
|
}
|
|
return [key, redactPII(value, seen)];
|
|
})
|
|
);
|
|
}
|
|
return obj;
|
|
};
|
|
|
|
/**
|
|
* Computes the difference between two objects and returns the new object with the changes.
|
|
* @param oldObj - The old object.
|
|
* @param newObj - The new object.
|
|
* @returns The difference between the two objects.
|
|
*/
|
|
export const deepDiff = (oldObj: any, newObj: any): any => {
|
|
if (typeof oldObj !== "object" || typeof newObj !== "object" || oldObj === null || newObj === null) {
|
|
if (JSON.stringify(oldObj) !== JSON.stringify(newObj)) {
|
|
return newObj;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
const diff: Record<string, any> = {};
|
|
const keys = new Set([...Object.keys(oldObj ?? {}), ...Object.keys(newObj ?? {})]);
|
|
for (const key of keys) {
|
|
const valueDiff = deepDiff(oldObj?.[key], newObj?.[key]);
|
|
if (valueDiff !== undefined) {
|
|
diff[key] = valueDiff;
|
|
}
|
|
}
|
|
return Object.keys(diff).length > 0 ? diff : undefined;
|
|
};
|
|
|
|
/**
|
|
* Sanitizes a URL for logging by redacting sensitive parameters.
|
|
* @param url - The URL to sanitize.
|
|
* @returns The sanitized URL.
|
|
*/
|
|
export const sanitizeUrlForLogging = (url: string): string => {
|
|
try {
|
|
const urlObj = new URL(url);
|
|
|
|
URL_SENSITIVE_KEYS.forEach((key) => {
|
|
if (urlObj.searchParams.has(key)) {
|
|
urlObj.searchParams.set(key, "********");
|
|
}
|
|
});
|
|
|
|
return urlObj.origin + urlObj.pathname + (urlObj.search ? `${urlObj.search}` : "");
|
|
} catch {
|
|
return "[invalid-url]";
|
|
}
|
|
};
|