privacy-brush 0.0.3

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 ADDED
@@ -0,0 +1,302 @@
1
+ <h1 align="center" title="PrivacyBrush">๐Ÿ›ก๏ธ Privโ–ˆcyBrโ–ˆsh ๐Ÿ–Œ๏ธ</h1>
2
+
3
+ > **Terminal Output Masking Tool | Safely Share Logs by Hiding Sensitive Information**
4
+
5
+ [![npm version](https://img.shields.io/npm/v/privacy-brush.svg)](https://www.npmjs.com/package/privacy-brush)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
+ [![Typecheck](https://github.com/legend80s/privacy-brush/actions/workflows/typecheck.yml/badge.svg?branch=master)](https://github.com/legend80s/privacy-brush/actions/workflows/typecheck.yml)
8
+
9
+ <p align="center">
10
+ <img src="https://raw.githubusercontent.com/legend80s/privacy-brush/main/docs/demo.gif" alt="PrivacyBrush Demo" width="800">
11
+ </p>
12
+
13
+ ## โœจ Features
14
+
15
+ - ๐ŸŽฏ **Smart Detection** - Auto-detects 20+ sensitive information patterns
16
+ - ๐Ÿ”ง **Highly Configurable** - Custom masking rules and characters
17
+ - โšก **High Performance** - Stream processing for large files
18
+ - ๐Ÿ›ก๏ธ **Privacy First** - Local processing only, no data leaves your machine
19
+ - ๐Ÿ“ฆ **Multiple Formats** - CLI, API, Stream, File processing
20
+ - ๐ŸŒ **Multi-language** - Supports English, Chinese, and other log formats
21
+ - ๐ŸŽจ **Customizable** - Add your own sensitive patterns
22
+
23
+ ## ๐Ÿš€ Quick Start
24
+
25
+ ### Basic Usage
26
+
27
+ ```bash
28
+ # Direct terminal output processing
29
+ flutter devices | pnpx privacy-brush
30
+ flutter doctor | pnpx privacy-brush
31
+
32
+ # Process files
33
+ privacy-brush input.log -o masked.log
34
+
35
+ # Real-time command output
36
+ echo 'Microsoft Windows [Version 10.0.12345.6785]' | privacy-brush
37
+ ```
38
+
39
+ ### In Your Node.js Project
40
+
41
+ ```javascript
42
+ // Or ES Module
43
+ import { PrivacyBrush } from 'privacy-brush';
44
+
45
+ // Create instance
46
+ const brush = new PrivacyBrush();
47
+
48
+ // Process text
49
+ const sensitiveText = `Windows [Version 10.0.12345.1234]
50
+ Chrome 144.0.1234.12
51
+ User IP: 192.123.1.123`;
52
+
53
+ const safeText = brush.maskText(sensitiveText);
54
+ console.log(safeText);
55
+
56
+ // Output:
57
+ // Windows [Version 10.โ–ˆ.โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ.โ–ˆโ–ˆโ–ˆโ–ˆ]
58
+ // Chrome 144.โ–ˆ.โ–ˆโ–ˆโ–ˆโ–ˆ.โ–ˆโ–ˆ
59
+ // User IP: 192.โ–ˆโ–ˆโ–ˆ.โ–ˆ.โ–ˆโ–ˆโ–ˆ
60
+ ```
61
+
62
+ ## ๐Ÿ“– Examples
63
+
64
+ ### Example 1: Process Flutter Output
65
+
66
+ **Original:**
67
+
68
+ ```bash
69
+ โฏ flutter devices
70
+ Found 4 connected devices:
71
+ Windows (desktop) โ€ข windows โ€ข windows-x64 โ€ข Microsoft Windows [Version 10.0.12345.1234]
72
+ Chrome (web) โ€ข chrome โ€ข web-javascript โ€ข Google Chrome 144.0.1234.60
73
+ ```
74
+
75
+ **After PrivacyBrush:**
76
+
77
+ ```bash
78
+ โฏ flutter devices | privacy-brush
79
+ Found 4 connected devices:
80
+ Windows (desktop) โ€ข windows โ€ข windows-x64 โ€ข Microsoft Windows [Version 10.โ–ˆ.โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ.โ–ˆโ–ˆโ–ˆโ–ˆ]
81
+ Chrome (web) โ€ข chrome โ€ข web-javascript โ€ข Google Chrome 144.โ–ˆ.โ–ˆโ–ˆโ–ˆโ–ˆ.โ–ˆโ–ˆ
82
+ ```
83
+
84
+ ### Example 2: Process Node.js Debug Logs
85
+
86
+ ```javascript
87
+ const masker = new PrivacyBrush({
88
+ maskChar: '*',
89
+ preserveFirstPart: false
90
+ });
91
+
92
+ const debugLog = `
93
+ DEBUG: User login from IP 192.168.1.100
94
+ DEBUG: Session ID: abc123def456
95
+ DEBUG: Browser: Chrome/144.0.1234.60
96
+ DEBUG: OS: Windows 10.0.12345
97
+ `;
98
+
99
+ console.log(masker.mask(debugLog));
100
+ // Output:
101
+ // DEBUG: User login from IP ***.***.*.***
102
+ // DEBUG: Session ID: ************
103
+ // DEBUG: Browser: Chrome/***.*.***.**
104
+ // DEBUG: OS: Windows **.*.*****
105
+ ```
106
+
107
+ ## โš™๏ธ Configuration
108
+
109
+ ### CLI Options
110
+
111
+ ```bash
112
+ # Basic usage
113
+ privacy-brush [input-file] [options]
114
+
115
+ # Options
116
+ --output, -o <file> Output to file
117
+ --char, -c <char> Mask character (default: โ–ˆ)
118
+ --preserve-first Keep first part of version numbers
119
+ --strict Strict mode (mask more info)
120
+ --config <file> Use config file
121
+ --list-patterns List all built-in patterns
122
+ --add-pattern <regex> Add custom regex pattern
123
+ --version Show version
124
+ --help Show help
125
+ ```
126
+
127
+ ### JavaScript API Options
128
+
129
+ ```javascript
130
+ const masker = new PrivacyBrush({
131
+ // Basic config
132
+ maskChar: 'โ–ˆ', // Mask character
133
+ preserveFirstPart: true, // Keep first part of versions
134
+
135
+ // Pattern config
136
+ patterns: {
137
+ ipAddress: true,
138
+ macAddress: true,
139
+ email: true,
140
+ phone: true,
141
+ creditCard: true,
142
+ jwtToken: true,
143
+ apiKey: true,
144
+
145
+ osVersion: true,
146
+ browserVersion: true,
147
+ appVersion: true,
148
+
149
+ deviceId: true,
150
+ serialNumber: true,
151
+
152
+ filePaths: false, // Don't mask file paths
153
+ localhost: false // Don't mask localhost
154
+ },
155
+
156
+ // Custom patterns
157
+ customPatterns: [
158
+ {
159
+ name: 'custom-id',
160
+ regex: /ID-\d{6}/g,
161
+ mask: 'ID-******'
162
+ }
163
+ ]
164
+ });
165
+ ```
166
+
167
+ ## ๐Ÿ”ง Built-in Patterns
168
+
169
+ PrivacyBrush includes 20+ pre-configured sensitive information patterns:
170
+
171
+ ### ๐Ÿ” Personal Information
172
+
173
+ - Email addresses `user@example.com` โ†’ `***@example.com`
174
+ - Phone numbers `13800138000` โ†’ `138****8000`
175
+ - ID numbers `110101199001011234` โ†’ `110101********1234`
176
+
177
+ ### ๐Ÿ’ป Technical Information
178
+
179
+ - IP addresses `192.168.1.100` โ†’ `192.168.*.*`
180
+ - MAC addresses `00:1A:2B:3C:4D:5E` โ†’ `00:**:**:**:**:**`
181
+ - Port numbers `:8080` โ†’ `:****`
182
+ - API keys `sk_live_1234567890` โ†’ `sk_live_********`
183
+
184
+ ### ๐Ÿ–ฅ๏ธ System & Browser
185
+
186
+ - Windows versions `10.0.12345.1234` โ†’ `10.โ–ˆโ–ˆโ–ˆ.โ–ˆโ–ˆโ–ˆ.โ–ˆโ–ˆโ–ˆ`
187
+ - Chrome versions `144.0.1234.60` โ†’ `144.โ–ˆโ–ˆโ–ˆ.โ–ˆโ–ˆโ–ˆ.โ–ˆโ–ˆโ–ˆ`
188
+ - Android versions `Android 16` โ†’ `Android โ–ˆโ–ˆ`
189
+
190
+ ### ๐Ÿข Business Data
191
+
192
+ - Credit cards `4111 1111 1111 1111` โ†’ `4111 **** **** 1111`
193
+ - JWT tokens `eyJhbGciOiJIUzI1...` โ†’ `eyJ********...`
194
+ - Session IDs `session-abc123def456` โ†’ `session-************`
195
+
196
+ ## ๐Ÿ› ๏ธ Advanced Usage
197
+
198
+ ### Stream Processing for Large Files
199
+
200
+ ```javascript
201
+ const fs = require('fs');
202
+ const { createMaskStream } = require('privacy-brush');
203
+
204
+ const inputStream = fs.createReadStream('huge.log');
205
+ const maskStream = createMaskStream();
206
+
207
+ inputStream
208
+ .pipe(maskStream)
209
+ .pipe(fs.createWriteStream('masked-huge.log'))
210
+ .on('finish', () => {
211
+ console.log('Large file processing completed!');
212
+ });
213
+ ```
214
+
215
+ ### Express.js Integration
216
+
217
+ ```javascript
218
+ const express = require('express');
219
+ const { PrivacyBrush } = require('privacy-brush');
220
+ const app = express();
221
+ const masker = new PrivacyBrush();
222
+
223
+ // Middleware: auto-mask sensitive info in responses
224
+ app.use((req, res, next) => {
225
+ const originalSend = res.send;
226
+ res.send = function(body) {
227
+ if (typeof body === 'string' && body.includes('sensitive')) {
228
+ body = masker.mask(body);
229
+ }
230
+ originalSend.call(this, body);
231
+ };
232
+ next();
233
+ });
234
+ ```
235
+
236
+ ### Git Hook Integration
237
+
238
+ ```bash
239
+ #!/bin/bash
240
+ # .git/hooks/pre-commit
241
+
242
+ for file in $(git diff --cached --name-only | grep -E '\.(log|txt|json)$'); do
243
+ if privacy-brush --check "$file"; then
244
+ echo "โŒ File $file contains unmasked sensitive information"
245
+ echo "Use: privacy-brush $file -o $file && git add $file"
246
+ exit 1
247
+ fi
248
+ done
249
+ ```
250
+
251
+ ## ๐Ÿ“ Configuration File
252
+
253
+ Create `privacy-brush.config.json`:
254
+
255
+ ```json
256
+ {
257
+ "maskChar": "โ–ˆ",
258
+ "preserveFirstPart": true,
259
+ "patterns": {
260
+ "ipAddress": true,
261
+ "email": true,
262
+ "phone": true,
263
+ "osVersion": true,
264
+ "browserVersion": true
265
+ },
266
+ "customPatterns": [
267
+ {
268
+ "name": "project-api-key",
269
+ "regex": "PROJECT_API_KEY=\\w{32}",
270
+ "mask": "PROJECT_API_KEY=******************************"
271
+ }
272
+ ]
273
+ }
274
+ ```
275
+
276
+ ## ๐Ÿค Contributing
277
+
278
+ We welcome contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
279
+
280
+ 1. Fork the repository
281
+ 2. Create a feature branch (`git checkout -b feature/amazing-feature`)
282
+ 3. Commit changes (`git commit -m 'Add amazing feature'`)
283
+ 4. Push to branch (`git push origin feature/amazing-feature`)
284
+ 5. Open a Pull Request
285
+
286
+ ## ๐Ÿ“„ License
287
+
288
+ MIT License ยฉ 2024 PrivacyBrush Contributors
289
+
290
+ ## ๐Ÿ“ž Support
291
+
292
+ - ๐Ÿ“ง Email: <support@privacy-brush.dev>
293
+ - ๐Ÿ› [Issue Tracker](https://github.com/legend80s/privacy-brush/issues)
294
+ - ๐Ÿ’ฌ [Discussions](https://github.com/legend80s/privacy-brush/discussions)
295
+ - ๐Ÿ“– [Documentation](https://privacy-brush.dev/docs)
296
+
297
+ ---
298
+
299
+ <p align="center">
300
+ <strong>Share Safely, Start with PrivacyBrush</strong><br>
301
+ <sub>Protect privacy, communicate with confidence</sub>
302
+ </p>
package/biome.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "$schema": "https://biomejs.dev/schemas/2.0.4/schema.json",
3
+ "vcs": {
4
+ "enabled": false,
5
+ "clientKind": "git",
6
+ "useIgnoreFile": false
7
+ },
8
+ "files": {
9
+ "ignoreUnknown": false
10
+ },
11
+ "formatter": {
12
+ "enabled": true,
13
+ "indentStyle": "space"
14
+ },
15
+ "linter": {
16
+ "enabled": true,
17
+ "rules": {
18
+ "recommended": true
19
+ }
20
+ },
21
+ "javascript": {
22
+ "formatter": {
23
+ "arrowParentheses": "asNeeded",
24
+ "semicolons": "asNeeded",
25
+ "quoteStyle": "double"
26
+ }
27
+ },
28
+ "assist": {
29
+ "enabled": true,
30
+ "actions": {
31
+ "source": {
32
+ "organizeImports": "on"
33
+ }
34
+ }
35
+ }
36
+ }
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "privacy-brush",
3
+ "version": "0.0.3",
4
+ "description": "Automatically mask sensitive information in terminal outputs and logs. Keep your data safe when sharing.",
5
+ "main": "src/index.mjs",
6
+ "module": "src/index.mjs",
7
+ "bin": "src/cli.mjs",
8
+ "scripts": {
9
+ "test": "node --test",
10
+ "typecheck": "tsgo --noEmit",
11
+ "check": "npm run typecheck && npm run test",
12
+ "========== Publishing ==========": "",
13
+ "pub:patch": "npm version patch",
14
+ "pub:minor": "npm version minor",
15
+ "pub:major": "npm version major",
16
+ "preversion": "git pull && git push origin HEAD && pnpm i && npm run check",
17
+ "postversion": "npm publish && git push origin HEAD && git push --tags",
18
+ "publishd": "npm publish --dry-run"
19
+ },
20
+ "keywords": [],
21
+ "author": "",
22
+ "license": "ISC",
23
+ "devDependencies": {
24
+ "@types/node": "^25.0.10"
25
+ }
26
+ }
package/src/cli.mjs ADDED
@@ -0,0 +1,116 @@
1
+ import { parseArgs } from "node:util"
2
+ import { PrivacyBrush } from "./index.mjs"
3
+
4
+ // ๆตๅผๅค„็†๏ผšๅฐ† stdin ้€š่ฟ‡ masker ็š„ Transform ๆตๅค„็†ๅŽ่พ“ๅ‡บๅˆฐ stdout
5
+ // Usage: some_command | node src/cli.mjs
6
+ // Example 1: echo "password" | node src/cli.mjs
7
+ // Example 2: flutter devices | node src/cli.mjs
8
+ // Example 3: โฏ echo 'Microsoft Windows [็‰ˆๆœฌ 10.0.12345.6785]' | node src/cli.mjs
9
+ // => Microsoft Windows [็‰ˆๆœฌ 10.โ–ˆ.โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ.โ–ˆโ–ˆโ–ˆโ–ˆ]
10
+ // Example 4: โฏ node src/cli.mjs
11
+ // Input: Microsoft Windows [็‰ˆๆœฌ 10.0.12345.6785]
12
+ // Output: Microsoft Windows [็‰ˆๆœฌ 10.โ–ˆ.โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ.โ–ˆโ–ˆโ–ˆโ–ˆ]
13
+
14
+ // get config from command line arguments use native `parseArgs`
15
+ // node src/cli.mjs --mask X --preserve-first false
16
+ const args = process.argv.slice(2)
17
+ // console.log("args:", args) // args: [ '--mask', 'X', '--preserve-first', 'false' ]
18
+
19
+ const verbose = args.includes("--verbose")
20
+
21
+ const [err, result] = safeCall(() =>
22
+ parseArgs({
23
+ allowPositionals: true,
24
+ allowNegative: true,
25
+
26
+ args,
27
+
28
+ options: {
29
+ mask: {
30
+ type: "string",
31
+ short: "m",
32
+ default: "โ–ˆ",
33
+ },
34
+ "preserve-first": {
35
+ type: "boolean",
36
+ short: "p",
37
+ default: true,
38
+ },
39
+ // help
40
+ help: {
41
+ type: "boolean",
42
+ short: "h",
43
+ },
44
+ // verbose
45
+ verbose: {
46
+ type: "boolean",
47
+ },
48
+ },
49
+ }),
50
+ )
51
+
52
+ await main()
53
+
54
+ async function main() {
55
+ if (err) {
56
+ console.error(verbose ? err : String(err))
57
+ console.error()
58
+ printHelp()
59
+
60
+ process.exit(1)
61
+ }
62
+
63
+ const { values } = result
64
+
65
+ if (values.help) {
66
+ printHelp()
67
+ process.exit(0)
68
+ }
69
+
70
+ // console.log("values:", values)
71
+ // console.log("positionals:", positionals)
72
+
73
+ const config = values
74
+
75
+ const masker = new PrivacyBrush({
76
+ maskChar: config.mask,
77
+ preserveFirstPart: config["preserve-first"],
78
+ })
79
+ const maskStream = await masker.createMaskStream()
80
+
81
+ // ๆฃ€ๆŸฅ stdin ๆ˜ฏๅฆ่ฟžๆŽฅๅˆฐ็ฎก้“๏ผˆๆœ‰ๆ•ฐๆฎ่พ“ๅ…ฅ๏ผ‰
82
+ const isPipedInput = !process.stdin.isTTY
83
+
84
+ // ๅฆ‚ๆžœไธๆ˜ฏ็ฎก้“่พ“ๅ…ฅ๏ผˆไบคไบ’ๆจกๅผ๏ผ‰๏ผŒๆ‰ๆ˜พ็คบๆ็คบ
85
+ if (!isPipedInput) {
86
+ process.stdout.write("Input (Press Ctrl+C to exit...):\n")
87
+ }
88
+
89
+ // ๅค„็†ๆ‰€ๆœ‰ๆ•ฐๆฎ
90
+ process.stdin.pipe(maskStream).pipe(process.stdout)
91
+ }
92
+ /**
93
+ * @template T
94
+ * @param {(...args: any[]) => T} fn
95
+ * @returns {[null, T] | [Error, null]}
96
+ */
97
+ function safeCall(fn) {
98
+ try {
99
+ const result = fn()
100
+ return [null, result]
101
+ } catch (error) {
102
+ // @ts-expect-error
103
+ return [error, null]
104
+ }
105
+ }
106
+
107
+ function printHelp() {
108
+ console.log(`Usage: node src/cli.mjs [options]
109
+
110
+ Options:
111
+ --mask, -m Character to use for masking (default: "โ–ˆ")
112
+ --preserve-first, -p Whether to preserve the first part of version numbers (default: true, \`--no-preserve-first\` to false)
113
+ --help, -h Show this help message (default: false)
114
+ --verbose Enable verbose output (default: false)
115
+ `)
116
+ }
@@ -0,0 +1,28 @@
1
+ // ๆตๅผๅค„็†
2
+
3
+ import { strict as assert } from "node:assert"
4
+ import { execSync } from "node:child_process"
5
+ import { test } from "node:test"
6
+
7
+ test("โฏ echo 'Microsoft Windows [Version 10.0.12345.6785]' | node src/cli.mjs", async () => {
8
+ const actual = execSync(
9
+ "echo Microsoft Windows [Version 10.0.12345.6785] | node src/cli.mjs",
10
+ ).toString("utf8")
11
+
12
+ // console.log(`actual:|${actual}|`)
13
+
14
+ const expected = "Microsoft Windows [Version 10.โ–ˆ.โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆ.โ–ˆโ–ˆโ–ˆโ–ˆ] \r\n"
15
+ assert.strictEqual(actual, expected)
16
+ })
17
+
18
+ test("--mask", async () => {
19
+ const actual = execSync(
20
+ 'echo Microsoft Windows [Version 10.0.12345.6785] | node src/cli.mjs --mask "๐Ÿ”’" --no-preserve-first',
21
+ ).toString("utf8")
22
+
23
+ // console.log(`actual:|${actual}|`)
24
+
25
+ const expected =
26
+ "Microsoft Windows [Version ๐Ÿ”’๐Ÿ”’.๐Ÿ”’.๐Ÿ”’๐Ÿ”’๐Ÿ”’๐Ÿ”’๐Ÿ”’.๐Ÿ”’๐Ÿ”’๐Ÿ”’๐Ÿ”’] \r\n"
27
+ assert.strictEqual(actual, expected)
28
+ })
package/src/index.mjs ADDED
@@ -0,0 +1,162 @@
1
+ /** @import { IConfig, IPattern, IPatternName } from "./type.js" */
2
+
3
+ import { defaultConfig } from "./lib/config.mjs"
4
+
5
+ export class PrivacyBrush {
6
+ /**
7
+ * @param {IConfig} [config]
8
+ */
9
+ constructor(config) {
10
+ this.config = {
11
+ ...defaultConfig,
12
+ ...config,
13
+ }
14
+ }
15
+
16
+ get defaultSensitivePatterns() {
17
+ /** @type {IPattern[]} */
18
+ const allPatterns = [
19
+ // ๆ“ไฝœ็ณป็ปŸ็‰ˆๆœฌ (Windows 10.0.19045.6456)
20
+ {
21
+ /** @type {IPatternName} */
22
+ name: "windows_version",
23
+ // match both Chinese "็‰ˆๆœฌ" and English "Version"
24
+ regex: /(\[(?:็‰ˆๆœฌ|Version)\s+)(\d+\.\d+\.\d+\.\d+)(\])/i,
25
+ /**
26
+ * Handle windows version masking.
27
+ * @param {string} match
28
+ * @param {string} prefix
29
+ * @param {string} version
30
+ * @param {string} suffix
31
+ * @returns {string}
32
+ */
33
+ replacer: (match, prefix, version, suffix) => {
34
+ return prefix + this.maskVersion(version) + suffix
35
+ },
36
+ },
37
+
38
+ // ๆต่งˆๅ™จ็‰ˆๆœฌ (Chrome 144.0.7559.60)
39
+ {
40
+ /** @type {IPatternName} */
41
+ name: "browser_version",
42
+ regex: /(Chrome|Edge)\s+(\d+\.\d+\.\d+\.\d+)/gi,
43
+ /**
44
+ * Handle browser version masking.
45
+ * @param {string} match
46
+ * @param {string} browser
47
+ * @param {string} version
48
+ * @returns {string}
49
+ */
50
+ replacer: (match, browser, version) => {
51
+ return `${browser} ${this.maskVersion(version)}`
52
+ },
53
+ },
54
+
55
+ // IPๅœฐๅ€
56
+ {
57
+ /** @type {IPatternName} */
58
+ name: "ip_address",
59
+ regex: /\b(\d{1,3}\.){3}\d{1,3}\b/g,
60
+ /**
61
+ * Handle IP address masking.
62
+ * @param {string} match
63
+ * @returns {string}
64
+ */
65
+ replacer: match => {
66
+ return this.maskVersion(match)
67
+ },
68
+ },
69
+ ]
70
+
71
+ return allPatterns
72
+ }
73
+
74
+ get maskChar() {
75
+ return this.config.maskChar ?? defaultConfig.maskChar
76
+ }
77
+
78
+ /**
79
+ *
80
+ * @returns {IPattern[]}
81
+ */
82
+ get sensitivePatterns() {
83
+ return this.defaultSensitivePatterns.filter(({ name }) =>
84
+ this.config.maskPatternNames?.includes(name),
85
+ )
86
+ }
87
+
88
+ /**
89
+ * Mask a version string.
90
+ * @param {string} version
91
+ * @returns {string}
92
+ */
93
+ maskVersion(version) {
94
+ const parts = version.split(".")
95
+
96
+ if (!this.config.preserveFirstPart) {
97
+ return parts.map(part => this.maskChar.repeat(part.length)).join(".")
98
+ }
99
+
100
+ return parts
101
+ .map((part, index) => {
102
+ return index === 0 ? part : this.maskChar.repeat(part.length)
103
+ })
104
+ .join(".")
105
+ }
106
+
107
+ /**
108
+ *
109
+ * @param {string} text
110
+ * @returns
111
+ */
112
+ maskText(text) {
113
+ let result = text
114
+
115
+ this.sensitivePatterns.forEach(pattern => {
116
+ result = result.replace(pattern.regex, pattern.replacer)
117
+ })
118
+
119
+ return result
120
+ }
121
+
122
+ /**
123
+ * ๆ‰น้‡ๅค„็†ๆ–‡ไปถ
124
+ * @param {string} inputPath
125
+ * @param {string} outputPath
126
+ * @returns
127
+ */
128
+ maskFile(inputPath, outputPath) {
129
+ try {
130
+ const fs = require("node:fs")
131
+
132
+ const content = fs.readFileSync(inputPath, "utf8")
133
+ const maskedContent = this.maskText(content)
134
+
135
+ if (outputPath) {
136
+ fs.writeFileSync(outputPath, maskedContent, "utf8")
137
+ console.log(`Masked file saved to: ${outputPath}`)
138
+ }
139
+
140
+ return maskedContent
141
+ } catch (error) {
142
+ console.error(
143
+ "Error processing file:",
144
+ error instanceof Error ? error.message : String(error),
145
+ )
146
+ throw error
147
+ }
148
+ }
149
+
150
+ // ๅฎžๆ—ถๆตๅค„็†
151
+ async createMaskStream() {
152
+ const { Transform } = await import("node:stream")
153
+
154
+ return new Transform({
155
+ transform: (chunk, encoding, callback) => {
156
+ const text = String(chunk)
157
+ const masked = this.maskText(text)
158
+ callback(null, masked)
159
+ },
160
+ })
161
+ }
162
+ }