Merged in feature/redis (pull request #1478)
Distributed cache * cache deleteKey now uses an options object instead of a lonely argument variable fuzzy * merge * remove debug logs and cleanup * cleanup * add fault handling * add fault handling * add pid when logging redis client creation * add identifier when logging redis client creation * cleanup * feat: add redis-api as it's own app * feature: use http wrapper for redis * feat: add the possibility to fallback to unstable_cache * Add error handling if redis cache is unresponsive * add logging for unstable_cache * merge * don't cache errors * fix: metadatabase on branchdeploys * Handle when /en/destinations throws add ErrorBoundary * Add sentry-logging when ErrorBoundary catches exception * Fix error handling for distributed cache * cleanup code * Added Application Insights back * Update generateApiKeys script and remove duplicate * Merge branch 'feature/redis' of bitbucket.org:scandic-swap/web into feature/redis * merge Approved-by: Linus Flood
This commit is contained in:
committed by
Linus Flood
parent
a8304e543e
commit
fa63b20ed0
34
apps/redis-api/src/utils/logger.ts
Normal file
34
apps/redis-api/src/utils/logger.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import pino from "pino";
|
||||
import { mask } from "./mask";
|
||||
import { env } from "@/env";
|
||||
|
||||
const serializers: { [key: string]: pino.SerializerFn } = {
|
||||
password: (payload) => {
|
||||
if (payload) {
|
||||
return env.IS_DEV
|
||||
? mask(payload)
|
||||
: mask(payload, {
|
||||
visibleStart: 0,
|
||||
visibleEnd: 0,
|
||||
});
|
||||
}
|
||||
|
||||
return payload;
|
||||
},
|
||||
email: (payload) => {
|
||||
if (payload) {
|
||||
return env.IS_DEV ? payload : mask(payload);
|
||||
}
|
||||
return payload;
|
||||
},
|
||||
};
|
||||
|
||||
export const baseLogger = pino({
|
||||
level: process.env.LOG_LEVEL || "info",
|
||||
timestamp: pino.stdTimeFunctions.isoTime,
|
||||
serializers,
|
||||
});
|
||||
|
||||
export const loggerModule = (loggerName: string) => {
|
||||
return baseLogger.child({ module: loggerName });
|
||||
};
|
||||
42
apps/redis-api/src/utils/mask.test.ts
Normal file
42
apps/redis-api/src/utils/mask.test.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { describe, it, expect } from "bun:test";
|
||||
import { mask } from "./mask";
|
||||
|
||||
describe("mask", () => {
|
||||
it("should return empty string for empty input", () => {
|
||||
expect(mask("")).toBe("");
|
||||
});
|
||||
|
||||
it("should mask string with default parameters", () => {
|
||||
expect(mask("1234567890")).toBe("12******90");
|
||||
});
|
||||
|
||||
it("should show custom number of characters at start", () => {
|
||||
expect(mask("1234567890", { visibleStart: 3 })).toBe("123*****90");
|
||||
});
|
||||
|
||||
it("should show custom number of characters at end", () => {
|
||||
expect(mask("1234567890", { visibleStart: 2, visibleEnd: 3 })).toBe(
|
||||
"12*****890",
|
||||
);
|
||||
});
|
||||
|
||||
it("should mask entire string when visible parts exceed length", () => {
|
||||
expect(mask("123", { visibleStart: 2, visibleEnd: 2 })).toBe("***");
|
||||
});
|
||||
|
||||
it("should handle undefined end part", () => {
|
||||
expect(mask("1234567890", { visibleStart: 2, visibleEnd: 0 })).toBe(
|
||||
"12********",
|
||||
);
|
||||
});
|
||||
|
||||
it("should handle long strings", () => {
|
||||
expect(mask("12345678901234567890")).toBe("12**********90");
|
||||
});
|
||||
|
||||
it("should handle emails", () => {
|
||||
expect(mask("test.testsson@scandichotels.com")).toBe(
|
||||
"te*********on@sc*********ls.com",
|
||||
);
|
||||
});
|
||||
});
|
||||
42
apps/redis-api/src/utils/mask.ts
Normal file
42
apps/redis-api/src/utils/mask.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Masks a string by replacing characters with a mask character
|
||||
* @param value - The string to mask
|
||||
* @param visibleStart - Number of characters to show at start (default: 0)
|
||||
* @param visibleEnd - Number of characters to show at end (default: 4)
|
||||
* @param maskChar - Character to use for masking (default: '*')
|
||||
* @returns The masked string
|
||||
*/
|
||||
const maskChar = "*";
|
||||
export function mask(
|
||||
value: string,
|
||||
options?: { visibleStart?: number; visibleEnd?: number; maxLength?: number },
|
||||
): string {
|
||||
if (!value) return "";
|
||||
|
||||
const { visibleStart = 2, visibleEnd = 2, maxLength = 10 } = options ?? {};
|
||||
|
||||
if (isEmail(value)) {
|
||||
return maskEmail(value);
|
||||
}
|
||||
|
||||
const totalVisible = visibleStart + visibleEnd;
|
||||
if (value.length <= totalVisible) {
|
||||
return maskChar.repeat(value.length);
|
||||
}
|
||||
|
||||
const start = value.slice(0, visibleStart);
|
||||
const middle = value.slice(visibleStart, -visibleEnd || undefined);
|
||||
const end = visibleEnd ? value.slice(-visibleEnd) : "";
|
||||
|
||||
const maskedLength = Math.min(middle.length, maxLength);
|
||||
return start + maskChar.repeat(maskedLength) + end;
|
||||
}
|
||||
|
||||
function maskEmail(email: string): string {
|
||||
const [local, domain] = email.split("@");
|
||||
if (!domain || !local) return mask(email);
|
||||
const [subDomain, tld] = domain.split(/\.(?=[^.]+$)/);
|
||||
return `${mask(local)}@${mask(subDomain ?? "")}.${tld}`;
|
||||
}
|
||||
|
||||
const isEmail = (value: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value);
|
||||
Reference in New Issue
Block a user