'use strict'; const Capabilities = require('../../const/capabilities'); const Iconv = require('iconv-lite'); const NativePasswordAuth = require('./auth/native-password-auth'); const Ed25519PasswordAuth = require('./auth/ed25519-password-auth'); const driverVersion = require('../../../package.json').version; const os = require('os'); /** * Send Handshake response packet * see https://mariadb.com/kb/en/library/1-connecting-connecting/#handshake-response-packet * * @param cmd current handshake command * @param out output writer * @param opts connection options * @param pluginName plugin name * @param info connection information */ module.exports.send = function send(cmd, out, opts, pluginName, info) { out.startPacket(cmd); info.defaultPluginName = pluginName; const pwd = Array.isArray(opts.password) ? opts.password[0] : opts.password; let authToken; let authPlugin; switch (pluginName) { case 'client_ed25519': authToken = Ed25519PasswordAuth.encryptPassword(pwd, info.seed); authPlugin = 'client_ed25519'; break; case 'mysql_clear_password': authToken = Buffer.from(pwd); authPlugin = 'mysql_clear_password'; break; default: authToken = NativePasswordAuth.encryptPassword(pwd, info.seed, 'sha1'); authPlugin = 'mysql_native_password'; break; } out.writeInt32(Number(info.clientCapabilities & BigInt(0xffffffff))); out.writeInt32(1024 * 1024 * 1024); // max packet size out.writeInt8(opts.collation.index); for (let i = 0; i < 19; i++) { out.writeInt8(0); } out.writeInt32(Number(info.clientCapabilities >> BigInt(32))); //null encoded user out.writeString(opts.user || ''); out.writeInt8(0); if (info.serverCapabilities & Capabilities.PLUGIN_AUTH_LENENC_CLIENT_DATA) { out.writeLengthCoded(authToken.length); out.writeBuffer(authToken, 0, authToken.length); } else if (info.serverCapabilities & Capabilities.SECURE_CONNECTION) { out.writeInt8(authToken.length); out.writeBuffer(authToken, 0, authToken.length); } else { out.writeBuffer(authToken, 0, authToken.length); out.writeInt8(0); } if (info.clientCapabilities & Capabilities.CONNECT_WITH_DB) { out.writeString(opts.database); out.writeInt8(0); info.database = opts.database; } if (info.clientCapabilities & Capabilities.PLUGIN_AUTH) { out.writeString(authPlugin); out.writeInt8(0); } if (info.clientCapabilities & Capabilities.CONNECT_ATTRS) { out.writeInt8(0xfc); let initPos = out.pos; //save position, assuming connection attributes length will be less than 2 bytes length out.writeInt16(0); const encoding = opts.collation.charset; writeParam(out, '_client_name', encoding); writeParam(out, 'MariaDB connector/Node', encoding); writeParam(out, '_client_version', encoding); writeParam(out, driverVersion, encoding); const address = cmd.getSocket().address().address; if (address) { writeParam(out, '_server_host', encoding); writeParam(out, address, encoding); } writeParam(out, '_os', encoding); writeParam(out, process.platform, encoding); writeParam(out, '_client_host', encoding); writeParam(out, os.hostname(), encoding); writeParam(out, '_node_version', encoding); writeParam(out, process.versions.node, encoding); if (opts.connectAttributes !== true) { let attrNames = Object.keys(opts.connectAttributes); for (let k = 0; k < attrNames.length; ++k) { writeParam(out, attrNames[k], encoding); writeParam(out, opts.connectAttributes[attrNames[k]], encoding); } } //write end size out.writeInt16AtPos(initPos); } out.flushBuffer(true); }; function writeParam(out, val, encoding) { let param = Buffer.isEncoding(encoding) ? Buffer.from(val, encoding) : Iconv.encode(val, encoding); out.writeLengthCoded(param.length); out.writeBuffer(param, 0, param.length); }