@tachybase/module-multi-app 1.6.0 → 1.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/README.md +34 -34
  2. package/README.zh-CN.md +34 -34
  3. package/client.d.ts +1 -1
  4. package/client.js +1 -1
  5. package/dist/externalVersion.js +5 -5
  6. package/dist/locale/en-US.json +48 -48
  7. package/dist/locale/es-ES.json +9 -9
  8. package/dist/locale/ko_KR.json +11 -11
  9. package/dist/locale/pt-BR.json +9 -9
  10. package/dist/locale/zh-CN.json +58 -58
  11. package/dist/node_modules/mariadb/callback.js +43 -8
  12. package/dist/node_modules/mariadb/check-node.js +30 -0
  13. package/dist/node_modules/mariadb/lib/cluster-callback.js +84 -0
  14. package/dist/node_modules/mariadb/lib/cluster.js +446 -0
  15. package/dist/node_modules/mariadb/lib/cmd/batch-bulk.js +576 -177
  16. package/dist/node_modules/mariadb/lib/cmd/change-user.js +54 -44
  17. package/dist/node_modules/mariadb/lib/cmd/class/ok-packet.js +3 -2
  18. package/dist/node_modules/mariadb/lib/cmd/class/prepare-cache-wrapper.js +46 -0
  19. package/dist/node_modules/mariadb/lib/cmd/class/prepare-result-packet.js +141 -0
  20. package/dist/node_modules/mariadb/lib/cmd/class/prepare-wrapper.js +70 -0
  21. package/dist/node_modules/mariadb/lib/cmd/close-prepare.js +38 -0
  22. package/dist/node_modules/mariadb/lib/cmd/column-definition.js +145 -47
  23. package/dist/node_modules/mariadb/lib/cmd/command.js +41 -75
  24. package/dist/node_modules/mariadb/lib/cmd/decoder/binary-decoder.js +282 -0
  25. package/dist/node_modules/mariadb/lib/cmd/decoder/text-decoder.js +210 -0
  26. package/dist/node_modules/mariadb/lib/cmd/{common-binary-cmd.js → encoder/binary-encoder.js} +34 -77
  27. package/dist/node_modules/mariadb/lib/cmd/encoder/text-encoder.js +311 -0
  28. package/dist/node_modules/mariadb/lib/cmd/execute-stream.js +61 -0
  29. package/dist/node_modules/mariadb/lib/cmd/execute.js +338 -0
  30. package/dist/node_modules/mariadb/lib/cmd/handshake/auth/caching-sha2-password-auth.js +25 -62
  31. package/dist/node_modules/mariadb/lib/cmd/handshake/auth/clear-password-auth.js +39 -6
  32. package/dist/node_modules/mariadb/lib/cmd/handshake/auth/ed25519-password-auth.js +48 -16
  33. package/dist/node_modules/mariadb/lib/cmd/handshake/auth/handshake.js +198 -0
  34. package/dist/node_modules/mariadb/lib/cmd/handshake/{initial-handshake.js → auth/initial-handshake.js} +10 -8
  35. package/dist/node_modules/mariadb/lib/cmd/handshake/auth/native-password-auth.js +22 -9
  36. package/dist/node_modules/mariadb/lib/cmd/handshake/auth/pam-password-auth.js +9 -4
  37. package/dist/node_modules/mariadb/lib/cmd/handshake/auth/parsec-auth.js +115 -0
  38. package/dist/node_modules/mariadb/lib/cmd/handshake/auth/plugin-auth.js +12 -5
  39. package/dist/node_modules/mariadb/lib/cmd/handshake/auth/sha256-password-auth.js +44 -33
  40. package/dist/node_modules/mariadb/lib/cmd/handshake/authentication.js +335 -0
  41. package/dist/node_modules/mariadb/lib/cmd/handshake/client-capabilities.js +20 -19
  42. package/dist/node_modules/mariadb/lib/cmd/handshake/ssl-request.js +6 -3
  43. package/dist/node_modules/mariadb/lib/cmd/parser.js +861 -0
  44. package/dist/node_modules/mariadb/lib/cmd/ping.js +17 -18
  45. package/dist/node_modules/mariadb/lib/cmd/prepare.js +170 -0
  46. package/dist/node_modules/mariadb/lib/cmd/query.js +281 -144
  47. package/dist/node_modules/mariadb/lib/cmd/quit.js +9 -6
  48. package/dist/node_modules/mariadb/lib/cmd/reset.js +15 -19
  49. package/dist/node_modules/mariadb/lib/cmd/stream.js +21 -6
  50. package/dist/node_modules/mariadb/lib/config/cluster-options.js +23 -0
  51. package/dist/node_modules/mariadb/lib/config/connection-options.js +196 -132
  52. package/dist/node_modules/mariadb/lib/config/pool-options.js +27 -19
  53. package/dist/node_modules/mariadb/lib/connection-callback.js +492 -120
  54. package/dist/node_modules/mariadb/lib/connection-promise.js +372 -0
  55. package/dist/node_modules/mariadb/lib/connection.js +1739 -1016
  56. package/dist/node_modules/mariadb/lib/const/capabilities.js +36 -30
  57. package/dist/node_modules/mariadb/lib/const/collations.js +972 -36
  58. package/dist/node_modules/mariadb/lib/const/connection_status.js +3 -0
  59. package/dist/node_modules/mariadb/lib/const/error-code.js +35 -11
  60. package/dist/node_modules/mariadb/lib/const/field-detail.js +3 -0
  61. package/dist/node_modules/mariadb/lib/const/field-type.js +7 -4
  62. package/dist/node_modules/mariadb/lib/const/server-status.js +4 -1
  63. package/dist/node_modules/mariadb/lib/const/state-change.js +3 -0
  64. package/dist/node_modules/mariadb/lib/filtered-cluster-callback.js +136 -0
  65. package/dist/node_modules/mariadb/lib/filtered-cluster.js +118 -0
  66. package/dist/node_modules/mariadb/lib/io/compression-input-stream.js +14 -13
  67. package/dist/node_modules/mariadb/lib/io/compression-output-stream.js +21 -18
  68. package/dist/node_modules/mariadb/lib/io/packet-input-stream.js +75 -64
  69. package/dist/node_modules/mariadb/lib/io/packet-node-encoded.js +13 -9
  70. package/dist/node_modules/mariadb/lib/io/packet-node-iconv.js +12 -10
  71. package/dist/node_modules/mariadb/lib/io/packet-output-stream.js +402 -134
  72. package/dist/node_modules/mariadb/lib/io/packet.js +287 -202
  73. package/dist/node_modules/mariadb/lib/lru-prepare-cache.js +84 -0
  74. package/dist/node_modules/mariadb/lib/misc/connection-information.js +15 -32
  75. package/dist/node_modules/mariadb/lib/misc/errors.js +68 -25
  76. package/dist/node_modules/mariadb/lib/misc/parse.js +207 -711
  77. package/dist/node_modules/mariadb/lib/misc/utils.js +34 -62
  78. package/dist/node_modules/mariadb/lib/pool-callback.js +213 -174
  79. package/dist/node_modules/mariadb/lib/pool-promise.js +228 -94
  80. package/dist/node_modules/mariadb/lib/pool.js +951 -0
  81. package/dist/node_modules/mariadb/package.json +1 -1
  82. package/dist/node_modules/mariadb/promise.js +1 -34
  83. package/dist/node_modules/mariadb/types/callback.d.ts +207 -0
  84. package/dist/node_modules/mariadb/types/index.d.ts +94 -674
  85. package/dist/node_modules/mariadb/types/share.d.ts +804 -0
  86. package/dist/node_modules/qs/package.json +1 -1
  87. package/dist/server/actions/apps.js +2 -2
  88. package/dist/server/app-lifecycle.d.ts +1 -1
  89. package/dist/server/app-lifecycle.js +4 -4
  90. package/dist/server/models/application.d.ts +1 -1
  91. package/package.json +7 -7
  92. package/server.d.ts +2 -2
  93. package/server.js +1 -1
  94. package/dist/node_modules/mariadb/lib/cmd/batch-rewrite.js +0 -372
  95. package/dist/node_modules/mariadb/lib/cmd/common-text-cmd.js +0 -427
  96. package/dist/node_modules/mariadb/lib/cmd/handshake/client-handshake-response.js +0 -126
  97. package/dist/node_modules/mariadb/lib/cmd/handshake/handshake.js +0 -292
  98. package/dist/node_modules/mariadb/lib/cmd/resultset.js +0 -607
  99. package/dist/node_modules/mariadb/lib/config/pool-cluster-options.js +0 -19
  100. package/dist/node_modules/mariadb/lib/filtered-pool-cluster.js +0 -81
  101. package/dist/node_modules/mariadb/lib/io/bulk-packet.js +0 -590
  102. package/dist/node_modules/mariadb/lib/io/rewrite-packet.js +0 -481
  103. package/dist/node_modules/mariadb/lib/pool-base.js +0 -611
  104. package/dist/node_modules/mariadb/lib/pool-cluster-callback.js +0 -66
  105. package/dist/node_modules/mariadb/lib/pool-cluster.js +0 -407
