123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- '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) {
- if (this.onResult) {
- this.onResult(err);
- } else {
- connection.emit('error', err);
- }
- return null;
- }
- }
- if (marker !== 0) {
- const err = new Error('Unexpected packet during handshake phase');
- if (this.onResult) {
- this.onResult(err);
- } else {
- connection.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;
|