Skip to content

Commit

Permalink
Merge pull request #6 from danilofuchs/chore/export-types
Browse files Browse the repository at this point in the history
chore: Export all TS types
  • Loading branch information
alanpcs authored Jan 19, 2021
2 parents 7afa65d + aab3c4a commit 2d5f82b
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 37 deletions.
1 change: 1 addition & 0 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { redactIt } from "./src/redact-it";
export * from "./typings";
25 changes: 17 additions & 8 deletions src/redact-it.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import {
Mask,
RedactIt,
RedacItConfig,
RedactItConfig,
ReplacerFunction,
PercentageMask,
CenterPercentageMask,
} from "../typings";

const percentageValueMasker = (
value: any,
mask: PercentageMask
mask: PercentageMask | CenterPercentageMask
): string | undefined => {
const redactor = mask.redactWith ?? "•";
const percentage = mask.percentage ?? 100;
const complementary = mask.complementary ?? false;
const complementary =
(mask.position === "center" && mask.complementary) ?? false;
const position = mask.position ?? "left";

const finalRedactor = (p1: string): string =>
Expand All @@ -29,21 +31,28 @@ const percentageValueMasker = (
if (position === "center") {
return `(.{${unmaskedLength / 2}})(.{${maskedLength}})(.+)`;
}
if (position === "right") {
return `(.{${unmaskedLength}})(.{${maskedLength}})`;
}
return `(.{${maskedLength}})(.{${unmaskedLength}})`;
};

const regex = new RegExp(regexString());

const masoq = (_match: any, p1: string, p2: string, p3?: string): string => {
if (p3 && complementary) {
// Center + complementary
return `${finalRedactor(p1)}${p2}${finalRedactor(p3)}`;
}
if (p3) {
// Center
return `${p1}${finalRedactor(p2)}${p3}`;
}
if (complementary || (position === "right" && !complementary)) {
if (position === "right") {
// Right
return `${p1}${finalRedactor(p2)}`;
}
// Left
return `${finalRedactor(p1)}${p2}`;
};

Expand All @@ -53,25 +62,25 @@ const percentageValueMasker = (
};

export const redactIt: RedactIt = (
configs?: RedacItConfig | RedacItConfig[]
configs?: RedactItConfig | RedactItConfig[]
): ReplacerFunction => {
const defaultMask: Mask = {
type: "replace",
redactWith: "[redacted]",
};

const defaultOptions: RedacItConfig = {
const defaultOptions: RedactItConfig = {
fields: ["password"],
mask: defaultMask,
};

const mappedFields: Map<string | RegExp, Mask> = new Map();

const optionsArray: RedacItConfig[] = Array.isArray(configs)
const optionsArray: RedactItConfig[] = Array.isArray(configs)
? configs
: [configs ?? defaultOptions];

optionsArray.forEach((option: RedacItConfig) => {
optionsArray.forEach((option: RedactItConfig) => {
option.fields.forEach((field) => {
mappedFields.set(field, option.mask ?? defaultMask);
});
Expand Down
46 changes: 37 additions & 9 deletions test/unit/redact-it.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,39 +129,41 @@ describe("Redact-it - Single configs argument", () => {
expect(JSON.parse(stringResult).card.number).to.be.eq("************4321");
});

it("should redact the last 4 digits of a 16 digits value when a 75% complementary percentage mask is used", async () => {
it("should redact the middle digits when position center is used", async () => {
const myData = { ...defaultObject };
const replacerFunction: ReplacerFunction = redactIt({
fields: ["number"],
fields: ["email"],
mask: {
type: "percentage",
redactWith: "*",
percentage: 75,
complementary: true,
percentage: 50,
position: "center",
},
});

const stringResult = JSON.stringify(myData, replacerFunction);

expect(JSON.parse(stringResult).card.number).to.be.eq("123456788765****");
expect(JSON.parse(stringResult).email).to.be.eq(
"foo123*************ar.com"
);
});

it("should redact the middle digits when position center is used", async () => {
it("should redact the last digits when position right is used", async () => {
const myData = { ...defaultObject };
const replacerFunction: ReplacerFunction = redactIt({
fields: ["email"],
mask: {
type: "percentage",
redactWith: "*",
percentage: 50,
position: "center",
percentage: 75,
position: "right",
},
});

const stringResult = JSON.stringify(myData, replacerFunction);

expect(JSON.parse(stringResult).email).to.be.eq(
"foo123*************ar.com"
"foo123*******************"
);
});

Expand Down Expand Up @@ -300,4 +302,30 @@ describe("Redact-it - Multiple configs argument", () => {
authorization: "•••••case",
});
});

it("overrides configs for same field", () => {
const myData = { ...defaultObject };
const replacerFunction = redactIt([
{
fields: ["email", "name"],
mask: {
type: "replace",
redactWith: "firstRule",
},
},
{
fields: ["email"],
mask: {
type: "replace",
redactWith: "secondRule",
},
},
]);

const stringResult = JSON.stringify(myData, replacerFunction);
const parsedResult = JSON.parse(stringResult);

expect(parsedResult.name).to.be.equal("firstRule");
expect(parsedResult.email).to.be.equal("secondRule");
});
});
72 changes: 52 additions & 20 deletions typings/index.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,77 @@
/**
* Mask options
* @param {string} type - Type of the mask to be applied
* @param {string} redactWith - Character or word to be used as the redacted part
* @param {number} percentage - Percentage of the value to apply the mask on
* @param {boolean} complementary - Whether the complemetary part of the percentage should be masked
*/
export type Mask = PercentageMask | UndefineMask | ReplaceMask;
export type Mask =
| PercentageMask
| CenterPercentageMask
| UndefineMask
| ReplaceMask;

export interface PercentageMask {
type: "percentage";
redactWith?: "*" | "•" | "[redacted]" | string;
/**
* Character to be used as the redacted part
* @default "•"
*/
redactWith?: "*" | "•" | string;
/**
* Percentage of the value to apply the mask on
* @default 100
*/
percentage?: number;
/**
* Which part of the value to redact
* @default "left"
*/
position?: "left" | "right";
}

export interface CenterPercentageMask {
type: "percentage";
position: "center";
/**
* Character to be used as the redacted part
* @default "•"
*/
redactWith?: "*" | "•" | string;
/**
* Percentage of the value to apply the mask on
* @default 100
*/
percentage?: number;
/**
* Whether the complementary part of the percentage should be masked
* @default false
*/
complementary?: boolean;
position?: "left" | "center" | "right";
}

export interface UndefineMask {
type: "undefine";
}
export interface ReplaceMask {
type: "replace";
/**
* Replace the value entirely with this string
* @default "[redacted]"
*/
redactWith: "[redacted]" | string;
}

/**
* Redact-it configs to customize how and which fields are going to be redacted
* @param {string[]} fields - Field names to redact
* @param {Mask} mask - Which mask to apply
*/
export interface RedacItConfig {
/** Redact-it configs to customize how and which fields are going to be redacted */
export interface RedactItConfig {
/** Field names to redact */
fields: (string | RegExp)[];
/** Which mask to apply */
mask?: Mask;
}

/** A replacer function compatible with JSON.stringify */
export type ReplacerFunction = (key: any, value: any) => any;

/**
* A function that takes the argument and creates a replacer function
* The arguement may be a single object of the RedacItConfig type or an array of these objects
* @param {RedacItConfig | RedacItConfig[]} configs - RedacItConfig to customize the redact function
* @param {function} replacer - A replacer function compatible with JSON.stringify
* The argument may be a single object of the RedactItConfig type or an array of these objects
* @param {RedactItConfig | RedactItConfig[]} configs - RedactItConfig to customize the redact function
* @return {ReplacerFunction} replacer - A replacer function compatible with JSON.stringify
*/
export type RedactIt = (
configs?: RedacItConfig | RedacItConfig[]
configs?: RedactItConfig | RedactItConfig[]
) => ReplacerFunction;

0 comments on commit 2d5f82b

Please sign in to comment.