server_handshake.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. var util = require('util');
  2. var ClientConstants = require('../constants/client.js');
  3. var CommandCode = require('../constants/commands.js');
  4. var Command = require('./command.js');
  5. var Packets = require('../packets/index.js');
  6. var auth41 = require('../auth_41.js');
  7. function ServerHandshake(args)
  8. {
  9. Command.call(this);
  10. this.args = args;
  11. /*
  12. this.protocolVersion = args.protocolVersion || 10;
  13. this.serverVersion = args.serverVersion;
  14. this.connectionId = args.connectionId,
  15. this.statusFlags = args.statusFlags,
  16. this.characterSet = args.characterSet,
  17. this.capabilityFlags = args.capabilityFlags || 512;
  18. */
  19. }
  20. util.inherits(ServerHandshake, Command);
  21. ServerHandshake.prototype.start = function(packet, connection) {
  22. var serverHelloPacket = new Packets.Handshake(this.args);
  23. this.serverHello = serverHelloPacket;
  24. serverHelloPacket.setScrambleData(function(err) {
  25. if (err)
  26. return connection.emit('error', new Error('Error generating random bytes'));
  27. connection.writePacket(serverHelloPacket.toPacket(0));
  28. });
  29. return ServerHandshake.prototype.readClientReply;
  30. };
  31. ServerHandshake.prototype.readClientReply = function(packet, connection) {
  32. // check auth here
  33. var clientHelloReply = new Packets.HandshakeResponse.fromPacket(packet);
  34. if (this.args.authCallback) {
  35. try {
  36. this.args.authCallback({
  37. user: clientHelloReply.user,
  38. database: clientHelloReply.database,
  39. address: connection.stream.remoteAddress,
  40. authPluginData1: this.serverHello.authPluginData1,
  41. authPluginData2: this.serverHello.authPluginData2,
  42. authToken: clientHelloReply.authToken,
  43. }, function(err, mysqlError) {
  44. //if (err)
  45. if (!mysqlError)
  46. connection.writeOk();
  47. else {
  48. // TODO create constants / errorToCode
  49. // 1045 = ER_ACCESS_DENIED_ERROR
  50. connection.writeError({ message: mysqlError.message || '', code: mysqlError.code || 1045 });
  51. connection.close();
  52. }
  53. });
  54. } catch(err) {
  55. throw err;
  56. // TODO
  57. // connection.writeError(err)
  58. }
  59. } else {
  60. connection.writeOk();
  61. }
  62. return ServerHandshake.prototype.dispatchCommands;
  63. };
  64. ServerHandshake.prototype.dispatchCommands = function(packet, connection) {
  65. // command from client to server
  66. var commandCode = packet.readInt8();
  67. switch (commandCode) {
  68. case CommandCode.QUIT:
  69. connection.emit('quit');
  70. // connection.stream.end();
  71. break;
  72. case CommandCode.INIT_DB:
  73. var schemaName = packet.readString();
  74. connection.emit('init_db', schemaName);
  75. connection.writeOk();
  76. break;
  77. case CommandCode.PING:
  78. // allow custom ping response (delayed/incorrect/etc)
  79. // if no listeners, respond with OK
  80. if (connection.listeners('ping').length === 0) {
  81. connection.writeOk();
  82. } else {
  83. connection.emit('ping');
  84. }
  85. break;
  86. case CommandCode.QUERY:
  87. var query = packet.readString();
  88. connection.emit('query', query);
  89. break;
  90. case CommandCode.FIELD_LIST:
  91. var table = packet.readNullTerminatedString();
  92. var fields = packet.readString();
  93. connection.emit('field_list', table, fields);
  94. break;
  95. default:
  96. console.log('Unknown command:', commandCode);
  97. }
  98. return ServerHandshake.prototype.dispatchCommands;
  99. };
  100. module.exports = ServerHandshake;
  101. // TODO: implement server-side 4.1 authentication
  102. /*
  103. 4.1 authentication: (http://bazaar.launchpad.net/~mysql/mysql-server/5.5/view/head:/sql/password.c)
  104. SERVER: public_seed=create_random_string()
  105. send(public_seed)
  106. CLIENT: recv(public_seed)
  107. hash_stage1=sha1("password")
  108. hash_stage2=sha1(hash_stage1)
  109. reply=xor(hash_stage1, sha1(public_seed,hash_stage2)
  110. // this three steps are done in scramble()
  111. send(reply)
  112. SERVER: recv(reply)
  113. hash_stage1=xor(reply, sha1(public_seed,hash_stage2))
  114. candidate_hash2=sha1(hash_stage1)
  115. check(candidate_hash2==hash_stage2)
  116. server stores sha1(sha1(password)) ( hash_stag2)
  117. */