@@ -1,14 +1,19 @@
1
+ // SPDX-License-Identifier: LGPL-2.1-or-later
2
+ // Copyright (c) 2015-2024 MariaDB Corporation Ab
3
+
1
4
  const PluginAuth = require('./plugin-auth');
2
5
 
3
6
  /**
4
7
  * Use PAM authentication
5
8
  */
6
9
  class PamPasswordAuth extends PluginAuth {
7
- constructor(packSeq, compressPackSeq, pluginData, resolve, reject, multiAuthResolver) {
8
- super(resolve, reject, multiAuthResolver);
10
+ constructor(packSeq, compressPackSeq, pluginData, cmdParam, reject, multiAuthResolver) {
11
+ super(cmdParam, multiAuthResolver, reject);
9
12
  this.pluginData = pluginData;
10
13
  this.sequenceNo = packSeq;
14
+ this.compressSequenceNo = compressPackSeq;
11
15
  this.counter = 0;
16
+ this.multiAuthResolver = multiAuthResolver;
12
17
  }
13
18
 
14
19
  start(out, opts, info) {
@@ -33,7 +38,7 @@ class PamPasswordAuth extends PluginAuth {
33
38
 
34
39
  if (pwd) out.writeString(pwd);
35
40
  out.writeInt8(0);
36
- out.flushBuffer(true);
41
+ out.flushPacket();
37
42
  }
38
43
 
39
44
  response(packet, out, opts, info) {
@@ -45,7 +50,7 @@ class PamPasswordAuth extends PluginAuth {
45
50
  case 0x00:
46
51
  case 0xff:
47
52
  this.emit('send_end');
48
- return this.successSend(packet, out, opts, info);
53
+ return this.multiAuthResolver(packet, out, opts, info);
49
54
 
50
55
  default:
51
56
  let promptData = packet.readBuffer();
@@ -0,0 +1,115 @@
1
+ // SPDX-License-Identifier: LGPL-2.1-or-later
2
+ // Copyright (c) 2015-2025 MariaDB Corporation Ab
3
+
4
+ 'use strict';
5
+
6
+ const PluginAuth = require('./plugin-auth');
7
+ const crypto = require('crypto');
8
+ const Errors = require('../../../misc/errors');
9
+
10
+ const pkcs8Ed25519header = Buffer.from([
11
+ 0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04, 0x20
12
+ ]);
13
+
14
+ /**
15
+ * Standard authentication plugin
16
+ */
17
+ class ParsecAuth extends PluginAuth {
18
+ #hash;
19
+ constructor(packSeq, compressPackSeq, pluginData, cmdParam, reject, multiAuthResolver) {
20
+ super(cmdParam, multiAuthResolver, reject);
21
+ this.multiAuthResolver = multiAuthResolver;
22
+ this.pluginData = pluginData;
23
+ this.sequenceNo = packSeq;
24
+ this.compressSequenceNo = compressPackSeq;
25
+ }
26
+
27
+ start(out, opts, info) {
28
+ if (!info.extSalt) {
29
+ out.startPacket(this);
30
+ out.writeEmptyPacket(true); // indicate need salt
31
+ this.onPacketReceive = this.requestForSalt;
32
+ } else {
33
+ this.parseExtSalt(Buffer.from(info.extSalt, 'hex'), info);
34
+ this.sendScramble(out, opts, info);
35
+ }
36
+ }
37
+
38
+ requestForSalt(packet, out, opts, info) {
39
+ this.parseExtSalt(packet.readBufferRemaining(), info);
40
+ this.sendScramble(out, opts, info);
41
+ }
42
+
43
+ parseExtSalt(extSalt, info) {
44
+ if (extSalt.length < 2 || extSalt[0] !== 0x50 || extSalt[1] > 3) {
45
+ // expected 'P' for KDF algorithm (PBKDF2) and maximum iteration of 8192
46
+ return this.throwError(
47
+ Errors.createFatalError('Wrong parsec authentication format', Errors.ER_AUTHENTICATION_BAD_PACKET, info),
48
+ info
49
+ );
50
+ }
51
+ this.iterations = extSalt[1];
52
+ this.salt = extSalt.slice(2);
53
+
54
+ // disable for now until https://jira.mariadb.org/browse/MDEV-34846
55
+ // info.extSalt = extSalt.toString('hex');
56
+ }
57
+
58
+ sendScramble(out, opts, info) {
59
+ const derivedKey = crypto.pbkdf2Sync(opts.password || '', this.salt, 1024 << this.iterations, 32, 'sha512');
60
+ const privateKey = toPkcs8der(derivedKey);
61
+
62
+ const rawPublicKey = this.getEd25519PublicKeyFromPrivateKey(derivedKey);
63
+
64
+ this.#hash = Buffer.concat([Buffer.from([0x50, this.iterations]), this.salt, rawPublicKey]);
65
+
66
+ const client_scramble = crypto.randomBytes(32);
67
+ const message = Buffer.concat([this.pluginData, client_scramble]);
68
+ const signature = crypto.sign(null, message, privateKey);
69
+
70
+ out.startPacket(this);
71
+ out.writeBuffer(client_scramble, 0, 32);
72
+ out.writeBuffer(signature, 0, 64);
73
+ out.flushPacket();
74
+ this.emit('send_end');
75
+ this.onPacketReceive = this.multiAuthResolver;
76
+ }
77
+
78
+ getEd25519PublicKeyFromPrivateKey(privateKeyBuffer) {
79
+ // Create a KeyObject from the raw private key
80
+ const privateKey = crypto.createPrivateKey({
81
+ key: Buffer.concat([pkcs8Ed25519header, privateKeyBuffer]),
82
+ format: 'der',
83
+ type: 'pkcs8',
84
+ name: 'ed25519'
85
+ });
86
+
87
+ // Get the corresponding public key
88
+ const publicKey = crypto.createPublicKey(privateKey);
89
+
90
+ // Export the public key in raw format
91
+ return publicKey
92
+ .export({
93
+ type: 'spki',
94
+ format: 'der'
95
+ })
96
+ .subarray(-32); // The last 32 bytes contain the raw key
97
+ }
98
+
99
+ permitHash() {
100
+ return true;
101
+ }
102
+
103
+ hash(conf) {
104
+ return this.#hash;
105
+ }
106
+ }
107
+
108
+ const toPkcs8der = (rawB64) => {
109
+ // prefix for a private Ed25519
110
+ const prefixPrivateEd25519 = Buffer.from('302e020100300506032b657004220420', 'hex');
111
+ const der = Buffer.concat([prefixPrivateEd25519, rawB64]);
112
+ return crypto.createPrivateKey({ key: der, format: 'der', type: 'pkcs8' });
113
+ };
114
+
115
+ module.exports = ParsecAuth;
@@ -1,3 +1,6 @@
1
+ // SPDX-License-Identifier: LGPL-2.1-or-later
2
+ // Copyright (c) 2015-2024 MariaDB Corporation Ab
3
+
1
4
  'use strict';
2
5
 
3
6
  const Command = require('../../command');
@@ -6,13 +9,17 @@ const Command = require('../../command');
6
9
  * Base authentication plugin
7
10
  */
8
11
  class PluginAuth extends Command {
9
- constructor(resolve, reject, multiAuthResolver) {
10
- super(resolve, reject);
11
- this.multiAuthResolver = multiAuthResolver;
12
+ constructor(cmdParam, multiAuthResolver, reject) {
13
+ super(cmdParam, multiAuthResolver, reject);
14
+ this.onPacketReceive = multiAuthResolver;
15
+ }
16
+
17
+ permitHash() {
18
+ return true;
12
19
  }
13
20
 
14
- successSend(packet, out, opts, info) {
15
- this.multiAuthResolver(packet, out, opts, info);
21
+ hash(conf) {
22
+ return null;
16
23
  }
17
24
  }
18
25
 
@@ -1,18 +1,25 @@
1
+ // SPDX-License-Identifier: LGPL-2.1-or-later
2
+ // Copyright (c) 2015-2024 MariaDB Corporation Ab
3
+
1
4
  const PluginAuth = require('./plugin-auth');
2
5
  const fs = require('fs');
3
6
  const crypto = require('crypto');
4
7
  const Errors = require('../../../misc/errors');
8
+ const Crypto = require('crypto');
5
9
 
6
10
  /**
7
11
  * Use Sha256 authentication
8
12
  */
9
13
  class Sha256PasswordAuth extends PluginAuth {
10
- constructor(packSeq, compressPackSeq, pluginData, resolve, reject, multiAuthResolver) {
11
- super(resolve, reject, multiAuthResolver);
14
+ constructor(packSeq, compressPackSeq, pluginData, cmdParam, reject, multiAuthResolver) {
15
+ super(cmdParam, multiAuthResolver, reject);
12
16
  this.pluginData = pluginData;
13
17
  this.sequenceNo = packSeq;
18
+ this.compressSequenceNo = compressPackSeq;
19
+ this.counter = 0;
14
20
  this.counter = 0;
15
21
  this.initialState = true;
22
+ this.multiAuthResolver = multiAuthResolver;
16
23
  }
17
24
 
18
25
  start(out, opts, info) {
@@ -33,7 +40,7 @@ class Sha256PasswordAuth extends PluginAuth {
33
40
  out.writeString(opts.password);
34
41
  }
35
42
  out.writeInt8(0);
36
- out.flushBuffer(true);
43
+ out.flushPacket();
37
44
  return;
38
45
  } else {
39
46
  // retrieve public key from configuration or from server
@@ -44,21 +51,18 @@ class Sha256PasswordAuth extends PluginAuth {
44
51
  // rsaPublicKey contain path
45
52
  key = fs.readFileSync(key, 'utf8');
46
53
  }
47
- this.publicKey = Sha256PasswordAuth.retreivePublicKey(key);
54
+ this.publicKey = Sha256PasswordAuth.retrievePublicKey(key);
48
55
  } catch (err) {
49
56
  return this.throwError(err, info);
50
57
  }
51
58
  } else {
52
59
  if (!opts.allowPublicKeyRetrieval) {
53
60
  return this.throwError(
54
- Errors.createError(
61
+ Errors.createFatalError(
55
62
  'RSA public key is not available client side. Either set option `rsaPublicKey` to indicate' +
56
63
  ' public key path, or allow public key retrieval with option `allowPublicKeyRetrieval`',
57
- null,
58
- true,
59
- info,
60
- '08S01',
61
- Errors.ER_CANNOT_RETRIEVE_RSA_KEY
64
+ Errors.ER_CANNOT_RETRIEVE_RSA_KEY,
65
+ info
62
66
  ),
63
67
  info
64
68
  );
@@ -68,33 +72,21 @@ class Sha256PasswordAuth extends PluginAuth {
68
72
  // ask public Key Retrieval
69
73
  out.startPacket(this);
70
74
  out.writeInt8(0x01);
71
- out.flushBuffer(true);
75
+ out.flushPacket();
72
76
  return;
73
77
  }
74
78
  }
75
79
 
76
80
  // send Sha256Password Packet
77
- Sha256PasswordAuth.sendSha256PwdPacket(
78
- this,
79
- this.pluginData,
80
- this.publicKey,
81
- opts.password,
82
- out
83
- );
81
+ Sha256PasswordAuth.sendSha256PwdPacket(this, this.pluginData, this.publicKey, opts.password, out);
84
82
  } else {
85
83
  // has request public key
86
- this.publicKey = Sha256PasswordAuth.retreivePublicKey(buffer.toString('utf8', 1));
87
- Sha256PasswordAuth.sendSha256PwdPacket(
88
- this,
89
- this.pluginData,
90
- this.publicKey,
91
- opts.password,
92
- out
93
- );
84
+ this.publicKey = Sha256PasswordAuth.retrievePublicKey(buffer.toString('utf8', 1));
85
+ Sha256PasswordAuth.sendSha256PwdPacket(this, this.pluginData, this.publicKey, opts.password, out);
94
86
  }
95
87
  }
96
88
 
97
- static retreivePublicKey(key) {
89
+ static retrievePublicKey(key) {
98
90
  return key.replace('(-+BEGIN PUBLIC KEY-+\\r?\\n|\\n?-+END PUBLIC KEY-+\\r?\\n?)', '');
99
91
  }
100
92
 
@@ -103,7 +95,29 @@ class Sha256PasswordAuth extends PluginAuth {
103
95
  out.startPacket(cmd);
104
96
  const enc = Sha256PasswordAuth.encrypt(truncatedSeed, password, publicKey);
105
97
  out.writeBuffer(enc, 0, enc.length);
106
- out.flushBuffer(cmd);
98
+ out.flushPacket();
99
+ }
100
+
101
+ static encryptSha256Password(password, seed) {
102
+ if (!password) return Buffer.alloc(0);
103
+
104
+ let hash = Crypto.createHash('sha256');
105
+ let stage1 = hash.update(password, 'utf8').digest();
106
+ hash = Crypto.createHash('sha256');
107
+
108
+ let stage2 = hash.update(stage1).digest();
109
+ hash = Crypto.createHash('sha256');
110
+
111
+ // order is different from sha 1 !!!!!
112
+ hash.update(stage2);
113
+ hash.update(seed);
114
+
115
+ let digest = hash.digest();
116
+ let returnBytes = Buffer.allocUnsafe(digest.length);
117
+ for (let i = 0; i < digest.length; i++) {
118
+ returnBytes[i] = stage1[i] ^ digest[i];
119
+ }
120
+ return returnBytes;
107
121
  }
108
122
 
109
123
  // encrypt password with public key
@@ -114,10 +128,7 @@ class Sha256PasswordAuth extends PluginAuth {
114
128
  for (let i = 0; i < xorBytes.length; i++) {
115
129
  xorBytes[i] = nullFinishedPwd[i] ^ seed[i % seedLength];
116
130
  }
117
- return crypto.publicEncrypt(
118
- { key: publicKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING },
119
- xorBytes
120
- );
131
+ return crypto.publicEncrypt({ key: publicKey, padding: crypto.constants.RSA_PKCS1_OAEP_PADDING }, xorBytes);
121
132
  }
122
133
 
123
134
  response(packet, out, opts, info) {
@@ -129,7 +140,7 @@ class Sha256PasswordAuth extends PluginAuth {
129
140
  case 0x00:
130
141
  case 0xff:
131
142
  this.emit('send_end');
132
- return this.successSend(packet, out, opts, info);
143
+ return this.multiAuthResolver(packet, out, opts, info);
133
144
 
134
145
  default:
135
146
  let promptData = packet.readBufferRemaining();
@@ -0,0 +1,335 @@
1
+ // SPDX-License-Identifier: LGPL-2.1-or-later
2
+ // Copyright (c) 2015-2025 MariaDB Corporation Ab
3
+
4
+ 'use strict';
5
+
6
+ const Command = require('../command');
7
+ const Errors = require('../../misc/errors');
8
+ const Capabilities = require('../../const/capabilities');
9
+ const Handshake = require('./auth/handshake');
10
+ const ServerStatus = require('../../const/server-status');
11
+ const StateChange = require('../../const/state-change');
12
+ const Collations = require('../../const/collations');
13
+ const Crypto = require('crypto');
14
+ const utils = require('../../misc/utils');
15
+ const tls = require('tls');
16
+ const authenticationPlugins = {
17
+ mysql_native_password: require('./auth/native-password-auth.js'),
18
+ mysql_clear_password: require('./auth/clear-password-auth'),
19
+ client_ed25519: require('./auth/ed25519-password-auth'),
20
+ parsec: require('./auth/parsec-auth'),
21
+ dialog: require('./auth/pam-password-auth'),
22
+ sha256_password: require('./auth/sha256-password-auth'),
23
+ caching_sha2_password: require('./auth/caching-sha2-password-auth')
24
+ };
25
+
26
+ /**
27
+ * Handle handshake.
28
+ * see https://mariadb.com/kb/en/library/1-connecting-connecting/
29
+ */
30
+ class Authentication extends Command {
31
+ constructor(cmdParam, resolve, reject, _createSecureContext, getSocket) {
32
+ super(cmdParam, resolve, reject);
33
+ this.cmdParam = cmdParam;
34
+ this._createSecureContext = _createSecureContext;
35
+ this.getSocket = getSocket;
36
+ this.plugin = new Handshake(this, getSocket, this.handshakeResult, reject);
37
+ }
38
+
39
+ onPacketReceive(packet, out, opts, info) {
40
+ this.plugin.sequenceNo = this.sequenceNo;
41
+ this.plugin.compressSequenceNo = this.compressSequenceNo;
42
+ this.plugin.onPacketReceive(packet, out, opts, info);
43
+ }
44
+
45
+ /**
46
+ * Fast-path handshake results :
47
+ * - if plugin was the one expected by server, server will send OK_Packet / ERR_Packet.
48
+ * - if not, server send an AuthSwitchRequest packet, indicating the specific PLUGIN to use with this user.
49
+ * dispatching to plugin handler then.
50
+ *
51
+ * @param packet current packet
52
+ * @param out output buffer
53
+ * @param opts options
54
+ * @param info connection info
55
+ * @returns {*} return null if authentication succeed, depending on plugin conversation if not finished
56
+ */
57
+ handshakeResult(packet, out, opts, info) {
58
+ const marker = packet.peek();
59
+ switch (marker) {
60
+ //*********************************************************************************************************
61
+ //* AuthSwitchRequest packet
62
+ //*********************************************************************************************************
63
+ case 0xfe:
64
+ this.dispatchAuthSwitchRequest(packet, out, opts, info);
65
+ return;
66
+
67
+ //*********************************************************************************************************
68
+ //* OK_Packet - authentication succeeded
69
+ //*********************************************************************************************************
70
+ case 0x00:
71
+ this.plugin.onPacketReceive = null;
72
+ packet.skip(1); //skip header
73
+ packet.skipLengthCodedNumber(); //skip affected rows
74
+ packet.skipLengthCodedNumber(); //skip last insert id
75
+ info.status = packet.readUInt16();
76
+
77
+ if (info.requireValidCert) {
78
+ if (info.selfSignedCertificate) {
79
+ // TLS was forced to trust, and certificate validation is required
80
+ packet.skip(2); //skip warning count
81
+ if (packet.remaining()) {
82
+ const validationHash = packet.readBufferLengthEncoded();
83
+ if (validationHash.length > 0) {
84
+ if (!this.plugin.permitHash() || !Boolean(this.cmdParam.opts.password)) {
85
+ return this.throwNewError(
86
+ 'Self signed certificates. Either set `ssl: { rejectUnauthorized: false }` (trust mode) or provide server certificate to client',
87
+ true,
88
+ info,
89
+ '08000',
90
+ Errors.ER_SELF_SIGNED_NO_PWD
91
+ );
92
+ }
93
+ if (this.validateFingerPrint(validationHash, info)) {
94
+ return this.successEnd();
95
+ }
96
+ }
97
+ }
98
+ return this.throwNewError('self-signed certificate', true, info, '08000', Errors.ER_SELF_SIGNED);
99
+ } else {
100
+ // certificate is not self signed, validate server identity
101
+ const validationFunction =
102
+ opts.ssl === true || typeof opts.ssl.checkServerIdentity !== 'function'
103
+ ? tls.checkServerIdentity
104
+ : opts.ssl.checkServerIdentity;
105
+ const identityError = validationFunction(
106
+ typeof opts.ssl === 'object' && opts.ssl.servername ? opts.ssl.servername : opts.host,
107
+ info.tlsCert
108
+ );
109
+ if (identityError) {
110
+ return this.throwNewError(
111
+ 'certificate identify Error: ' + identityError.message,
112
+ true,
113
+ info,
114
+ '08000',
115
+ Errors.ER_TLS_IDENTITY_ERROR
116
+ );
117
+ }
118
+ }
119
+ }
120
+
121
+ let mustRedirect = false;
122
+ if (info.status & ServerStatus.SESSION_STATE_CHANGED) {
123
+ packet.skip(2); //skip warning count
124
+ packet.skipLengthCodedNumber();
125
+ while (packet.remaining()) {
126
+ const len = packet.readUnsignedLength();
127
+ if (len > 0) {
128
+ const subPacket = packet.subPacketLengthEncoded(len);
129
+ while (subPacket.remaining()) {
130
+ const type = subPacket.readUInt8();
131
+ switch (type) {
132
+ case StateChange.SESSION_TRACK_SYSTEM_VARIABLES:
133
+ let subSubPacket;
134
+ do {
135
+ subSubPacket = subPacket.subPacketLengthEncoded(subPacket.readUnsignedLength());
136
+ const variable = subSubPacket.readStringLengthEncoded();
137
+ const value = subSubPacket.readStringLengthEncoded();
138
+
139
+ switch (variable) {
140
+ case 'character_set_client':
141
+ info.collation = Collations.fromCharset(value);
142
+ if (info.collation === undefined) {
143
+ this.throwError(new Error("unknown charset : '" + value + "'"), info);
144
+ return;
145
+ }
146
+ opts.emit('collation', info.collation);
147
+ break;
148
+
149
+ case 'redirect_url':
150
+ if (value !== '') {
151
+ mustRedirect = true;
152
+ info.redirect(value, this.successEnd.bind(this));
153
+ }
154
+ break;
155
+
156
+ case 'maxscale':
157
+ info.maxscaleVersion = value;
158
+ break;
159
+
160
+ case 'connection_id':
161
+ info.threadId = parseInt(value);
162
+ break;
163
+
164
+ default:
165
+ //variable not used by driver
166
+ }
167
+ } while (subSubPacket.remaining() > 0);
168
+ break;
169
+
170
+ case StateChange.SESSION_TRACK_SCHEMA:
171
+ const subSubPacket2 = subPacket.subPacketLengthEncoded(subPacket.readUnsignedLength());
172
+ info.database = subSubPacket2.readStringLengthEncoded();
173
+ break;
174
+ }
175
+ }
176
+ }
177
+ }
178
+ }
179
+ if (!mustRedirect) this.successEnd();
180
+ return;
181
+
182
+ //*********************************************************************************************************
183
+ //* ERR_Packet
184
+ //*********************************************************************************************************
185
+ case 0xff:
186
+ this.plugin.onPacketReceive = null;
187
+ const authErr = packet.readError(info, this.displaySql(), undefined);
188
+ authErr.fatal = true;
189
+ if (info.requireValidCert && info.selfSignedCertificate) {
190
+ // TLS was forced to trust, and certificate validation is required
191
+ return this.plugin.throwNewError(
192
+ 'Self signed certificates. Either set `ssl: { rejectUnauthorized: false }` (trust mode) or provide server certificate to client',
193
+ true,
194
+ info,
195
+ '08000',
196
+ Errors.ER_SELF_SIGNED_NO_PWD
197
+ );
198
+ }
199
+ return this.plugin.throwError(authErr, info);
200
+
201
+ //*********************************************************************************************************
202
+ //* unexpected
203
+ //*********************************************************************************************************
204
+ default:
205
+ this.throwNewError(
206
+ `Unexpected type of packet during handshake phase : ${marker}`,
207
+ true,
208
+ info,
209
+ '42000',
210
+ Errors.ER_AUTHENTICATION_BAD_PACKET
211
+ );
212
+ }
213
+ }
214
+
215
+ validateFingerPrint(validationHash, info) {
216
+ if (validationHash.length === 0 || !info.tlsFingerprint) return false;
217
+
218
+ // 0x01 = SHA256 encryption
219
+ if (validationHash[0] !== 0x01) {
220
+ const err = Errors.createFatalError(
221
+ `Unexpected hash format for fingerprint hash encoding`,
222
+ Errors.ER_UNEXPECTED_PACKET,
223
+ this.info
224
+ );
225
+ if (this.opts.logger.error) this.opts.logger.error(err);
226
+ return false;
227
+ }
228
+
229
+ const pwdHash = this.plugin.hash(this.cmdParam.opts);
230
+
231
+ let hash = Crypto.createHash('sha256');
232
+ let digest = hash.update(pwdHash).update(info.seed).update(Buffer.from(info.tlsFingerprint, 'hex')).digest();
233
+ const hashHex = utils.toHexString(digest);
234
+ const serverValidationHex = validationHash.toString('ascii', 1, validationHash.length).toLowerCase();
235
+ return hashHex === serverValidationHex;
236
+ }
237
+
238
+ /**
239
+ * Handle authentication switch request : dispatch to plugin handler.
240
+ *
241
+ * @param packet packet
242
+ * @param out output writer
243
+ * @param opts options
244
+ * @param info connection information
245
+ */
246
+ dispatchAuthSwitchRequest(packet, out, opts, info) {
247
+ let pluginName, pluginData;
248
+ if (info.clientCapabilities & Capabilities.PLUGIN_AUTH) {
249
+ packet.skip(1); //header
250
+ if (packet.remaining()) {
251
+ //AuthSwitchRequest packet.
252
+ pluginName = packet.readStringNullEnded();
253
+ pluginData = packet.readBufferRemaining();
254
+ } else {
255
+ //OldAuthSwitchRequest
256
+ pluginName = 'mysql_old_password';
257
+ pluginData = info.seed.subarray(0, 8);
258
+ }
259
+ } else {
260
+ pluginName = packet.readStringNullEnded('ascii');
261
+ pluginData = packet.readBufferRemaining();
262
+ }
263
+
264
+ if (
265
+ info.requireValidCert &&
266
+ info.selfSignedCertificate &&
267
+ Boolean(this.cmdParam.opts.password) &&
268
+ !this.plugin.permitHash()
269
+ ) {
270
+ return this.throwNewError(
271
+ `Unsupported authentication plugin ${pluginName} with Self signed certificates. Either set 'ssl: { rejectUnauthorized: false }' (trust mode) or provide server certificate to client`,
272
+ true,
273
+ info,
274
+ '08000',
275
+ Errors.ER_SELF_SIGNED_BAD_PLUGIN
276
+ );
277
+ }
278
+
279
+ if (opts.restrictedAuth && !opts.restrictedAuth.includes(pluginName)) {
280
+ this.throwNewError(
281
+ `Unsupported authentication plugin ${pluginName}. Authorized plugin: ${opts.restrictedAuth.toString()}`,
282
+ true,
283
+ info,
284
+ '42000',
285
+ Errors.ER_NOT_SUPPORTED_AUTH_PLUGIN
286
+ );
287
+ return;
288
+ }
289
+ try {
290
+ this.plugin.emit('end');
291
+ this.plugin.onPacketReceive = null;
292
+ this.plugin = Authentication.pluginHandler(
293
+ pluginName,
294
+ this.plugin.sequenceNo,
295
+ this.plugin.compressSequenceNo,
296
+ pluginData,
297
+ info,
298
+ opts,
299
+ out,
300
+ this.cmdParam,
301
+ this.reject,
302
+ this.handshakeResult.bind(this)
303
+ );
304
+ this.plugin.start(out, opts, info);
305
+ } catch (err) {
306
+ this.reject(err);
307
+ }
308
+ }
309
+
310
+ static pluginHandler(
311
+ pluginName,
312
+ packSeq,
313
+ compressPackSeq,
314
+ pluginData,
315
+ info,
316
+ opts,
317
+ out,
318
+ cmdParam,
319
+ authReject,
320
+ multiAuthResolver
321
+ ) {
322
+ let pluginAuth = authenticationPlugins[pluginName];
323
+ if (!pluginAuth) {
324
+ throw Errors.createFatalError(
325
+ `Client does not support authentication protocol '${pluginName}' requested by server.`,
326
+ Errors.ER_AUTHENTICATION_PLUGIN_NOT_SUPPORTED,
327
+ info,
328
+ '08004'
329
+ );
330
+ }
331
+ return new pluginAuth(packSeq, compressPackSeq, pluginData, cmdParam, authReject, multiAuthResolver);
332
+ }
333
+ }
334
+
335
+ module.exports = Authentication;