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 CHANGED
@@ -9,9 +9,9 @@
9
9
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
10
10
  [![tsgo](https://github.com/legend80s/privacy-brush/actions/workflows/typecheck.yml/badge.svg?branch=master)](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
- const fs = require('fs');
208
- const { createMaskStream } = require('privacy-brush');
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
- ### Express.js Integration
210
+ import { PrivacyBrush } from "privacy-brush"
222
211
 
223
- ```javascript
224
- const express = require('express');
225
- const { PrivacyBrush } = require('privacy-brush');
226
- const app = express();
227
- const masker = new PrivacyBrush();
228
-
229
- // Middleware: auto-mask sensitive info in responses
230
- app.use((req, res, next) => {
231
- const originalSend = res.send;
232
- res.send = function(body) {
233
- if (typeof body === 'string' && body.includes('sensitive')) {
234
- body = masker.mask(body);
235
- }
236
- originalSend.call(this, body);
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "privacy-brush",
3
- "version": "1.0.2",
3
+ "version": "1.1.1",
4
4
  "description": "Automatically mask sensitive information in terminal outputs and logs. Keep your data safe when sharing.",
5
5
  "main": "src/index.mjs",
6
6
  "module": "src/index.mjs",
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\/([^\/]+)\//g,
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 = String(chunk)
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
  })
@@ -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
- const masker = new PrivacyBrush()
12
-
13
- // 处理终端输出
14
- const terminalOutput = `❯ flutter devices
15
- Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source!
16
- Found 4 connected devices:
17
- sdk gphone64 x86 64 (mobile) • emulator-5554android-x64 • Android 16 (API 36) (emulator)
18
- Windows (desktop) windows windows-x64 • Microsoft Windows [版本 ${WINDOWS_VERSION_SAMPLE}]
19
- Chrome (web) • chrome • web-javascript • Google Chrome ${GOOGLE_BROWSER_VERSION_SAMPLE}
20
- Edge (web) • edge • web-javascript Microsoft Edge ${EDGE_BROWSER_VERSION_SAMPLE}
21
-
22
- Run "flutter emulators" to list and start any available device emulators.
23
-
24
- If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try
25
- increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for
26
- troubleshooting tips.
27
- `
28
-
29
- const safeOutput = masker.maskText(terminalOutput)
30
-
31
- // console.log("safeOutput:", safeOutput)
32
-
33
- const expectedOutput = `❯ flutter devices
34
- Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source!
35
- Found 4 connected devices:
36
- sdk gphone64 x86 64 (mobile) • emulator-5554android-x64 • Android 16 (API 36) (emulator)
37
- Windows (desktop) windows windows-x64 • Microsoft Windows [版本 10.█.█████.████]
38
- Chrome (web) • chrome • web-javascript • Google Chrome 144.█.████.██
39
- Edge (web) • edge • web-javascript Microsoft Edge 144.█.████.██
40
-
41
- Run "flutter emulators" to list and start any available device emulators.
42
-
43
- If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try
44
- increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for
45
- troubleshooting tips.
46
- `
47
-
48
- assert.strictEqual(safeOutput, expectedOutput)
49
- })
50
-
51
- test("use custom maskChar and not preserveFirstPart", () => {
52
- // 使用示例
53
- const masker = new PrivacyBrush({
54
- maskChar: "░",
55
- preserveFirstPart: false,
56
- })
57
-
58
- // 处理终端输出
59
- const terminalOutput = `❯ flutter devices
60
- Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source!
61
- Found 4 connected devices:
62
- sdk gphone64 x86 64 (mobile) • emulator-5554 • android-x64 • Android 16 (API 36) (emulator)
63
- Windows (desktop) • windows • windows-x64 • Microsoft Windows [版本 ${WINDOWS_VERSION_SAMPLE}]
64
- Chrome (web) • chrome • web-javascript • Google Chrome ${GOOGLE_BROWSER_VERSION_SAMPLE}
65
- Edge (web) • edge • web-javascript Microsoft Edge ${EDGE_BROWSER_VERSION_SAMPLE}
66
-
67
- Run "flutter emulators" to list and start any available device emulators.
68
-
69
- If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try
70
- increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for
71
- troubleshooting tips.
72
- `
73
-
74
- const safeOutput = masker.maskText(terminalOutput)
75
-
76
- // console.log("safeOutput2:", safeOutput)
77
-
78
- const expectedOutput = `❯ flutter devices
79
- Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source!
80
- Found 4 connected devices:
81
- sdk gphone64 x86 64 (mobile) • emulator-5554 • android-x64 • Android 16 (API 36) (emulator)
82
- Windows (desktop) • windows • windows-x64 • Microsoft Windows [版本 ░░.░.░░░░░.░░░░]
83
- Chrome (web) • chrome • web-javascript • Google Chrome ░░░.░.░░░░.░░
84
- Edge (web) • edge • web-javascript Microsoft Edge ░░░.░.░░░░.░░
85
-
86
- Run "flutter emulators" to list and start any available device emulators.
87
-
88
- If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try
89
- increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for
90
- troubleshooting tips.
91
- `
92
-
93
- assert.strictEqual(safeOutput, expectedOutput)
94
- })
95
-
96
- test("only mask browser_version", () => {
97
- // 使用示例
98
- const masker = new PrivacyBrush({
99
- maskPatternNames: ["browser_version"],
100
- })
101
-
102
- // 处理终端输出
103
- const terminalOutput = `❯ flutter devices
104
- Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source!
105
- Found 4 connected devices:
106
- sdk gphone64 x86 64 (mobile) • emulator-5554 • android-x64 • Android 16 (API 36) (emulator)
107
- Windows (desktop) • windows • windows-x64 • Microsoft Windows [版本 ${WINDOWS_VERSION_SAMPLE}]
108
- Chrome (web) • chrome • web-javascript Google Chrome ${GOOGLE_BROWSER_VERSION_SAMPLE}
109
- Edge (web) • edge • web-javascript • Microsoft Edge ${EDGE_BROWSER_VERSION_SAMPLE}
110
-
111
- Run "flutter emulators" to list and start any available device emulators.
112
-
113
- If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try
114
- increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for
115
- troubleshooting tips.
116
- `
117
-
118
- const safeOutput = masker.maskText(terminalOutput)
119
-
120
- // console.log("safeOutput3:", safeOutput)
121
-
122
- const expectedOutput = `❯ flutter devices
123
- Flutter assets will be downloaded from https://storage.flutter-io.cn. Make sure you trust this source!
124
- Found 4 connected devices:
125
- sdk gphone64 x86 64 (mobile) • emulator-5554 • android-x64 • Android 16 (API 36) (emulator)
126
- Windows (desktop) • windows • windows-x64 • Microsoft Windows [版本 ${WINDOWS_VERSION_SAMPLE}]
127
- Chrome (web) • chrome • web-javascript Google Chrome 144.█.████.██
128
- Edge (web) • edge • web-javascript • Microsoft Edge 144.█.████.██
129
-
130
- Run "flutter emulators" to list and start any available device emulators.
131
-
132
- If you expected another device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try
133
- increasing the time to wait for connected devices with the "--device-timeout" flag. Visit https://flutter.dev/setup/ for
134
- troubleshooting tips.
135
- `
136
-
137
- assert.strictEqual(safeOutput, expectedOutput)
138
- })
139
-
140
- test("mask IP", () => {
141
- // 使用示例
142
- const masker = new PrivacyBrush()
143
-
144
- // 处理终端输出
145
- const terminalOutput = `Windows [Version 10.0.12345.1234]
146
- Chrome 144.0.1234.12
147
- User IP: 10.12.123.12`
148
-
149
- const safeOutput = masker.maskText(terminalOutput)
150
-
151
- // console.log("safeOutput3:", safeOutput)
152
-
153
- const expectedOutput = `Windows [Version 10.█.█████.████]
154
- Chrome 144.█.████.██
155
- User IP: 10.██.███.██`
156
-
157
- assert.strictEqual(safeOutput, expectedOutput)
158
- })
159
-
160
- // // 处理日志文件
161
- // masker.maskFile('terminal_log.txt', 'masked_log.txt');
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-javascriptGoogle 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-javascriptGoogle 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
+ })
@@ -8,7 +8,9 @@ export const defaultConfig = {
8
8
  "windows_version",
9
9
  "browser_version",
10
10
  "ip_address",
11
+ "mac_address",
11
12
  "user_name_in_path",
13
+ "uuid",
12
14
  ],
13
15
  customPatterns: [],
14
16
  }
@@ -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
@@ -10,6 +10,7 @@ export type IPatternName =
10
10
  | "browser_version"
11
11
  | "android_version"
12
12
  | "ip_address"
13
+ | "uuid"
13
14
  | (string & {})
14
15
 
15
16
  export type IPattern = {
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 . . . . . . . : ������