change-user.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. 'use strict';
  2. const Iconv = require('iconv-lite');
  3. const Capabilities = require('../const/capabilities');
  4. const Ed25519PasswordAuth = require('./handshake/auth/ed25519-password-auth');
  5. const NativePasswordAuth = require('./handshake/auth/native-password-auth');
  6. const Collations = require('../const/collations');
  7. const Handshake = require('./handshake/handshake');
  8. /**
  9. * send a COM_CHANGE_USER: resets the connection and re-authenticates with the given credentials
  10. * see https://mariadb.com/kb/en/library/com_change_user/
  11. */
  12. class ChangeUser extends Handshake {
  13. constructor(options, resolve, reject, addCommand) {
  14. super(resolve, reject, () => {}, addCommand);
  15. this.opts = options;
  16. }
  17. start(out, opts, info) {
  18. this.configAssign(opts, this.opts);
  19. let authToken;
  20. const pwd = Array.isArray(this.opts.password) ? this.opts.password[0] : this.opts.password;
  21. switch (info.defaultPluginName) {
  22. case 'mysql_native_password':
  23. case '':
  24. authToken = NativePasswordAuth.encryptPassword(pwd, info.seed, 'sha1');
  25. break;
  26. case 'client_ed25519':
  27. authToken = Ed25519PasswordAuth.encryptPassword(pwd, info.seed);
  28. break;
  29. default:
  30. authToken = Buffer.alloc(0);
  31. break;
  32. }
  33. out.startPacket(this);
  34. out.writeInt8(0x11);
  35. out.writeString(this.opts.user || '');
  36. out.writeInt8(0);
  37. if (info.serverCapabilities & Capabilities.SECURE_CONNECTION) {
  38. out.writeInt8(authToken.length);
  39. out.writeBuffer(authToken, 0, authToken.length);
  40. } else {
  41. out.writeBuffer(authToken, 0, authToken.length);
  42. out.writeInt8(0);
  43. }
  44. if (info.clientCapabilities & Capabilities.CONNECT_WITH_DB) {
  45. out.writeString(this.opts.database);
  46. out.writeInt8(0);
  47. info.database = this.opts.database;
  48. }
  49. out.writeInt16(this.opts.collation.index);
  50. if (info.clientCapabilities & Capabilities.PLUGIN_AUTH) {
  51. out.writeString(info.defaultPluginName);
  52. out.writeInt8(0);
  53. }
  54. if (info.clientCapabilities & Capabilities.CONNECT_ATTRS) {
  55. out.writeInt8(0xfc);
  56. let initPos = out.pos; //save position, assuming connection attributes length will be less than 2 bytes length
  57. out.writeInt16(0);
  58. const encoding = this.opts.collation.charset;
  59. writeParam(out, '_client_name', encoding);
  60. writeParam(out, 'MariaDB connector/Node', encoding);
  61. let packageJson = require('../../package.json');
  62. writeParam(out, '_client_version', encoding);
  63. writeParam(out, packageJson.version, encoding);
  64. writeParam(out, '_node_version', encoding);
  65. writeParam(out, process.versions.node, encoding);
  66. if (opts.connectAttributes !== true) {
  67. let attrNames = Object.keys(this.opts.connectAttributes);
  68. for (let k = 0; k < attrNames.length; ++k) {
  69. writeParam(out, attrNames[k], encoding);
  70. writeParam(out, this.opts.connectAttributes[attrNames[k]], encoding);
  71. }
  72. }
  73. //write end size
  74. out.writeInt16AtPos(initPos);
  75. }
  76. out.flushBuffer(true);
  77. this.onPacketReceive = this.handshakeResult;
  78. }
  79. /**
  80. * Assign global configuration option used by result-set to current query option.
  81. * a little faster than Object.assign() since doest copy all information
  82. *
  83. * @param connOpts connection global configuration
  84. * @param opt current options
  85. */
  86. configAssign(connOpts, opt) {
  87. if (!opt) {
  88. this.opts = connOpts;
  89. return;
  90. }
  91. this.opts.database = opt.database ? opt.database : connOpts.database;
  92. this.opts.connectAttributes = opt.connectAttributes
  93. ? opt.connectAttributes
  94. : connOpts.connectAttributes;
  95. if (opt.charset && typeof opt.charset === 'string') {
  96. this.opts.collation = Collations.fromCharset(opt.charset.toLowerCase());
  97. if (this.opts.collation === undefined) {
  98. this.opts.collation = Collations.fromName(opt.charset.toUpperCase());
  99. if (this.opts.collation !== undefined) {
  100. console.log(
  101. "warning: please use option 'collation' " +
  102. "in replacement of 'charset' when using a collation name ('" +
  103. opt.charset +
  104. "')\n" +
  105. "(collation looks like 'UTF8MB4_UNICODE_CI', charset like 'utf8')."
  106. );
  107. }
  108. }
  109. if (this.opts.collation === undefined)
  110. throw new RangeError("Unknown charset '" + opt.charset + "'");
  111. } else if (opt.collation && typeof opt.collation === 'string') {
  112. const initial = opt.collation;
  113. this.opts.collation = Collations.fromName(initial.toUpperCase());
  114. if (this.opts.collation === undefined)
  115. throw new RangeError("Unknown collation '" + initial + "'");
  116. } else {
  117. this.opts.collation = Collations.fromIndex(opt.charsetNumber) || connOpts.collation;
  118. }
  119. connOpts.password = opt.password;
  120. }
  121. }
  122. function writeParam(out, val, encoding) {
  123. let param = Buffer.isEncoding(encoding)
  124. ? Buffer.from(val, encoding)
  125. : Iconv.encode(val, encoding);
  126. out.writeLengthCoded(param.length);
  127. out.writeBuffer(param, 0, param.length);
  128. }
  129. module.exports = ChangeUser;