From 779af1b8368368bd359aee9bbeb8b86cbb759a76 Mon Sep 17 00:00:00 2001 From: Arthur Schreiber Date: Fri, 17 Jul 2026 10:53:57 +0000 Subject: [PATCH] refactor: move the `loginError` property from `Connection` into `Login7TokenHandler` One less thing to keep track of on the `Connection` class itself. A fresh `Login7TokenHandler` is created for each login response message (including each iteration of the NTLM challenge loop), so scoping the error to the handler removes the need to reset it between login attempts. Co-Authored-By: Claude Fable 5 --- src/connection.ts | 19 ++++++------------- src/token/handler.ts | 17 ++++++++++------- 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/src/connection.ts b/src/connection.ts index 3577a0866..2dc6b5740 100644 --- a/src/connection.ts +++ b/src/connection.ts @@ -954,10 +954,6 @@ class Connection extends EventEmitter { * @private */ declare closed: boolean; - /** - * @private - */ - declare loginError: undefined | AggregateError | ConnectionError; /** * @private */ @@ -3491,13 +3487,12 @@ class Connection extends EventEmitter { if (handler.loginAckReceived) { return handler.routingData; - } else if (this.loginError) { - throw this.loginError; + } else if (handler.loginError) { + throw handler.loginError; } else { throw new ConnectionError('Login failed.', 'ELOGIN'); } } finally { - this.loginError = undefined; signal.removeEventListener('abort', onAbort); } } @@ -3547,14 +3542,13 @@ class Connection extends EventEmitter { }); this.ntlmpacket = undefined; - } else if (this.loginError) { - throw this.loginError; + } else if (handler.loginError) { + throw handler.loginError; } else { throw new ConnectionError('Login failed.', 'ELOGIN'); } } } finally { - this.loginError = undefined; signal.removeEventListener('abort', onAbort); } } @@ -3655,13 +3649,12 @@ class Connection extends EventEmitter { // sent the fedAuth token message, the rest is similar to standard login 7 this.transitionTo(this.STATE.SENT_LOGIN7_WITH_STANDARD_LOGIN); return await this.performSentLogin7WithStandardLogin(signal); - } else if (this.loginError) { - throw this.loginError; + } else if (handler.loginError) { + throw handler.loginError; } else { throw new ConnectionError('Login failed.', 'ELOGIN'); } } finally { - this.loginError = undefined; signal.removeEventListener('abort', onAbort); } } diff --git a/src/token/handler.ts b/src/token/handler.ts index 9fcdfd35a..1d0174f41 100644 --- a/src/token/handler.ts +++ b/src/token/handler.ts @@ -250,10 +250,13 @@ export class Login7TokenHandler extends TokenHandler { declare loginAckReceived: boolean; + declare loginError: ConnectionError | undefined; + constructor(connection: Connection) { super(); this.loginAckReceived = false; this.connection = connection; + this.loginError = undefined; } onInfoMessage(token: InfoMessageToken) { @@ -270,7 +273,7 @@ export class Login7TokenHandler extends TokenHandler { error.isTransient = true; } - this.connection.loginError = error; + this.loginError = error; } onSSPI(token: SSPIToken) { @@ -309,27 +312,27 @@ export class Login7TokenHandler extends TokenHandler { if (authentication.type === 'azure-active-directory-password' || authentication.type === 'azure-active-directory-access-token' || authentication.type === 'azure-active-directory-msi-vm' || authentication.type === 'azure-active-directory-msi-app-service' || authentication.type === 'azure-active-directory-service-principal-secret' || authentication.type === 'azure-active-directory-default') { if (token.fedAuth === undefined) { - this.connection.loginError = new ConnectionError('Did not receive Active Directory authentication acknowledgement'); + this.loginError = new ConnectionError('Did not receive Active Directory authentication acknowledgement'); } else if (token.fedAuth.length !== 0) { - this.connection.loginError = new ConnectionError(`Active Directory authentication acknowledgment for ${authentication.type} authentication method includes extra data`); + this.loginError = new ConnectionError(`Active Directory authentication acknowledgment for ${authentication.type} authentication method includes extra data`); } } else if (token.fedAuth === undefined && token.utf8Support === undefined) { - this.connection.loginError = new ConnectionError('Received acknowledgement for unknown feature'); + this.loginError = new ConnectionError('Received acknowledgement for unknown feature'); } else if (token.fedAuth) { - this.connection.loginError = new ConnectionError('Did not request Active Directory authentication, but received the acknowledgment'); + this.loginError = new ConnectionError('Did not request Active Directory authentication, but received the acknowledgment'); } } onLoginAck(token: LoginAckToken) { if (!token.tdsVersion) { // unsupported TDS version - this.connection.loginError = new ConnectionError('Server responded with unknown TDS version.', 'ETDS'); + this.loginError = new ConnectionError('Server responded with unknown TDS version.', 'ETDS'); return; } if (!token.interface) { // unsupported interface - this.connection.loginError = new ConnectionError('Server responded with unsupported interface.', 'EINTERFACENOTSUPP'); + this.loginError = new ConnectionError('Server responded with unsupported interface.', 'EINTERFACENOTSUPP'); return; }