privacy-brush 1.0.0 → 1.0.2
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/.github/workflows/typecheck.yml +32 -31
- package/.nvmrc +1 -0
- package/README-zh.md +496 -496
- package/README.md +314 -302
- package/package.json +26 -5
- package/src/cli.mjs +25 -5
- package/src/cli.test.mjs +25 -16
- package/src/index.mjs +17 -0
- package/src/lib/config.mjs +6 -1
- package/src/lib/parse-args.mjs +4 -0
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "privacy-brush",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
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",
|
|
7
7
|
"bin": "src/cli.mjs",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"test": "node --test",
|
|
9
|
+
"test": "node --test || nvm use 22 && sleep 0.5 && node --test",
|
|
10
10
|
"typecheck": "tsgo --noEmit",
|
|
11
11
|
"check": "npm run typecheck && npm run test",
|
|
12
12
|
"========== Publishing ==========": "",
|
|
@@ -17,10 +17,31 @@
|
|
|
17
17
|
"postversion": "npm publish && git push origin HEAD && git push --tags",
|
|
18
18
|
"publishd": "npm publish --dry-run"
|
|
19
19
|
},
|
|
20
|
-
"keywords": [
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
"keywords": [
|
|
21
|
+
"privacy",
|
|
22
|
+
"mask",
|
|
23
|
+
"masking",
|
|
24
|
+
"sensitive",
|
|
25
|
+
"guard",
|
|
26
|
+
"shield",
|
|
27
|
+
"safe",
|
|
28
|
+
"sharing",
|
|
29
|
+
"sanitize",
|
|
30
|
+
"obfuscate",
|
|
31
|
+
"blur",
|
|
32
|
+
"logs",
|
|
33
|
+
"terminal",
|
|
34
|
+
"security"
|
|
35
|
+
],
|
|
36
|
+
"author": "legend80s",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "git+https://github.com/legend80s/privacy-brush.git"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/legend80s/privacy-brush",
|
|
23
43
|
"devDependencies": {
|
|
44
|
+
"@typescript/native-preview": "7.0.0-dev.20260122.2",
|
|
24
45
|
"@types/node": "^25.0.10"
|
|
25
46
|
}
|
|
26
47
|
}
|
package/src/cli.mjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
1
3
|
import { PrivacyBrush } from "./index.mjs"
|
|
2
4
|
import { parsedResult, verbose } from "./lib/parse-args.mjs"
|
|
3
5
|
|
|
@@ -26,6 +28,7 @@ async function main() {
|
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
const { values } = result
|
|
31
|
+
verbose && console.log("values:", values)
|
|
29
32
|
|
|
30
33
|
if (values.help) {
|
|
31
34
|
await printHelp()
|
|
@@ -37,9 +40,6 @@ async function main() {
|
|
|
37
40
|
return
|
|
38
41
|
}
|
|
39
42
|
|
|
40
|
-
verbose && console.log("values:", values)
|
|
41
|
-
// console.log("positionals:", positionals)
|
|
42
|
-
|
|
43
43
|
const config = values
|
|
44
44
|
|
|
45
45
|
const masker = new PrivacyBrush({
|
|
@@ -48,6 +48,23 @@ async function main() {
|
|
|
48
48
|
customPatterns: config.pattern,
|
|
49
49
|
})
|
|
50
50
|
|
|
51
|
+
if (values["list-patterns"]) {
|
|
52
|
+
// instantiate PrivacyBrush to access default patterns
|
|
53
|
+
const patterns = masker.defaultSensitivePatterns
|
|
54
|
+
|
|
55
|
+
console.log("\nBuilt-in patterns:")
|
|
56
|
+
console.table(patterns.map(({ replacer: _, ...args }) => args))
|
|
57
|
+
|
|
58
|
+
if (masker.customSensitivePatterns.length) {
|
|
59
|
+
console.log("Custom patterns:")
|
|
60
|
+
console.table(
|
|
61
|
+
masker.customSensitivePatterns.map(({ replacer: _, ...args }) => args),
|
|
62
|
+
)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
|
|
51
68
|
// If an input file is provided, process it. If --output-file is provided write there, otherwise print to stdout.
|
|
52
69
|
if (config["input-file"]) {
|
|
53
70
|
try {
|
|
@@ -113,10 +130,13 @@ pnpx privacy-brush [options]
|
|
|
113
130
|
|
|
114
131
|
|
|
115
132
|
## Options:
|
|
116
|
-
--input-file, -i
|
|
117
|
-
--output-file, -o
|
|
133
|
+
--input-file, -i Path to input file to mask and print to stdout
|
|
134
|
+
--output-file, -o Path to write masked output (if given, write to this file)
|
|
118
135
|
--mask, -m Character to use for masking (default: "█")
|
|
119
136
|
--preserve-first, -p Whether to preserve the first part of version numbers (default: true, \`--no-preserve-first\` to false)
|
|
137
|
+
--pattern, -r Custom regex pattern(s) to mask (can be used multiple times. E.g. --pattern '\\d{2,}' --pattern 'sk-([0-9a-z]{20,})')
|
|
138
|
+
--list-patterns List all built-in patterns
|
|
139
|
+
|
|
120
140
|
--help, -h Show this help message (default: false)
|
|
121
141
|
--verbose Enable verbose output (default: false)
|
|
122
142
|
--version, -v Show version information (default: false)
|
package/src/cli.test.mjs
CHANGED
|
@@ -27,12 +27,13 @@ test("❯ echo | node src/cli.mjs", async () => {
|
|
|
27
27
|
test("--mask", async () => {
|
|
28
28
|
const actual = execSync(
|
|
29
29
|
'echo Microsoft Windows [Version 10.0.12345.6785] | node src/cli.mjs --mask "🔒" --no-preserve-first',
|
|
30
|
-
)
|
|
30
|
+
)
|
|
31
|
+
.toString("utf8")
|
|
32
|
+
.trim()
|
|
31
33
|
|
|
32
34
|
// console.log(`actual:|${actual}|`)
|
|
33
35
|
|
|
34
|
-
const expected =
|
|
35
|
-
"Microsoft Windows [Version 🔒🔒.🔒.🔒🔒🔒🔒🔒.🔒🔒🔒🔒] \r\n"
|
|
36
|
+
const expected = "Microsoft Windows [Version 🔒🔒.🔒.🔒🔒🔒🔒🔒.🔒🔒🔒🔒]"
|
|
36
37
|
assert.strictEqual(actual, expected)
|
|
37
38
|
})
|
|
38
39
|
|
|
@@ -78,33 +79,41 @@ DEBUG: OS: Windows 10.0.12345
|
|
|
78
79
|
test(`custom patterns`, () => {
|
|
79
80
|
const input = `DEEPSEEK_API_KEY=sk-af75149812524eb08eb302bf9604c8e8`
|
|
80
81
|
|
|
81
|
-
const actual =
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
const actual = spawnSync(
|
|
83
|
+
"node",
|
|
84
|
+
["src/cli.mjs", "--pattern", "/sk-([a-z0-9]{20,})/"],
|
|
85
|
+
{ input },
|
|
86
|
+
).stdout.toString("utf8")
|
|
84
87
|
|
|
85
|
-
const expected = "DEEPSEEK_API_KEY=sk-████████████████████████████████
|
|
88
|
+
const expected = "DEEPSEEK_API_KEY=sk-████████████████████████████████"
|
|
86
89
|
assert.strictEqual(actual, expected)
|
|
87
90
|
})
|
|
88
91
|
|
|
89
|
-
test(`custom patterns`, () => {
|
|
92
|
+
test(`custom patterns without ()`, () => {
|
|
90
93
|
const input = `DEEPSEEK_API_KEY=sk-af75149812524eb08eb302bf9604c8e8`
|
|
91
94
|
|
|
92
|
-
const actual =
|
|
93
|
-
|
|
94
|
-
|
|
95
|
+
const actual = spawnSync(
|
|
96
|
+
"node",
|
|
97
|
+
["src/cli.mjs", "--pattern", "/sk-[a-z0-9]{20,}/"],
|
|
98
|
+
{ input },
|
|
99
|
+
)
|
|
100
|
+
.stdout.toString("utf8")
|
|
101
|
+
.trim()
|
|
95
102
|
|
|
96
|
-
const expected = "DEEPSEEK_API_KEY=███████████████████████████████████
|
|
103
|
+
const expected = "DEEPSEEK_API_KEY=███████████████████████████████████"
|
|
97
104
|
assert.strictEqual(actual, expected)
|
|
98
105
|
})
|
|
99
106
|
|
|
100
107
|
test(`custom patterns`, () => {
|
|
101
108
|
const input = `DEEPSEEK_API_KEY=sk-af75149812524eb08eb302bf9604c8e8`
|
|
102
109
|
|
|
103
|
-
const actual =
|
|
104
|
-
|
|
105
|
-
|
|
110
|
+
const actual = spawnSync(
|
|
111
|
+
"node",
|
|
112
|
+
["src/cli.mjs", "--pattern", "/([0-9]{2,})/"],
|
|
113
|
+
{ input },
|
|
114
|
+
).stdout.toString("utf8")
|
|
106
115
|
|
|
107
|
-
const expected = "DEEPSEEK_API_KEY=sk-af███████████eb██eb███bf████c8e8
|
|
116
|
+
const expected = "DEEPSEEK_API_KEY=sk-af███████████eb██eb███bf████c8e8"
|
|
108
117
|
assert.strictEqual(actual, expected)
|
|
109
118
|
})
|
|
110
119
|
|
package/src/index.mjs
CHANGED
|
@@ -68,6 +68,22 @@ export class PrivacyBrush {
|
|
|
68
68
|
return this.maskVersion(match)
|
|
69
69
|
},
|
|
70
70
|
},
|
|
71
|
+
|
|
72
|
+
// user name `/Users/test/code/` => `/Users/████/code/`
|
|
73
|
+
{
|
|
74
|
+
/** @type {IPatternName} */
|
|
75
|
+
name: "user_name_in_path",
|
|
76
|
+
regex: /\/Users\/([^\/]+)\//g,
|
|
77
|
+
/**
|
|
78
|
+
* Handle user name in file path masking.
|
|
79
|
+
* @param {string} match
|
|
80
|
+
* @param {string} userName
|
|
81
|
+
* @returns {string}
|
|
82
|
+
*/
|
|
83
|
+
replacer: (match, userName) => {
|
|
84
|
+
return match.replace(userName, this.maskChar.repeat(userName.length))
|
|
85
|
+
},
|
|
86
|
+
},
|
|
71
87
|
]
|
|
72
88
|
|
|
73
89
|
return allPatterns
|
|
@@ -187,6 +203,7 @@ export class PrivacyBrush {
|
|
|
187
203
|
let result = text
|
|
188
204
|
|
|
189
205
|
this.sensitivePatterns.forEach(pattern => {
|
|
206
|
+
verbose && console.log("pattern:", pattern)
|
|
190
207
|
result = result.replace(pattern.regex, pattern.replacer)
|
|
191
208
|
})
|
|
192
209
|
|
package/src/lib/config.mjs
CHANGED
|
@@ -4,6 +4,11 @@
|
|
|
4
4
|
export const defaultConfig = {
|
|
5
5
|
maskChar: "█",
|
|
6
6
|
preserveFirstPart: true, // 是否保留版本号的第一部分
|
|
7
|
-
maskPatternNames: [
|
|
7
|
+
maskPatternNames: [
|
|
8
|
+
"windows_version",
|
|
9
|
+
"browser_version",
|
|
10
|
+
"ip_address",
|
|
11
|
+
"user_name_in_path",
|
|
12
|
+
],
|
|
8
13
|
customPatterns: [],
|
|
9
14
|
}
|