Skip to content

Commit 65d76db

Browse files
committed
1 parent abcbc54 commit 65d76db

23 files changed

+1404
-12
lines changed

node_modules/.gitignore

+6
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,12 @@
157157
!/npm-packlist
158158
!/npm-pick-manifest
159159
!/npm-profile
160+
!/npm-profile/node_modules/
161+
/npm-profile/node_modules/*
162+
!/npm-profile/node_modules/@npmcli/
163+
/npm-profile/node_modules/@npmcli/*
164+
!/npm-profile/node_modules/@npmcli/redact
165+
!/npm-profile/node_modules/npm-registry-fetch
160166
!/npm-registry-fetch
161167
!/npm-user-validate
162168
!/p-map

node_modules/npm-profile/lib/index.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -276,8 +276,7 @@ class WebLoginNotSupported extends HttpErrorBase {
276276
}
277277
}
278278

279-
const sleep = (ms) =>
280-
new Promise((resolve, reject) => setTimeout(resolve, ms))
279+
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
281280

282281
module.exports = {
283282
adduserCouch,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2024 npm
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
const deepMap = (input, handler = v => v, path = ['$'], seen = new Set([input])) => {
2+
if (Array.isArray(input)) {
3+
const result = []
4+
for (let i = 0; i < input.length; i++) {
5+
const element = input[i]
6+
const elementPath = [...path, i]
7+
if (element instanceof Object) {
8+
if (!seen.has(element)) { // avoid getting stuck in circular reference
9+
seen.add(element)
10+
result.push(deepMap(handler(element, elementPath), handler, elementPath, seen))
11+
}
12+
} else {
13+
result.push(handler(element, elementPath))
14+
}
15+
}
16+
return result
17+
}
18+
19+
if (input === null) {
20+
return null
21+
} else if (typeof input === 'object' || typeof input === 'function') {
22+
const result = {}
23+
24+
if (input instanceof Error) {
25+
// `name` property is not included in `Object.getOwnPropertyNames(error)`
26+
result.errorType = input.name
27+
}
28+
29+
for (const propertyName of Object.getOwnPropertyNames(input)) {
30+
// skip logging internal properties
31+
if (propertyName.startsWith('_')) {
32+
continue
33+
}
34+
35+
try {
36+
const property = input[propertyName]
37+
const propertyPath = [...path, propertyName]
38+
if (property instanceof Object) {
39+
if (!seen.has(property)) { // avoid getting stuck in circular reference
40+
seen.add(property)
41+
result[propertyName] = deepMap(
42+
handler(property, propertyPath), handler, propertyPath, seen
43+
)
44+
}
45+
} else {
46+
result[propertyName] = handler(property, propertyPath)
47+
}
48+
} catch (err) {
49+
// a getter may throw an error
50+
result[propertyName] = `[error getting value: ${err.message}]`
51+
}
52+
}
53+
return result
54+
}
55+
56+
return handler(input, path)
57+
}
58+
59+
module.exports = { deepMap }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
const matchers = require('./matchers')
2+
const { redactUrlPassword } = require('./utils')
3+
4+
const REPLACE = '***'
5+
6+
const redact = (value) => {
7+
if (typeof value !== 'string' || !value) {
8+
return value
9+
}
10+
return redactUrlPassword(value, REPLACE)
11+
.replace(matchers.NPM_SECRET.pattern, `npm_${REPLACE}`)
12+
.replace(matchers.UUID.pattern, REPLACE)
13+
}
14+
15+
// split on \s|= similar to how nopt parses options
16+
const splitAndRedact = (str) => {
17+
// stateful regex, don't move out of this scope
18+
const splitChars = /[\s=]/g
19+
20+
let match = null
21+
let result = ''
22+
let index = 0
23+
while (match = splitChars.exec(str)) {
24+
result += redact(str.slice(index, match.index)) + match[0]
25+
index = splitChars.lastIndex
26+
}
27+
28+
return result + redact(str.slice(index))
29+
}
30+
31+
// replaces auth info in an array of arguments or in a strings
32+
const redactLog = (arg) => {
33+
if (typeof arg === 'string') {
34+
return splitAndRedact(arg)
35+
} else if (Array.isArray(arg)) {
36+
return arg.map((a) => typeof a === 'string' ? splitAndRedact(a) : a)
37+
}
38+
return arg
39+
}
40+
41+
module.exports = {
42+
redact,
43+
redactLog,
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
const TYPE_REGEX = 'regex'
2+
const TYPE_URL = 'url'
3+
const TYPE_PATH = 'path'
4+
5+
const NPM_SECRET = {
6+
type: TYPE_REGEX,
7+
pattern: /\b(npms?_)[a-zA-Z0-9]{36,48}\b/gi,
8+
replacement: `[REDACTED_NPM_SECRET]`,
9+
}
10+
11+
const AUTH_HEADER = {
12+
type: TYPE_REGEX,
13+
pattern: /\b(Basic\s+|Bearer\s+)[\w+=\-.]+\b/gi,
14+
replacement: `[REDACTED_AUTH_HEADER]`,
15+
}
16+
17+
const JSON_WEB_TOKEN = {
18+
type: TYPE_REGEX,
19+
pattern: /\b[A-Za-z0-9-_]{10,}(?!\.\d+\.)\.[A-Za-z0-9-_]{3,}\.[A-Za-z0-9-_]{20,}\b/gi,
20+
replacement: `[REDACTED_JSON_WEB_TOKEN]`,
21+
}
22+
23+
const UUID = {
24+
type: TYPE_REGEX,
25+
pattern: /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/gi,
26+
replacement: `[REDACTED_UUID]`,
27+
}
28+
29+
const URL_MATCHER = {
30+
type: TYPE_REGEX,
31+
pattern: /(?:https?|ftp):\/\/[^\s/"$.?#].[^\s"]*/gi,
32+
replacement: '[REDACTED_URL]',
33+
}
34+
35+
const DEEP_HEADER_AUTHORIZATION = {
36+
type: TYPE_PATH,
37+
predicate: ({ path }) => path.endsWith('.headers.authorization'),
38+
replacement: '[REDACTED_HEADER_AUTHORIZATION]',
39+
}
40+
41+
const DEEP_HEADER_SET_COOKIE = {
42+
type: TYPE_PATH,
43+
predicate: ({ path }) => path.endsWith('.headers.set-cookie'),
44+
replacement: '[REDACTED_HEADER_SET_COOKIE]',
45+
}
46+
47+
const REWRITE_REQUEST = {
48+
type: TYPE_PATH,
49+
predicate: ({ path }) => path.endsWith('.request'),
50+
replacement: (input) => ({
51+
method: input?.method,
52+
path: input?.path,
53+
headers: input?.headers,
54+
url: input?.url,
55+
}),
56+
}
57+
58+
const REWRITE_RESPONSE = {
59+
type: TYPE_PATH,
60+
predicate: ({ path }) => path.endsWith('.response'),
61+
replacement: (input) => ({
62+
data: input?.data,
63+
status: input?.status,
64+
headers: input?.headers,
65+
}),
66+
}
67+
68+
module.exports = {
69+
TYPE_REGEX,
70+
TYPE_URL,
71+
TYPE_PATH,
72+
NPM_SECRET,
73+
AUTH_HEADER,
74+
JSON_WEB_TOKEN,
75+
UUID,
76+
URL_MATCHER,
77+
DEEP_HEADER_AUTHORIZATION,
78+
DEEP_HEADER_SET_COOKIE,
79+
REWRITE_REQUEST,
80+
REWRITE_RESPONSE,
81+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
const {
2+
AUTH_HEADER,
3+
JSON_WEB_TOKEN,
4+
NPM_SECRET,
5+
DEEP_HEADER_AUTHORIZATION,
6+
DEEP_HEADER_SET_COOKIE,
7+
REWRITE_REQUEST,
8+
REWRITE_RESPONSE,
9+
} = require('./matchers')
10+
11+
const {
12+
redactUrlMatcher,
13+
redactUrlPasswordMatcher,
14+
redactMatchers,
15+
} = require('./utils')
16+
17+
const { deepMap } = require('./deep-map')
18+
19+
const _redact = redactMatchers(
20+
NPM_SECRET,
21+
AUTH_HEADER,
22+
JSON_WEB_TOKEN,
23+
DEEP_HEADER_AUTHORIZATION,
24+
DEEP_HEADER_SET_COOKIE,
25+
REWRITE_REQUEST,
26+
REWRITE_RESPONSE,
27+
redactUrlMatcher(
28+
redactUrlPasswordMatcher()
29+
)
30+
)
31+
32+
const redact = (input) => deepMap(input, (value, path) => _redact(value, { path }))
33+
34+
module.exports = { redact }

0 commit comments

Comments
 (0)