oceanbase 0.0.1
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/License +19 -0
- package/README.md +250 -0
- package/index.d.ts +1 -0
- package/index.js +77 -0
- package/lib/auth_41.js +95 -0
- package/lib/auth_plugins/caching_sha2_password.js +108 -0
- package/lib/auth_plugins/caching_sha2_password.md +18 -0
- package/lib/auth_plugins/index.js +8 -0
- package/lib/auth_plugins/mysql_clear_password.js +17 -0
- package/lib/auth_plugins/mysql_native_password.js +34 -0
- package/lib/auth_plugins/sha256_password.js +68 -0
- package/lib/base/connection.js +978 -0
- package/lib/base/pool.js +237 -0
- package/lib/base/pool_connection.js +70 -0
- package/lib/commands/auth_switch.js +111 -0
- package/lib/commands/binlog_dump.js +109 -0
- package/lib/commands/change_user.js +68 -0
- package/lib/commands/client_handshake.js +241 -0
- package/lib/commands/close_statement.js +18 -0
- package/lib/commands/command.js +54 -0
- package/lib/commands/execute.js +112 -0
- package/lib/commands/index.js +27 -0
- package/lib/commands/ping.js +36 -0
- package/lib/commands/prepare.js +143 -0
- package/lib/commands/query.js +366 -0
- package/lib/commands/quit.js +29 -0
- package/lib/commands/register_slave.js +27 -0
- package/lib/commands/server_handshake.js +203 -0
- package/lib/compressed_protocol.js +127 -0
- package/lib/connection.js +12 -0
- package/lib/connection_config.js +326 -0
- package/lib/constants/charset_encodings.js +316 -0
- package/lib/constants/charsets.js +317 -0
- package/lib/constants/client.js +40 -0
- package/lib/constants/commands.js +36 -0
- package/lib/constants/cursor.js +8 -0
- package/lib/constants/encoding_charset.js +50 -0
- package/lib/constants/errors.js +3973 -0
- package/lib/constants/field_flags.js +20 -0
- package/lib/constants/server_status.js +44 -0
- package/lib/constants/session_track.js +11 -0
- package/lib/constants/ssl_profiles.js +11 -0
- package/lib/constants/types.js +64 -0
- package/lib/create_connection.js +10 -0
- package/lib/create_pool.js +10 -0
- package/lib/create_pool_cluster.js +9 -0
- package/lib/helpers.js +86 -0
- package/lib/packet_parser.js +195 -0
- package/lib/packets/auth_next_factor.js +35 -0
- package/lib/packets/auth_switch_request.js +38 -0
- package/lib/packets/auth_switch_request_more_data.js +33 -0
- package/lib/packets/auth_switch_response.js +30 -0
- package/lib/packets/binary_row.js +95 -0
- package/lib/packets/binlog_dump.js +33 -0
- package/lib/packets/binlog_query_statusvars.js +115 -0
- package/lib/packets/change_user.js +97 -0
- package/lib/packets/close_statement.js +21 -0
- package/lib/packets/column_definition.js +291 -0
- package/lib/packets/execute.js +214 -0
- package/lib/packets/handshake.js +112 -0
- package/lib/packets/handshake_response.js +144 -0
- package/lib/packets/index.js +152 -0
- package/lib/packets/packet.js +931 -0
- package/lib/packets/prepare_statement.js +27 -0
- package/lib/packets/prepared_statement_header.js +16 -0
- package/lib/packets/query.js +27 -0
- package/lib/packets/register_slave.js +46 -0
- package/lib/packets/resultset_header.js +124 -0
- package/lib/packets/ssl_request.js +25 -0
- package/lib/packets/text_row.js +47 -0
- package/lib/parsers/binary_parser.js +235 -0
- package/lib/parsers/parser_cache.js +68 -0
- package/lib/parsers/static_binary_parser.js +213 -0
- package/lib/parsers/static_text_parser.js +152 -0
- package/lib/parsers/string.js +50 -0
- package/lib/parsers/text_parser.js +214 -0
- package/lib/pool.js +12 -0
- package/lib/pool_cluster.js +369 -0
- package/lib/pool_config.js +30 -0
- package/lib/pool_connection.js +12 -0
- package/lib/promise/connection.js +222 -0
- package/lib/promise/inherit_events.js +27 -0
- package/lib/promise/make_done_cb.js +19 -0
- package/lib/promise/pool.js +112 -0
- package/lib/promise/pool_cluster.js +54 -0
- package/lib/promise/pool_connection.js +19 -0
- package/lib/promise/prepared_statement_info.js +32 -0
- package/lib/results_stream.js +38 -0
- package/lib/server.js +37 -0
- package/package.json +80 -0
- package/promise.d.ts +131 -0
- package/promise.js +202 -0
- package/typings/mysql/LICENSE.txt +15 -0
- package/typings/mysql/index.d.ts +95 -0
- package/typings/mysql/info.txt +1 -0
- package/typings/mysql/lib/Auth.d.ts +30 -0
- package/typings/mysql/lib/Connection.d.ts +453 -0
- package/typings/mysql/lib/Pool.d.ts +69 -0
- package/typings/mysql/lib/PoolCluster.d.ts +90 -0
- package/typings/mysql/lib/PoolConnection.d.ts +10 -0
- package/typings/mysql/lib/Server.d.ts +11 -0
- package/typings/mysql/lib/constants/CharsetToEncoding.d.ts +8 -0
- package/typings/mysql/lib/constants/Charsets.d.ts +326 -0
- package/typings/mysql/lib/constants/Types.d.ts +70 -0
- package/typings/mysql/lib/constants/index.d.ts +5 -0
- package/typings/mysql/lib/parsers/ParserCache.d.ts +4 -0
- package/typings/mysql/lib/parsers/index.d.ts +18 -0
- package/typings/mysql/lib/parsers/typeCast.d.ts +54 -0
- package/typings/mysql/lib/protocol/packets/Field.d.ts +10 -0
- package/typings/mysql/lib/protocol/packets/FieldPacket.d.ts +27 -0
- package/typings/mysql/lib/protocol/packets/OkPacket.d.ts +23 -0
- package/typings/mysql/lib/protocol/packets/ProcedurePacket.d.ts +13 -0
- package/typings/mysql/lib/protocol/packets/ResultSetHeader.d.ts +18 -0
- package/typings/mysql/lib/protocol/packets/RowDataPacket.d.ts +9 -0
- package/typings/mysql/lib/protocol/packets/index.d.ts +28 -0
- package/typings/mysql/lib/protocol/packets/params/ErrorPacketParams.d.ts +6 -0
- package/typings/mysql/lib/protocol/packets/params/OkPacketParams.d.ts +9 -0
- package/typings/mysql/lib/protocol/sequences/ExecutableBase.d.ts +40 -0
- package/typings/mysql/lib/protocol/sequences/Prepare.d.ts +65 -0
- package/typings/mysql/lib/protocol/sequences/Query.d.ts +170 -0
- package/typings/mysql/lib/protocol/sequences/QueryableBase.d.ts +40 -0
- package/typings/mysql/lib/protocol/sequences/Sequence.d.ts +5 -0
- package/typings/mysql/lib/protocol/sequences/promise/ExecutableBase.d.ts +21 -0
- package/typings/mysql/lib/protocol/sequences/promise/QueryableBase.d.ts +21 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const CursorType = require('../constants/cursor');
|
|
4
|
+
const CommandCodes = require('../constants/commands');
|
|
5
|
+
const Types = require('../constants/types');
|
|
6
|
+
const Packet = require('../packets/packet');
|
|
7
|
+
const CharsetToEncoding = require('../constants/charset_encodings.js');
|
|
8
|
+
|
|
9
|
+
function isJSON(value) {
|
|
10
|
+
return (
|
|
11
|
+
Array.isArray(value) ||
|
|
12
|
+
value.constructor === Object ||
|
|
13
|
+
(typeof value.toJSON === 'function' && !Buffer.isBuffer(value))
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Converts a value to an object describing type, String/Buffer representation and length
|
|
19
|
+
* @param {*} value
|
|
20
|
+
*/
|
|
21
|
+
function toParameter(value, encoding, timezone) {
|
|
22
|
+
let type = Types.VAR_STRING;
|
|
23
|
+
let length;
|
|
24
|
+
let writer = function (value) {
|
|
25
|
+
// eslint-disable-next-line no-invalid-this
|
|
26
|
+
return Packet.prototype.writeLengthCodedString.call(this, value, encoding);
|
|
27
|
+
};
|
|
28
|
+
if (value !== null) {
|
|
29
|
+
switch (typeof value) {
|
|
30
|
+
case 'undefined':
|
|
31
|
+
throw new TypeError('Bind parameters must not contain undefined');
|
|
32
|
+
|
|
33
|
+
case 'number':
|
|
34
|
+
type = Types.DOUBLE;
|
|
35
|
+
length = 8;
|
|
36
|
+
writer = Packet.prototype.writeDouble;
|
|
37
|
+
break;
|
|
38
|
+
|
|
39
|
+
case 'boolean':
|
|
40
|
+
value = value | 0;
|
|
41
|
+
type = Types.TINY;
|
|
42
|
+
length = 1;
|
|
43
|
+
writer = Packet.prototype.writeInt8;
|
|
44
|
+
break;
|
|
45
|
+
|
|
46
|
+
case 'object':
|
|
47
|
+
if (Object.prototype.toString.call(value) === '[object Date]') {
|
|
48
|
+
type = Types.DATETIME;
|
|
49
|
+
length = 12;
|
|
50
|
+
writer = function (value) {
|
|
51
|
+
// eslint-disable-next-line no-invalid-this
|
|
52
|
+
return Packet.prototype.writeDate.call(this, value, timezone);
|
|
53
|
+
};
|
|
54
|
+
} else if (isJSON(value)) {
|
|
55
|
+
value = JSON.stringify(value);
|
|
56
|
+
type = Types.JSON;
|
|
57
|
+
} else if (Buffer.isBuffer(value)) {
|
|
58
|
+
length = Packet.lengthCodedNumberLength(value.length) + value.length;
|
|
59
|
+
writer = Packet.prototype.writeLengthCodedBuffer;
|
|
60
|
+
}
|
|
61
|
+
break;
|
|
62
|
+
|
|
63
|
+
default:
|
|
64
|
+
value = value.toString();
|
|
65
|
+
}
|
|
66
|
+
} else {
|
|
67
|
+
value = '';
|
|
68
|
+
type = Types.NULL;
|
|
69
|
+
}
|
|
70
|
+
if (!length) {
|
|
71
|
+
length = Packet.lengthCodedStringLength(value, encoding);
|
|
72
|
+
}
|
|
73
|
+
return { value, type, length, writer };
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
class Execute {
|
|
77
|
+
constructor(id, parameters, charsetNumber, timezone) {
|
|
78
|
+
this.id = id;
|
|
79
|
+
this.parameters = parameters;
|
|
80
|
+
this.encoding = CharsetToEncoding[charsetNumber];
|
|
81
|
+
this.timezone = timezone;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
static fromPacket(packet, encoding) {
|
|
85
|
+
const stmtId = packet.readInt32();
|
|
86
|
+
const flags = packet.readInt8();
|
|
87
|
+
const iterationCount = packet.readInt32();
|
|
88
|
+
|
|
89
|
+
let i = packet.offset;
|
|
90
|
+
while (i < packet.end - 1) {
|
|
91
|
+
if (
|
|
92
|
+
(packet.buffer[i + 1] === Types.VAR_STRING ||
|
|
93
|
+
packet.buffer[i + 1] === Types.NULL ||
|
|
94
|
+
packet.buffer[i + 1] === Types.DOUBLE ||
|
|
95
|
+
packet.buffer[i + 1] === Types.TINY ||
|
|
96
|
+
packet.buffer[i + 1] === Types.DATETIME ||
|
|
97
|
+
packet.buffer[i + 1] === Types.JSON) &&
|
|
98
|
+
packet.buffer[i] === 1 &&
|
|
99
|
+
packet.buffer[i + 2] === 0
|
|
100
|
+
) {
|
|
101
|
+
break;
|
|
102
|
+
} else {
|
|
103
|
+
packet.readInt8();
|
|
104
|
+
}
|
|
105
|
+
i++;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const types = [];
|
|
109
|
+
|
|
110
|
+
for (let i = packet.offset + 1; i < packet.end - 1; i++) {
|
|
111
|
+
if (
|
|
112
|
+
(packet.buffer[i] === Types.VAR_STRING ||
|
|
113
|
+
packet.buffer[i] === Types.NULL ||
|
|
114
|
+
packet.buffer[i] === Types.DOUBLE ||
|
|
115
|
+
packet.buffer[i] === Types.TINY ||
|
|
116
|
+
packet.buffer[i] === Types.DATETIME ||
|
|
117
|
+
packet.buffer[i] === Types.JSON) &&
|
|
118
|
+
packet.buffer[i + 1] === 0
|
|
119
|
+
) {
|
|
120
|
+
types.push(packet.buffer[i]);
|
|
121
|
+
packet.skip(2);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
packet.skip(1);
|
|
126
|
+
|
|
127
|
+
const values = [];
|
|
128
|
+
for (let i = 0; i < types.length; i++) {
|
|
129
|
+
if (types[i] === Types.VAR_STRING) {
|
|
130
|
+
values.push(packet.readLengthCodedString(encoding));
|
|
131
|
+
} else if (types[i] === Types.DOUBLE) {
|
|
132
|
+
values.push(packet.readDouble());
|
|
133
|
+
} else if (types[i] === Types.TINY) {
|
|
134
|
+
values.push(packet.readInt8());
|
|
135
|
+
} else if (types[i] === Types.DATETIME) {
|
|
136
|
+
values.push(packet.readDateTime());
|
|
137
|
+
} else if (types[i] === Types.JSON) {
|
|
138
|
+
values.push(JSON.parse(packet.readLengthCodedString(encoding)));
|
|
139
|
+
}
|
|
140
|
+
if (types[i] === Types.NULL) {
|
|
141
|
+
values.push(null);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return { stmtId, flags, iterationCount, values };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
toPacket() {
|
|
149
|
+
// TODO: don't try to calculate packet length in advance, allocate some big buffer in advance (header + 256 bytes?)
|
|
150
|
+
// and copy + reallocate if not enough
|
|
151
|
+
// 0 + 4 - length, seqId
|
|
152
|
+
// 4 + 1 - COM_EXECUTE
|
|
153
|
+
// 5 + 4 - stmtId
|
|
154
|
+
// 9 + 1 - flags
|
|
155
|
+
// 10 + 4 - iteration-count (always 1)
|
|
156
|
+
let length = 14;
|
|
157
|
+
let parameters;
|
|
158
|
+
if (this.parameters && this.parameters.length > 0) {
|
|
159
|
+
length += Math.floor((this.parameters.length + 7) / 8);
|
|
160
|
+
length += 1; // new-params-bound-flag
|
|
161
|
+
length += 2 * this.parameters.length; // type byte for each parameter if new-params-bound-flag is set
|
|
162
|
+
parameters = this.parameters.map((value) =>
|
|
163
|
+
toParameter(value, this.encoding, this.timezone)
|
|
164
|
+
);
|
|
165
|
+
length += parameters.reduce(
|
|
166
|
+
(accumulator, parameter) => accumulator + parameter.length,
|
|
167
|
+
0
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
const buffer = Buffer.allocUnsafe(length);
|
|
171
|
+
const packet = new Packet(0, buffer, 0, length);
|
|
172
|
+
packet.offset = 4;
|
|
173
|
+
packet.writeInt8(CommandCodes.STMT_EXECUTE);
|
|
174
|
+
packet.writeInt32(this.id);
|
|
175
|
+
packet.writeInt8(CursorType.NO_CURSOR); // flags
|
|
176
|
+
packet.writeInt32(1); // iteration-count, always 1
|
|
177
|
+
if (parameters) {
|
|
178
|
+
let bitmap = 0;
|
|
179
|
+
let bitValue = 1;
|
|
180
|
+
parameters.forEach((parameter) => {
|
|
181
|
+
if (parameter.type === Types.NULL) {
|
|
182
|
+
bitmap += bitValue;
|
|
183
|
+
}
|
|
184
|
+
bitValue *= 2;
|
|
185
|
+
if (bitValue === 256) {
|
|
186
|
+
packet.writeInt8(bitmap);
|
|
187
|
+
bitmap = 0;
|
|
188
|
+
bitValue = 1;
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
if (bitValue !== 1) {
|
|
192
|
+
packet.writeInt8(bitmap);
|
|
193
|
+
}
|
|
194
|
+
// TODO: explain meaning of the flag
|
|
195
|
+
// afaik, if set n*2 bytes with type of parameter are sent before parameters
|
|
196
|
+
// if not, previous execution types are used (TODO prooflink)
|
|
197
|
+
packet.writeInt8(1); // new-params-bound-flag
|
|
198
|
+
// Write parameter types
|
|
199
|
+
parameters.forEach((parameter) => {
|
|
200
|
+
packet.writeInt8(parameter.type); // field type
|
|
201
|
+
packet.writeInt8(0); // parameter flag
|
|
202
|
+
});
|
|
203
|
+
// Write parameter values
|
|
204
|
+
parameters.forEach((parameter) => {
|
|
205
|
+
if (parameter.type !== Types.NULL) {
|
|
206
|
+
parameter.writer.call(packet, parameter.value);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
return packet;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
module.exports = Execute;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const Packet = require('../packets/packet');
|
|
4
|
+
const ClientConstants = require('../constants/client.js');
|
|
5
|
+
|
|
6
|
+
// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake
|
|
7
|
+
|
|
8
|
+
class Handshake {
|
|
9
|
+
constructor(args) {
|
|
10
|
+
this.protocolVersion = args.protocolVersion;
|
|
11
|
+
this.serverVersion = args.serverVersion;
|
|
12
|
+
this.capabilityFlags = args.capabilityFlags;
|
|
13
|
+
this.connectionId = args.connectionId;
|
|
14
|
+
this.authPluginData1 = args.authPluginData1;
|
|
15
|
+
this.authPluginData2 = args.authPluginData2;
|
|
16
|
+
this.characterSet = args.characterSet;
|
|
17
|
+
this.statusFlags = args.statusFlags;
|
|
18
|
+
this.authPluginName = args.authPluginName;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
setScrambleData(cb) {
|
|
22
|
+
require('crypto').randomBytes(20, (err, data) => {
|
|
23
|
+
if (err) {
|
|
24
|
+
cb(err);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
this.authPluginData1 = data.slice(0, 8);
|
|
28
|
+
this.authPluginData2 = data.slice(8, 20);
|
|
29
|
+
cb();
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
toPacket(sequenceId) {
|
|
34
|
+
const length = 68 + Buffer.byteLength(this.serverVersion, 'utf8');
|
|
35
|
+
const buffer = Buffer.alloc(length + 4, 0); // zero fill, 10 bytes filler later needs to contain zeros
|
|
36
|
+
const packet = new Packet(sequenceId, buffer, 0, length + 4);
|
|
37
|
+
packet.offset = 4;
|
|
38
|
+
packet.writeInt8(this.protocolVersion);
|
|
39
|
+
packet.writeString(this.serverVersion, 'cesu8');
|
|
40
|
+
packet.writeInt8(0);
|
|
41
|
+
packet.writeInt32(this.connectionId);
|
|
42
|
+
packet.writeBuffer(this.authPluginData1);
|
|
43
|
+
packet.writeInt8(0);
|
|
44
|
+
const capabilityFlagsBuffer = Buffer.allocUnsafe(4);
|
|
45
|
+
capabilityFlagsBuffer.writeUInt32LE(this.capabilityFlags, 0);
|
|
46
|
+
packet.writeBuffer(capabilityFlagsBuffer.slice(0, 2));
|
|
47
|
+
packet.writeInt8(this.characterSet);
|
|
48
|
+
packet.writeInt16(this.statusFlags);
|
|
49
|
+
packet.writeBuffer(capabilityFlagsBuffer.slice(2, 4));
|
|
50
|
+
packet.writeInt8(21); // authPluginDataLength
|
|
51
|
+
packet.skip(10);
|
|
52
|
+
packet.writeBuffer(this.authPluginData2);
|
|
53
|
+
packet.writeInt8(0);
|
|
54
|
+
packet.writeString('mysql_native_password', 'latin1');
|
|
55
|
+
packet.writeInt8(0);
|
|
56
|
+
return packet;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
static fromPacket(packet) {
|
|
60
|
+
const args = {};
|
|
61
|
+
args.protocolVersion = packet.readInt8();
|
|
62
|
+
args.serverVersion = packet.readNullTerminatedString('cesu8');
|
|
63
|
+
args.connectionId = packet.readInt32();
|
|
64
|
+
args.authPluginData1 = packet.readBuffer(8);
|
|
65
|
+
packet.skip(1);
|
|
66
|
+
const capabilityFlagsBuffer = Buffer.allocUnsafe(4);
|
|
67
|
+
capabilityFlagsBuffer[0] = packet.readInt8();
|
|
68
|
+
capabilityFlagsBuffer[1] = packet.readInt8();
|
|
69
|
+
if (packet.haveMoreData()) {
|
|
70
|
+
args.characterSet = packet.readInt8();
|
|
71
|
+
args.statusFlags = packet.readInt16();
|
|
72
|
+
// upper 2 bytes
|
|
73
|
+
capabilityFlagsBuffer[2] = packet.readInt8();
|
|
74
|
+
capabilityFlagsBuffer[3] = packet.readInt8();
|
|
75
|
+
args.capabilityFlags = capabilityFlagsBuffer.readUInt32LE(0);
|
|
76
|
+
if (args.capabilityFlags & ClientConstants.PLUGIN_AUTH) {
|
|
77
|
+
args.authPluginDataLength = packet.readInt8();
|
|
78
|
+
} else {
|
|
79
|
+
args.authPluginDataLength = 0;
|
|
80
|
+
packet.skip(1);
|
|
81
|
+
}
|
|
82
|
+
packet.skip(10);
|
|
83
|
+
} else {
|
|
84
|
+
args.capabilityFlags = capabilityFlagsBuffer.readUInt16LE(0);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const isSecureConnection =
|
|
88
|
+
args.capabilityFlags & ClientConstants.SECURE_CONNECTION;
|
|
89
|
+
if (isSecureConnection) {
|
|
90
|
+
const authPluginDataLength = args.authPluginDataLength;
|
|
91
|
+
if (authPluginDataLength === 0) {
|
|
92
|
+
// for Secure Password Authentication
|
|
93
|
+
args.authPluginDataLength = 20;
|
|
94
|
+
args.authPluginData2 = packet.readBuffer(12);
|
|
95
|
+
packet.skip(1);
|
|
96
|
+
} else {
|
|
97
|
+
// length > 0
|
|
98
|
+
// for Custom Auth Plugin (PLUGIN_AUTH)
|
|
99
|
+
const len = Math.max(13, authPluginDataLength - 8);
|
|
100
|
+
args.authPluginData2 = packet.readBuffer(len);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (args.capabilityFlags & ClientConstants.PLUGIN_AUTH) {
|
|
105
|
+
args.authPluginName = packet.readNullTerminatedString('ascii');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return new Handshake(args);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
module.exports = Handshake;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const ClientConstants = require('../constants/client.js');
|
|
4
|
+
const CharsetToEncoding = require('../constants/charset_encodings.js');
|
|
5
|
+
const Packet = require('../packets/packet.js');
|
|
6
|
+
|
|
7
|
+
const auth41 = require('../auth_41.js');
|
|
8
|
+
|
|
9
|
+
class HandshakeResponse {
|
|
10
|
+
constructor(handshake) {
|
|
11
|
+
this.user = handshake.user || '';
|
|
12
|
+
this.database = handshake.database || '';
|
|
13
|
+
this.password = handshake.password || '';
|
|
14
|
+
this.passwordSha1 = handshake.passwordSha1;
|
|
15
|
+
this.authPluginData1 = handshake.authPluginData1;
|
|
16
|
+
this.authPluginData2 = handshake.authPluginData2;
|
|
17
|
+
this.compress = handshake.compress;
|
|
18
|
+
this.clientFlags = handshake.flags;
|
|
19
|
+
// TODO: pre-4.1 auth support
|
|
20
|
+
let authToken;
|
|
21
|
+
if (this.passwordSha1) {
|
|
22
|
+
authToken = auth41.calculateTokenFromPasswordSha(
|
|
23
|
+
this.passwordSha1,
|
|
24
|
+
this.authPluginData1,
|
|
25
|
+
this.authPluginData2
|
|
26
|
+
);
|
|
27
|
+
} else {
|
|
28
|
+
authToken = auth41.calculateToken(
|
|
29
|
+
this.password,
|
|
30
|
+
this.authPluginData1,
|
|
31
|
+
this.authPluginData2
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
this.authToken = authToken;
|
|
35
|
+
this.charsetNumber = handshake.charsetNumber;
|
|
36
|
+
this.encoding = CharsetToEncoding[handshake.charsetNumber];
|
|
37
|
+
this.connectAttributes = handshake.connectAttributes;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
serializeResponse(buffer) {
|
|
41
|
+
const isSet = (flag) => this.clientFlags & ClientConstants[flag];
|
|
42
|
+
const packet = new Packet(0, buffer, 0, buffer.length);
|
|
43
|
+
packet.offset = 4;
|
|
44
|
+
packet.writeInt32(this.clientFlags);
|
|
45
|
+
packet.writeInt32(0); // max packet size. todo: move to config
|
|
46
|
+
packet.writeInt8(this.charsetNumber);
|
|
47
|
+
packet.skip(23);
|
|
48
|
+
const encoding = this.encoding;
|
|
49
|
+
packet.writeNullTerminatedString(this.user, encoding);
|
|
50
|
+
let k;
|
|
51
|
+
if (isSet('PLUGIN_AUTH_LENENC_CLIENT_DATA')) {
|
|
52
|
+
packet.writeLengthCodedNumber(this.authToken.length);
|
|
53
|
+
packet.writeBuffer(this.authToken);
|
|
54
|
+
} else if (isSet('SECURE_CONNECTION')) {
|
|
55
|
+
packet.writeInt8(this.authToken.length);
|
|
56
|
+
packet.writeBuffer(this.authToken);
|
|
57
|
+
} else {
|
|
58
|
+
packet.writeBuffer(this.authToken);
|
|
59
|
+
packet.writeInt8(0);
|
|
60
|
+
}
|
|
61
|
+
if (isSet('CONNECT_WITH_DB')) {
|
|
62
|
+
packet.writeNullTerminatedString(this.database, encoding);
|
|
63
|
+
}
|
|
64
|
+
if (isSet('PLUGIN_AUTH')) {
|
|
65
|
+
// TODO: pass from config
|
|
66
|
+
packet.writeNullTerminatedString('mysql_native_password', 'latin1');
|
|
67
|
+
}
|
|
68
|
+
if (isSet('CONNECT_ATTRS')) {
|
|
69
|
+
const connectAttributes = this.connectAttributes || {};
|
|
70
|
+
const attrNames = Object.keys(connectAttributes);
|
|
71
|
+
let keysLength = 0;
|
|
72
|
+
for (k = 0; k < attrNames.length; ++k) {
|
|
73
|
+
keysLength += Packet.lengthCodedStringLength(attrNames[k], encoding);
|
|
74
|
+
keysLength += Packet.lengthCodedStringLength(
|
|
75
|
+
connectAttributes[attrNames[k]],
|
|
76
|
+
encoding
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
packet.writeLengthCodedNumber(keysLength);
|
|
80
|
+
for (k = 0; k < attrNames.length; ++k) {
|
|
81
|
+
packet.writeLengthCodedString(attrNames[k], encoding);
|
|
82
|
+
packet.writeLengthCodedString(
|
|
83
|
+
connectAttributes[attrNames[k]],
|
|
84
|
+
encoding
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return packet;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
toPacket() {
|
|
92
|
+
if (typeof this.user !== 'string') {
|
|
93
|
+
throw new Error('"user" connection config property must be a string');
|
|
94
|
+
}
|
|
95
|
+
if (typeof this.database !== 'string') {
|
|
96
|
+
throw new Error('"database" connection config property must be a string');
|
|
97
|
+
}
|
|
98
|
+
// dry run: calculate resulting packet length
|
|
99
|
+
const p = this.serializeResponse(Packet.MockBuffer());
|
|
100
|
+
return this.serializeResponse(Buffer.alloc(p.offset));
|
|
101
|
+
}
|
|
102
|
+
static fromPacket(packet) {
|
|
103
|
+
const args = {};
|
|
104
|
+
args.clientFlags = packet.readInt32();
|
|
105
|
+
function isSet(flag) {
|
|
106
|
+
return args.clientFlags & ClientConstants[flag];
|
|
107
|
+
}
|
|
108
|
+
args.maxPacketSize = packet.readInt32();
|
|
109
|
+
args.charsetNumber = packet.readInt8();
|
|
110
|
+
const encoding = CharsetToEncoding[args.charsetNumber];
|
|
111
|
+
args.encoding = encoding;
|
|
112
|
+
packet.skip(23);
|
|
113
|
+
args.user = packet.readNullTerminatedString(encoding);
|
|
114
|
+
let authTokenLength;
|
|
115
|
+
if (isSet('PLUGIN_AUTH_LENENC_CLIENT_DATA')) {
|
|
116
|
+
authTokenLength = packet.readLengthCodedNumber(encoding);
|
|
117
|
+
args.authToken = packet.readBuffer(authTokenLength);
|
|
118
|
+
} else if (isSet('SECURE_CONNECTION')) {
|
|
119
|
+
authTokenLength = packet.readInt8();
|
|
120
|
+
args.authToken = packet.readBuffer(authTokenLength);
|
|
121
|
+
} else {
|
|
122
|
+
args.authToken = packet.readNullTerminatedString(encoding);
|
|
123
|
+
}
|
|
124
|
+
if (isSet('CONNECT_WITH_DB')) {
|
|
125
|
+
args.database = packet.readNullTerminatedString(encoding);
|
|
126
|
+
}
|
|
127
|
+
if (isSet('PLUGIN_AUTH')) {
|
|
128
|
+
args.authPluginName = packet.readNullTerminatedString(encoding);
|
|
129
|
+
}
|
|
130
|
+
if (isSet('CONNECT_ATTRS')) {
|
|
131
|
+
const keysLength = packet.readLengthCodedNumber(encoding);
|
|
132
|
+
const keysEnd = packet.offset + keysLength;
|
|
133
|
+
const attrs = {};
|
|
134
|
+
while (packet.offset < keysEnd) {
|
|
135
|
+
attrs[packet.readLengthCodedString(encoding)] =
|
|
136
|
+
packet.readLengthCodedString(encoding);
|
|
137
|
+
}
|
|
138
|
+
args.connectAttributes = attrs;
|
|
139
|
+
}
|
|
140
|
+
return args;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
module.exports = HandshakeResponse;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
// This file was modified by Oracle on June 1, 2021.
|
|
2
|
+
// A utility method was introduced to generate an Error instance from a
|
|
3
|
+
// binary server packet.
|
|
4
|
+
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
|
|
5
|
+
|
|
6
|
+
// This file was modified by Oracle on September 21, 2021.
|
|
7
|
+
// The new AuthNextFactor packet is now available.
|
|
8
|
+
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
|
|
9
|
+
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
const process = require('process');
|
|
13
|
+
|
|
14
|
+
const AuthNextFactor = require('./auth_next_factor');
|
|
15
|
+
const AuthSwitchRequest = require('./auth_switch_request');
|
|
16
|
+
const AuthSwitchRequestMoreData = require('./auth_switch_request_more_data');
|
|
17
|
+
const AuthSwitchResponse = require('./auth_switch_response');
|
|
18
|
+
const BinaryRow = require('./binary_row');
|
|
19
|
+
const BinlogDump = require('./binlog_dump');
|
|
20
|
+
const ChangeUser = require('./change_user');
|
|
21
|
+
const CloseStatement = require('./close_statement');
|
|
22
|
+
const ColumnDefinition = require('./column_definition');
|
|
23
|
+
const Execute = require('./execute');
|
|
24
|
+
const Handshake = require('./handshake');
|
|
25
|
+
const HandshakeResponse = require('./handshake_response');
|
|
26
|
+
const PrepareStatement = require('./prepare_statement');
|
|
27
|
+
const PreparedStatementHeader = require('./prepared_statement_header');
|
|
28
|
+
const Query = require('./query');
|
|
29
|
+
const RegisterSlave = require('./register_slave');
|
|
30
|
+
const ResultSetHeader = require('./resultset_header');
|
|
31
|
+
const SSLRequest = require('./ssl_request');
|
|
32
|
+
const TextRow = require('./text_row');
|
|
33
|
+
|
|
34
|
+
const ctorMap = {
|
|
35
|
+
AuthNextFactor,
|
|
36
|
+
AuthSwitchRequest,
|
|
37
|
+
AuthSwitchRequestMoreData,
|
|
38
|
+
AuthSwitchResponse,
|
|
39
|
+
BinaryRow,
|
|
40
|
+
BinlogDump,
|
|
41
|
+
ChangeUser,
|
|
42
|
+
CloseStatement,
|
|
43
|
+
ColumnDefinition,
|
|
44
|
+
Execute,
|
|
45
|
+
Handshake,
|
|
46
|
+
HandshakeResponse,
|
|
47
|
+
PrepareStatement,
|
|
48
|
+
PreparedStatementHeader,
|
|
49
|
+
Query,
|
|
50
|
+
RegisterSlave,
|
|
51
|
+
ResultSetHeader,
|
|
52
|
+
SSLRequest,
|
|
53
|
+
TextRow,
|
|
54
|
+
};
|
|
55
|
+
Object.entries(ctorMap).forEach(([name, ctor]) => {
|
|
56
|
+
module.exports[name] = ctor;
|
|
57
|
+
// monkey-patch it to include name if debug is on
|
|
58
|
+
if (process.env.NODE_DEBUG) {
|
|
59
|
+
if (ctor.prototype.toPacket) {
|
|
60
|
+
const old = ctor.prototype.toPacket;
|
|
61
|
+
ctor.prototype.toPacket = function () {
|
|
62
|
+
const p = old.call(this);
|
|
63
|
+
p._name = name;
|
|
64
|
+
return p;
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// simple packets:
|
|
71
|
+
const Packet = require('./packet');
|
|
72
|
+
exports.Packet = Packet;
|
|
73
|
+
|
|
74
|
+
class OK {
|
|
75
|
+
static toPacket(args, encoding) {
|
|
76
|
+
args = args || {};
|
|
77
|
+
const affectedRows = args.affectedRows || 0;
|
|
78
|
+
const insertId = args.insertId || 0;
|
|
79
|
+
const serverStatus = args.serverStatus || 0;
|
|
80
|
+
const warningCount = args.warningCount || 0;
|
|
81
|
+
const message = args.message || '';
|
|
82
|
+
|
|
83
|
+
let length = 9 + Packet.lengthCodedNumberLength(affectedRows);
|
|
84
|
+
length += Packet.lengthCodedNumberLength(insertId);
|
|
85
|
+
|
|
86
|
+
const buffer = Buffer.allocUnsafe(length);
|
|
87
|
+
const packet = new Packet(0, buffer, 0, length);
|
|
88
|
+
packet.offset = 4;
|
|
89
|
+
packet.writeInt8(0);
|
|
90
|
+
packet.writeLengthCodedNumber(affectedRows);
|
|
91
|
+
packet.writeLengthCodedNumber(insertId);
|
|
92
|
+
packet.writeInt16(serverStatus);
|
|
93
|
+
packet.writeInt16(warningCount);
|
|
94
|
+
packet.writeString(message, encoding);
|
|
95
|
+
packet._name = 'OK';
|
|
96
|
+
return packet;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
exports.OK = OK;
|
|
101
|
+
|
|
102
|
+
// warnings, statusFlags
|
|
103
|
+
class EOF {
|
|
104
|
+
static toPacket(warnings, statusFlags) {
|
|
105
|
+
if (typeof warnings === 'undefined') {
|
|
106
|
+
warnings = 0;
|
|
107
|
+
}
|
|
108
|
+
if (typeof statusFlags === 'undefined') {
|
|
109
|
+
statusFlags = 0;
|
|
110
|
+
}
|
|
111
|
+
const packet = new Packet(0, Buffer.allocUnsafe(9), 0, 9);
|
|
112
|
+
packet.offset = 4;
|
|
113
|
+
packet.writeInt8(0xfe);
|
|
114
|
+
packet.writeInt16(warnings);
|
|
115
|
+
packet.writeInt16(statusFlags);
|
|
116
|
+
packet._name = 'EOF';
|
|
117
|
+
return packet;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
exports.EOF = EOF;
|
|
122
|
+
|
|
123
|
+
class Error {
|
|
124
|
+
static toPacket(args, encoding) {
|
|
125
|
+
const length = 13 + Buffer.byteLength(args.message, 'utf8');
|
|
126
|
+
const packet = new Packet(0, Buffer.allocUnsafe(length), 0, length);
|
|
127
|
+
packet.offset = 4;
|
|
128
|
+
packet.writeInt8(0xff);
|
|
129
|
+
packet.writeInt16(args.code);
|
|
130
|
+
// TODO: sql state parameter
|
|
131
|
+
packet.writeString('#_____', encoding);
|
|
132
|
+
packet.writeString(args.message, encoding);
|
|
133
|
+
packet._name = 'Error';
|
|
134
|
+
return packet;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
static fromPacket(packet) {
|
|
138
|
+
packet.readInt8(); // marker
|
|
139
|
+
const code = packet.readInt16();
|
|
140
|
+
packet.readString(1, 'ascii'); // sql state marker
|
|
141
|
+
// The SQL state of the ERR_Packet which is always 5 bytes long.
|
|
142
|
+
// https://dev.mysql.com/doc/dev/mysql-server/8.0.11/page_protocol_basic_dt_strings.html#sect_protocol_basic_dt_string_fix
|
|
143
|
+
packet.readString(5, 'ascii'); // sql state (ignore for now)
|
|
144
|
+
const message = packet.readNullTerminatedString('utf8');
|
|
145
|
+
const error = new Error();
|
|
146
|
+
error.message = message;
|
|
147
|
+
error.code = code;
|
|
148
|
+
return error;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
exports.Error = Error;
|