1
0
mirror of https://github.com/redis/node-redis.git synced 2025-08-09 00:22:08 +03:00

Auth before select database (#1679)

* Auth before select database

* fix #1681

Co-authored-by: leibale <leibale1998@gmail.com>
This commit is contained in:
mustard
2021-10-19 05:53:43 +08:00
committed by GitHub
parent 83ddbbfc0a
commit d958c3dcf8
4 changed files with 62 additions and 10 deletions

View File

@@ -119,6 +119,18 @@ describe('Client', () => {
assert.equal(client.isOpen, false);
});
itWithClient(TestRedisServers.PASSWORD, 'should execute AUTH before SELECT', async client => {
assert.equal(
(await client.clientInfo()).db,
2
);
}, {
minimumRedisVersion: [6, 2],
clientOptions: {
database: 2
}
});
});
describe('legacyMode', () => {

View File

@@ -177,24 +177,44 @@ export default class RedisClient<M extends RedisModules, S extends RedisScripts>
#initiateSocket(): RedisSocket {
const socketInitiator = async (): Promise<void> => {
const v4Commands = this.#options?.legacyMode ? this.#v4 : this,
promises = [];
const promises = [];
if (this.#selectedDB !== 0) {
promises.push(v4Commands.select(RedisClient.commandOptions({ asap: true }), this.#selectedDB));
promises.push(
this.#queue.addCommand(
['SELECT', this.#selectedDB.toString()],
{ asap: true }
)
);
}
if (this.#options?.readonly) {
promises.push(v4Commands.readonly(RedisClient.commandOptions({ asap: true })));
promises.push(
this.#queue.addCommand(
COMMANDS.READONLY.transformArguments(),
{ asap: true }
)
);
}
if (this.#options?.username || this.#options?.password) {
promises.push(v4Commands.auth(RedisClient.commandOptions({ asap: true }), this.#options));
promises.push(
this.#queue.addCommand(
COMMANDS.AUTH.transformArguments({
username: this.#options.username,
password: this.#options.password ?? ''
}),
{ asap: true }
)
);
}
const resubscribePromise = this.#queue.resubscribe();
if (resubscribePromise) {
promises.push(resubscribePromise);
}
if (promises.length) {
this.#tick();
}
@@ -410,7 +430,7 @@ export default class RedisClient<M extends RedisModules, S extends RedisScripts>
quit = this.QUIT;
#tick(): void {
if (!this.#socket.isSocketExists) {
if (!this.#socket.isSocketExists || this.#socket.writableNeedDrain) {
return;
}

View File

@@ -76,6 +76,14 @@ export default class RedisSocket extends EventEmitter {
return !!this.#socket;
}
// `writable.writableNeedDrain` was added in v15.2.0 and therefore can't be used
// https://nodejs.org/api/stream.html#stream_writable_writableneeddrain
#writableNeedDrain = false;
get writableNeedDrain(): boolean {
return this.#writableNeedDrain;
}
constructor(initiator?: RedisSocketInitiator, options?: RedisSocketOptions) {
super();
@@ -163,7 +171,10 @@ export default class RedisSocket extends EventEmitter {
this.#onSocketError(new Error('Socket closed unexpectedly'));
}
})
.on('drain', () => this.emit('drain'))
.on('drain', () => {
this.#writableNeedDrain = false;
this.emit('drain');
})
.on('data', (data: Buffer) => this.emit('data', data));
resolve(socket);
@@ -198,7 +209,9 @@ export default class RedisSocket extends EventEmitter {
throw new ClientClosedError();
}
return this.#socket.write(toWrite);
const wasFullyWritten = this.#socket.write(toWrite);
this.#writableNeedDrain = !wasFullyWritten;
return wasFullyWritten;
}
async disconnect(ignoreIsOpen = false): Promise<void> {

View File

@@ -284,16 +284,23 @@ export function describeHandleMinimumRedisVersion(minimumVersion: PartialRedisVe
});
}
interface RedisClientTestOptions extends RedisTestOptions {
clientOptions?: RedisClientOptions<{}, {}>;
}
export function itWithClient(
type: TestRedisServers,
title: string,
fn: (client: RedisClientType) => Promise<void>,
options?: RedisTestOptions
options?: RedisClientTestOptions
): void {
it(title, async function () {
if (handleMinimumRedisVersion(this, options?.minimumRedisVersion)) return;
const client = RedisClient.create(TEST_REDIS_SERVERS[type]);
const client = RedisClient.create({
...TEST_REDIS_SERVERS[type],
...options?.clientOptions
});
await client.connect();