privacy-brush 1.0.2 → 1.1.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/README.md +20 -33
- package/package.json +1 -1
- package/src/index.mjs +61 -4
- package/src/index.test.mjs +216 -161
- package/src/lib/config.mjs +2 -0
- package/src/lib/iconv-lite.mjs +55 -0
- package/src/type.ts +1 -0
- package/temp.txt +30 -0
package/README.md
CHANGED
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
[](https://opensource.org/licenses/MIT)
|
|
10
10
|
[](https://github.com/legend80s/privacy-brush/actions/workflows/typecheck.yml)
|
|
11
11
|
|
|
12
|
-
<p align="center">
|
|
12
|
+
<!-- <p align="center">
|
|
13
13
|
<img src="https://raw.githubusercontent.com/legend80s/privacy-brush/main/docs/demo.gif" alt="PrivacyBrush Demo" width="800">
|
|
14
|
-
</p>
|
|
14
|
+
</p> -->
|
|
15
15
|
|
|
16
16
|
## ✨ Features
|
|
17
17
|
|
|
@@ -204,39 +204,26 @@ PrivacyBrush includes 20+ pre-configured sensitive information patterns:
|
|
|
204
204
|
### Stream Processing for Large Files
|
|
205
205
|
|
|
206
206
|
```javascript
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
const inputStream = fs.createReadStream('huge.log');
|
|
211
|
-
const maskStream = createMaskStream();
|
|
212
|
-
|
|
213
|
-
inputStream
|
|
214
|
-
.pipe(maskStream)
|
|
215
|
-
.pipe(fs.createWriteStream('masked-huge.log'))
|
|
216
|
-
.on('finish', () => {
|
|
217
|
-
console.log('Large file processing completed!');
|
|
218
|
-
});
|
|
219
|
-
```
|
|
207
|
+
import { createReadStream, createWriteStream } from "node:fs"
|
|
208
|
+
import { pipeline } from "node:stream/promises"
|
|
220
209
|
|
|
221
|
-
|
|
210
|
+
import { PrivacyBrush } from "privacy-brush"
|
|
222
211
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const
|
|
226
|
-
const
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
next();
|
|
239
|
-
});
|
|
212
|
+
const brush = new PrivacyBrush()
|
|
213
|
+
|
|
214
|
+
const inputStream = createReadStream("./test/fixtures/huge.log")
|
|
215
|
+
const maskStream = await brush.createMaskStream()
|
|
216
|
+
|
|
217
|
+
const dist = `./test/fixtures/masked-huge-${Date.now()}.generated.log`
|
|
218
|
+
|
|
219
|
+
// biome-ignore format: one stream per line
|
|
220
|
+
await pipeline(
|
|
221
|
+
inputStream,
|
|
222
|
+
maskStream,
|
|
223
|
+
createWriteStream(dist)
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
console.log("✅ Large file processing completed!", dist)
|
|
240
227
|
```
|
|
241
228
|
|
|
242
229
|
### Git Hook Integration
|
package/package.json
CHANGED
package/src/index.mjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { createRequire } from "node:module"
|
|
4
4
|
import { defaultConfig } from "./lib/config.mjs"
|
|
5
|
+
import { tryDecode } from "./lib/iconv-lite.mjs"
|
|
5
6
|
import { verbose } from "./lib/parse-args.mjs"
|
|
6
7
|
|
|
7
8
|
export class PrivacyBrush {
|
|
@@ -73,7 +74,7 @@ export class PrivacyBrush {
|
|
|
73
74
|
{
|
|
74
75
|
/** @type {IPatternName} */
|
|
75
76
|
name: "user_name_in_path",
|
|
76
|
-
regex: /\/Users\/([
|
|
77
|
+
regex: /\/Users\/([^/]+)\//g,
|
|
77
78
|
/**
|
|
78
79
|
* Handle user name in file path masking.
|
|
79
80
|
* @param {string} match
|
|
@@ -84,6 +85,32 @@ export class PrivacyBrush {
|
|
|
84
85
|
return match.replace(userName, this.maskChar.repeat(userName.length))
|
|
85
86
|
},
|
|
86
87
|
},
|
|
88
|
+
|
|
89
|
+
// uuid
|
|
90
|
+
{
|
|
91
|
+
name: "uuid",
|
|
92
|
+
regex:
|
|
93
|
+
/\b[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\b/g,
|
|
94
|
+
/**
|
|
95
|
+
* Handle UUID masking.
|
|
96
|
+
* @param {string} match
|
|
97
|
+
* @returns {string}
|
|
98
|
+
*/
|
|
99
|
+
replacer: match => {
|
|
100
|
+
return this.maskUUID(match)
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
// mac address (CA:FE:BA:BE:12:34 or CA-FE-BA-BE-12-34)
|
|
105
|
+
{
|
|
106
|
+
name: "mac_address",
|
|
107
|
+
// match six hex pairs separated by ':' or '-'
|
|
108
|
+
regex:
|
|
109
|
+
/\b(?:[0-9A-Fa-f]{2}([:-]))(?:[0-9A-Fa-f]{2}\1){4}[0-9A-Fa-f]{2}\b/g,
|
|
110
|
+
replacer: match => {
|
|
111
|
+
return match.replace(/[0-9A-Fa-f]{2}/g, () => this.maskChar.repeat(2))
|
|
112
|
+
},
|
|
113
|
+
},
|
|
87
114
|
]
|
|
88
115
|
|
|
89
116
|
return allPatterns
|
|
@@ -240,15 +267,45 @@ export class PrivacyBrush {
|
|
|
240
267
|
}
|
|
241
268
|
}
|
|
242
269
|
|
|
270
|
+
/**
|
|
271
|
+
* mask uuid by version
|
|
272
|
+
* - version 4: 6ba7b810-xxxx-4xxx-xxxx-xxxxxxxxxxxx
|
|
273
|
+
* - other versions: xxxxxxxx-xxxx-vxxx-xxxx-xxxxxxxxxxxx (v is 1-5)
|
|
274
|
+
* @param {string} uuid
|
|
275
|
+
* @returns
|
|
276
|
+
*/
|
|
277
|
+
maskUUID(uuid) {
|
|
278
|
+
return uuid.replace(
|
|
279
|
+
/\b([0-9a-fA-F]{8})-([0-9a-fA-F]{4})-([1-5])([0-9a-fA-F]{3})-([0-9a-fA-F]{4})-([0-9a-fA-F]{12})\b/g,
|
|
280
|
+
(match, p1, p2, p3, p4, p5, p6) => {
|
|
281
|
+
/** @type {(target: string) => string} */
|
|
282
|
+
const mask = target => this.maskChar.repeat(target.length)
|
|
283
|
+
|
|
284
|
+
const maskedP2 = mask(p2)
|
|
285
|
+
const maskedP4 = mask(p4)
|
|
286
|
+
const maskedP5 = mask(p5)
|
|
287
|
+
const maskedP6 = mask(p6)
|
|
288
|
+
|
|
289
|
+
if (p3 === "4") {
|
|
290
|
+
return `${p1}-${maskedP2}-4${maskedP4}-${maskedP5}-${maskedP6}`
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const maskedP1 = mask(p1)
|
|
294
|
+
|
|
295
|
+
return `${maskedP1}-${maskedP2}-${p3}${maskedP4}-${maskedP5}-${maskedP6}`
|
|
296
|
+
},
|
|
297
|
+
)
|
|
298
|
+
}
|
|
299
|
+
|
|
243
300
|
// 实时流处理
|
|
244
301
|
async createMaskStream() {
|
|
245
302
|
const { Transform } = await import("node:stream")
|
|
246
303
|
|
|
247
304
|
return new Transform({
|
|
248
|
-
transform: (chunk, encoding, callback) => {
|
|
249
|
-
const text =
|
|
250
|
-
|
|
305
|
+
transform: (/** @type {Buffer} */ chunk, encoding, callback) => {
|
|
306
|
+
const text = tryDecode(chunk)
|
|
251
307
|
const masked = this.maskText(text)
|
|
308
|
+
|
|
252
309
|
callback(null, masked)
|
|
253
310
|
},
|
|
254
311
|
})
|
package/src/index.test.mjs
CHANGED
|
@@ -1,161 +1,216 @@
|
|
|
1
|
-
import { strict as assert } from "node:assert"
|
|
2
|
-
import { test } from "node:test"
|
|
3
|
-
import { PrivacyBrush } from "./index.mjs"
|
|
4
|
-
|
|
5
|
-
const WINDOWS_VERSION_SAMPLE = "10.0.12345.6785"
|
|
6
|
-
const GOOGLE_BROWSER_VERSION_SAMPLE = "144.0.1234.56"
|
|
7
|
-
const EDGE_BROWSER_VERSION_SAMPLE = "144.0.3421.12"
|
|
8
|
-
|
|
9
|
-
test("default configurations", () => {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
1
|
+
import { strict as assert } from "node:assert"
|
|
2
|
+
import { test } from "node:test"
|
|
3
|
+
import { PrivacyBrush } from "./index.mjs"
|
|
4
|
+
|
|
5
|
+
const WINDOWS_VERSION_SAMPLE = "10.0.12345.6785"
|
|
6
|
+
const GOOGLE_BROWSER_VERSION_SAMPLE = "144.0.1234.56"
|
|
7
|
+
const EDGE_BROWSER_VERSION_SAMPLE = "144.0.3421.12"
|
|
8
|
+
|
|
9
|
+
test("default configurations", () => {
|
|
10
|
+
const masker = new PrivacyBrush()
|
|
11
|
+
|
|
12
|
+
const terminalOutput = `❯ flutter devices
|
|
13
|
+
Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source!
|
|
14
|
+
Found 4 connected devices:
|
|
15
|
+
sdk gphone64 x86 64 (mobile) • emulator-5554 • android-x64 • Android 16 (API 36) (emulator)
|
|
16
|
+
Windows (desktop) • windows • windows-x64 • Microsoft Windows [版本 ${WINDOWS_VERSION_SAMPLE}]
|
|
17
|
+
Chrome (web) • chrome • web-javascript • Google Chrome ${GOOGLE_BROWSER_VERSION_SAMPLE}
|
|
18
|
+
Edge (web) • edge • web-javascript • Microsoft Edge ${EDGE_BROWSER_VERSION_SAMPLE}
|
|
19
|
+
|
|
20
|
+
Run "flutter emulators" to list and start any available device emulators.
|
|
21
|
+
|
|
22
|
+
If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try
|
|
23
|
+
increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for
|
|
24
|
+
troubleshooting tips.
|
|
25
|
+
`
|
|
26
|
+
|
|
27
|
+
const safeOutput = masker.maskText(terminalOutput)
|
|
28
|
+
|
|
29
|
+
// console.log("safeOutput:", safeOutput)
|
|
30
|
+
|
|
31
|
+
const expectedOutput = `❯ flutter devices
|
|
32
|
+
Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source!
|
|
33
|
+
Found 4 connected devices:
|
|
34
|
+
sdk gphone64 x86 64 (mobile) • emulator-5554 • android-x64 • Android 16 (API 36) (emulator)
|
|
35
|
+
Windows (desktop) • windows • windows-x64 • Microsoft Windows [版本 10.█.█████.████]
|
|
36
|
+
Chrome (web) • chrome • web-javascript • Google Chrome 144.█.████.██
|
|
37
|
+
Edge (web) • edge • web-javascript • Microsoft Edge 144.█.████.██
|
|
38
|
+
|
|
39
|
+
Run "flutter emulators" to list and start any available device emulators.
|
|
40
|
+
|
|
41
|
+
If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try
|
|
42
|
+
increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for
|
|
43
|
+
troubleshooting tips.
|
|
44
|
+
`
|
|
45
|
+
|
|
46
|
+
assert.strictEqual(safeOutput, expectedOutput)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test("use custom maskChar and not preserveFirstPart", () => {
|
|
50
|
+
const masker = new PrivacyBrush({
|
|
51
|
+
maskChar: "░",
|
|
52
|
+
preserveFirstPart: false,
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const terminalOutput = `❯ flutter devices
|
|
56
|
+
Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source!
|
|
57
|
+
Found 4 connected devices:
|
|
58
|
+
sdk gphone64 x86 64 (mobile) • emulator-5554 • android-x64 • Android 16 (API 36) (emulator)
|
|
59
|
+
Windows (desktop) • windows • windows-x64 • Microsoft Windows [版本 ${WINDOWS_VERSION_SAMPLE}]
|
|
60
|
+
Chrome (web) • chrome • web-javascript • Google Chrome ${GOOGLE_BROWSER_VERSION_SAMPLE}
|
|
61
|
+
Edge (web) • edge • web-javascript • Microsoft Edge ${EDGE_BROWSER_VERSION_SAMPLE}
|
|
62
|
+
|
|
63
|
+
Run "flutter emulators" to list and start any available device emulators.
|
|
64
|
+
|
|
65
|
+
If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try
|
|
66
|
+
increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for
|
|
67
|
+
troubleshooting tips.
|
|
68
|
+
`
|
|
69
|
+
|
|
70
|
+
const safeOutput = masker.maskText(terminalOutput)
|
|
71
|
+
|
|
72
|
+
// console.log("safeOutput2:", safeOutput)
|
|
73
|
+
|
|
74
|
+
const expectedOutput = `❯ flutter devices
|
|
75
|
+
Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source!
|
|
76
|
+
Found 4 connected devices:
|
|
77
|
+
sdk gphone64 x86 64 (mobile) • emulator-5554 • android-x64 • Android 16 (API 36) (emulator)
|
|
78
|
+
Windows (desktop) • windows • windows-x64 • Microsoft Windows [版本 ░░.░.░░░░░.░░░░]
|
|
79
|
+
Chrome (web) • chrome • web-javascript • Google Chrome ░░░.░.░░░░.░░
|
|
80
|
+
Edge (web) • edge • web-javascript • Microsoft Edge ░░░.░.░░░░.░░
|
|
81
|
+
|
|
82
|
+
Run "flutter emulators" to list and start any available device emulators.
|
|
83
|
+
|
|
84
|
+
If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try
|
|
85
|
+
increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for
|
|
86
|
+
troubleshooting tips.
|
|
87
|
+
`
|
|
88
|
+
|
|
89
|
+
assert.strictEqual(safeOutput, expectedOutput)
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
test("only mask browser_version", () => {
|
|
93
|
+
const masker = new PrivacyBrush({
|
|
94
|
+
maskPatternNames: ["browser_version"],
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
const terminalOutput = `❯ flutter devices
|
|
98
|
+
Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source!
|
|
99
|
+
Found 4 connected devices:
|
|
100
|
+
sdk gphone64 x86 64 (mobile) • emulator-5554 • android-x64 • Android 16 (API 36) (emulator)
|
|
101
|
+
Windows (desktop) • windows • windows-x64 • Microsoft Windows [版本 ${WINDOWS_VERSION_SAMPLE}]
|
|
102
|
+
Chrome (web) • chrome • web-javascript • Google Chrome ${GOOGLE_BROWSER_VERSION_SAMPLE}
|
|
103
|
+
Edge (web) • edge • web-javascript • Microsoft Edge ${EDGE_BROWSER_VERSION_SAMPLE}
|
|
104
|
+
|
|
105
|
+
Run "flutter emulators" to list and start any available device emulators.
|
|
106
|
+
|
|
107
|
+
If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try
|
|
108
|
+
increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for
|
|
109
|
+
troubleshooting tips.
|
|
110
|
+
`
|
|
111
|
+
|
|
112
|
+
const safeOutput = masker.maskText(terminalOutput)
|
|
113
|
+
|
|
114
|
+
// console.log("safeOutput3:", safeOutput)
|
|
115
|
+
|
|
116
|
+
const expectedOutput = `❯ flutter devices
|
|
117
|
+
Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source!
|
|
118
|
+
Found 4 connected devices:
|
|
119
|
+
sdk gphone64 x86 64 (mobile) • emulator-5554 • android-x64 • Android 16 (API 36) (emulator)
|
|
120
|
+
Windows (desktop) • windows • windows-x64 • Microsoft Windows [版本 ${WINDOWS_VERSION_SAMPLE}]
|
|
121
|
+
Chrome (web) • chrome • web-javascript • Google Chrome 144.█.████.██
|
|
122
|
+
Edge (web) • edge • web-javascript • Microsoft Edge 144.█.████.██
|
|
123
|
+
|
|
124
|
+
Run "flutter emulators" to list and start any available device emulators.
|
|
125
|
+
|
|
126
|
+
If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try
|
|
127
|
+
increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for
|
|
128
|
+
troubleshooting tips.
|
|
129
|
+
`
|
|
130
|
+
|
|
131
|
+
assert.strictEqual(safeOutput, expectedOutput)
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
test("mask username in path", () => {
|
|
135
|
+
const masker = new PrivacyBrush()
|
|
136
|
+
|
|
137
|
+
const input = `/c/Users/legend80s/AppData/ /Users/test/code/`
|
|
138
|
+
const safeOutput = masker.maskText(input)
|
|
139
|
+
const expectedOutput = `/c/Users/█████████/AppData/ /Users/████/code/`
|
|
140
|
+
|
|
141
|
+
assert.strictEqual(safeOutput, expectedOutput)
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
test("mask IP", () => {
|
|
145
|
+
const masker = new PrivacyBrush()
|
|
146
|
+
|
|
147
|
+
const terminalOutput = `Windows [Version 10.0.12345.1234]
|
|
148
|
+
Chrome 144.0.1234.12
|
|
149
|
+
User IP: 10.12.123.12`
|
|
150
|
+
|
|
151
|
+
const safeOutput = masker.maskText(terminalOutput)
|
|
152
|
+
|
|
153
|
+
// console.log("safeOutput3:", safeOutput)
|
|
154
|
+
|
|
155
|
+
const expectedOutput = `Windows [Version 10.█.█████.████]
|
|
156
|
+
Chrome 144.█.████.██
|
|
157
|
+
User IP: 10.██.███.██`
|
|
158
|
+
|
|
159
|
+
assert.strictEqual(safeOutput, expectedOutput)
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
test("mask uuid", () => {
|
|
163
|
+
const masker = new PrivacyBrush()
|
|
164
|
+
|
|
165
|
+
const terminalOutput = `
|
|
166
|
+
UUID v1: 11111111-1111-1111-8111-111111111111
|
|
167
|
+
UUID v2: 22222222-2222-2222-8222-222222222222
|
|
168
|
+
UUID v3: 33333333-3333-3333-8333-333333333333
|
|
169
|
+
UUID v4: 44444444-4444-4444-8444-444444444444
|
|
170
|
+
UUID v5: 55555555-5555-5555-8555-555555555555
|
|
171
|
+
`
|
|
172
|
+
|
|
173
|
+
const safeOutput = masker.maskText(terminalOutput)
|
|
174
|
+
|
|
175
|
+
// console.log("safeOutput3:", safeOutput)
|
|
176
|
+
|
|
177
|
+
const expectedOutput = `
|
|
178
|
+
UUID v1: ████████-████-1███-████-████████████
|
|
179
|
+
UUID v2: ████████-████-2███-████-████████████
|
|
180
|
+
UUID v3: ████████-████-3███-████-████████████
|
|
181
|
+
UUID v4: 44444444-████-4███-████-████████████
|
|
182
|
+
UUID v5: ████████-████-5███-████-████████████
|
|
183
|
+
`
|
|
184
|
+
|
|
185
|
+
assert.strictEqual(safeOutput, expectedOutput)
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
test("mask mac address", () => {
|
|
189
|
+
const masker = new PrivacyBrush()
|
|
190
|
+
|
|
191
|
+
const input = `
|
|
192
|
+
CA:FE:BA:BE:12:34 # "Cafe Babe"
|
|
193
|
+
DE:AD:BE:EF:CA:FE # "Dead Beef Cafe"
|
|
194
|
+
BA:DC:0F:FE:E0:0D # "Bad Coffee Feed"
|
|
195
|
+
|
|
196
|
+
CA-FE-BA-BE-12-34 # "Cafe Babe"
|
|
197
|
+
DE-AD-BE-EF-CA-FE # "Dead Beef Cafe"
|
|
198
|
+
BA-DC-0F-FE-E0-0D # "Bad Coffee Feed"
|
|
199
|
+
`
|
|
200
|
+
|
|
201
|
+
const safeOutput = masker.maskText(input)
|
|
202
|
+
|
|
203
|
+
// console.log("safeOutput3:", safeOutput)
|
|
204
|
+
|
|
205
|
+
const expectedOutput = `
|
|
206
|
+
██:██:██:██:██:██ # "Cafe Babe"
|
|
207
|
+
██:██:██:██:██:██ # "Dead Beef Cafe"
|
|
208
|
+
██:██:██:██:██:██ # "Bad Coffee Feed"
|
|
209
|
+
|
|
210
|
+
██-██-██-██-██-██ # "Cafe Babe"
|
|
211
|
+
██-██-██-██-██-██ # "Dead Beef Cafe"
|
|
212
|
+
██-██-██-██-██-██ # "Bad Coffee Feed"
|
|
213
|
+
`
|
|
214
|
+
|
|
215
|
+
assert.strictEqual(safeOutput, expectedOutput)
|
|
216
|
+
})
|
package/src/lib/config.mjs
CHANGED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { verbose } from "./parse-args.mjs"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param {Buffer} chunk
|
|
7
|
+
* @returns {string}
|
|
8
|
+
* @example
|
|
9
|
+
* ❯ getmac -v | node src/cli.mjs # should decode gbk
|
|
10
|
+
* ❯ ipconfig -all | node src/cli.mjs # should decode gbk
|
|
11
|
+
*/
|
|
12
|
+
export function tryDecode(chunk) {
|
|
13
|
+
const utf8 = chunk.toString("utf8")
|
|
14
|
+
|
|
15
|
+
if (!isLikelyGibberish(utf8)) {
|
|
16
|
+
return utf8
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const decoder = new TextDecoder("gbk")
|
|
20
|
+
|
|
21
|
+
verbose &&
|
|
22
|
+
console.log("[transform] isLikelyGibberish try decoding with `gbk`")
|
|
23
|
+
|
|
24
|
+
const result = decoder.decode(chunk)
|
|
25
|
+
|
|
26
|
+
if (!isLikelyGibberish(result)) {
|
|
27
|
+
return result
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
verbose && console.log("[transform] still gibberish, using utf8")
|
|
31
|
+
|
|
32
|
+
return utf8
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 检查是否是乱码
|
|
37
|
+
* @param {string} text
|
|
38
|
+
* @returns {boolean}
|
|
39
|
+
*/
|
|
40
|
+
function isLikelyGibberish(text) {
|
|
41
|
+
// Windows 命令行常见乱码模式
|
|
42
|
+
const patterns = [
|
|
43
|
+
/�/g, // Unicode 替换字符
|
|
44
|
+
// /涓/g, // 常见 UTF-8 转 GBK 乱码
|
|
45
|
+
// /嶏/g, // 常见乱码字符
|
|
46
|
+
// /[À-Å]/g, // 带重音的大写字母
|
|
47
|
+
// /[È-Ë]/g, // 更多重音字母
|
|
48
|
+
// /[Ì-Ï]/g,
|
|
49
|
+
// /å/g,
|
|
50
|
+
// /ä/g,
|
|
51
|
+
// /ö/g, // 北欧字符
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
return patterns.some(pattern => pattern.test(text))
|
|
55
|
+
}
|
package/src/type.ts
CHANGED
package/temp.txt
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
|
|
2
|
+
Windows IP ����
|
|
3
|
+
|
|
4
|
+
������ . . . . . . . . . . . . . : PC-LIUCHUANZONG
|
|
5
|
+
�� DNS �� . . . . . . . . . . . : CETHIK.COM
|
|
6
|
+
�ڵ����� . . . . . . . . . . . . : ���
|
|
7
|
+
IP ·�������� . . . . . . . . . . : ��
|
|
8
|
+
WINS ���������� . . . . . . . . . : ��
|
|
9
|
+
DNS �������б� . . . . . . . . : CETHIK.COM
|
|
10
|
+
NHY_INTERNET
|
|
11
|
+
|
|
12
|
+
��̫�������� ��̫��:
|
|
13
|
+
|
|
14
|
+
�����ض��� DNS �� . . . . . . . : NHY_INTERNET
|
|
15
|
+
����. . . . . . . . . . . . . . . : Realtek PCIe GbE Family Controller
|
|
16
|
+
������ַ. . . . . . . . . . . . . : F4-6B-8C-8F-CF-52
|
|
17
|
+
DHCP ������ . . . . . . . . . . . : ��
|
|
18
|
+
�Զ�����������. . . . . . . . . . : ��
|
|
19
|
+
�������� IPv6 ��ַ. . . . . . . . : fe80::b051:a4c7:c108:5ef0%14(��ѡ)
|
|
20
|
+
IPv4 ��ַ . . . . . . . . . . . . : 10.88.103.87(��ѡ)
|
|
21
|
+
�������� . . . . . . . . . . . . : 255.255.255.0
|
|
22
|
+
�����Լ��ʱ�� . . . . . . . . . : 2026��1��28�� 8:31:05
|
|
23
|
+
��Լ���ڵ�ʱ�� . . . . . . . . . : 2162��3��6�� 17:56:12
|
|
24
|
+
Ĭ������. . . . . . . . . . . . . : 10.88.103.254
|
|
25
|
+
DHCP ������ . . . . . . . . . . . : 10.88.103.254
|
|
26
|
+
DHCPv6 IAID . . . . . . . . . . . : 250899340
|
|
27
|
+
DHCPv6 �ͻ��� DUID . . . . . . . : 00-01-00-01-2B-6D-1A-B3-F4-6B-8C-8F-CF-52
|
|
28
|
+
DNS ������ . . . . . . . . . . . : 10.88.250.2
|
|
29
|
+
114.114.114.114
|
|
30
|
+
TCPIP �ϵ� NetBIOS . . . . . . . : ������
|