aboutsummaryrefslogtreecommitdiff
path: root/node_modules/mysql2/lib/commands/client_handshake.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/mysql2/lib/commands/client_handshake.js')
-rw-r--r--node_modules/mysql2/lib/commands/client_handshake.js200
1 files changed, 200 insertions, 0 deletions
diff --git a/node_modules/mysql2/lib/commands/client_handshake.js b/node_modules/mysql2/lib/commands/client_handshake.js
new file mode 100644
index 0000000..c5e5de0
--- /dev/null
+++ b/node_modules/mysql2/lib/commands/client_handshake.js
@@ -0,0 +1,200 @@
+// This file was modified by Oracle on June 17, 2021.
+// Handshake errors are now maked as fatal and the corresponding events are
+// emitted in the command instance itself.
+// Modifications copyright (c) 2021, Oracle and/or its affiliates.
+
+'use strict';
+
+const Command = require('./command.js');
+const Packets = require('../packets/index.js');
+const ClientConstants = require('../constants/client.js');
+const CharsetToEncoding = require('../constants/charset_encodings.js');
+const auth41 = require('../auth_41.js');
+
+function flagNames(flags) {
+ const res = [];
+ for (const c in ClientConstants) {
+ if (flags & ClientConstants[c]) {
+ res.push(c.replace(/_/g, ' ').toLowerCase());
+ }
+ }
+ return res;
+}
+
+class ClientHandshake extends Command {
+ constructor(clientFlags) {
+ super();
+ this.handshake = null;
+ this.clientFlags = clientFlags;
+ }
+
+ start() {
+ return ClientHandshake.prototype.handshakeInit;
+ }
+
+ sendSSLRequest(connection) {
+ const sslRequest = new Packets.SSLRequest(
+ this.clientFlags,
+ connection.config.charsetNumber
+ );
+ connection.writePacket(sslRequest.toPacket());
+ }
+
+ sendCredentials(connection) {
+ if (connection.config.debug) {
+ // eslint-disable-next-line
+ console.log(
+ 'Sending handshake packet: flags:%d=(%s)',
+ this.clientFlags,
+ flagNames(this.clientFlags).join(', ')
+ );
+ }
+ this.user = connection.config.user;
+ this.password = connection.config.password;
+ this.passwordSha1 = connection.config.passwordSha1;
+ this.database = connection.config.database;
+ this.autPluginName = this.handshake.autPluginName;
+ const handshakeResponse = new Packets.HandshakeResponse({
+ flags: this.clientFlags,
+ user: this.user,
+ database: this.database,
+ password: this.password,
+ passwordSha1: this.passwordSha1,
+ charsetNumber: connection.config.charsetNumber,
+ authPluginData1: this.handshake.authPluginData1,
+ authPluginData2: this.handshake.authPluginData2,
+ compress: connection.config.compress,
+ connectAttributes: connection.config.connectAttributes
+ });
+ connection.writePacket(handshakeResponse.toPacket());
+ }
+
+ calculateNativePasswordAuthToken(authPluginData) {
+ // TODO: dont split into authPluginData1 and authPluginData2, instead join when 1 & 2 received
+ const authPluginData1 = authPluginData.slice(0, 8);
+ const authPluginData2 = authPluginData.slice(8, 20);
+ let authToken;
+ if (this.passwordSha1) {
+ authToken = auth41.calculateTokenFromPasswordSha(
+ this.passwordSha1,
+ authPluginData1,
+ authPluginData2
+ );
+ } else {
+ authToken = auth41.calculateToken(
+ this.password,
+ authPluginData1,
+ authPluginData2
+ );
+ }
+ return authToken;
+ }
+
+ handshakeInit(helloPacket, connection) {
+ this.on('error', e => {
+ connection._fatalError = e;
+ connection._protocolError = e;
+ });
+ this.handshake = Packets.Handshake.fromPacket(helloPacket);
+ if (connection.config.debug) {
+ // eslint-disable-next-line
+ console.log(
+ 'Server hello packet: capability flags:%d=(%s)',
+ this.handshake.capabilityFlags,
+ flagNames(this.handshake.capabilityFlags).join(', ')
+ );
+ }
+ connection.serverCapabilityFlags = this.handshake.capabilityFlags;
+ connection.serverEncoding = CharsetToEncoding[this.handshake.characterSet];
+ connection.connectionId = this.handshake.connectionId;
+ const serverSSLSupport =
+ this.handshake.capabilityFlags & ClientConstants.SSL;
+ // use compression only if requested by client and supported by server
+ connection.config.compress =
+ connection.config.compress &&
+ this.handshake.capabilityFlags & ClientConstants.COMPRESS;
+ this.clientFlags = this.clientFlags | connection.config.compress;
+ if (connection.config.ssl) {
+ // client requires SSL but server does not support it
+ if (!serverSSLSupport) {
+ const err = new Error('Server does not support secure connnection');
+ err.code = 'HANDSHAKE_NO_SSL_SUPPORT';
+ err.fatal = true;
+ this.emit('error', err);
+ return false;
+ }
+ // send ssl upgrade request and immediately upgrade connection to secure
+ this.clientFlags |= ClientConstants.SSL;
+ this.sendSSLRequest(connection);
+ connection.startTLS(err => {
+ // after connection is secure
+ if (err) {
+ // SSL negotiation error are fatal
+ err.code = 'HANDSHAKE_SSL_ERROR';
+ err.fatal = true;
+ this.emit('error', err);
+ return;
+ }
+ // rest of communication is encrypted
+ this.sendCredentials(connection);
+ });
+ } else {
+ this.sendCredentials(connection);
+ }
+ return ClientHandshake.prototype.handshakeResult;
+ }
+
+ handshakeResult(packet, connection) {
+ const marker = packet.peekByte();
+ if (marker === 0xfe || marker === 1) {
+ const authSwitch = require('./auth_switch');
+ try {
+ if (marker === 1) {
+ authSwitch.authSwitchRequestMoreData(packet, connection, this);
+ } else {
+ authSwitch.authSwitchRequest(packet, connection, this);
+ }
+ return ClientHandshake.prototype.handshakeResult;
+ } catch (err) {
+ // Authentication errors are fatal
+ err.code = 'AUTH_SWITCH_PLUGIN_ERROR';
+ err.fatal = true;
+
+ if (this.onResult) {
+ this.onResult(err);
+ } else {
+ this.emit('error', err);
+ }
+ return null;
+ }
+ }
+ if (marker !== 0) {
+ const err = new Error('Unexpected packet during handshake phase');
+ // Unknown handshake errors are fatal
+ err.code = 'HANDSHAKE_UNKNOWN_ERROR';
+ err.fatal = true;
+
+ if (this.onResult) {
+ this.onResult(err);
+ } else {
+ this.emit('error', err);
+ }
+ return null;
+ }
+ // this should be called from ClientHandshake command only
+ // and skipped when called from ChangeUser command
+ if (!connection.authorized) {
+ connection.authorized = true;
+ if (connection.config.compress) {
+ const enableCompression = require('../compressed_protocol.js')
+ .enableCompression;
+ enableCompression(connection);
+ }
+ }
+ if (this.onResult) {
+ this.onResult(null);
+ }
+ return null;
+ }
+}
+module.exports = ClientHandshake;