var util = require('util'); var ClientConstants = require('../constants/client.js'); var CommandCode = require('../constants/commands.js'); var Command = require('./command.js'); var Packets = require('../packets/index.js'); var auth41 = require('../auth_41.js'); function ServerHandshake(args) { Command.call(this); this.args = args; /* this.protocolVersion = args.protocolVersion || 10; this.serverVersion = args.serverVersion; this.connectionId = args.connectionId, this.statusFlags = args.statusFlags, this.characterSet = args.characterSet, this.capabilityFlags = args.capabilityFlags || 512; */ } util.inherits(ServerHandshake, Command); ServerHandshake.prototype.start = function(packet, connection) { var serverHelloPacket = new Packets.Handshake(this.args); this.serverHello = serverHelloPacket; serverHelloPacket.setScrambleData(function(err) { if (err) return connection.emit('error', new Error('Error generating random bytes')); connection.writePacket(serverHelloPacket.toPacket(0)); }); return ServerHandshake.prototype.readClientReply; }; ServerHandshake.prototype.readClientReply = function(packet, connection) { // check auth here var clientHelloReply = new Packets.HandshakeResponse.fromPacket(packet); if (this.args.authCallback) { try { this.args.authCallback({ user: clientHelloReply.user, database: clientHelloReply.database, address: connection.stream.remoteAddress, authPluginData1: this.serverHello.authPluginData1, authPluginData2: this.serverHello.authPluginData2, authToken: clientHelloReply.authToken, }, function(err, mysqlError) { //if (err) if (!mysqlError) connection.writeOk(); else { // TODO create constants / errorToCode // 1045 = ER_ACCESS_DENIED_ERROR connection.writeError({ message: mysqlError.message || '', code: mysqlError.code || 1045 }); connection.close(); } }); } catch(err) { throw err; // TODO // connection.writeError(err) } } else { connection.writeOk(); } return ServerHandshake.prototype.dispatchCommands; }; ServerHandshake.prototype.dispatchCommands = function(packet, connection) { // command from client to server var commandCode = packet.readInt8(); switch (commandCode) { case CommandCode.QUIT: connection.stream.end(); break; case CommandCode.INIT_DB: var schemaName = packet.readString(); connection.emit('init_db', schemaName); connection.writeOk(); break; case CommandCode.PING: // allow custom ping response (delayed/incorrect/etc) // if no listeners, respond with OK if (connection.listeners('ping').length === 0) { connection.writeOk(); } else { connection.emit('ping'); } break; case CommandCode.QUERY: var query = packet.readString(); connection.emit('query', query); break; case CommandCode.FIELD_LIST: var table = packet.readNullTerminatedString(); var fields = packet.readString(); connection.emit('field_list', table, fields); break; default: console.log('Unknown command:', commandCode); } return ServerHandshake.prototype.dispatchCommands; }; module.exports = ServerHandshake; // TODO: implement server-side 4.1 authentication /* 4.1 authentication: (http://bazaar.launchpad.net/~mysql/mysql-server/5.5/view/head:/sql/password.c) SERVER: public_seed=create_random_string() send(public_seed) CLIENT: recv(public_seed) hash_stage1=sha1("password") hash_stage2=sha1(hash_stage1) reply=xor(hash_stage1, sha1(public_seed,hash_stage2) // this three steps are done in scramble() send(reply) SERVER: recv(reply) hash_stage1=xor(reply, sha1(public_seed,hash_stage2)) candidate_hash2=sha1(hash_stage1) check(candidate_hash2==hash_stage2) server stores sha1(sha1(password)) ( hash_stag2) */