@arcjet/redact 1.6.1 → 1.7.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +71 -0
- package/dist/index.js +123 -0
- package/package.json +33 -30
- package/index.d.ts +0 -68
- package/index.js +0 -159
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { SensitiveInfoEntity } from "@arcjet/redact-wasm";
|
|
2
|
+
|
|
3
|
+
//#region src/index.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Types of standard sensitive information that can be detected.
|
|
6
|
+
*/
|
|
7
|
+
type ArcjetSensitiveInfoType = Exclude<SensitiveInfoEntity["tag"], "custom">;
|
|
8
|
+
/**
|
|
9
|
+
* Options for the `redact` function.
|
|
10
|
+
*
|
|
11
|
+
* @template DetectedEntities
|
|
12
|
+
* Custom entity names that are returned from `detect` and optionally listed in `entities`.
|
|
13
|
+
* @template ListedEntities
|
|
14
|
+
* Entity names that can be listed in the `entities` option.
|
|
15
|
+
*/
|
|
16
|
+
type RedactOptions<DetectedEntities extends string | undefined = undefined, ListedEntities extends ArcjetSensitiveInfoType | Exclude<DetectedEntities, undefined> = ArcjetSensitiveInfoType | Exclude<DetectedEntities, undefined>> = {
|
|
17
|
+
/**
|
|
18
|
+
* Entities to redact.
|
|
19
|
+
*/
|
|
20
|
+
entities?: ReadonlyArray<ListedEntities | Exclude<DetectedEntities, undefined>>;
|
|
21
|
+
/**
|
|
22
|
+
* Size of tokens to consider.
|
|
23
|
+
*/
|
|
24
|
+
contextWindowSize?: number;
|
|
25
|
+
/**
|
|
26
|
+
* Custom detection function to identify sensitive information.
|
|
27
|
+
*
|
|
28
|
+
* @template DetectedEntities
|
|
29
|
+
* Custom entity names that are returned from `detect` and optionally listed in `entities`.
|
|
30
|
+
* @template ListedEntities
|
|
31
|
+
* Entity names that can be listed in the `entities` option.
|
|
32
|
+
* @param tokens
|
|
33
|
+
* Tokens.
|
|
34
|
+
* @returns
|
|
35
|
+
* List of entities (or undefined).
|
|
36
|
+
*/
|
|
37
|
+
detect?: (tokens: string[]) => ReadonlyArray<DetectedEntities>;
|
|
38
|
+
/**
|
|
39
|
+
* Custom replace function to redact sensitive information.
|
|
40
|
+
*
|
|
41
|
+
* @template DetectedEntities
|
|
42
|
+
* Custom entity names that are returned from `detect` and optionally listed in `entities`.
|
|
43
|
+
* @template ListedEntities
|
|
44
|
+
* Entity names that can be listed in the `entities` option.
|
|
45
|
+
* @param entity
|
|
46
|
+
* Entity to redact.
|
|
47
|
+
* @param plaintext
|
|
48
|
+
* The plaintext string to redact.
|
|
49
|
+
* @returns
|
|
50
|
+
* Redacted string or nothing.
|
|
51
|
+
*/
|
|
52
|
+
replace?: (entity: ListedEntities, plaintext: string) => string | undefined;
|
|
53
|
+
};
|
|
54
|
+
type Unredact = (input: string) => string;
|
|
55
|
+
/**
|
|
56
|
+
* Redact sensitive info.
|
|
57
|
+
*
|
|
58
|
+
* @template DetectedEntities
|
|
59
|
+
* Custom entity names that are returned from `detect` and optionally listed in `entities`.
|
|
60
|
+
* @template ListedEntities
|
|
61
|
+
* Entity names that can be listed in the `entities` option.
|
|
62
|
+
* @param candidate
|
|
63
|
+
* Value to redact.
|
|
64
|
+
* @param options
|
|
65
|
+
* Configuration.
|
|
66
|
+
* @returns
|
|
67
|
+
* Promise to a tuple with the redacted string and a function to unredact it.
|
|
68
|
+
*/
|
|
69
|
+
declare function redact<const DetectedEntities extends string | undefined = undefined, const ListedEntities extends ArcjetSensitiveInfoType | Exclude<DetectedEntities, undefined> = ArcjetSensitiveInfoType | Exclude<DetectedEntities, undefined>>(candidate: string, options?: RedactOptions<DetectedEntities, ListedEntities>): Promise<[string, Unredact]>;
|
|
70
|
+
//#endregion
|
|
71
|
+
export { ArcjetSensitiveInfoType, RedactOptions, redact };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { initializeWasm } from "@arcjet/redact-wasm";
|
|
2
|
+
//#region src/index.ts
|
|
3
|
+
/**
|
|
4
|
+
* Turn an entity name into a `SensitiveInfoEntity`.
|
|
5
|
+
*
|
|
6
|
+
* See also `protocolSensitiveInfoEntitiesToAnalyze` in `arcjet/index.ts`.
|
|
7
|
+
*
|
|
8
|
+
* @param entity
|
|
9
|
+
* Entity name.
|
|
10
|
+
* @returns
|
|
11
|
+
* Entity object.
|
|
12
|
+
*/
|
|
13
|
+
function userEntitiesToWasm(entity) {
|
|
14
|
+
if (typeof entity !== "string") throw new Error("redaction entities must be strings");
|
|
15
|
+
if (entity === "credit-card-number" || entity === "email" || entity === "ip-address" || entity === "phone-number") return { tag: entity };
|
|
16
|
+
return {
|
|
17
|
+
tag: "custom",
|
|
18
|
+
val: entity
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Turn a `SensitiveInfoEntity` object into its name.
|
|
23
|
+
*
|
|
24
|
+
* See also `analyzeSensitiveInfoEntitiesToString` in `arcjet/index.ts`.
|
|
25
|
+
*
|
|
26
|
+
* @param entity
|
|
27
|
+
* Entity object.
|
|
28
|
+
* @returns
|
|
29
|
+
* Entity name.
|
|
30
|
+
*/
|
|
31
|
+
function wasmEntitiesToString(entity) {
|
|
32
|
+
if (entity.tag === "credit-card-number" || entity.tag === "email" || entity.tag === "ip-address" || entity.tag === "phone-number") return entity.tag;
|
|
33
|
+
return entity.val;
|
|
34
|
+
}
|
|
35
|
+
function performReplacementInText(text, replacement, start, end) {
|
|
36
|
+
return text.substring(0, start) + replacement + text.substring(end);
|
|
37
|
+
}
|
|
38
|
+
/* c8 ignore start */
|
|
39
|
+
function noOpDetect(_tokens) {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
function noOpReplace(_input, _plaintext) {}
|
|
43
|
+
function getWasmOptions(options) {
|
|
44
|
+
if (typeof options === "object" && options !== null) {
|
|
45
|
+
const entities = options.entities;
|
|
46
|
+
if (entities !== void 0) {
|
|
47
|
+
if (!Array.isArray(entities)) throw new Error("entities must be an array");
|
|
48
|
+
if (entities.length < 1) throw new Error("no entities configured for redaction");
|
|
49
|
+
}
|
|
50
|
+
return entities ? {
|
|
51
|
+
entities: entities.map(userEntitiesToWasm),
|
|
52
|
+
contextWindowSize: options.contextWindowSize || 1,
|
|
53
|
+
skipCustomDetect: typeof options.detect !== "function",
|
|
54
|
+
skipCustomRedact: typeof options.replace !== "function"
|
|
55
|
+
} : {
|
|
56
|
+
contextWindowSize: options.contextWindowSize || 1,
|
|
57
|
+
skipCustomDetect: typeof options.detect !== "function",
|
|
58
|
+
skipCustomRedact: typeof options.replace !== "function"
|
|
59
|
+
};
|
|
60
|
+
} else return {
|
|
61
|
+
contextWindowSize: 1,
|
|
62
|
+
skipCustomDetect: true,
|
|
63
|
+
skipCustomRedact: true
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
async function callRedactWasm(candidate, options) {
|
|
67
|
+
let convertedDetect = noOpDetect;
|
|
68
|
+
if (typeof options?.detect === "function") {
|
|
69
|
+
const detect = options.detect;
|
|
70
|
+
convertedDetect = (tokens) => {
|
|
71
|
+
return detect(tokens).filter((e) => typeof e !== "undefined").map((e) => userEntitiesToWasm(e));
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
let convertedReplace = noOpReplace;
|
|
75
|
+
if (typeof options?.replace === "function") {
|
|
76
|
+
const replace = options.replace;
|
|
77
|
+
convertedReplace = (identifiedType, plaintext) => {
|
|
78
|
+
return replace(wasmEntitiesToString(identifiedType), plaintext);
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
const wasm = await initializeWasm(convertedDetect, convertedReplace);
|
|
82
|
+
if (typeof wasm !== "undefined") {
|
|
83
|
+
const config = getWasmOptions(options);
|
|
84
|
+
return wasm.redact(candidate, config).map((e) => {
|
|
85
|
+
return {
|
|
86
|
+
...e,
|
|
87
|
+
identifiedType: wasmEntitiesToString(e.identifiedType)
|
|
88
|
+
};
|
|
89
|
+
});
|
|
90
|
+
} else throw new Error("redact failed to run because Wasm is not supported in this environment");
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Redact sensitive info.
|
|
94
|
+
*
|
|
95
|
+
* @template DetectedEntities
|
|
96
|
+
* Custom entity names that are returned from `detect` and optionally listed in `entities`.
|
|
97
|
+
* @template ListedEntities
|
|
98
|
+
* Entity names that can be listed in the `entities` option.
|
|
99
|
+
* @param candidate
|
|
100
|
+
* Value to redact.
|
|
101
|
+
* @param options
|
|
102
|
+
* Configuration.
|
|
103
|
+
* @returns
|
|
104
|
+
* Promise to a tuple with the redacted string and a function to unredact it.
|
|
105
|
+
*/
|
|
106
|
+
async function redact(candidate, options) {
|
|
107
|
+
const redactions = await callRedactWasm(candidate, options);
|
|
108
|
+
redactions.reverse();
|
|
109
|
+
for (const redaction of redactions) candidate = performReplacementInText(candidate, redaction.redacted, redaction.start, redaction.end);
|
|
110
|
+
function unredact(input) {
|
|
111
|
+
for (const redaction of redactions) {
|
|
112
|
+
let position;
|
|
113
|
+
while (position !== -1) {
|
|
114
|
+
position = input.indexOf(redaction.redacted);
|
|
115
|
+
if (position !== -1) input = performReplacementInText(input, redaction.original, position, position + redaction.redacted.length);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return input;
|
|
119
|
+
}
|
|
120
|
+
return [candidate, unredact];
|
|
121
|
+
}
|
|
122
|
+
//#endregion
|
|
123
|
+
export { redact };
|
package/package.json
CHANGED
|
@@ -1,59 +1,62 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arcjet/redact",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0-rc.1",
|
|
4
4
|
"description": "Arcjet sensitive information redaction library",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"arcjet",
|
|
7
7
|
"redact",
|
|
8
|
-
"
|
|
9
|
-
"
|
|
8
|
+
"util",
|
|
9
|
+
"utility"
|
|
10
10
|
],
|
|
11
|
-
"license": "Apache-2.0",
|
|
12
11
|
"homepage": "https://arcjet.com",
|
|
13
|
-
"repository": {
|
|
14
|
-
"type": "git",
|
|
15
|
-
"url": "git+https://github.com/arcjet/arcjet-js.git",
|
|
16
|
-
"directory": "redact"
|
|
17
|
-
},
|
|
18
12
|
"bugs": {
|
|
19
13
|
"url": "https://github.com/arcjet/arcjet-js/issues",
|
|
20
14
|
"email": "support@arcjet.com"
|
|
21
15
|
},
|
|
16
|
+
"license": "Apache-2.0",
|
|
22
17
|
"author": {
|
|
23
18
|
"name": "Arcjet",
|
|
24
19
|
"email": "support@arcjet.com",
|
|
25
20
|
"url": "https://arcjet.com"
|
|
26
21
|
},
|
|
27
|
-
"
|
|
28
|
-
"
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/arcjet/arcjet-js.git",
|
|
25
|
+
"directory": "redact"
|
|
29
26
|
},
|
|
30
|
-
"type": "module",
|
|
31
|
-
"main": "./index.js",
|
|
32
|
-
"types": "./index.d.ts",
|
|
33
27
|
"files": [
|
|
34
|
-
"
|
|
35
|
-
"index.js"
|
|
28
|
+
"dist"
|
|
36
29
|
],
|
|
30
|
+
"type": "module",
|
|
31
|
+
"main": "./dist/index.js",
|
|
32
|
+
"types": "./dist/index.d.ts",
|
|
33
|
+
"exports": {
|
|
34
|
+
".": {
|
|
35
|
+
"types": "./dist/index.d.ts",
|
|
36
|
+
"default": "./dist/index.js"
|
|
37
|
+
},
|
|
38
|
+
"./package.json": "./package.json"
|
|
39
|
+
},
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public",
|
|
42
|
+
"tag": "latest"
|
|
43
|
+
},
|
|
37
44
|
"scripts": {
|
|
38
|
-
"build": "
|
|
39
|
-
"
|
|
40
|
-
"test-api": "node --test -- test/*.test.
|
|
41
|
-
"test-coverage": "node --experimental-test-coverage --test -- test/*.test.
|
|
42
|
-
"test": "npm run build && npm run
|
|
45
|
+
"build": "tsdown",
|
|
46
|
+
"typecheck": "tsgo --noEmit",
|
|
47
|
+
"test-api": "node --test -- test/*.test.ts",
|
|
48
|
+
"test-coverage": "node --experimental-test-coverage --test -- test/*.test.ts",
|
|
49
|
+
"test": "npm run build && npm run test-coverage"
|
|
43
50
|
},
|
|
44
51
|
"dependencies": {
|
|
45
|
-
"@arcjet/redact-wasm": "1.
|
|
52
|
+
"@arcjet/redact-wasm": "1.7.0-rc.1"
|
|
46
53
|
},
|
|
47
54
|
"devDependencies": {
|
|
48
|
-
"@arcjet/eslint-config": "1.6.1",
|
|
49
|
-
"@arcjet/rollup-config": "1.6.1",
|
|
50
|
-
"@rollup/wasm-node": "4.62.2",
|
|
51
55
|
"@types/node": "22.19.21",
|
|
52
|
-
"
|
|
53
|
-
"typescript": "
|
|
56
|
+
"tsdown": "0.22.3",
|
|
57
|
+
"typescript": "6.0.3"
|
|
54
58
|
},
|
|
55
|
-
"
|
|
56
|
-
"
|
|
57
|
-
"tag": "latest"
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=22.21.0 <23 || >=24.5.0"
|
|
58
61
|
}
|
|
59
62
|
}
|
package/index.d.ts
DELETED
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import type { SensitiveInfoEntity } from "@arcjet/redact-wasm";
|
|
2
|
-
/**
|
|
3
|
-
* Types of standard sensitive information that can be detected.
|
|
4
|
-
*/
|
|
5
|
-
export type ArcjetSensitiveInfoType = Exclude<SensitiveInfoEntity["tag"], "custom">;
|
|
6
|
-
/**
|
|
7
|
-
* Options for the `redact` function.
|
|
8
|
-
*
|
|
9
|
-
* @template DetectedEntities
|
|
10
|
-
* Custom entity names that are returned from `detect` and optionally listed in `entities`.
|
|
11
|
-
* @template ListedEntities
|
|
12
|
-
* Entity names that can be listed in the `entities` option.
|
|
13
|
-
*/
|
|
14
|
-
export type RedactOptions<DetectedEntities extends string | undefined = undefined, ListedEntities extends ArcjetSensitiveInfoType | Exclude<DetectedEntities, undefined> = ArcjetSensitiveInfoType | Exclude<DetectedEntities, undefined>> = {
|
|
15
|
-
/**
|
|
16
|
-
* Entities to redact.
|
|
17
|
-
*/
|
|
18
|
-
entities?: ReadonlyArray<ListedEntities | Exclude<DetectedEntities, undefined>>;
|
|
19
|
-
/**
|
|
20
|
-
* Size of tokens to consider.
|
|
21
|
-
*/
|
|
22
|
-
contextWindowSize?: number;
|
|
23
|
-
/**
|
|
24
|
-
* Custom detection function to identify sensitive information.
|
|
25
|
-
*
|
|
26
|
-
* @template DetectedEntities
|
|
27
|
-
* Custom entity names that are returned from `detect` and optionally listed in `entities`.
|
|
28
|
-
* @template ListedEntities
|
|
29
|
-
* Entity names that can be listed in the `entities` option.
|
|
30
|
-
* @param tokens
|
|
31
|
-
* Tokens.
|
|
32
|
-
* @returns
|
|
33
|
-
* List of entities (or undefined).
|
|
34
|
-
*/
|
|
35
|
-
detect?: (tokens: string[]) => ReadonlyArray<DetectedEntities>;
|
|
36
|
-
/**
|
|
37
|
-
* Custom replace function to redact sensitive information.
|
|
38
|
-
*
|
|
39
|
-
* @template DetectedEntities
|
|
40
|
-
* Custom entity names that are returned from `detect` and optionally listed in `entities`.
|
|
41
|
-
* @template ListedEntities
|
|
42
|
-
* Entity names that can be listed in the `entities` option.
|
|
43
|
-
* @param entity
|
|
44
|
-
* Entity to redact.
|
|
45
|
-
* @param plaintext
|
|
46
|
-
* The plaintext string to redact.
|
|
47
|
-
* @returns
|
|
48
|
-
* Redacted string or nothing.
|
|
49
|
-
*/
|
|
50
|
-
replace?: (entity: ListedEntities, plaintext: string) => string | undefined;
|
|
51
|
-
};
|
|
52
|
-
type Unredact = (input: string) => string;
|
|
53
|
-
/**
|
|
54
|
-
* Redact sensitive info.
|
|
55
|
-
*
|
|
56
|
-
* @template DetectedEntities
|
|
57
|
-
* Custom entity names that are returned from `detect` and optionally listed in `entities`.
|
|
58
|
-
* @template ListedEntities
|
|
59
|
-
* Entity names that can be listed in the `entities` option.
|
|
60
|
-
* @param candidate
|
|
61
|
-
* Value to redact.
|
|
62
|
-
* @param options
|
|
63
|
-
* Configuration.
|
|
64
|
-
* @returns
|
|
65
|
-
* Promise to a tuple with the redacted string and a function to unredact it.
|
|
66
|
-
*/
|
|
67
|
-
export declare function redact<const DetectedEntities extends string | undefined = undefined, const ListedEntities extends ArcjetSensitiveInfoType | Exclude<DetectedEntities, undefined> = ArcjetSensitiveInfoType | Exclude<DetectedEntities, undefined>>(candidate: string, options?: RedactOptions<DetectedEntities, ListedEntities>): Promise<[string, Unredact]>;
|
|
68
|
-
export {};
|
package/index.js
DELETED
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import { initializeWasm } from '@arcjet/redact-wasm';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Turn an entity name into a `SensitiveInfoEntity`.
|
|
5
|
-
*
|
|
6
|
-
* See also `protocolSensitiveInfoEntitiesToAnalyze` in `arcjet/index.ts`.
|
|
7
|
-
*
|
|
8
|
-
* @param entity
|
|
9
|
-
* Entity name.
|
|
10
|
-
* @returns
|
|
11
|
-
* Entity object.
|
|
12
|
-
*/
|
|
13
|
-
function userEntitiesToWasm(entity) {
|
|
14
|
-
if (typeof entity !== "string") {
|
|
15
|
-
throw new Error("redaction entities must be strings");
|
|
16
|
-
}
|
|
17
|
-
if (entity === "credit-card-number" ||
|
|
18
|
-
entity === "email" ||
|
|
19
|
-
entity === "ip-address" ||
|
|
20
|
-
entity === "phone-number") {
|
|
21
|
-
return { tag: entity };
|
|
22
|
-
}
|
|
23
|
-
return { tag: "custom", val: entity };
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Turn a `SensitiveInfoEntity` object into its name.
|
|
27
|
-
*
|
|
28
|
-
* See also `analyzeSensitiveInfoEntitiesToString` in `arcjet/index.ts`.
|
|
29
|
-
*
|
|
30
|
-
* @param entity
|
|
31
|
-
* Entity object.
|
|
32
|
-
* @returns
|
|
33
|
-
* Entity name.
|
|
34
|
-
*/
|
|
35
|
-
function wasmEntitiesToString(entity) {
|
|
36
|
-
if (entity.tag === "credit-card-number" ||
|
|
37
|
-
entity.tag === "email" ||
|
|
38
|
-
entity.tag === "ip-address" ||
|
|
39
|
-
entity.tag === "phone-number") {
|
|
40
|
-
return entity.tag;
|
|
41
|
-
}
|
|
42
|
-
return entity.val;
|
|
43
|
-
}
|
|
44
|
-
function performReplacementInText(text, replacement, start, end) {
|
|
45
|
-
return text.substring(0, start) + replacement + text.substring(end);
|
|
46
|
-
}
|
|
47
|
-
/* c8 ignore start */
|
|
48
|
-
// Coverage is ignored on these no-op functions because they are never executed
|
|
49
|
-
// due to the `skipCustomDetect` and `skipCustomReplace` options.
|
|
50
|
-
function noOpDetect(_tokens) {
|
|
51
|
-
return [];
|
|
52
|
-
}
|
|
53
|
-
function noOpReplace(_input, _plaintext) {
|
|
54
|
-
return undefined;
|
|
55
|
-
}
|
|
56
|
-
function getWasmOptions(options) {
|
|
57
|
-
if (typeof options === "object" && options !== null) {
|
|
58
|
-
const entities = options.entities;
|
|
59
|
-
if (entities !== undefined) {
|
|
60
|
-
if (!Array.isArray(entities)) {
|
|
61
|
-
throw new Error("entities must be an array");
|
|
62
|
-
}
|
|
63
|
-
if (entities.length < 1) {
|
|
64
|
-
throw new Error("no entities configured for redaction");
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
// `entities` is an optional field but not allowed to be `undefined`.
|
|
68
|
-
return entities
|
|
69
|
-
? {
|
|
70
|
-
entities: entities.map(userEntitiesToWasm),
|
|
71
|
-
contextWindowSize: options.contextWindowSize || 1,
|
|
72
|
-
skipCustomDetect: typeof options.detect !== "function",
|
|
73
|
-
skipCustomRedact: typeof options.replace !== "function",
|
|
74
|
-
}
|
|
75
|
-
: {
|
|
76
|
-
contextWindowSize: options.contextWindowSize || 1,
|
|
77
|
-
skipCustomDetect: typeof options.detect !== "function",
|
|
78
|
-
skipCustomRedact: typeof options.replace !== "function",
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
else {
|
|
82
|
-
return {
|
|
83
|
-
contextWindowSize: 1,
|
|
84
|
-
skipCustomDetect: true,
|
|
85
|
-
skipCustomRedact: true,
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
async function callRedactWasm(candidate, options) {
|
|
90
|
-
let convertedDetect = noOpDetect;
|
|
91
|
-
if (typeof options?.detect === "function") {
|
|
92
|
-
const detect = options.detect;
|
|
93
|
-
convertedDetect = (tokens) => {
|
|
94
|
-
return detect(tokens)
|
|
95
|
-
.filter((e) => typeof e !== "undefined")
|
|
96
|
-
.map((e) => userEntitiesToWasm(e));
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
let convertedReplace = noOpReplace;
|
|
100
|
-
if (typeof options?.replace === "function") {
|
|
101
|
-
const replace = options.replace;
|
|
102
|
-
convertedReplace = (identifiedType, plaintext) => {
|
|
103
|
-
return replace(
|
|
104
|
-
// @ts-expect-error because we know this is coming from Wasm
|
|
105
|
-
wasmEntitiesToString(identifiedType), plaintext);
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
const wasm = await initializeWasm(convertedDetect, convertedReplace);
|
|
109
|
-
if (typeof wasm !== "undefined") {
|
|
110
|
-
const config = getWasmOptions(options);
|
|
111
|
-
return wasm.redact(candidate, config).map((e) => {
|
|
112
|
-
return {
|
|
113
|
-
...e,
|
|
114
|
-
identifiedType: wasmEntitiesToString(e.identifiedType),
|
|
115
|
-
};
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
else {
|
|
119
|
-
throw new Error("redact failed to run because Wasm is not supported in this environment");
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
/**
|
|
123
|
-
* Redact sensitive info.
|
|
124
|
-
*
|
|
125
|
-
* @template DetectedEntities
|
|
126
|
-
* Custom entity names that are returned from `detect` and optionally listed in `entities`.
|
|
127
|
-
* @template ListedEntities
|
|
128
|
-
* Entity names that can be listed in the `entities` option.
|
|
129
|
-
* @param candidate
|
|
130
|
-
* Value to redact.
|
|
131
|
-
* @param options
|
|
132
|
-
* Configuration.
|
|
133
|
-
* @returns
|
|
134
|
-
* Promise to a tuple with the redacted string and a function to unredact it.
|
|
135
|
-
*/
|
|
136
|
-
async function redact(candidate, options) {
|
|
137
|
-
const redactions = await callRedactWasm(candidate, options);
|
|
138
|
-
// Need to apply the redactions in reverse order so that the offsets aren't changed
|
|
139
|
-
// when we redact with strings that are longer/shorter than the original.
|
|
140
|
-
redactions.reverse();
|
|
141
|
-
for (const redaction of redactions) {
|
|
142
|
-
candidate = performReplacementInText(candidate, redaction.redacted, redaction.start, redaction.end);
|
|
143
|
-
}
|
|
144
|
-
function unredact(input) {
|
|
145
|
-
for (const redaction of redactions) {
|
|
146
|
-
let position;
|
|
147
|
-
while (position !== -1) {
|
|
148
|
-
position = input.indexOf(redaction.redacted);
|
|
149
|
-
if (position !== -1) {
|
|
150
|
-
input = performReplacementInText(input, redaction.original, position, position + redaction.redacted.length);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
return input;
|
|
155
|
-
}
|
|
156
|
-
return [candidate, unredact];
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
export { redact };
|