-
Notifications
You must be signed in to change notification settings - Fork 9
feat(mongodb-react): add shouldRedactCommand, redactUriCredentials MONGOSH-2991 #599
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
7ce9d8c
f2c9bea
93b40a8
4d0517b
7e75778
6ea96b4
370d518
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -161,13 +161,82 @@ describe('mongodb-redact', function () { | |
| expect(res).to.equal('<url>'); | ||
| }); | ||
|
|
||
| it('should redact MongoDB connection URIs', function () { | ||
| let res = redact( | ||
| 'mongodb://db1.example.net,db2.example.net:2500/?replicaSet=test&connectTimeoutMS=300000', | ||
| ); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| res = redact('mongodb://localhost,localhost:27018,localhost:27019'); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| describe('MongoDB connection strings', function () { | ||
| it('should redact MongoDB connection URIs', function () { | ||
| let res = redact( | ||
| 'mongodb://db1.example.net,db2.example.net:2500/?replicaSet=test&connectTimeoutMS=300000', | ||
| ); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| res = redact('mongodb://localhost,localhost:27018,localhost:27019'); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| }); | ||
|
|
||
| it('should redact MongoDB URIs with credentials', function () { | ||
| let res = redact('mongodb://user:password@localhost:27017/admin'); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| res = redact('mongodb://admin:[email protected]/mydb'); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| }); | ||
|
|
||
| it('should redact MongoDB URIs with special characters in usernames and passwords', function () { | ||
| let res = redact('mongodb://user:p%40ss!word@localhost:27017/'); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| res = redact('mongodb://ad!min:te%st#[email protected]:27017/'); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| res = redact('mongodb://!user:my%20pass@localhost/mydb'); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| res = redact( | ||
| 'mongodb://user:p&ssw!rd#[email protected]:27017/db?authSource=admin', | ||
| ); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| }); | ||
|
|
||
| it('should redact MongoDB SRV URIs', function () { | ||
| let res = redact( | ||
| 'mongodb+srv://user:[email protected]/test', | ||
| ); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| res = redact( | ||
| 'mongodb+srv://admin:[email protected]/mydb?retryWrites=true', | ||
| ); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| }); | ||
|
|
||
| it('should redact MongoDB URIs with query parameters', function () { | ||
| let res = redact( | ||
| 'mongodb://localhost:27017/mydb?ssl=true&replicaSet=rs0', | ||
| ); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| res = redact( | ||
| 'mongodb://user:[email protected]/db?authSource=admin&readPreference=primary', | ||
| ); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| }); | ||
|
|
||
| it('should redact MongoDB URIs with replica sets', function () { | ||
| let res = redact( | ||
| 'mongodb://host1:27017,host2:27017,host3:27017/?replicaSet=myReplSet', | ||
| ); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| res = redact('mongodb://user:pass@host1,host2,host3/db?replicaSet=rs0'); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| }); | ||
|
|
||
| it('should redact MongoDB URIs with IP addresses', function () { | ||
| let res = redact('mongodb://192.168.1.100:27017/mydb'); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| res = redact('mongodb://user:[email protected]:27017/admin'); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| }); | ||
|
|
||
| it('should redact simple MongoDB URIs', function () { | ||
| let res = redact('mongodb://localhost'); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| res = redact('mongodb://localhost:27017'); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| res = redact('mongodb://localhost/mydb'); | ||
| expect(res).to.equal('<mongodb uri>'); | ||
| }); | ||
| }); | ||
|
|
||
| it('should redact general linux/unix user paths', function () { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,173 @@ | ||
| import { expect } from 'chai'; | ||
| import { redactUriCredentials } from './redact-uri-credentials'; | ||
| import redact from '.'; | ||
|
|
||
| describe('redactUriCredentials', function () { | ||
| const testCases: Array<{ | ||
| description: string; | ||
| input: string; | ||
| expected: string; | ||
| }> = [ | ||
| { | ||
| description: 'should redact username and password', | ||
| input: 'mongodb://user:password@localhost:27017/admin', | ||
| expected: 'mongodb://<credentials>@localhost:27017/admin', | ||
| }, | ||
| { | ||
| description: 'should redact only username when no password', | ||
| input: 'mongodb://user@localhost:27017/admin', | ||
| expected: 'mongodb://<credentials>@localhost:27017/admin', | ||
| }, | ||
| { | ||
| description: 'should redact credentials in SRV URIs', | ||
| input: 'mongodb+srv://admin:[email protected]/test', | ||
| expected: 'mongodb+srv://<credentials>@cluster0.example.com/test', | ||
| }, | ||
| { | ||
| description: 'should redact passwords with ! character', | ||
| input: 'mongodb://user:p@ss!word@localhost:27017/', | ||
| expected: 'mongodb://<credentials>@localhost:27017/', | ||
| }, | ||
| { | ||
| description: 'should redact passwords with # character', | ||
| input: 'mongodb://admin:test#[email protected]:27017/', | ||
| expected: 'mongodb://<credentials>@db.example.com:27017/', | ||
| }, | ||
| { | ||
| description: 'should redact passwords with $ character', | ||
| input: 'mongodb://user:price$100@localhost:27017/', | ||
| expected: 'mongodb://<credentials>@localhost:27017/', | ||
| }, | ||
| { | ||
| description: 'should redact passwords with % character', | ||
| input: 'mongodb://user:test%pass@localhost:27017/', | ||
| expected: 'mongodb://<credentials>@localhost:27017/', | ||
| }, | ||
| { | ||
| description: 'should redact passwords with & character', | ||
| input: 'mongodb://user:rock&roll@localhost:27017/', | ||
| expected: 'mongodb://<credentials>@localhost:27017/', | ||
| }, | ||
| { | ||
| description: 'should redact URL-encoded passwords', | ||
| input: 'mongodb://user:my%20password@localhost:27017/', | ||
| expected: 'mongodb://<credentials>@localhost:27017/', | ||
| }, | ||
| { | ||
| description: | ||
| 'should redact complex passwords with multiple special characters', | ||
| input: 'mongodb://user:p&ssw!rd#[email protected]:27017/db?authSource=admin', | ||
| expected: 'mongodb://<credentials>@host.com:27017/db?authSource=admin', | ||
| }, | ||
| { | ||
| description: 'should redact usernames with special characters', | ||
| input: 'mongodb://us!er:password@localhost:27017/', | ||
| expected: 'mongodb://<credentials>@localhost:27017/', | ||
| }, | ||
| { | ||
| description: 'should return URI unchanged when no credentials', | ||
| input: 'mongodb://localhost:27017/admin', | ||
| expected: 'mongodb://localhost:27017/admin', | ||
| }, | ||
| { | ||
| description: 'should handle simple localhost URI', | ||
| input: 'mongodb://localhost', | ||
| expected: 'mongodb://localhost/', | ||
| }, | ||
| { | ||
| description: 'should handle URI with database', | ||
| input: 'mongodb://localhost/mydb', | ||
| expected: 'mongodb://localhost/mydb', | ||
| }, | ||
| { | ||
| description: 'should handle URI with query parameters', | ||
| input: 'mongodb://localhost:27017/mydb?ssl=true&replicaSet=rs0', | ||
| expected: 'mongodb://localhost:27017/mydb?ssl=true&replicaSet=rs0', | ||
| }, | ||
| // URIs with replica sets | ||
| { | ||
| description: 'should redact credentials in replica set URIs', | ||
| input: | ||
| 'mongodb://user:pass@host1:27017,host2:27017,host3:27017/db?replicaSet=rs0', | ||
| expected: | ||
| 'mongodb://<credentials>@host1:27017,host2:27017,host3:27017/db?replicaSet=rs0', | ||
| }, | ||
| { | ||
| description: 'should handle replica set URIs without credentials', | ||
| input: | ||
| 'mongodb://host1:27017,host2:27017,host3:27017/?replicaSet=myReplSet', | ||
| expected: | ||
| 'mongodb://host1:27017,host2:27017,host3:27017/?replicaSet=myReplSet', | ||
| }, | ||
| // URIs with IP addresses | ||
| { | ||
| description: 'should redact credentials with IP address host', | ||
| input: 'mongodb://user:[email protected]:27017/mydb', | ||
| expected: 'mongodb://<credentials>@192.168.1.100:27017/mydb', | ||
| }, | ||
| { | ||
| description: 'should handle IP address URIs without credentials', | ||
| input: 'mongodb://10.0.0.5:27017/admin', | ||
| expected: 'mongodb://10.0.0.5:27017/admin', | ||
| }, | ||
| // SRV URIs | ||
| { | ||
| description: 'should handle SRV URIs without credentials', | ||
| input: 'mongodb+srv://cluster0.example.com/test', | ||
| expected: 'mongodb+srv://cluster0.example.com/test', | ||
| }, | ||
| // URIs with query parameters | ||
| { | ||
| description: 'should redact credentials and preserve query parameters', | ||
| input: | ||
| 'mongodb://user:[email protected]/db?authSource=admin&readPreference=primary', | ||
| expected: | ||
| 'mongodb://<credentials>@host.com/db?authSource=admin&readPreference=primary', | ||
| }, | ||
| { | ||
| description: 'should handle URIs with SSL options', | ||
| input: | ||
| 'mongodb://admin:secret@localhost:27017/mydb?ssl=true&tlsAllowInvalidCertificates=true', | ||
| expected: | ||
| 'mongodb://<credentials>@localhost:27017/mydb?ssl=true&tlsAllowInvalidCertificates=true', | ||
| }, | ||
| { | ||
| description: 'should redact credentials in SRV URIs with query params', | ||
| input: | ||
| 'mongodb+srv://admin:[email protected]/mydb?retryWrites=true', | ||
| expected: | ||
| 'mongodb+srv://<credentials>@mycluster.mongodb.net/mydb?retryWrites=true', | ||
| }, | ||
| // Edge cases | ||
| { | ||
| description: 'should handle empty password', | ||
| input: 'mongodb://user:@localhost:27017/', | ||
| expected: 'mongodb://<credentials>@localhost:27017/', | ||
| }, | ||
| { | ||
| description: | ||
| 'should handle password with only special characters (URL-encoded)', | ||
| input: 'mongodb://user:%21%40%23%24%25@localhost:27017/', | ||
| expected: 'mongodb://<credentials>@localhost:27017/', | ||
| }, | ||
| { | ||
| description: 'should handle very long passwords', | ||
| input: `mongodb://user:${'a'.repeat(100)}@localhost:27017/`, | ||
| expected: 'mongodb://<credentials>@localhost:27017/', | ||
| }, | ||
| { | ||
| description: 'should handle international characters in password', | ||
| input: 'mongodb://user:пароль@localhost:27017/', | ||
| expected: 'mongodb://<credentials>@localhost:27017/', | ||
| }, | ||
| ]; | ||
|
|
||
| testCases.forEach(({ description, input, expected }) => { | ||
| it(description, function () { | ||
| const result = redactUriCredentials(input); | ||
| expect(result).to.equal(expected); | ||
|
|
||
| expect(redact(input)).to.equal('<mongodb uri>'); | ||
| }); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| import { redactConnectionString } from 'mongodb-connection-string-url'; | ||
|
|
||
| export function redactUriCredentials(uri: string): string { | ||
|
||
| return redactConnectionString(uri); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
by the way this is now at
7.0.0, I'm keeping at same version as mongosh to minimize side effects for nowThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What you can do, if you want to, is to specify
and give control to the user of this package, since it's pretty reasonable to assume that both of these would work just fine