restore-redact 1.0.0

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/index.js ADDED
@@ -0,0 +1,3 @@
1
+ 'use strict';
2
+
3
+ module.exports = require('./restore-redact');
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "restore-redact",
3
+ "version": "1.0.0",
4
+ "description": "Detect and tokenise secrets in objects/strings, then restore original values on demand",
5
+ "main": "index.js",
6
+ "exports": {
7
+ ".": "./index.js"
8
+ },
9
+ "files": [
10
+ "index.js",
11
+ "restore-redact.js"
12
+ ],
13
+ "scripts": {
14
+ "test": "jest"
15
+ },
16
+ "keywords": [
17
+ "secrets",
18
+ "redact",
19
+ "detect",
20
+ "restore",
21
+ "leakguard"
22
+ ],
23
+ "author": "",
24
+ "license": "ISC",
25
+ "engines": {
26
+ "node": ">=18"
27
+ },
28
+ "dependencies": {
29
+ "@leakguard/guard": "^3.0.2"
30
+ },
31
+ "devDependencies": {
32
+ "jest": "^30.4.2"
33
+ }
34
+ }
@@ -0,0 +1,85 @@
1
+ 'use strict';
2
+
3
+ const { randomUUID } = require('crypto');
4
+ const { CoreSecretDetector, ContentRedactor } = require('@leakguard/guard');
5
+
6
+ const store = new Map();
7
+ const detector = new CoreSecretDetector();
8
+
9
+ const TOKEN_RE = /\[REDACTED:([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\]/g;
10
+
11
+ function escapeRegex(s) {
12
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
13
+ }
14
+
15
+ function replaceValues(data, valueToToken) {
16
+ if (typeof data === 'string') {
17
+ let result = data;
18
+ for (const [value, token] of valueToToken) {
19
+ result = result.replace(new RegExp(escapeRegex(value), 'g'), token);
20
+ }
21
+ return result;
22
+ }
23
+ if (Array.isArray(data)) {
24
+ return data.map(item => replaceValues(item, valueToToken));
25
+ }
26
+ if (data !== null && typeof data === 'object') {
27
+ const out = {};
28
+ for (const [k, v] of Object.entries(data)) {
29
+ out[k] = replaceValues(v, valueToToken);
30
+ }
31
+ return out;
32
+ }
33
+ return data;
34
+ }
35
+
36
+ function restoreValues(data) {
37
+ if (typeof data === 'string') {
38
+ return data.replace(TOKEN_RE, (_, id) => store.has(id) ? store.get(id) : `[REDACTED:${id}]`);
39
+ }
40
+ if (Array.isArray(data)) {
41
+ return data.map(item => restoreValues(item));
42
+ }
43
+ if (data !== null && typeof data === 'object') {
44
+ const out = {};
45
+ for (const [k, v] of Object.entries(data)) {
46
+ out[k] = restoreValues(v);
47
+ }
48
+ return out;
49
+ }
50
+ return data;
51
+ }
52
+
53
+ function detect(data) {
54
+ const detection = detector.detect(data);
55
+
56
+ if (!detection.hasSecrets) {
57
+ return data;
58
+ }
59
+
60
+ const valueToToken = new Map();
61
+ for (const secret of detection.detectedSecrets) {
62
+ if (!valueToToken.has(secret.value)) {
63
+ const id = randomUUID();
64
+ store.set(id, secret.value);
65
+ valueToToken.set(secret.value, `[REDACTED:${id}]`);
66
+ }
67
+ }
68
+
69
+ const redactor = new ContentRedactor({
70
+ customRedactor: (content) => replaceValues(content, valueToToken),
71
+ });
72
+
73
+ const { redacted } = redactor.redactContent(data, detection);
74
+ return redacted;
75
+ }
76
+
77
+ function restore(redactedData) {
78
+ return restoreValues(redactedData);
79
+ }
80
+
81
+ function clear() {
82
+ store.clear();
83
+ }
84
+
85
+ module.exports = { detect, restore, clear };