Spaces:
Paused
Paused
| ; | |
| const Packet = require('../packets/packet'); | |
| const ClientConstants = require('../constants/client.js'); | |
| // https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake | |
| class Handshake { | |
| constructor(args) { | |
| this.protocolVersion = args.protocolVersion; | |
| this.serverVersion = args.serverVersion; | |
| this.capabilityFlags = args.capabilityFlags; | |
| this.connectionId = args.connectionId; | |
| this.authPluginData1 = args.authPluginData1; | |
| this.authPluginData2 = args.authPluginData2; | |
| this.characterSet = args.characterSet; | |
| this.statusFlags = args.statusFlags; | |
| this.autPluginName = args.autPluginName; | |
| } | |
| setScrambleData(cb) { | |
| require('crypto').randomBytes(20, (err, data) => { | |
| if (err) { | |
| cb(err); | |
| return; | |
| } | |
| this.authPluginData1 = data.slice(0, 8); | |
| this.authPluginData2 = data.slice(8, 20); | |
| cb(); | |
| }); | |
| } | |
| toPacket(sequenceId) { | |
| const length = 68 + Buffer.byteLength(this.serverVersion, 'utf8'); | |
| const buffer = Buffer.alloc(length + 4, 0); // zero fill, 10 bytes filler later needs to contain zeros | |
| const packet = new Packet(sequenceId, buffer, 0, length + 4); | |
| packet.offset = 4; | |
| packet.writeInt8(this.protocolVersion); | |
| packet.writeString(this.serverVersion, 'cesu8'); | |
| packet.writeInt8(0); | |
| packet.writeInt32(this.connectionId); | |
| packet.writeBuffer(this.authPluginData1); | |
| packet.writeInt8(0); | |
| const capabilityFlagsBuffer = Buffer.allocUnsafe(4); | |
| capabilityFlagsBuffer.writeUInt32LE(this.capabilityFlags, 0); | |
| packet.writeBuffer(capabilityFlagsBuffer.slice(0, 2)); | |
| packet.writeInt8(this.characterSet); | |
| packet.writeInt16(this.statusFlags); | |
| packet.writeBuffer(capabilityFlagsBuffer.slice(2, 4)); | |
| packet.writeInt8(21); // authPluginDataLength | |
| packet.skip(10); | |
| packet.writeBuffer(this.authPluginData2); | |
| packet.writeInt8(0); | |
| packet.writeString('mysql_native_password', 'latin1'); | |
| packet.writeInt8(0); | |
| return packet; | |
| } | |
| static fromPacket(packet) { | |
| const args = {}; | |
| args.protocolVersion = packet.readInt8(); | |
| args.serverVersion = packet.readNullTerminatedString('cesu8'); | |
| args.connectionId = packet.readInt32(); | |
| args.authPluginData1 = packet.readBuffer(8); | |
| packet.skip(1); | |
| const capabilityFlagsBuffer = Buffer.allocUnsafe(4); | |
| capabilityFlagsBuffer[0] = packet.readInt8(); | |
| capabilityFlagsBuffer[1] = packet.readInt8(); | |
| if (packet.haveMoreData()) { | |
| args.characterSet = packet.readInt8(); | |
| args.statusFlags = packet.readInt16(); | |
| // upper 2 bytes | |
| capabilityFlagsBuffer[2] = packet.readInt8(); | |
| capabilityFlagsBuffer[3] = packet.readInt8(); | |
| args.capabilityFlags = capabilityFlagsBuffer.readUInt32LE(0); | |
| if (args.capabilityFlags & ClientConstants.PLUGIN_AUTH) { | |
| args.authPluginDataLength = packet.readInt8(); | |
| } else { | |
| args.authPluginDataLength = 0; | |
| packet.skip(1); | |
| } | |
| packet.skip(10); | |
| } else { | |
| args.capabilityFlags = capabilityFlagsBuffer.readUInt16LE(0); | |
| } | |
| const isSecureConnection = | |
| args.capabilityFlags & ClientConstants.SECURE_CONNECTION; | |
| if (isSecureConnection) { | |
| const authPluginDataLength = args.authPluginDataLength; | |
| if (authPluginDataLength === 0) { | |
| // for Secure Password Authentication | |
| args.authPluginDataLength = 20; | |
| args.authPluginData2 = packet.readBuffer(12); | |
| packet.skip(1); | |
| } else { | |
| // length > 0 | |
| // for Custom Auth Plugin (PLUGIN_AUTH) | |
| const len = Math.max(13, authPluginDataLength - 8); | |
| args.authPluginData2 = packet.readBuffer(len); | |
| } | |
| } | |
| if (args.capabilityFlags & ClientConstants.PLUGIN_AUTH) { | |
| args.autPluginName = packet.readNullTerminatedString('ascii'); | |
| } | |
| return new Handshake(args); | |
| } | |
| } | |
| module.exports = Handshake; | |