@tachybase/module-multi-app 0.23.8
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.
- package/.turbo/turbo-build.log +14 -0
- package/README.md +34 -0
- package/README.zh-CN.md +34 -0
- package/client.d.ts +1 -0
- package/client.js +1 -0
- package/dist/client/AppManager.d.ts +2 -0
- package/dist/client/AppNameInput.d.ts +2 -0
- package/dist/client/MultiAppBlockInitializer.d.ts +2 -0
- package/dist/client/MultiAppManagerProvider.d.ts +2 -0
- package/dist/client/MultiAppManagerProvider.style.d.ts +5 -0
- package/dist/client/Settings.d.ts +2 -0
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.js +1 -0
- package/dist/client/settings/schemas/applications.d.ts +13 -0
- package/dist/client/utils.d.ts +4 -0
- package/dist/constants.d.ts +1 -0
- package/dist/constants.js +27 -0
- package/dist/externalVersion.js +16 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +39 -0
- package/dist/locale/en-US.json +27 -0
- package/dist/locale/es-ES.json +9 -0
- package/dist/locale/ko_KR.json +11 -0
- package/dist/locale/pt-BR.json +9 -0
- package/dist/locale/zh-CN.json +27 -0
- package/dist/node_modules/mariadb/LICENSE +502 -0
- package/dist/node_modules/mariadb/callback.js +41 -0
- package/dist/node_modules/mariadb/lib/cmd/batch-bulk.js +278 -0
- package/dist/node_modules/mariadb/lib/cmd/batch-rewrite.js +372 -0
- package/dist/node_modules/mariadb/lib/cmd/change-user.js +149 -0
- package/dist/node_modules/mariadb/lib/cmd/class/ok-packet.js +17 -0
- package/dist/node_modules/mariadb/lib/cmd/column-definition.js +102 -0
- package/dist/node_modules/mariadb/lib/cmd/command.js +168 -0
- package/dist/node_modules/mariadb/lib/cmd/common-binary-cmd.js +327 -0
- package/dist/node_modules/mariadb/lib/cmd/common-text-cmd.js +427 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/caching-sha2-password-auth.js +168 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/clear-password-auth.js +23 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/ed25519-password-auth.js +761 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/native-password-auth.js +55 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/pam-password-auth.js +58 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/plugin-auth.js +19 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/auth/sha256-password-auth.js +142 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/client-capabilities.js +74 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/client-handshake-response.js +126 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/handshake.js +292 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/initial-handshake.js +74 -0
- package/dist/node_modules/mariadb/lib/cmd/handshake/ssl-request.js +29 -0
- package/dist/node_modules/mariadb/lib/cmd/ping.js +52 -0
- package/dist/node_modules/mariadb/lib/cmd/query.js +255 -0
- package/dist/node_modules/mariadb/lib/cmd/quit.js +28 -0
- package/dist/node_modules/mariadb/lib/cmd/reset.js +54 -0
- package/dist/node_modules/mariadb/lib/cmd/resultset.js +607 -0
- package/dist/node_modules/mariadb/lib/cmd/stream.js +45 -0
- package/dist/node_modules/mariadb/lib/config/connection-options.js +258 -0
- package/dist/node_modules/mariadb/lib/config/pool-cluster-options.js +19 -0
- package/dist/node_modules/mariadb/lib/config/pool-options.js +47 -0
- package/dist/node_modules/mariadb/lib/connection-callback.js +160 -0
- package/dist/node_modules/mariadb/lib/connection.js +1460 -0
- package/dist/node_modules/mariadb/lib/const/capabilities.js +64 -0
- package/dist/node_modules/mariadb/lib/const/collations.js +473 -0
- package/dist/node_modules/mariadb/lib/const/connection_status.js +13 -0
- package/dist/node_modules/mariadb/lib/const/error-code.js +1282 -0
- package/dist/node_modules/mariadb/lib/const/field-detail.js +35 -0
- package/dist/node_modules/mariadb/lib/const/field-type.js +71 -0
- package/dist/node_modules/mariadb/lib/const/server-status.js +30 -0
- package/dist/node_modules/mariadb/lib/const/state-change.js +12 -0
- package/dist/node_modules/mariadb/lib/filtered-pool-cluster.js +81 -0
- package/dist/node_modules/mariadb/lib/io/bulk-packet.js +590 -0
- package/dist/node_modules/mariadb/lib/io/compression-input-stream.js +141 -0
- package/dist/node_modules/mariadb/lib/io/compression-output-stream.js +171 -0
- package/dist/node_modules/mariadb/lib/io/packet-input-stream.js +193 -0
- package/dist/node_modules/mariadb/lib/io/packet-node-encoded.js +36 -0
- package/dist/node_modules/mariadb/lib/io/packet-node-iconv.js +37 -0
- package/dist/node_modules/mariadb/lib/io/packet-output-stream.js +502 -0
- package/dist/node_modules/mariadb/lib/io/packet.js +515 -0
- package/dist/node_modules/mariadb/lib/io/rewrite-packet.js +481 -0
- package/dist/node_modules/mariadb/lib/misc/connection-information.js +96 -0
- package/dist/node_modules/mariadb/lib/misc/errors.js +123 -0
- package/dist/node_modules/mariadb/lib/misc/parse.js +1033 -0
- package/dist/node_modules/mariadb/lib/misc/utils.js +298 -0
- package/dist/node_modules/mariadb/lib/pool-base.js +611 -0
- package/dist/node_modules/mariadb/lib/pool-callback.js +202 -0
- package/dist/node_modules/mariadb/lib/pool-cluster-callback.js +66 -0
- package/dist/node_modules/mariadb/lib/pool-cluster.js +407 -0
- package/dist/node_modules/mariadb/lib/pool-promise.js +108 -0
- package/dist/node_modules/mariadb/package.json +1 -0
- package/dist/node_modules/mariadb/promise.js +34 -0
- package/dist/node_modules/mariadb/types/index.d.ts +870 -0
- package/dist/server/actions/apps.d.ts +5 -0
- package/dist/server/actions/apps.js +117 -0
- package/dist/server/app-lifecycle.d.ts +8 -0
- package/dist/server/app-lifecycle.js +99 -0
- package/dist/server/app-start-env.d.ts +2 -0
- package/dist/server/app-start-env.js +105 -0
- package/dist/server/collections/applications.d.ts +2 -0
- package/dist/server/collections/applications.js +82 -0
- package/dist/server/index.d.ts +4 -0
- package/dist/server/index.js +29 -0
- package/dist/server/middlewares/app-selector.d.ts +1 -0
- package/dist/server/middlewares/app-selector.js +47 -0
- package/dist/server/middlewares/index.d.ts +2 -0
- package/dist/server/middlewares/index.js +23 -0
- package/dist/server/middlewares/inject-app-list.d.ts +1 -0
- package/dist/server/middlewares/inject-app-list.js +48 -0
- package/dist/server/migrations/20240820153000-add-apps-tmpl.d.ts +6 -0
- package/dist/server/migrations/20240820153000-add-apps-tmpl.js +47 -0
- package/dist/server/migrations/20241126124904-add-createdBy.d.ts +6 -0
- package/dist/server/migrations/20241126124904-add-createdBy.js +41 -0
- package/dist/server/models/application.d.ts +10 -0
- package/dist/server/models/application.js +57 -0
- package/dist/server/server.d.ts +19 -0
- package/dist/server/server.js +246 -0
- package/dist/swagger/index.d.ts +197 -0
- package/dist/swagger/index.js +227 -0
- package/package.json +38 -0
- package/server.d.ts +2 -0
- package/server.js +1 -0
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Command = require('../command');
|
|
4
|
+
const InitialHandshake = require('./initial-handshake');
|
|
5
|
+
const ClientHandshakeResponse = require('./client-handshake-response');
|
|
6
|
+
const SslRequest = require('./ssl-request');
|
|
7
|
+
const ClientCapabilities = require('./client-capabilities');
|
|
8
|
+
const Errors = require('../../misc/errors');
|
|
9
|
+
const Capabilities = require('../../const/capabilities');
|
|
10
|
+
const process = require('process');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Handle handshake.
|
|
14
|
+
* see https://mariadb.com/kb/en/library/1-connecting-connecting/
|
|
15
|
+
*/
|
|
16
|
+
class Handshake extends Command {
|
|
17
|
+
constructor(resolve, reject, _createSecureContext, _addCommand, getSocket) {
|
|
18
|
+
super(resolve, reject);
|
|
19
|
+
this._createSecureContext = _createSecureContext;
|
|
20
|
+
this._addCommand = _addCommand;
|
|
21
|
+
this.getSocket = getSocket;
|
|
22
|
+
this.onPacketReceive = this.parseHandshakeInit;
|
|
23
|
+
this.plugin = this;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
ensureOptionCompatibility(opts, info) {
|
|
27
|
+
if (
|
|
28
|
+
opts.multipleStatements &&
|
|
29
|
+
(info.serverCapabilities & Capabilities.MULTI_STATEMENTS) === 0
|
|
30
|
+
) {
|
|
31
|
+
return this.throwNewError(
|
|
32
|
+
"Option `multipleStatements` enable, but server doesn'permits multi-statment",
|
|
33
|
+
true,
|
|
34
|
+
info,
|
|
35
|
+
'08S01',
|
|
36
|
+
Errors.ER_CLIENT_OPTION_INCOMPATIBILITY
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (opts.permitLocalInfile && (info.serverCapabilities & Capabilities.LOCAL_FILES) === 0) {
|
|
41
|
+
return this.throwNewError(
|
|
42
|
+
"Option `permitLocalInfile` enable, but server doesn'permits using local file",
|
|
43
|
+
true,
|
|
44
|
+
info,
|
|
45
|
+
'08S01',
|
|
46
|
+
Errors.ER_CLIENT_OPTION_INCOMPATIBILITY
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
parseHandshakeInit(packet, out, opts, info) {
|
|
52
|
+
if (packet.peek() === 0xff) {
|
|
53
|
+
//in case that some host is not permit to connect server
|
|
54
|
+
const authErr = packet.readError(info);
|
|
55
|
+
authErr.fatal = true;
|
|
56
|
+
return this.throwError(authErr, info);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
let handshake = new InitialHandshake(packet, info);
|
|
60
|
+
this.ensureOptionCompatibility(opts, info);
|
|
61
|
+
ClientCapabilities.init(opts, info);
|
|
62
|
+
|
|
63
|
+
if (opts.ssl) {
|
|
64
|
+
if (info.serverCapabilities & Capabilities.SSL) {
|
|
65
|
+
info.clientCapabilities |= Capabilities.SSL;
|
|
66
|
+
SslRequest.send(this, out, info, opts);
|
|
67
|
+
this._createSecureContext(
|
|
68
|
+
function () {
|
|
69
|
+
ClientHandshakeResponse.send(this, out, opts, handshake.pluginName, info);
|
|
70
|
+
}.bind(this)
|
|
71
|
+
);
|
|
72
|
+
} else {
|
|
73
|
+
return this.throwNewError(
|
|
74
|
+
'Trying to connect with ssl, but ssl not enabled in the server',
|
|
75
|
+
true,
|
|
76
|
+
info,
|
|
77
|
+
'08S01',
|
|
78
|
+
Errors.ER_SERVER_SSL_DISABLED
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
} else {
|
|
82
|
+
ClientHandshakeResponse.send(this, out, opts, handshake.pluginName, info);
|
|
83
|
+
}
|
|
84
|
+
this.onPacketReceive = this.handshakeResult;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Fast-path handshake results :
|
|
89
|
+
* - if plugin was the one expected by server, server will send OK_Packet / ERR_Packet.
|
|
90
|
+
* - if not, server send an AuthSwitchRequest packet, indicating the specific PLUGIN to use with this user.
|
|
91
|
+
* dispatching to plugin handler then.
|
|
92
|
+
*
|
|
93
|
+
* @param packet current packet
|
|
94
|
+
* @param out output buffer
|
|
95
|
+
* @param opts options
|
|
96
|
+
* @param info connection info
|
|
97
|
+
* @returns {*} return null if authentication succeed, depending on plugin conversation if not finished
|
|
98
|
+
*/
|
|
99
|
+
handshakeResult(packet, out, opts, info) {
|
|
100
|
+
const marker = packet.peek();
|
|
101
|
+
switch (marker) {
|
|
102
|
+
//*********************************************************************************************************
|
|
103
|
+
//* AuthSwitchRequest packet
|
|
104
|
+
//*********************************************************************************************************
|
|
105
|
+
case 0xfe:
|
|
106
|
+
this.plugin.onPacketReceive = null;
|
|
107
|
+
this.plugin.emit('send_end');
|
|
108
|
+
this.plugin.emit('end');
|
|
109
|
+
this.dispatchAuthSwitchRequest(packet, out, opts, info);
|
|
110
|
+
return;
|
|
111
|
+
|
|
112
|
+
//*********************************************************************************************************
|
|
113
|
+
//* OK_Packet - authentication succeeded
|
|
114
|
+
//*********************************************************************************************************
|
|
115
|
+
case 0x00:
|
|
116
|
+
this.plugin.onPacketReceive = null;
|
|
117
|
+
packet.skip(1); //skip header
|
|
118
|
+
packet.skipLengthCodedNumber(); //skip affected rows
|
|
119
|
+
packet.skipLengthCodedNumber(); //skip last insert id
|
|
120
|
+
info.status = packet.readUInt16();
|
|
121
|
+
this.plugin.emit('send_end');
|
|
122
|
+
return this.plugin.successEnd();
|
|
123
|
+
|
|
124
|
+
//*********************************************************************************************************
|
|
125
|
+
//* ERR_Packet
|
|
126
|
+
//*********************************************************************************************************
|
|
127
|
+
case 0xff:
|
|
128
|
+
this.plugin.onPacketReceive = null;
|
|
129
|
+
const authErr = packet.readError(info, this.displaySql());
|
|
130
|
+
authErr.fatal = true;
|
|
131
|
+
return this.plugin.throwError(authErr, info);
|
|
132
|
+
|
|
133
|
+
//*********************************************************************************************************
|
|
134
|
+
//* unexpected
|
|
135
|
+
//*********************************************************************************************************
|
|
136
|
+
default:
|
|
137
|
+
this.throwNewError(
|
|
138
|
+
'Unexpected type of packet during handshake phase : ' + marker,
|
|
139
|
+
true,
|
|
140
|
+
info,
|
|
141
|
+
'42000',
|
|
142
|
+
Errors.ER_AUTHENTICATION_BAD_PACKET
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Handle authentication switch request : dispatch to plugin handler.
|
|
149
|
+
*
|
|
150
|
+
* @param packet packet
|
|
151
|
+
* @param out output writer
|
|
152
|
+
* @param opts options
|
|
153
|
+
* @param info connection information
|
|
154
|
+
*/
|
|
155
|
+
dispatchAuthSwitchRequest(packet, out, opts, info) {
|
|
156
|
+
let pluginName, pluginData;
|
|
157
|
+
if (info.clientCapabilities & Capabilities.PLUGIN_AUTH) {
|
|
158
|
+
packet.skip(1); //header
|
|
159
|
+
if (packet.remaining()) {
|
|
160
|
+
//AuthSwitchRequest packet.
|
|
161
|
+
pluginName = packet.readStringNullEnded();
|
|
162
|
+
pluginData = packet.readBufferRemaining();
|
|
163
|
+
} else {
|
|
164
|
+
//OldAuthSwitchRequest
|
|
165
|
+
pluginName = 'mysql_old_password';
|
|
166
|
+
pluginData = info.seed.slice(0, 8);
|
|
167
|
+
}
|
|
168
|
+
} else {
|
|
169
|
+
pluginName = packet.readStringNullEnded('cesu8');
|
|
170
|
+
pluginData = packet.readBufferRemaining();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
this.plugin = Handshake.pluginHandler(
|
|
175
|
+
pluginName,
|
|
176
|
+
this.plugin.sequenceNo,
|
|
177
|
+
this.plugin.compressSequenceNo,
|
|
178
|
+
pluginData,
|
|
179
|
+
info,
|
|
180
|
+
opts,
|
|
181
|
+
out,
|
|
182
|
+
this.resolve,
|
|
183
|
+
this.reject,
|
|
184
|
+
this.handshakeResult.bind(this)
|
|
185
|
+
);
|
|
186
|
+
} catch (err) {
|
|
187
|
+
this.reject(err);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (!this.plugin) {
|
|
192
|
+
this.reject(
|
|
193
|
+
Errors.createError(
|
|
194
|
+
"Client does not support authentication protocol '" +
|
|
195
|
+
pluginName +
|
|
196
|
+
"' requested by server. ",
|
|
197
|
+
null,
|
|
198
|
+
true,
|
|
199
|
+
info,
|
|
200
|
+
'08004',
|
|
201
|
+
Errors.ER_AUTHENTICATION_PLUGIN_NOT_SUPPORTED
|
|
202
|
+
)
|
|
203
|
+
);
|
|
204
|
+
} else {
|
|
205
|
+
this._addCommand(this.plugin, false);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
static pluginHandler(
|
|
210
|
+
pluginName,
|
|
211
|
+
packSeq,
|
|
212
|
+
compressPackSeq,
|
|
213
|
+
pluginData,
|
|
214
|
+
info,
|
|
215
|
+
opts,
|
|
216
|
+
out,
|
|
217
|
+
authResolve,
|
|
218
|
+
authReject,
|
|
219
|
+
multiAuthResolver
|
|
220
|
+
) {
|
|
221
|
+
let pluginAuth;
|
|
222
|
+
switch (pluginName) {
|
|
223
|
+
case 'mysql_native_password':
|
|
224
|
+
pluginAuth = require('./auth/native-password-auth.js');
|
|
225
|
+
break;
|
|
226
|
+
|
|
227
|
+
case 'mysql_clear_password':
|
|
228
|
+
pluginAuth = require('./auth/clear-password-auth.js');
|
|
229
|
+
break;
|
|
230
|
+
|
|
231
|
+
case 'client_ed25519':
|
|
232
|
+
pluginAuth = require('./auth/ed25519-password-auth.js');
|
|
233
|
+
break;
|
|
234
|
+
|
|
235
|
+
case 'dialog':
|
|
236
|
+
pluginAuth = require('./auth/pam-password-auth.js');
|
|
237
|
+
break;
|
|
238
|
+
|
|
239
|
+
case 'sha256_password':
|
|
240
|
+
if (!Handshake.ensureNodeVersion(11, 6, 0)) {
|
|
241
|
+
throw Errors.createError(
|
|
242
|
+
'sha256_password authentication plugin require node 11.6+',
|
|
243
|
+
null,
|
|
244
|
+
true,
|
|
245
|
+
info,
|
|
246
|
+
'08004',
|
|
247
|
+
Errors.ER_MINIMUM_NODE_VERSION_REQUIRED
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
pluginAuth = require('./auth/sha256-password-auth.js');
|
|
251
|
+
break;
|
|
252
|
+
|
|
253
|
+
case 'caching_sha2_password':
|
|
254
|
+
if (!Handshake.ensureNodeVersion(11, 6, 0)) {
|
|
255
|
+
throw Errors.createError(
|
|
256
|
+
'caching_sha2_password authentication plugin require node 11.6+',
|
|
257
|
+
null,
|
|
258
|
+
true,
|
|
259
|
+
info,
|
|
260
|
+
'08004',
|
|
261
|
+
Errors.ER_MINIMUM_NODE_VERSION_REQUIRED
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
pluginAuth = require('./auth/caching-sha2-password-auth.js');
|
|
265
|
+
break;
|
|
266
|
+
|
|
267
|
+
//TODO "auth_gssapi_client"
|
|
268
|
+
|
|
269
|
+
default:
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
return new pluginAuth(
|
|
273
|
+
packSeq,
|
|
274
|
+
compressPackSeq,
|
|
275
|
+
pluginData,
|
|
276
|
+
authResolve,
|
|
277
|
+
authReject,
|
|
278
|
+
multiAuthResolver
|
|
279
|
+
);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
static ensureNodeVersion(major, minor, patch) {
|
|
283
|
+
const ver = process.versions.node.split('.');
|
|
284
|
+
return (
|
|
285
|
+
ver[0] > major ||
|
|
286
|
+
(ver[0] === major && ver[1] > minor) ||
|
|
287
|
+
(ver[0] === major && ver[1] === minor && ver[2] >= patch)
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
module.exports = Handshake;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Capabilities = require('../../const/capabilities');
|
|
4
|
+
const ConnectionInformation = require('../../misc/connection-information');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Parser server initial handshake.
|
|
8
|
+
* see https://mariadb.com/kb/en/library/1-connecting-connecting/#initial-handshake-packet
|
|
9
|
+
*/
|
|
10
|
+
class InitialHandshake {
|
|
11
|
+
constructor(packet, info) {
|
|
12
|
+
//protocolVersion
|
|
13
|
+
packet.skip(1);
|
|
14
|
+
info.serverVersion = {};
|
|
15
|
+
info.serverVersion.raw = packet.readStringNullEnded();
|
|
16
|
+
info.threadId = packet.readUInt32();
|
|
17
|
+
|
|
18
|
+
let seed1 = packet.readBuffer(8);
|
|
19
|
+
packet.skip(1); //reserved byte
|
|
20
|
+
|
|
21
|
+
let serverCapabilities = BigInt(packet.readUInt16());
|
|
22
|
+
//skip characterSet
|
|
23
|
+
packet.skip(1);
|
|
24
|
+
info.status = packet.readUInt16();
|
|
25
|
+
serverCapabilities += BigInt(packet.readUInt16()) << BigInt(16);
|
|
26
|
+
|
|
27
|
+
let saltLength = 0;
|
|
28
|
+
if (serverCapabilities & Capabilities.PLUGIN_AUTH) {
|
|
29
|
+
saltLength = Math.max(12, packet.readUInt8() - 9);
|
|
30
|
+
} else {
|
|
31
|
+
packet.skip(1);
|
|
32
|
+
}
|
|
33
|
+
if (serverCapabilities & Capabilities.MYSQL) {
|
|
34
|
+
packet.skip(10);
|
|
35
|
+
} else {
|
|
36
|
+
packet.skip(6);
|
|
37
|
+
serverCapabilities += BigInt(packet.readUInt32()) << BigInt(32);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (serverCapabilities & Capabilities.SECURE_CONNECTION) {
|
|
41
|
+
let seed2 = packet.readBuffer(saltLength);
|
|
42
|
+
info.seed = Buffer.concat([seed1, seed2]);
|
|
43
|
+
} else {
|
|
44
|
+
info.seed = seed1;
|
|
45
|
+
}
|
|
46
|
+
packet.skip(1);
|
|
47
|
+
info.serverCapabilities = serverCapabilities;
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* check for MariaDB 10.x replication hack , remove fake prefix if needed
|
|
51
|
+
* MDEV-4088: in 10.0+, the real version string maybe prefixed with "5.5.5-",
|
|
52
|
+
* to workaround bugs in Oracle MySQL replication
|
|
53
|
+
**/
|
|
54
|
+
|
|
55
|
+
if (info.serverVersion.raw.startsWith('5.5.5-')) {
|
|
56
|
+
info.serverVersion.mariaDb = true;
|
|
57
|
+
info.serverVersion.raw = info.serverVersion.raw.substring('5.5.5-'.length);
|
|
58
|
+
} else {
|
|
59
|
+
//Support for MDEV-7780 faking server version
|
|
60
|
+
info.serverVersion.mariaDb =
|
|
61
|
+
info.serverVersion.raw.includes('MariaDB') ||
|
|
62
|
+
(serverCapabilities & Capabilities.MYSQL) === BigInt(0);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (serverCapabilities & Capabilities.PLUGIN_AUTH) {
|
|
66
|
+
this.pluginName = packet.readStringNullEnded();
|
|
67
|
+
} else {
|
|
68
|
+
this.pluginName = '';
|
|
69
|
+
}
|
|
70
|
+
ConnectionInformation.parseVersionString(info);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
module.exports = InitialHandshake;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
const Capabilities = require('../../const/capabilities');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Send SSL Request packet.
|
|
6
|
+
* see : https://mariadb.com/kb/en/library/1-connecting-connecting/#sslrequest-packet
|
|
7
|
+
*
|
|
8
|
+
* @param cmd current command
|
|
9
|
+
* @param out output writer
|
|
10
|
+
* @param info client information
|
|
11
|
+
* @param opts connection options
|
|
12
|
+
*/
|
|
13
|
+
module.exports.send = function sendSSLRequest(cmd, out, info, opts) {
|
|
14
|
+
out.startPacket(cmd);
|
|
15
|
+
out.writeInt32(Number(info.clientCapabilities & BigInt(0xffffffff)));
|
|
16
|
+
out.writeInt32(1024 * 1024 * 1024); // max packet size
|
|
17
|
+
out.writeInt8(opts.collation.index);
|
|
18
|
+
for (let i = 0; i < 19; i++) {
|
|
19
|
+
out.writeInt8(0);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (info.serverCapabilities & Capabilities.MYSQL) {
|
|
23
|
+
out.writeInt32(0);
|
|
24
|
+
} else {
|
|
25
|
+
out.writeInt32(Number(info.clientCapabilities >> BigInt(32)));
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
out.flushBuffer(true);
|
|
29
|
+
};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Command = require('./command');
|
|
4
|
+
const Errors = require('../misc/errors');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* send a COM_PING: permits sending a packet containing one byte to check that the connection is active.
|
|
8
|
+
* see https://mariadb.com/kb/en/library/com_ping/
|
|
9
|
+
*/
|
|
10
|
+
class Ping extends Command {
|
|
11
|
+
constructor(resolve, reject) {
|
|
12
|
+
super(resolve, reject);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
start(out, opts, info) {
|
|
16
|
+
out.startPacket(this);
|
|
17
|
+
out.writeInt8(0x0e);
|
|
18
|
+
out.flushBuffer(true);
|
|
19
|
+
this.emit('send_end');
|
|
20
|
+
this.onPacketReceive = this.readPingResponsePacket;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Read ping response packet.
|
|
25
|
+
* packet can be :
|
|
26
|
+
* - an ERR_Packet
|
|
27
|
+
* - a OK_Packet
|
|
28
|
+
*
|
|
29
|
+
* @param packet query response
|
|
30
|
+
* @param out output writer
|
|
31
|
+
* @param opts connection options
|
|
32
|
+
* @param info connection info
|
|
33
|
+
*/
|
|
34
|
+
readPingResponsePacket(packet, out, opts, info) {
|
|
35
|
+
if (packet.peek() !== 0x00) {
|
|
36
|
+
return this.throwNewError(
|
|
37
|
+
'unexpected packet',
|
|
38
|
+
false,
|
|
39
|
+
info,
|
|
40
|
+
'42000',
|
|
41
|
+
Errors.ER_PING_BAD_PACKET
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
packet.skip(1); //skip header
|
|
45
|
+
packet.skipLengthCodedNumber(); //affected rows
|
|
46
|
+
packet.skipLengthCodedNumber(); //insert ids
|
|
47
|
+
info.status = packet.readUInt16();
|
|
48
|
+
this.successEnd(null);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
module.exports = Ping;
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const CommonText = require('./common-text-cmd');
|
|
4
|
+
const Errors = require('../misc/errors');
|
|
5
|
+
const Parse = require('../misc/parse');
|
|
6
|
+
const QUOTE = 0x27;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Protocol COM_QUERY
|
|
10
|
+
* see : https://mariadb.com/kb/en/library/com_query/
|
|
11
|
+
*/
|
|
12
|
+
class Query extends CommonText {
|
|
13
|
+
constructor(resolve, reject, options, connOpts, sql, values) {
|
|
14
|
+
super(resolve, reject, options, connOpts, sql, values);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Send COM_QUERY
|
|
19
|
+
*
|
|
20
|
+
* @param out output writer
|
|
21
|
+
* @param opts connection options
|
|
22
|
+
* @param info connection information
|
|
23
|
+
*/
|
|
24
|
+
start(out, opts, info) {
|
|
25
|
+
if (this.initialValues === undefined) {
|
|
26
|
+
//shortcut if no parameters
|
|
27
|
+
out.startPacket(this);
|
|
28
|
+
out.writeInt8(0x03);
|
|
29
|
+
if (!this.handleTimeout(out, info)) return;
|
|
30
|
+
out.writeString(this.sql);
|
|
31
|
+
out.flushBuffer(true);
|
|
32
|
+
this.emit('send_end');
|
|
33
|
+
return (this.onPacketReceive = this.readResponsePacket);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (this.opts.namedPlaceholders) {
|
|
37
|
+
try {
|
|
38
|
+
const parsed = Parse.splitQueryPlaceholder(
|
|
39
|
+
this.sql,
|
|
40
|
+
info,
|
|
41
|
+
this.initialValues,
|
|
42
|
+
this.displaySql.bind(this)
|
|
43
|
+
);
|
|
44
|
+
this.queryParts = parsed.parts;
|
|
45
|
+
this.values = parsed.values;
|
|
46
|
+
} catch (err) {
|
|
47
|
+
this.emit('send_end');
|
|
48
|
+
return this.throwError(err, info);
|
|
49
|
+
}
|
|
50
|
+
} else {
|
|
51
|
+
this.queryParts = Parse.splitQuery(this.sql);
|
|
52
|
+
this.values = Array.isArray(this.initialValues) ? this.initialValues : [this.initialValues];
|
|
53
|
+
if (!this.validateParameters(info)) return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
out.startPacket(this);
|
|
57
|
+
out.writeInt8(0x03);
|
|
58
|
+
if (!this.handleTimeout(out, info)) return;
|
|
59
|
+
out.writeString(this.queryParts[0]);
|
|
60
|
+
this.onPacketReceive = this.readResponsePacket;
|
|
61
|
+
|
|
62
|
+
//********************************************
|
|
63
|
+
// send params
|
|
64
|
+
//********************************************
|
|
65
|
+
const len = this.queryParts.length;
|
|
66
|
+
for (let i = 1; i < len; i++) {
|
|
67
|
+
const value = this.values[i - 1];
|
|
68
|
+
|
|
69
|
+
if (
|
|
70
|
+
value !== null &&
|
|
71
|
+
typeof value === 'object' &&
|
|
72
|
+
typeof value.pipe === 'function' &&
|
|
73
|
+
typeof value.read === 'function'
|
|
74
|
+
) {
|
|
75
|
+
this.sending = true;
|
|
76
|
+
//********************************************
|
|
77
|
+
// param is stream,
|
|
78
|
+
// now all params will be written by event
|
|
79
|
+
//********************************************
|
|
80
|
+
this.registerStreamSendEvent(out, info);
|
|
81
|
+
this.currentParam = i;
|
|
82
|
+
out.writeInt8(QUOTE); //'
|
|
83
|
+
|
|
84
|
+
value.on('data', function (chunk) {
|
|
85
|
+
out.writeBufferEscape(chunk);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
value.on(
|
|
89
|
+
'end',
|
|
90
|
+
function () {
|
|
91
|
+
out.writeInt8(QUOTE); //'
|
|
92
|
+
out.writeString(this.queryParts[this.currentParam++]);
|
|
93
|
+
this.paramWritten();
|
|
94
|
+
}.bind(this)
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
return;
|
|
98
|
+
} else {
|
|
99
|
+
//********************************************
|
|
100
|
+
// param isn't stream. directly write in buffer
|
|
101
|
+
//********************************************
|
|
102
|
+
this.writeParam(out, value, this.opts, info);
|
|
103
|
+
out.writeString(this.queryParts[i]);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
out.flushBuffer(true);
|
|
107
|
+
this.emit('send_end');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* If timeout is set, prepend query with SET STATEMENT max_statement_time=xx FOR, or throw an error
|
|
112
|
+
* @param out buffer
|
|
113
|
+
* @param info server information
|
|
114
|
+
* @returns {boolean} false if an error has been thrown
|
|
115
|
+
*/
|
|
116
|
+
handleTimeout(out, info) {
|
|
117
|
+
if (this.opts.timeout) {
|
|
118
|
+
if (info.isMariaDB()) {
|
|
119
|
+
if (info.hasMinVersion(10, 1, 2)) {
|
|
120
|
+
out.writeString('SET STATEMENT max_statement_time=' + this.opts.timeout / 1000 + ' FOR ');
|
|
121
|
+
return true;
|
|
122
|
+
} else {
|
|
123
|
+
const err = Errors.createError(
|
|
124
|
+
'Cannot use timeout for MariaDB server before 10.1.2. timeout value: ' +
|
|
125
|
+
this.opts.timeout,
|
|
126
|
+
this.sql,
|
|
127
|
+
false,
|
|
128
|
+
info,
|
|
129
|
+
'HY000',
|
|
130
|
+
Errors.ER_TIMEOUT_NOT_SUPPORTED
|
|
131
|
+
);
|
|
132
|
+
this.emit('send_end');
|
|
133
|
+
this.throwError(err, info);
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
//not available for MySQL
|
|
138
|
+
// max_execution time exist, but only for select, and as hint
|
|
139
|
+
const err = Errors.createError(
|
|
140
|
+
'Cannot use timeout for MySQL server. timeout value: ' + this.opts.timeout,
|
|
141
|
+
this.sql,
|
|
142
|
+
false,
|
|
143
|
+
info,
|
|
144
|
+
'HY000',
|
|
145
|
+
Errors.ER_TIMEOUT_NOT_SUPPORTED
|
|
146
|
+
);
|
|
147
|
+
this.emit('send_end');
|
|
148
|
+
this.throwError(err, info);
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Validate that parameters exists and are defined.
|
|
157
|
+
*
|
|
158
|
+
* @param info connection info
|
|
159
|
+
* @returns {boolean} return false if any error occur.
|
|
160
|
+
*/
|
|
161
|
+
validateParameters(info) {
|
|
162
|
+
//validate parameter size.
|
|
163
|
+
if (this.queryParts.length - 1 > this.values.length) {
|
|
164
|
+
this.emit('send_end');
|
|
165
|
+
this.throwNewError(
|
|
166
|
+
'Parameter at position ' + (this.values.length + 1) + ' is not set',
|
|
167
|
+
false,
|
|
168
|
+
info,
|
|
169
|
+
'HY000',
|
|
170
|
+
Errors.ER_MISSING_PARAMETER
|
|
171
|
+
);
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
//validate parameter is defined.
|
|
176
|
+
for (let i = 0; i < this.queryParts.length - 1; i++) {
|
|
177
|
+
if (this.values[i] === undefined) {
|
|
178
|
+
this.emit('send_end');
|
|
179
|
+
this.throwNewError(
|
|
180
|
+
'Parameter at position ' + (i + 1) + ' is undefined\n' + this.displaySql(),
|
|
181
|
+
false,
|
|
182
|
+
info,
|
|
183
|
+
'HY000',
|
|
184
|
+
Errors.ER_PARAMETER_UNDEFINED
|
|
185
|
+
);
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Define params events.
|
|
195
|
+
* Each parameter indicate that he is written to socket,
|
|
196
|
+
* emitting event so next stream parameter can be written.
|
|
197
|
+
*/
|
|
198
|
+
registerStreamSendEvent(out, info) {
|
|
199
|
+
// note : Implementation use recursive calls, but stack won't never get near v8 max call stack size
|
|
200
|
+
//since event launched for stream parameter only
|
|
201
|
+
this.paramWritten = function () {
|
|
202
|
+
while (true) {
|
|
203
|
+
if (this.currentParam === this.queryParts.length) {
|
|
204
|
+
//********************************************
|
|
205
|
+
// all parameters are written.
|
|
206
|
+
// flush packet
|
|
207
|
+
//********************************************
|
|
208
|
+
out.flushBuffer(true);
|
|
209
|
+
this.sending = false;
|
|
210
|
+
this.emit('send_end');
|
|
211
|
+
return;
|
|
212
|
+
} else {
|
|
213
|
+
const value = this.values[this.currentParam - 1];
|
|
214
|
+
|
|
215
|
+
if (value === null) {
|
|
216
|
+
out.writeStringAscii('NULL');
|
|
217
|
+
out.writeString(this.queryParts[this.currentParam++]);
|
|
218
|
+
continue;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (
|
|
222
|
+
typeof value === 'object' &&
|
|
223
|
+
typeof value.pipe === 'function' &&
|
|
224
|
+
typeof value.read === 'function'
|
|
225
|
+
) {
|
|
226
|
+
//********************************************
|
|
227
|
+
// param is stream,
|
|
228
|
+
//********************************************
|
|
229
|
+
out.writeInt8(QUOTE);
|
|
230
|
+
value.once(
|
|
231
|
+
'end',
|
|
232
|
+
function () {
|
|
233
|
+
out.writeInt8(QUOTE);
|
|
234
|
+
out.writeString(this.queryParts[this.currentParam++]);
|
|
235
|
+
this.paramWritten();
|
|
236
|
+
}.bind(this)
|
|
237
|
+
);
|
|
238
|
+
value.on('data', function (chunk) {
|
|
239
|
+
out.writeBufferEscape(chunk);
|
|
240
|
+
});
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
//********************************************
|
|
245
|
+
// param isn't stream. directly write in buffer
|
|
246
|
+
//********************************************
|
|
247
|
+
this.writeParam(out, value, this.opts, info);
|
|
248
|
+
out.writeString(this.queryParts[this.currentParam++]);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}.bind(this);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
module.exports = Query;
|