Skip to content

Commit cbc5421

Browse files
authored
feat: support username in URI (#1284)
1 parent 0b001e0 commit cbc5421

4 files changed

Lines changed: 92 additions & 6 deletions

File tree

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,13 @@ You can also specify connection options as a [`redis://` URL](http://www.iana.or
135135
```javascript
136136
// Connect to 127.0.0.1:6380, db 4, using password "authpassword":
137137
new Redis("redis://:authpassword@127.0.0.1:6380/4");
138+
139+
// Username can also be passed via URI.
140+
// It's worth to noticing that for compatibility reasons `allowUsernameInURI`
141+
// need to be provided, otherwise the username part will be ignored.
142+
new Redis(
143+
"redis://username:authpassword@127.0.0.1:6380/4?allowUsernameInURI=true"
144+
);
138145
```
139146

140147
See [API Documentation](API.md#new_Redis) for all available options.

lib/utils/index.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,19 @@ export function parseURL(url) {
255255
parsed = urllibParse(url, true, true);
256256
}
257257

258+
const options = parsed.query || {};
259+
const allowUsernameInURI =
260+
options.allowUsernameInURI && options.allowUsernameInURI !== "false";
261+
delete options.allowUsernameInURI;
262+
258263
const result: any = {};
259264
if (parsed.auth) {
260-
const index = parsed.auth.indexOf(":")
261-
result.password = index === -1 ? '' : parsed.auth.slice(index + 1)
265+
const index = parsed.auth.indexOf(":");
266+
if (allowUsernameInURI) {
267+
result.username =
268+
index === -1 ? parsed.auth : parsed.auth.slice(0, index);
269+
}
270+
result.password = index === -1 ? "" : parsed.auth.slice(index + 1);
262271
}
263272
if (parsed.pathname) {
264273
if (parsed.protocol === "redis:" || parsed.protocol === "rediss:") {
@@ -275,7 +284,7 @@ export function parseURL(url) {
275284
if (parsed.port) {
276285
result.port = parsed.port;
277286
}
278-
defaults(result, parsed.query);
287+
defaults(result, options);
279288

280289
return result;
281290
}

test/functional/auth.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,25 @@ describe("auth", function () {
170170
redis = new Redis({ port: 17379, username, password });
171171
});
172172

173+
it("should handle auth with Redis URL string with username and password (Redis >=6) (redis://foo:bar@baz.com/) correctly", function (done) {
174+
let username = "user";
175+
let password = "pass";
176+
let redis;
177+
new MockServer(17379, function (argv) {
178+
if (
179+
argv[0] === "auth" &&
180+
argv[1] === username &&
181+
argv[2] === password
182+
) {
183+
redis.disconnect();
184+
done();
185+
}
186+
});
187+
redis = new Redis(
188+
`redis://user:pass@localhost:17379/?allowUsernameInURI=true`
189+
);
190+
});
191+
173192
it('should not emit "error" when the Redis >=6 server doesn\'t need auth', function (done) {
174193
new MockServer(17379, function (argv) {
175194
if (argv[0] === "auth" && argv[1] === "pass") {

test/unit/utils.ts

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,7 @@ describe("utils", function () {
204204
password: "pass:word",
205205
key: "value",
206206
});
207-
expect(
208-
utils.parseURL("redis://user@127.0.0.1:6380/4?key=value")
209-
).to.eql({
207+
expect(utils.parseURL("redis://user@127.0.0.1:6380/4?key=value")).to.eql({
210208
host: "127.0.0.1",
211209
port: "6380",
212210
db: "4",
@@ -226,6 +224,59 @@ describe("utils", function () {
226224
key: "value",
227225
});
228226
});
227+
228+
it("supports allowUsernameInURI", function () {
229+
expect(
230+
utils.parseURL(
231+
"redis://user:pass@127.0.0.1:6380/4?allowUsernameInURI=true"
232+
)
233+
).to.eql({
234+
host: "127.0.0.1",
235+
port: "6380",
236+
db: "4",
237+
username: "user",
238+
password: "pass",
239+
});
240+
expect(
241+
utils.parseURL(
242+
"redis://user:pass@127.0.0.1:6380/4?allowUsernameInURI=false"
243+
)
244+
).to.eql({
245+
host: "127.0.0.1",
246+
port: "6380",
247+
db: "4",
248+
password: "pass",
249+
});
250+
expect(
251+
utils.parseURL(
252+
"redis://user:pass:word@127.0.0.1:6380/4?key=value&allowUsernameInURI=true"
253+
)
254+
).to.eql({
255+
host: "127.0.0.1",
256+
port: "6380",
257+
db: "4",
258+
username: "user",
259+
password: "pass:word",
260+
key: "value",
261+
});
262+
expect(
263+
utils.parseURL(
264+
"redis://user@127.0.0.1:6380/4?key=value&allowUsernameInURI=true"
265+
)
266+
).to.eql({
267+
host: "127.0.0.1",
268+
port: "6380",
269+
db: "4",
270+
username: "user",
271+
password: "",
272+
key: "value",
273+
});
274+
expect(
275+
utils.parseURL("redis://127.0.0.1/?allowUsernameInURI=true")
276+
).to.eql({
277+
host: "127.0.0.1",
278+
});
279+
});
229280
});
230281

231282
describe(".sample", function () {

0 commit comments

Comments
 (0)