Skip to content

Commit 7e75778

Browse files
committed
chore: add redact URI credentials
1 parent 4d0517b commit 7e75778

File tree

6 files changed

+186
-6
lines changed

6 files changed

+186
-6
lines changed

package-lock.json

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/mongodb-redact/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
"typescript": "^5.0.4"
7272
},
7373
"dependencies": {
74-
"regexp.escape": "^2.0.1"
74+
"regexp.escape": "^2.0.1",
75+
"mongodb-connection-string-url": "^3.0.1"
7576
}
7677
}

packages/mongodb-redact/src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,7 @@ export function redact<T>(
4646
return message;
4747
}
4848

49+
export { redactUriCredentials } from './redact-uri-credentials';
50+
4951
export default redact;
5052
export type { Secret } from './secrets';
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
import { expect } from 'chai';
2+
import { redactUriCredentials } from './redact-uri-credentials';
3+
import redact from '.';
4+
5+
describe('redactUriCredentials', function () {
6+
const testCases: Array<{
7+
description: string;
8+
input: string;
9+
expected: string;
10+
}> = [
11+
{
12+
description: 'should redact username and password',
13+
input: 'mongodb://user:password@localhost:27017/admin',
14+
expected: 'mongodb://<credentials>@localhost:27017/admin',
15+
},
16+
{
17+
description: 'should redact only username when no password',
18+
input: 'mongodb://user@localhost:27017/admin',
19+
expected: 'mongodb://<credentials>@localhost:27017/admin',
20+
},
21+
{
22+
description: 'should redact credentials in SRV URIs',
23+
input: 'mongodb+srv://admin:[email protected]/test',
24+
expected: 'mongodb+srv://<credentials>@cluster0.example.com/test',
25+
},
26+
{
27+
description: 'should redact passwords with ! character',
28+
input: 'mongodb://user:p@ss!word@localhost:27017/',
29+
expected: 'mongodb://<credentials>@localhost:27017/',
30+
},
31+
{
32+
description: 'should redact passwords with # character',
33+
input: 'mongodb://admin:test#[email protected]:27017/',
34+
expected: 'mongodb://<credentials>@db.example.com:27017/',
35+
},
36+
{
37+
description: 'should redact passwords with $ character',
38+
input: 'mongodb://user:price$100@localhost:27017/',
39+
expected: 'mongodb://<credentials>@localhost:27017/',
40+
},
41+
{
42+
description: 'should redact passwords with % character',
43+
input: 'mongodb://user:test%pass@localhost:27017/',
44+
expected: 'mongodb://<credentials>@localhost:27017/',
45+
},
46+
{
47+
description: 'should redact passwords with & character',
48+
input: 'mongodb://user:rock&roll@localhost:27017/',
49+
expected: 'mongodb://<credentials>@localhost:27017/',
50+
},
51+
{
52+
description: 'should redact URL-encoded passwords',
53+
input: 'mongodb://user:my%20password@localhost:27017/',
54+
expected: 'mongodb://<credentials>@localhost:27017/',
55+
},
56+
{
57+
description:
58+
'should redact complex passwords with multiple special characters',
59+
input: 'mongodb://user:p&ssw!rd#[email protected]:27017/db?authSource=admin',
60+
expected: 'mongodb://<credentials>@host.com:27017/db?authSource=admin',
61+
},
62+
{
63+
description: 'should redact usernames with special characters',
64+
input: 'mongodb://us!er:password@localhost:27017/',
65+
expected: 'mongodb://<credentials>@localhost:27017/',
66+
},
67+
{
68+
description: 'should return URI unchanged when no credentials',
69+
input: 'mongodb://localhost:27017/admin',
70+
expected: 'mongodb://localhost:27017/admin',
71+
},
72+
{
73+
description: 'should handle simple localhost URI',
74+
input: 'mongodb://localhost',
75+
expected: 'mongodb://localhost/',
76+
},
77+
{
78+
description: 'should handle URI with database',
79+
input: 'mongodb://localhost/mydb',
80+
expected: 'mongodb://localhost/mydb',
81+
},
82+
{
83+
description: 'should handle URI with query parameters',
84+
input: 'mongodb://localhost:27017/mydb?ssl=true&replicaSet=rs0',
85+
expected: 'mongodb://localhost:27017/mydb?ssl=true&replicaSet=rs0',
86+
},
87+
// URIs with replica sets
88+
{
89+
description: 'should redact credentials in replica set URIs',
90+
input:
91+
'mongodb://user:pass@host1:27017,host2:27017,host3:27017/db?replicaSet=rs0',
92+
expected:
93+
'mongodb://<credentials>@host1:27017,host2:27017,host3:27017/db?replicaSet=rs0',
94+
},
95+
{
96+
description: 'should handle replica set URIs without credentials',
97+
input:
98+
'mongodb://host1:27017,host2:27017,host3:27017/?replicaSet=myReplSet',
99+
expected:
100+
'mongodb://host1:27017,host2:27017,host3:27017/?replicaSet=myReplSet',
101+
},
102+
// URIs with IP addresses
103+
{
104+
description: 'should redact credentials with IP address host',
105+
input: 'mongodb://user:[email protected]:27017/mydb',
106+
expected: 'mongodb://<credentials>@192.168.1.100:27017/mydb',
107+
},
108+
{
109+
description: 'should handle IP address URIs without credentials',
110+
input: 'mongodb://10.0.0.5:27017/admin',
111+
expected: 'mongodb://10.0.0.5:27017/admin',
112+
},
113+
// SRV URIs
114+
{
115+
description: 'should handle SRV URIs without credentials',
116+
input: 'mongodb+srv://cluster0.example.com/test',
117+
expected: 'mongodb+srv://cluster0.example.com/test',
118+
},
119+
// URIs with query parameters
120+
{
121+
description: 'should redact credentials and preserve query parameters',
122+
input:
123+
'mongodb://user:[email protected]/db?authSource=admin&readPreference=primary',
124+
expected:
125+
'mongodb://<credentials>@host.com/db?authSource=admin&readPreference=primary',
126+
},
127+
{
128+
description: 'should handle URIs with SSL options',
129+
input:
130+
'mongodb://admin:secret@localhost:27017/mydb?ssl=true&tlsAllowInvalidCertificates=true',
131+
expected:
132+
'mongodb://<credentials>@localhost:27017/mydb?ssl=true&tlsAllowInvalidCertificates=true',
133+
},
134+
{
135+
description: 'should redact credentials in SRV URIs with query params',
136+
input:
137+
'mongodb+srv://admin:[email protected]/mydb?retryWrites=true',
138+
expected:
139+
'mongodb+srv://<credentials>@mycluster.mongodb.net/mydb?retryWrites=true',
140+
},
141+
// Edge cases
142+
{
143+
description: 'should handle empty password',
144+
input: 'mongodb://user:@localhost:27017/',
145+
expected: 'mongodb://<credentials>@localhost:27017/',
146+
},
147+
{
148+
description:
149+
'should handle password with only special characters (URL-encoded)',
150+
input: 'mongodb://user:%21%40%23%24%25@localhost:27017/',
151+
expected: 'mongodb://<credentials>@localhost:27017/',
152+
},
153+
{
154+
description: 'should handle very long passwords',
155+
input: `mongodb://user:${'a'.repeat(100)}@localhost:27017/`,
156+
expected: 'mongodb://<credentials>@localhost:27017/',
157+
},
158+
{
159+
description: 'should handle international characters in password',
160+
input: 'mongodb://user:пароль@localhost:27017/',
161+
expected: 'mongodb://<credentials>@localhost:27017/',
162+
},
163+
];
164+
165+
testCases.forEach(({ description, input, expected }) => {
166+
it(description, function () {
167+
const result = redactUriCredentials(input);
168+
expect(result).to.equal(expected);
169+
170+
expect(redact(input)).to.equal('<mongodb uri>');
171+
});
172+
});
173+
});
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { redactConnectionString } from 'mongodb-connection-string-url';
2+
3+
export function redactUriCredentials(uri: string): string {
4+
return redactConnectionString(uri);
5+
}

packages/mongodb-redact/src/regexes.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,8 @@ export const regexes = [
2727
'$1<email>$6',
2828
],
2929

30-
// MongoDB connection strings (before IP addresses to handle mongodb://IP:port URIs)
31-
[
32-
/(mongodb(?:\+srv)?:\/\/)(www\.)?(?:[^:/@\s]+:[^@\s]*@)?[-a-zA-Z0-9@:%._+~#=,]{2,256}(\.[a-z]{2,6})?\b([-a-zA-Z0-9@:%_+.~#?&/=]*)/gim,
33-
'<mongodb uri>',
34-
],
30+
// MongoDB connection strings
31+
[/mongodb(?:\+srv)?:\/\/\S+/gim, '<mongodb uri>'],
3532

3633
// IP addresses
3734
[

0 commit comments

Comments
 (0)