@depup/mysql2 3.19.0-depup.0
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 +114 -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 +114 -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 +988 -0
- package/lib/base/pool.js +282 -0
- package/lib/base/pool_connection.js +77 -0
- package/lib/commands/auth_switch.js +129 -0
- package/lib/commands/binlog_dump.js +109 -0
- package/lib/commands/change_user.js +68 -0
- package/lib/commands/client_handshake.js +383 -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 +361 -0
- package/lib/commands/quit.js +29 -0
- package/lib/commands/register_slave.js +27 -0
- package/lib/commands/server_handshake.js +202 -0
- package/lib/compressed_protocol.js +153 -0
- package/lib/connection.js +12 -0
- package/lib/connection_config.js +293 -0
- package/lib/constants/charset_encodings.js +317 -0
- package/lib/constants/charsets.js +317 -0
- package/lib/constants/client.js +38 -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 +83 -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 +173 -0
- package/lib/packets/index.js +152 -0
- package/lib/packets/packet.js +946 -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 +375 -0
- package/lib/pool_config.js +30 -0
- package/lib/pool_connection.js +12 -0
- package/lib/promise/connection.js +228 -0
- package/lib/promise/inherit_events.js +27 -0
- package/lib/promise/make_done_cb.js +19 -0
- package/lib/promise/pool.js +118 -0
- package/lib/promise/pool_cluster.js +54 -0
- package/lib/promise/pool_connection.js +23 -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 +96 -0
- package/promise.d.ts +139 -0
- package/promise.js +208 -0
- package/typings/mysql/LICENSE.txt +15 -0
- package/typings/mysql/index.d.ts +84 -0
- package/typings/mysql/info.txt +1 -0
- package/typings/mysql/lib/Auth.d.ts +30 -0
- package/typings/mysql/lib/Connection.d.ts +442 -0
- package/typings/mysql/lib/Pool.d.ts +71 -0
- package/typings/mysql/lib/PoolCluster.d.ts +92 -0
- package/typings/mysql/lib/PoolConnection.d.ts +11 -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 +41 -0
- package/typings/mysql/lib/protocol/sequences/Prepare.d.ts +65 -0
- package/typings/mysql/lib/protocol/sequences/Query.d.ts +228 -0
- package/typings/mysql/lib/protocol/sequences/QueryableBase.d.ts +41 -0
- package/typings/mysql/lib/protocol/sequences/Sequence.d.ts +5 -0
- package/typings/mysql/lib/protocol/sequences/promise/ExecutableBase.d.ts +17 -0
- package/typings/mysql/lib/protocol/sequences/promise/QueryableBase.d.ts +18 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const CommandCode = require('../constants/commands.js');
|
|
4
|
+
const Errors = require('../constants/errors.js');
|
|
5
|
+
|
|
6
|
+
const Command = require('./command.js');
|
|
7
|
+
const Packets = require('../packets/index.js');
|
|
8
|
+
|
|
9
|
+
class ServerHandshake extends Command {
|
|
10
|
+
constructor(args) {
|
|
11
|
+
super();
|
|
12
|
+
this.args = args;
|
|
13
|
+
/*
|
|
14
|
+
this.protocolVersion = args.protocolVersion || 10;
|
|
15
|
+
this.serverVersion = args.serverVersion;
|
|
16
|
+
this.connectionId = args.connectionId,
|
|
17
|
+
this.statusFlags = args.statusFlags,
|
|
18
|
+
this.characterSet = args.characterSet,
|
|
19
|
+
this.capabilityFlags = args.capabilityFlags || 512;
|
|
20
|
+
*/
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
start(packet, connection) {
|
|
24
|
+
const serverHelloPacket = new Packets.Handshake(this.args);
|
|
25
|
+
this.serverHello = serverHelloPacket;
|
|
26
|
+
serverHelloPacket.setScrambleData((err) => {
|
|
27
|
+
if (err) {
|
|
28
|
+
connection.emit('error', new Error('Error generating random bytes'));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
connection.writePacket(serverHelloPacket.toPacket(0));
|
|
32
|
+
});
|
|
33
|
+
return ServerHandshake.prototype.readClientReply;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
readClientReply(packet, connection) {
|
|
37
|
+
// check auth here
|
|
38
|
+
const clientHelloReply = Packets.HandshakeResponse.fromPacket(packet);
|
|
39
|
+
// TODO check we don't have something similar already
|
|
40
|
+
connection.clientHelloReply = clientHelloReply;
|
|
41
|
+
if (this.args.authCallback) {
|
|
42
|
+
this.args.authCallback(
|
|
43
|
+
{
|
|
44
|
+
user: clientHelloReply.user,
|
|
45
|
+
database: clientHelloReply.database,
|
|
46
|
+
address: connection.stream.remoteAddress,
|
|
47
|
+
authPluginData1: this.serverHello.authPluginData1,
|
|
48
|
+
authPluginData2: this.serverHello.authPluginData2,
|
|
49
|
+
authToken: clientHelloReply.authToken,
|
|
50
|
+
},
|
|
51
|
+
(err, mysqlError) => {
|
|
52
|
+
// if (err)
|
|
53
|
+
if (!mysqlError) {
|
|
54
|
+
connection.writeOk();
|
|
55
|
+
} else {
|
|
56
|
+
// TODO create constants / errorToCode
|
|
57
|
+
// 1045 = ER_ACCESS_DENIED_ERROR
|
|
58
|
+
connection.writeError({
|
|
59
|
+
message: mysqlError.message || '',
|
|
60
|
+
code: mysqlError.code || 1045,
|
|
61
|
+
});
|
|
62
|
+
connection.close();
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
} else {
|
|
67
|
+
connection.writeOk();
|
|
68
|
+
}
|
|
69
|
+
return ServerHandshake.prototype.dispatchCommands;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
_isStatement(query, name) {
|
|
73
|
+
const firstWord = query.split(' ')[0].toUpperCase();
|
|
74
|
+
return firstWord === name;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
dispatchCommands(packet, connection) {
|
|
78
|
+
// command from client to server
|
|
79
|
+
let knownCommand = true;
|
|
80
|
+
const encoding = connection.clientHelloReply.encoding;
|
|
81
|
+
const commandCode = packet.readInt8();
|
|
82
|
+
switch (commandCode) {
|
|
83
|
+
case CommandCode.STMT_PREPARE:
|
|
84
|
+
if (connection.listeners('stmt_prepare').length) {
|
|
85
|
+
const query = packet.readString(undefined, encoding);
|
|
86
|
+
connection.emit('stmt_prepare', query);
|
|
87
|
+
} else {
|
|
88
|
+
connection.writeError({
|
|
89
|
+
code: Errors.HA_ERR_INTERNAL_ERROR,
|
|
90
|
+
message: 'No query handler for prepared statements.',
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
break;
|
|
94
|
+
case CommandCode.STMT_EXECUTE:
|
|
95
|
+
if (connection.listeners('stmt_execute').length) {
|
|
96
|
+
const { stmtId, flags, iterationCount, values } =
|
|
97
|
+
Packets.Execute.fromPacket(packet, encoding);
|
|
98
|
+
connection.emit(
|
|
99
|
+
'stmt_execute',
|
|
100
|
+
stmtId,
|
|
101
|
+
flags,
|
|
102
|
+
iterationCount,
|
|
103
|
+
values
|
|
104
|
+
);
|
|
105
|
+
} else {
|
|
106
|
+
connection.writeError({
|
|
107
|
+
code: Errors.HA_ERR_INTERNAL_ERROR,
|
|
108
|
+
message: 'No query handler for execute statements.',
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
break;
|
|
112
|
+
case CommandCode.QUIT:
|
|
113
|
+
if (connection.listeners('quit').length) {
|
|
114
|
+
connection.emit('quit');
|
|
115
|
+
} else {
|
|
116
|
+
connection.stream.end();
|
|
117
|
+
}
|
|
118
|
+
break;
|
|
119
|
+
case CommandCode.INIT_DB:
|
|
120
|
+
if (connection.listeners('init_db').length) {
|
|
121
|
+
const schemaName = packet.readString(undefined, encoding);
|
|
122
|
+
connection.emit('init_db', schemaName);
|
|
123
|
+
} else {
|
|
124
|
+
connection.writeOk();
|
|
125
|
+
}
|
|
126
|
+
break;
|
|
127
|
+
case CommandCode.QUERY:
|
|
128
|
+
if (connection.listeners('query').length) {
|
|
129
|
+
const query = packet.readString(undefined, encoding);
|
|
130
|
+
if (
|
|
131
|
+
this._isStatement(query, 'PREPARE') ||
|
|
132
|
+
this._isStatement(query, 'SET')
|
|
133
|
+
) {
|
|
134
|
+
connection.emit('stmt_prepare', query);
|
|
135
|
+
} else if (this._isStatement(query, 'EXECUTE')) {
|
|
136
|
+
connection.emit('stmt_execute', null, null, null, null, query);
|
|
137
|
+
} else connection.emit('query', query);
|
|
138
|
+
} else {
|
|
139
|
+
connection.writeError({
|
|
140
|
+
code: Errors.HA_ERR_INTERNAL_ERROR,
|
|
141
|
+
message: 'No query handler',
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
break;
|
|
145
|
+
case CommandCode.FIELD_LIST:
|
|
146
|
+
if (connection.listeners('field_list').length) {
|
|
147
|
+
const table = packet.readNullTerminatedString(encoding);
|
|
148
|
+
const fields = packet.readString(undefined, encoding);
|
|
149
|
+
connection.emit('field_list', table, fields);
|
|
150
|
+
} else {
|
|
151
|
+
connection.writeError({
|
|
152
|
+
code: Errors.ER_WARN_DEPRECATED_SYNTAX,
|
|
153
|
+
message:
|
|
154
|
+
'As of MySQL 5.7.11, COM_FIELD_LIST is deprecated and will be removed in a future version of MySQL.',
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
break;
|
|
158
|
+
case CommandCode.PING:
|
|
159
|
+
if (connection.listeners('ping').length) {
|
|
160
|
+
connection.emit('ping');
|
|
161
|
+
} else {
|
|
162
|
+
connection.writeOk();
|
|
163
|
+
}
|
|
164
|
+
break;
|
|
165
|
+
default:
|
|
166
|
+
knownCommand = false;
|
|
167
|
+
}
|
|
168
|
+
if (connection.listeners('packet').length) {
|
|
169
|
+
connection.emit('packet', packet.clone(), knownCommand, commandCode);
|
|
170
|
+
} else if (!knownCommand) {
|
|
171
|
+
console.log('Unknown command:', commandCode);
|
|
172
|
+
}
|
|
173
|
+
return ServerHandshake.prototype.dispatchCommands;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
module.exports = ServerHandshake;
|
|
178
|
+
|
|
179
|
+
// TODO: implement server-side 4.1 authentication
|
|
180
|
+
/*
|
|
181
|
+
4.1 authentication: (http://bazaar.launchpad.net/~mysql/mysql-server/5.5/view/head:/sql/password.c)
|
|
182
|
+
|
|
183
|
+
SERVER: public_seed=create_random_string()
|
|
184
|
+
send(public_seed)
|
|
185
|
+
|
|
186
|
+
CLIENT: recv(public_seed)
|
|
187
|
+
hash_stage1=sha1("password")
|
|
188
|
+
hash_stage2=sha1(hash_stage1)
|
|
189
|
+
reply=xor(hash_stage1, sha1(public_seed,hash_stage2)
|
|
190
|
+
|
|
191
|
+
// this three steps are done in scramble()
|
|
192
|
+
|
|
193
|
+
send(reply)
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
SERVER: recv(reply)
|
|
197
|
+
hash_stage1=xor(reply, sha1(public_seed,hash_stage2))
|
|
198
|
+
candidate_hash2=sha1(hash_stage1)
|
|
199
|
+
check(candidate_hash2==hash_stage2)
|
|
200
|
+
|
|
201
|
+
server stores sha1(sha1(password)) ( hash_stag2)
|
|
202
|
+
*/
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// connection mixins
|
|
4
|
+
// implementation of http://dev.mysql.com/doc/internals/en/compression.html
|
|
5
|
+
|
|
6
|
+
const zlib = require('zlib');
|
|
7
|
+
const PacketParser = require('./packet_parser.js');
|
|
8
|
+
|
|
9
|
+
class Queue {
|
|
10
|
+
constructor() {
|
|
11
|
+
this._queue = [];
|
|
12
|
+
this._running = false;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
push(fn) {
|
|
16
|
+
this._queue.push(fn);
|
|
17
|
+
if (!this._running) {
|
|
18
|
+
this._running = true;
|
|
19
|
+
process.nextTick(() => this._next());
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
_next() {
|
|
24
|
+
const task = this._queue.shift();
|
|
25
|
+
if (!task) {
|
|
26
|
+
this._running = false;
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
task({
|
|
30
|
+
done: () => process.nextTick(() => this._next()),
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function handleCompressedPacket(packet) {
|
|
36
|
+
// eslint-disable-next-line consistent-this, no-invalid-this
|
|
37
|
+
const connection = this;
|
|
38
|
+
const deflatedLength = packet.readInt24();
|
|
39
|
+
const body = packet.readBuffer();
|
|
40
|
+
|
|
41
|
+
if (deflatedLength !== 0) {
|
|
42
|
+
connection.inflateQueue.push((task) => {
|
|
43
|
+
zlib.inflate(body, (err, data) => {
|
|
44
|
+
if (err) {
|
|
45
|
+
connection._handleNetworkError(err);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
connection._bumpCompressedSequenceId(packet.numPackets);
|
|
49
|
+
connection._inflatedPacketsParser.execute(data);
|
|
50
|
+
task.done();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
} else {
|
|
54
|
+
connection.inflateQueue.push((task) => {
|
|
55
|
+
connection._bumpCompressedSequenceId(packet.numPackets);
|
|
56
|
+
connection._inflatedPacketsParser.execute(body);
|
|
57
|
+
task.done();
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function writeCompressed(buffer) {
|
|
63
|
+
// http://dev.mysql.com/doc/internals/en/example-several-mysql-packets.html
|
|
64
|
+
// note: sending a MySQL Packet of the size 2^24−5 to 2^24−1 via compression
|
|
65
|
+
// leads to at least one extra compressed packet.
|
|
66
|
+
// (this is because "length of the packet before compression" need to fit
|
|
67
|
+
// into 3 byte unsigned int. "length of the packet before compression" includes
|
|
68
|
+
// 4 byte packet header, hence 2^24−5)
|
|
69
|
+
const MAX_COMPRESSED_LENGTH = 16777210;
|
|
70
|
+
let start;
|
|
71
|
+
if (buffer.length > MAX_COMPRESSED_LENGTH) {
|
|
72
|
+
for (start = 0; start < buffer.length; start += MAX_COMPRESSED_LENGTH) {
|
|
73
|
+
writeCompressed.call(
|
|
74
|
+
// eslint-disable-next-line no-invalid-this
|
|
75
|
+
this,
|
|
76
|
+
buffer.slice(start, start + MAX_COMPRESSED_LENGTH)
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// eslint-disable-next-line no-invalid-this, consistent-this
|
|
83
|
+
const connection = this;
|
|
84
|
+
|
|
85
|
+
let packetLen = buffer.length;
|
|
86
|
+
const compressHeader = Buffer.allocUnsafe(7);
|
|
87
|
+
|
|
88
|
+
// seqqueue is used here because zlib async execution is routed via thread pool
|
|
89
|
+
// internally and when we have multiple compressed packets arriving we need
|
|
90
|
+
// to assemble uncompressed result sequentially
|
|
91
|
+
(function (seqId) {
|
|
92
|
+
connection.deflateQueue.push((task) => {
|
|
93
|
+
zlib.deflate(buffer, (err, compressed) => {
|
|
94
|
+
if (err) {
|
|
95
|
+
connection._handleFatalError(err);
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
let compressedLength = compressed.length;
|
|
99
|
+
|
|
100
|
+
if (compressedLength < packetLen) {
|
|
101
|
+
compressHeader.writeUInt8(compressedLength & 0xff, 0);
|
|
102
|
+
compressHeader.writeUInt16LE(compressedLength >> 8, 1);
|
|
103
|
+
compressHeader.writeUInt8(seqId, 3);
|
|
104
|
+
compressHeader.writeUInt8(packetLen & 0xff, 4);
|
|
105
|
+
compressHeader.writeUInt16LE(packetLen >> 8, 5);
|
|
106
|
+
connection.writeUncompressed(compressHeader);
|
|
107
|
+
connection.writeUncompressed(compressed);
|
|
108
|
+
} else {
|
|
109
|
+
// http://dev.mysql.com/doc/internals/en/uncompressed-payload.html
|
|
110
|
+
// To send an uncompressed payload:
|
|
111
|
+
// - set length of payload before compression to 0
|
|
112
|
+
// - the compressed payload contains the uncompressed payload instead.
|
|
113
|
+
compressedLength = packetLen;
|
|
114
|
+
packetLen = 0;
|
|
115
|
+
compressHeader.writeUInt8(compressedLength & 0xff, 0);
|
|
116
|
+
compressHeader.writeUInt16LE(compressedLength >> 8, 1);
|
|
117
|
+
compressHeader.writeUInt8(seqId, 3);
|
|
118
|
+
compressHeader.writeUInt8(packetLen & 0xff, 4);
|
|
119
|
+
compressHeader.writeUInt16LE(packetLen >> 8, 5);
|
|
120
|
+
connection.writeUncompressed(compressHeader);
|
|
121
|
+
connection.writeUncompressed(buffer);
|
|
122
|
+
}
|
|
123
|
+
task.done();
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
})(connection.compressedSequenceId);
|
|
127
|
+
connection._bumpCompressedSequenceId(1);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function enableCompression(connection) {
|
|
131
|
+
connection._lastWrittenPacketId = 0;
|
|
132
|
+
connection._lastReceivedPacketId = 0;
|
|
133
|
+
|
|
134
|
+
connection._handleCompressedPacket = handleCompressedPacket;
|
|
135
|
+
connection._inflatedPacketsParser = new PacketParser((p) => {
|
|
136
|
+
connection.handlePacket(p);
|
|
137
|
+
}, 4);
|
|
138
|
+
connection._inflatedPacketsParser._lastPacket = 0;
|
|
139
|
+
connection.packetParser = new PacketParser((packet) => {
|
|
140
|
+
connection._handleCompressedPacket(packet);
|
|
141
|
+
}, 7);
|
|
142
|
+
|
|
143
|
+
connection.writeUncompressed = connection.write;
|
|
144
|
+
connection.write = writeCompressed;
|
|
145
|
+
|
|
146
|
+
connection.inflateQueue = new Queue();
|
|
147
|
+
connection.deflateQueue = new Queue();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
module.exports = {
|
|
151
|
+
enableCompression: enableCompression,
|
|
152
|
+
Queue: Queue,
|
|
153
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const BaseConnection = require('./base/connection.js');
|
|
4
|
+
|
|
5
|
+
class Connection extends BaseConnection {
|
|
6
|
+
promise(promiseImpl) {
|
|
7
|
+
const PromiseConnection = require('./promise/connection.js');
|
|
8
|
+
return new PromiseConnection(this, promiseImpl);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
module.exports = Connection;
|
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
// This file was modified by Oracle on September 21, 2021.
|
|
2
|
+
// New connection options for additional authentication factors were
|
|
3
|
+
// introduced.
|
|
4
|
+
// Multi-factor authentication capability is now enabled if one of these
|
|
5
|
+
// options is used.
|
|
6
|
+
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
|
|
7
|
+
|
|
8
|
+
'use strict';
|
|
9
|
+
|
|
10
|
+
const { URL } = require('url');
|
|
11
|
+
const ClientConstants = require('./constants/client');
|
|
12
|
+
const Charsets = require('./constants/charsets');
|
|
13
|
+
const { version } = require('../package.json');
|
|
14
|
+
let SSLProfiles = null;
|
|
15
|
+
|
|
16
|
+
const validOptions = {
|
|
17
|
+
authPlugins: 1,
|
|
18
|
+
authSwitchHandler: 1,
|
|
19
|
+
bigNumberStrings: 1,
|
|
20
|
+
charset: 1,
|
|
21
|
+
charsetNumber: 1,
|
|
22
|
+
compress: 1,
|
|
23
|
+
connectAttributes: 1,
|
|
24
|
+
connectTimeout: 1,
|
|
25
|
+
database: 1,
|
|
26
|
+
dateStrings: 1,
|
|
27
|
+
debug: 1,
|
|
28
|
+
decimalNumbers: 1,
|
|
29
|
+
enableKeepAlive: 1,
|
|
30
|
+
flags: 1,
|
|
31
|
+
host: 1,
|
|
32
|
+
insecureAuth: 1,
|
|
33
|
+
infileStreamFactory: 1,
|
|
34
|
+
isServer: 1,
|
|
35
|
+
keepAliveInitialDelay: 1,
|
|
36
|
+
localAddress: 1,
|
|
37
|
+
maxPreparedStatements: 1,
|
|
38
|
+
multipleStatements: 1,
|
|
39
|
+
namedPlaceholders: 1,
|
|
40
|
+
nestTables: 1,
|
|
41
|
+
password: 1,
|
|
42
|
+
// with multi-factor authentication, the main password (used for the first
|
|
43
|
+
// authentication factor) can be provided via password1
|
|
44
|
+
password1: 1,
|
|
45
|
+
password2: 1,
|
|
46
|
+
password3: 1,
|
|
47
|
+
passwordSha1: 1,
|
|
48
|
+
pool: 1,
|
|
49
|
+
port: 1,
|
|
50
|
+
queryFormat: 1,
|
|
51
|
+
rowsAsArray: 1,
|
|
52
|
+
socketPath: 1,
|
|
53
|
+
ssl: 1,
|
|
54
|
+
stream: 1,
|
|
55
|
+
stringifyObjects: 1,
|
|
56
|
+
supportBigNumbers: 1,
|
|
57
|
+
timezone: 1,
|
|
58
|
+
trace: 1,
|
|
59
|
+
typeCast: 1,
|
|
60
|
+
uri: 1,
|
|
61
|
+
user: 1,
|
|
62
|
+
disableEval: 1,
|
|
63
|
+
// These options are used for Pool
|
|
64
|
+
connectionLimit: 1,
|
|
65
|
+
maxIdle: 1,
|
|
66
|
+
idleTimeout: 1,
|
|
67
|
+
Promise: 1,
|
|
68
|
+
queueLimit: 1,
|
|
69
|
+
waitForConnections: 1,
|
|
70
|
+
jsonStrings: 1,
|
|
71
|
+
gracefulEnd: 1,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
class ConnectionConfig {
|
|
75
|
+
constructor(options) {
|
|
76
|
+
if (typeof options === 'string') {
|
|
77
|
+
options = ConnectionConfig.parseUrl(options);
|
|
78
|
+
} else if (options && options.uri) {
|
|
79
|
+
const uriOptions = ConnectionConfig.parseUrl(options.uri);
|
|
80
|
+
for (const key in uriOptions) {
|
|
81
|
+
if (!Object.prototype.hasOwnProperty.call(uriOptions, key)) continue;
|
|
82
|
+
if (options[key]) continue;
|
|
83
|
+
options[key] = uriOptions[key];
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
for (const key in options) {
|
|
87
|
+
if (!Object.prototype.hasOwnProperty.call(options, key)) continue;
|
|
88
|
+
if (validOptions[key] !== 1) {
|
|
89
|
+
// REVIEW: Should this be emitted somehow?
|
|
90
|
+
console.error(
|
|
91
|
+
`Ignoring invalid configuration option passed to Connection: ${key}. This is currently a warning, but in future versions of MySQL2, an error will be thrown if you pass an invalid configuration option to a Connection`
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
this.isServer = options.isServer;
|
|
96
|
+
this.stream = options.stream;
|
|
97
|
+
this.host = options.host || 'localhost';
|
|
98
|
+
this.port =
|
|
99
|
+
(typeof options.port === 'string'
|
|
100
|
+
? parseInt(options.port, 10)
|
|
101
|
+
: options.port) || 3306;
|
|
102
|
+
this.localAddress = options.localAddress;
|
|
103
|
+
this.socketPath = options.socketPath;
|
|
104
|
+
this.user = options.user || undefined;
|
|
105
|
+
// for the purpose of multi-factor authentication, or not, the main
|
|
106
|
+
// password (used for the 1st authentication factor) can also be
|
|
107
|
+
// provided via the "password1" option
|
|
108
|
+
this.password = options.password || options.password1 || undefined;
|
|
109
|
+
this.password2 = options.password2 || undefined;
|
|
110
|
+
this.password3 = options.password3 || undefined;
|
|
111
|
+
this.passwordSha1 = options.passwordSha1 || undefined;
|
|
112
|
+
this.database = options.database;
|
|
113
|
+
this.connectTimeout = isNaN(options.connectTimeout)
|
|
114
|
+
? 10 * 1000
|
|
115
|
+
: options.connectTimeout;
|
|
116
|
+
this.insecureAuth = options.insecureAuth || false;
|
|
117
|
+
this.infileStreamFactory = options.infileStreamFactory || undefined;
|
|
118
|
+
this.supportBigNumbers = options.supportBigNumbers || false;
|
|
119
|
+
this.bigNumberStrings = options.bigNumberStrings || false;
|
|
120
|
+
this.decimalNumbers = options.decimalNumbers || false;
|
|
121
|
+
this.dateStrings = options.dateStrings || false;
|
|
122
|
+
this.debug = options.debug;
|
|
123
|
+
this.trace = options.trace !== false;
|
|
124
|
+
this.stringifyObjects = options.stringifyObjects || false;
|
|
125
|
+
this.enableKeepAlive = options.enableKeepAlive !== false;
|
|
126
|
+
this.keepAliveInitialDelay = options.keepAliveInitialDelay;
|
|
127
|
+
if (
|
|
128
|
+
options.timezone &&
|
|
129
|
+
!/^(?:local|Z|[ +-]\d\d:\d\d)$/.test(options.timezone)
|
|
130
|
+
) {
|
|
131
|
+
// strictly supports timezones specified by mysqljs/mysql:
|
|
132
|
+
// https://github.com/mysqljs/mysql#user-content-connection-options
|
|
133
|
+
|
|
134
|
+
console.error(
|
|
135
|
+
`Ignoring invalid timezone passed to Connection: ${options.timezone}. This is currently a warning, but in future versions of MySQL2, an error will be thrown if you pass an invalid configuration option to a Connection`
|
|
136
|
+
);
|
|
137
|
+
// SqlStrings falls back to UTC on invalid timezone
|
|
138
|
+
this.timezone = 'Z';
|
|
139
|
+
} else {
|
|
140
|
+
this.timezone = options.timezone || 'local';
|
|
141
|
+
}
|
|
142
|
+
this.queryFormat = options.queryFormat;
|
|
143
|
+
this.pool = options.pool || undefined;
|
|
144
|
+
this.ssl =
|
|
145
|
+
typeof options.ssl === 'string'
|
|
146
|
+
? ConnectionConfig.getSSLProfile(options.ssl)
|
|
147
|
+
: options.ssl || false;
|
|
148
|
+
this.multipleStatements = options.multipleStatements || false;
|
|
149
|
+
this.rowsAsArray = options.rowsAsArray || false;
|
|
150
|
+
this.namedPlaceholders = options.namedPlaceholders || false;
|
|
151
|
+
this.nestTables =
|
|
152
|
+
options.nestTables === undefined ? undefined : options.nestTables;
|
|
153
|
+
this.typeCast = options.typeCast === undefined ? true : options.typeCast;
|
|
154
|
+
this.disableEval = Boolean(options.disableEval);
|
|
155
|
+
if (this.timezone[0] === ' ') {
|
|
156
|
+
// "+" is a url encoded char for space so it
|
|
157
|
+
// gets translated to space when giving a
|
|
158
|
+
// connection string..
|
|
159
|
+
this.timezone = `+${this.timezone.slice(1)}`;
|
|
160
|
+
}
|
|
161
|
+
if (this.ssl) {
|
|
162
|
+
if (typeof this.ssl !== 'object') {
|
|
163
|
+
throw new TypeError(
|
|
164
|
+
`SSL profile must be an object, instead it's a ${typeof this.ssl}`
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
// Default rejectUnauthorized to true
|
|
168
|
+
this.ssl.rejectUnauthorized = this.ssl.rejectUnauthorized !== false;
|
|
169
|
+
}
|
|
170
|
+
this.maxPacketSize = 0;
|
|
171
|
+
this.charsetNumber = options.charset
|
|
172
|
+
? ConnectionConfig.getCharsetNumber(options.charset)
|
|
173
|
+
: options.charsetNumber || Charsets.UTF8MB4_UNICODE_CI;
|
|
174
|
+
this.compress = options.compress || false;
|
|
175
|
+
this.authPlugins = options.authPlugins;
|
|
176
|
+
this.authSwitchHandler = options.authSwitchHandler;
|
|
177
|
+
this.clientFlags = ConnectionConfig.mergeFlags(
|
|
178
|
+
ConnectionConfig.getDefaultFlags(options),
|
|
179
|
+
options.flags || ''
|
|
180
|
+
);
|
|
181
|
+
// Default connection attributes
|
|
182
|
+
// https://dev.mysql.com/doc/refman/8.0/en/performance-schema-connection-attribute-tables.html
|
|
183
|
+
const defaultConnectAttributes = {
|
|
184
|
+
_client_name: 'Node-MySQL-2',
|
|
185
|
+
_client_version: version,
|
|
186
|
+
};
|
|
187
|
+
this.connectAttributes = {
|
|
188
|
+
...defaultConnectAttributes,
|
|
189
|
+
...(options.connectAttributes || {}),
|
|
190
|
+
};
|
|
191
|
+
this.maxPreparedStatements = options.maxPreparedStatements || 16000;
|
|
192
|
+
this.jsonStrings = options.jsonStrings || false;
|
|
193
|
+
this.gracefulEnd = options.gracefulEnd || false;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
static mergeFlags(default_flags, user_flags) {
|
|
197
|
+
let flags = 0x0,
|
|
198
|
+
i;
|
|
199
|
+
if (!Array.isArray(user_flags)) {
|
|
200
|
+
user_flags = String(user_flags || '')
|
|
201
|
+
.toUpperCase()
|
|
202
|
+
.split(/\s*,+\s*/);
|
|
203
|
+
}
|
|
204
|
+
// add default flags unless "blacklisted"
|
|
205
|
+
for (i in default_flags) {
|
|
206
|
+
if (user_flags.indexOf(`-${default_flags[i]}`) >= 0) {
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
flags |= ClientConstants[default_flags[i]] || 0x0;
|
|
210
|
+
}
|
|
211
|
+
// add user flags unless already already added
|
|
212
|
+
for (i in user_flags) {
|
|
213
|
+
if (user_flags[i][0] === '-') {
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (default_flags.indexOf(user_flags[i]) >= 0) {
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
flags |= ClientConstants[user_flags[i]] || 0x0;
|
|
220
|
+
}
|
|
221
|
+
return flags;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
static getDefaultFlags(options) {
|
|
225
|
+
const defaultFlags = [
|
|
226
|
+
'LONG_PASSWORD',
|
|
227
|
+
'FOUND_ROWS',
|
|
228
|
+
'LONG_FLAG',
|
|
229
|
+
'CONNECT_WITH_DB',
|
|
230
|
+
'ODBC',
|
|
231
|
+
'LOCAL_FILES',
|
|
232
|
+
'IGNORE_SPACE',
|
|
233
|
+
'PROTOCOL_41',
|
|
234
|
+
'IGNORE_SIGPIPE',
|
|
235
|
+
'TRANSACTIONS',
|
|
236
|
+
'RESERVED',
|
|
237
|
+
'SECURE_CONNECTION',
|
|
238
|
+
'MULTI_RESULTS',
|
|
239
|
+
'TRANSACTIONS',
|
|
240
|
+
'SESSION_TRACK',
|
|
241
|
+
'CONNECT_ATTRS',
|
|
242
|
+
];
|
|
243
|
+
if (options && options.multipleStatements) {
|
|
244
|
+
defaultFlags.push('MULTI_STATEMENTS');
|
|
245
|
+
}
|
|
246
|
+
defaultFlags.push('PLUGIN_AUTH');
|
|
247
|
+
defaultFlags.push('PLUGIN_AUTH_LENENC_CLIENT_DATA');
|
|
248
|
+
|
|
249
|
+
return defaultFlags;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
static getCharsetNumber(charset) {
|
|
253
|
+
const num = Charsets[charset.toUpperCase()];
|
|
254
|
+
if (num === undefined) {
|
|
255
|
+
throw new TypeError(`Unknown charset '${charset}'`);
|
|
256
|
+
}
|
|
257
|
+
return num;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
static getSSLProfile(name) {
|
|
261
|
+
if (!SSLProfiles) {
|
|
262
|
+
SSLProfiles = require('./constants/ssl_profiles.js');
|
|
263
|
+
}
|
|
264
|
+
const ssl = SSLProfiles[name];
|
|
265
|
+
if (ssl === undefined) {
|
|
266
|
+
throw new TypeError(`Unknown SSL profile '${name}'`);
|
|
267
|
+
}
|
|
268
|
+
return ssl;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
static parseUrl(url) {
|
|
272
|
+
const parsedUrl = new URL(url);
|
|
273
|
+
const options = {
|
|
274
|
+
host: decodeURIComponent(parsedUrl.hostname),
|
|
275
|
+
port: parseInt(parsedUrl.port, 10),
|
|
276
|
+
database: decodeURIComponent(parsedUrl.pathname.slice(1)),
|
|
277
|
+
user: decodeURIComponent(parsedUrl.username),
|
|
278
|
+
password: decodeURIComponent(parsedUrl.password),
|
|
279
|
+
};
|
|
280
|
+
parsedUrl.searchParams.forEach((value, key) => {
|
|
281
|
+
try {
|
|
282
|
+
// Try to parse this as a JSON expression first
|
|
283
|
+
options[key] = JSON.parse(value);
|
|
284
|
+
} catch {
|
|
285
|
+
// Otherwise assume it is a plain string
|
|
286
|
+
options[key] = value;
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
return options;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
module.exports = ConnectionConfig;
|