Spaces:
Paused
Paused
| ; | |
| const ClientConstants = require('../constants/client.js'); | |
| const CharsetToEncoding = require('../constants/charset_encodings.js'); | |
| const Packet = require('../packets/packet.js'); | |
| const auth41 = require('../auth_41.js'); | |
| class HandshakeResponse { | |
| constructor(handshake) { | |
| this.user = handshake.user || ''; | |
| this.database = handshake.database || ''; | |
| this.password = handshake.password || ''; | |
| this.passwordSha1 = handshake.passwordSha1; | |
| this.authPluginData1 = handshake.authPluginData1; | |
| this.authPluginData2 = handshake.authPluginData2; | |
| this.compress = handshake.compress; | |
| this.clientFlags = handshake.flags; | |
| // TODO: pre-4.1 auth support | |
| let authToken; | |
| if (this.passwordSha1) { | |
| authToken = auth41.calculateTokenFromPasswordSha( | |
| this.passwordSha1, | |
| this.authPluginData1, | |
| this.authPluginData2 | |
| ); | |
| } else { | |
| authToken = auth41.calculateToken( | |
| this.password, | |
| this.authPluginData1, | |
| this.authPluginData2 | |
| ); | |
| } | |
| this.authToken = authToken; | |
| this.charsetNumber = handshake.charsetNumber; | |
| this.encoding = CharsetToEncoding[handshake.charsetNumber]; | |
| this.connectAttributes = handshake.connectAttributes; | |
| } | |
| serializeResponse(buffer) { | |
| const isSet = flag => this.clientFlags & ClientConstants[flag]; | |
| const packet = new Packet(0, buffer, 0, buffer.length); | |
| packet.offset = 4; | |
| packet.writeInt32(this.clientFlags); | |
| packet.writeInt32(0); // max packet size. todo: move to config | |
| packet.writeInt8(this.charsetNumber); | |
| packet.skip(23); | |
| const encoding = this.encoding; | |
| packet.writeNullTerminatedString(this.user, encoding); | |
| let k; | |
| if (isSet('PLUGIN_AUTH_LENENC_CLIENT_DATA')) { | |
| packet.writeLengthCodedNumber(this.authToken.length); | |
| packet.writeBuffer(this.authToken); | |
| } else if (isSet('SECURE_CONNECTION')) { | |
| packet.writeInt8(this.authToken.length); | |
| packet.writeBuffer(this.authToken); | |
| } else { | |
| packet.writeBuffer(this.authToken); | |
| packet.writeInt8(0); | |
| } | |
| if (isSet('CONNECT_WITH_DB')) { | |
| packet.writeNullTerminatedString(this.database, encoding); | |
| } | |
| if (isSet('PLUGIN_AUTH')) { | |
| // TODO: pass from config | |
| packet.writeNullTerminatedString('mysql_native_password', 'latin1'); | |
| } | |
| if (isSet('CONNECT_ATTRS')) { | |
| const connectAttributes = this.connectAttributes || {}; | |
| const attrNames = Object.keys(connectAttributes); | |
| let keysLength = 0; | |
| for (k = 0; k < attrNames.length; ++k) { | |
| keysLength += Packet.lengthCodedStringLength(attrNames[k], encoding); | |
| keysLength += Packet.lengthCodedStringLength( | |
| connectAttributes[attrNames[k]], | |
| encoding | |
| ); | |
| } | |
| packet.writeLengthCodedNumber(keysLength); | |
| for (k = 0; k < attrNames.length; ++k) { | |
| packet.writeLengthCodedString(attrNames[k], encoding); | |
| packet.writeLengthCodedString( | |
| connectAttributes[attrNames[k]], | |
| encoding | |
| ); | |
| } | |
| } | |
| return packet; | |
| } | |
| toPacket() { | |
| if (typeof this.user !== 'string') { | |
| throw new Error('"user" connection config property must be a string'); | |
| } | |
| if (typeof this.database !== 'string') { | |
| throw new Error('"database" connection config property must be a string'); | |
| } | |
| // dry run: calculate resulting packet length | |
| const p = this.serializeResponse(Packet.MockBuffer()); | |
| return this.serializeResponse(Buffer.alloc(p.offset)); | |
| } | |
| static fromPacket(packet) { | |
| const args = {}; | |
| args.clientFlags = packet.readInt32(); | |
| function isSet(flag) { | |
| return args.clientFlags & ClientConstants[flag]; | |
| } | |
| args.maxPacketSize = packet.readInt32(); | |
| args.charsetNumber = packet.readInt8(); | |
| const encoding = CharsetToEncoding[args.charsetNumber]; | |
| args.encoding = encoding; | |
| packet.skip(23); | |
| args.user = packet.readNullTerminatedString(encoding); | |
| let authTokenLength; | |
| if (isSet('PLUGIN_AUTH_LENENC_CLIENT_DATA')) { | |
| authTokenLength = packet.readLengthCodedNumber(encoding); | |
| args.authToken = packet.readBuffer(authTokenLength); | |
| } else if (isSet('SECURE_CONNECTION')) { | |
| authTokenLength = packet.readInt8(); | |
| args.authToken = packet.readBuffer(authTokenLength); | |
| } else { | |
| args.authToken = packet.readNullTerminatedString(encoding); | |
| } | |
| if (isSet('CONNECT_WITH_DB')) { | |
| args.database = packet.readNullTerminatedString(encoding); | |
| } | |
| if (isSet('PLUGIN_AUTH')) { | |
| args.authPluginName = packet.readNullTerminatedString(encoding); | |
| } | |
| if (isSet('CONNECT_ATTRS')) { | |
| const keysLength = packet.readLengthCodedNumber(encoding); | |
| const keysEnd = packet.offset + keysLength; | |
| const attrs = {}; | |
| while (packet.offset < keysEnd) { | |
| attrs[ | |
| packet.readLengthCodedString(encoding) | |
| ] = packet.readLengthCodedString(encoding); | |
| } | |
| args.connectAttributes = attrs; | |
| } | |
| return args; | |
| } | |
| } | |
| module.exports = HandshakeResponse; | |