change_user.js 3.2 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. 'use strict';
  2. const CommandCode = require('../constants/commands.js');
  3. const ClientConstants = require('../constants/client.js');
  4. const Packet = require('../packets/packet.js');
  5. const auth41 = require('../auth_41.js');
  6. const CharsetToEncoding = require('../constants/charset_encodings.js');
  7. // https://dev.mysql.com/doc/internals/en/com-change-user.html#packet-COM_CHANGE_USER
  8. class ChangeUser {
  9. constructor(opts) {
  10. this.flags = opts.flags;
  11. this.user = opts.user || '';
  12. this.database = opts.database || '';
  13. this.password = opts.password || '';
  14. this.passwordSha1 = opts.passwordSha1;
  15. this.authPluginData1 = opts.authPluginData1;
  16. this.authPluginData2 = opts.authPluginData2;
  17. this.connectAttributes = opts.connectAttrinutes || {};
  18. let authToken;
  19. if (this.passwordSha1) {
  20. authToken = auth41.calculateTokenFromPasswordSha(
  21. this.passwordSha1,
  22. this.authPluginData1,
  23. this.authPluginData2
  24. );
  25. } else {
  26. authToken = auth41.calculateToken(
  27. this.password,
  28. this.authPluginData1,
  29. this.authPluginData2
  30. );
  31. }
  32. this.authToken = authToken;
  33. this.charsetNumber = opts.charsetNumber;
  34. }
  35. // TODO
  36. // ChangeUser.fromPacket = function(packet)
  37. // };
  38. serializeToBuffer(buffer) {
  39. const isSet = flag => this.flags & ClientConstants[flag];
  40. const packet = new Packet(0, buffer, 0, buffer.length);
  41. packet.offset = 4;
  42. const encoding = CharsetToEncoding[this.charsetNumber];
  43. packet.writeInt8(CommandCode.CHANGE_USER);
  44. packet.writeNullTerminatedString(this.user, encoding);
  45. if (isSet('SECURE_CONNECTION')) {
  46. packet.writeInt8(this.authToken.length);
  47. packet.writeBuffer(this.authToken);
  48. } else {
  49. packet.writeBuffer(this.authToken);
  50. packet.writeInt8(0);
  51. }
  52. packet.writeNullTerminatedString(this.database, encoding);
  53. packet.writeInt16(this.charsetNumber);
  54. if (isSet('PLUGIN_AUTH')) {
  55. // TODO: read this from parameters
  56. packet.writeNullTerminatedString('mysql_native_password', 'latin1');
  57. }
  58. if (isSet('CONNECT_ATTRS')) {
  59. const connectAttributes = this.connectAttributes;
  60. const attrNames = Object.keys(connectAttributes);
  61. let keysLength = 0;
  62. for (let k = 0; k < attrNames.length; ++k) {
  63. keysLength += Packet.lengthCodedStringLength(attrNames[k], encoding);
  64. keysLength += Packet.lengthCodedStringLength(
  65. connectAttributes[attrNames[k]],
  66. encoding
  67. );
  68. }
  69. packet.writeLengthCodedNumber(keysLength);
  70. for (let k = 0; k < attrNames.length; ++k) {
  71. packet.writeLengthCodedString(attrNames[k], encoding);
  72. packet.writeLengthCodedString(
  73. connectAttributes[attrNames[k]],
  74. encoding
  75. );
  76. }
  77. }
  78. return packet;
  79. }
  80. toPacket() {
  81. if (typeof this.user !== 'string') {
  82. throw new Error('"user" connection config property must be a string');
  83. }
  84. if (typeof this.database !== 'string') {
  85. throw new Error('"database" connection config property must be a string');
  86. }
  87. // dry run: calculate resulting packet length
  88. const p = this.serializeToBuffer(Packet.MockBuffer());
  89. return this.serializeToBuffer(Buffer.allocUnsafe(p.offset));
  90. }
  91. }
  92. module.exports = ChangeUser;