mysql2
Version:
fast mysql driver. Implements core protocol, prepared statements, ssl and compression in native JS
174 lines (149 loc) • 5.08 kB
JavaScript
var util = require('util');
var ClientConstants = require('../constants/client.js');
var CommandCode = require('../constants/commands.js');
var Errors = require('../constants/errors.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) {
connection.emit('error', new Error('Error generating random bytes'));
return;
}
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);
// TODO check we don't have something similar already
connection.clientHelloReply = clientHelloReply;
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 knownCommand = true;
var encoding = connection.clientHelloReply.encoding;
var commandCode = packet.readInt8();
switch (commandCode) {
case CommandCode.QUIT:
if (connection.listeners('quit').length) {
connection.emit('quit');
} else {
connection.stream.end();
}
break;
case CommandCode.INIT_DB:
if (connection.listeners('init_db').length) {
var schemaName = packet.readString(encoding);
connection.emit('init_db', schemaName);
} else {
connection.writeOk();
}
break;
case CommandCode.QUERY:
if (connection.listeners('query').length) {
var query = packet.readString(undefined, encoding);
connection.emit('query', query);
} else {
connection.writeError({
code: Errors.HA_ERR_INTERNAL_ERROR,
message: 'No query handler'
});
}
break;
case CommandCode.FIELD_LIST:
if (connection.listeners('field_list').length) {
var table = packet.readNullTerminatedString();
var fields = packet.readString(encoding);
connection.emit('field_list', table, fields);
} else {
connection.writeError({
code: Errors.ER_WARN_DEPRECATED_SYNTAX,
message: 'As of MySQL 5.7.11, COM_FIELD_LIST is deprecated and will be removed in a future version of MySQL.'
});
}
break;
case CommandCode.PING:
if (connection.listeners('ping').length) {
connection.emit('ping');
} else {
connection.writeOk();
}
break;
default:
knownCommand = false;
}
if (connection.listeners('packet').length) {
connection.emit('packet', packet.clone(), knownCommand, commandCode);
} else {
if (!knownCommand) {
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)
*/