feat: add sqlstring and supports-color modules
- Introduced sqlstring module for SQL escape and formatting. - Added supports-color module to detect terminal color support. - Created dashboard and login views with Bootstrap styling. - Implemented user schema in SQL with mock data for testing.
This commit is contained in:
111
backend/node_modules/mysql2/lib/commands/auth_switch.js
generated
vendored
Normal file
111
backend/node_modules/mysql2/lib/commands/auth_switch.js
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
// This file was modified by Oracle on July 5, 2021.
|
||||
// Errors generated by asynchronous authentication plugins are now being
|
||||
// handled and subsequently emitted at the command level.
|
||||
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
|
||||
|
||||
'use strict';
|
||||
|
||||
const Packets = require('../packets/index.js');
|
||||
const sha256_password = require('../auth_plugins/sha256_password');
|
||||
const caching_sha2_password = require('../auth_plugins/caching_sha2_password.js');
|
||||
const mysql_native_password = require('../auth_plugins/mysql_native_password.js');
|
||||
const mysql_clear_password = require('../auth_plugins/mysql_clear_password.js');
|
||||
|
||||
const standardAuthPlugins = {
|
||||
sha256_password: sha256_password({}),
|
||||
caching_sha2_password: caching_sha2_password({}),
|
||||
mysql_native_password: mysql_native_password({}),
|
||||
mysql_clear_password: mysql_clear_password({}),
|
||||
};
|
||||
|
||||
function warnLegacyAuthSwitch() {
|
||||
console.warn(
|
||||
'WARNING! authSwitchHandler api is deprecated, please use new authPlugins api'
|
||||
);
|
||||
}
|
||||
|
||||
function authSwitchPluginError(error, command) {
|
||||
// Authentication errors are fatal
|
||||
error.code = 'AUTH_SWITCH_PLUGIN_ERROR';
|
||||
error.fatal = true;
|
||||
|
||||
command.emit('error', error);
|
||||
}
|
||||
|
||||
function authSwitchRequest(packet, connection, command) {
|
||||
const { pluginName, pluginData } =
|
||||
Packets.AuthSwitchRequest.fromPacket(packet);
|
||||
let authPlugin =
|
||||
connection.config.authPlugins && connection.config.authPlugins[pluginName];
|
||||
|
||||
// legacy plugin api don't allow to override mysql_native_password
|
||||
// if pluginName is mysql_native_password it's using standard auth4.1 auth
|
||||
if (
|
||||
connection.config.authSwitchHandler &&
|
||||
pluginName !== 'mysql_native_password'
|
||||
) {
|
||||
const legacySwitchHandler = connection.config.authSwitchHandler;
|
||||
warnLegacyAuthSwitch();
|
||||
legacySwitchHandler({ pluginName, pluginData }, (err, data) => {
|
||||
if (err) {
|
||||
return authSwitchPluginError(err, command);
|
||||
}
|
||||
connection.writePacket(new Packets.AuthSwitchResponse(data).toPacket());
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (!authPlugin) {
|
||||
authPlugin = standardAuthPlugins[pluginName];
|
||||
}
|
||||
if (!authPlugin) {
|
||||
throw new Error(
|
||||
`Server requests authentication using unknown plugin ${pluginName}. See ${'TODO: add plugins doco here'} on how to configure or author authentication plugins.`
|
||||
);
|
||||
}
|
||||
connection._authPlugin = authPlugin({ connection, command });
|
||||
Promise.resolve(connection._authPlugin(pluginData))
|
||||
.then((data) => {
|
||||
if (data) {
|
||||
connection.writePacket(new Packets.AuthSwitchResponse(data).toPacket());
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
authSwitchPluginError(err, command);
|
||||
});
|
||||
}
|
||||
|
||||
function authSwitchRequestMoreData(packet, connection, command) {
|
||||
const { data } = Packets.AuthSwitchRequestMoreData.fromPacket(packet);
|
||||
|
||||
if (connection.config.authSwitchHandler) {
|
||||
const legacySwitchHandler = connection.config.authSwitchHandler;
|
||||
warnLegacyAuthSwitch();
|
||||
legacySwitchHandler({ pluginData: data }, (err, data) => {
|
||||
if (err) {
|
||||
return authSwitchPluginError(err, command);
|
||||
}
|
||||
connection.writePacket(new Packets.AuthSwitchResponse(data).toPacket());
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (!connection._authPlugin) {
|
||||
throw new Error(
|
||||
'AuthPluginMoreData received but no auth plugin instance found'
|
||||
);
|
||||
}
|
||||
Promise.resolve(connection._authPlugin(data))
|
||||
.then((data) => {
|
||||
if (data) {
|
||||
connection.writePacket(new Packets.AuthSwitchResponse(data).toPacket());
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
authSwitchPluginError(err, command);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
authSwitchRequest,
|
||||
authSwitchRequestMoreData,
|
||||
};
|
109
backend/node_modules/mysql2/lib/commands/binlog_dump.js
generated
vendored
Normal file
109
backend/node_modules/mysql2/lib/commands/binlog_dump.js
generated
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
'use strict';
|
||||
|
||||
const Command = require('./command');
|
||||
const Packets = require('../packets');
|
||||
|
||||
const eventParsers = [];
|
||||
|
||||
class BinlogEventHeader {
|
||||
constructor(packet) {
|
||||
this.timestamp = packet.readInt32();
|
||||
this.eventType = packet.readInt8();
|
||||
this.serverId = packet.readInt32();
|
||||
this.eventSize = packet.readInt32();
|
||||
this.logPos = packet.readInt32();
|
||||
this.flags = packet.readInt16();
|
||||
}
|
||||
}
|
||||
|
||||
class BinlogDump extends Command {
|
||||
constructor(opts) {
|
||||
super();
|
||||
// this.onResult = callback;
|
||||
this.opts = opts;
|
||||
}
|
||||
|
||||
start(packet, connection) {
|
||||
const newPacket = new Packets.BinlogDump(this.opts);
|
||||
connection.writePacket(newPacket.toPacket(1));
|
||||
return BinlogDump.prototype.binlogData;
|
||||
}
|
||||
|
||||
binlogData(packet) {
|
||||
// ok - continue consuming events
|
||||
// error - error
|
||||
// eof - end of binlog
|
||||
if (packet.isEOF()) {
|
||||
this.emit('eof');
|
||||
return null;
|
||||
}
|
||||
// binlog event header
|
||||
packet.readInt8();
|
||||
const header = new BinlogEventHeader(packet);
|
||||
const EventParser = eventParsers[header.eventType];
|
||||
let event;
|
||||
if (EventParser) {
|
||||
event = new EventParser(packet);
|
||||
} else {
|
||||
event = {
|
||||
name: 'UNKNOWN',
|
||||
};
|
||||
}
|
||||
event.header = header;
|
||||
this.emit('event', event);
|
||||
return BinlogDump.prototype.binlogData;
|
||||
}
|
||||
}
|
||||
|
||||
class RotateEvent {
|
||||
constructor(packet) {
|
||||
this.pposition = packet.readInt32();
|
||||
// TODO: read uint64 here
|
||||
packet.readInt32(); // positionDword2
|
||||
this.nextBinlog = packet.readString();
|
||||
this.name = 'RotateEvent';
|
||||
}
|
||||
}
|
||||
|
||||
class FormatDescriptionEvent {
|
||||
constructor(packet) {
|
||||
this.binlogVersion = packet.readInt16();
|
||||
this.serverVersion = packet.readString(50).replace(/\u0000.*/, ''); // eslint-disable-line no-control-regex
|
||||
this.createTimestamp = packet.readInt32();
|
||||
this.eventHeaderLength = packet.readInt8(); // should be 19
|
||||
this.eventsLength = packet.readBuffer();
|
||||
this.name = 'FormatDescriptionEvent';
|
||||
}
|
||||
}
|
||||
|
||||
class QueryEvent {
|
||||
constructor(packet) {
|
||||
const parseStatusVars = require('../packets/binlog_query_statusvars.js');
|
||||
this.slaveProxyId = packet.readInt32();
|
||||
this.executionTime = packet.readInt32();
|
||||
const schemaLength = packet.readInt8();
|
||||
this.errorCode = packet.readInt16();
|
||||
const statusVarsLength = packet.readInt16();
|
||||
const statusVars = packet.readBuffer(statusVarsLength);
|
||||
this.schema = packet.readString(schemaLength);
|
||||
packet.readInt8(); // should be zero
|
||||
this.statusVars = parseStatusVars(statusVars);
|
||||
this.query = packet.readString();
|
||||
this.name = 'QueryEvent';
|
||||
}
|
||||
}
|
||||
|
||||
class XidEvent {
|
||||
constructor(packet) {
|
||||
this.binlogVersion = packet.readInt16();
|
||||
this.xid = packet.readInt64();
|
||||
this.name = 'XidEvent';
|
||||
}
|
||||
}
|
||||
|
||||
eventParsers[2] = QueryEvent;
|
||||
eventParsers[4] = RotateEvent;
|
||||
eventParsers[15] = FormatDescriptionEvent;
|
||||
eventParsers[16] = XidEvent;
|
||||
|
||||
module.exports = BinlogDump;
|
68
backend/node_modules/mysql2/lib/commands/change_user.js
generated
vendored
Normal file
68
backend/node_modules/mysql2/lib/commands/change_user.js
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
// This file was modified by Oracle on September 21, 2021.
|
||||
// The changes involve saving additional authentication factor passwords
|
||||
// in the command scope and enabling multi-factor authentication in the
|
||||
// client-side when the server supports it.
|
||||
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
|
||||
|
||||
'use strict';
|
||||
|
||||
const Command = require('./command.js');
|
||||
const Packets = require('../packets/index.js');
|
||||
const ClientConstants = require('../constants/client');
|
||||
const ClientHandshake = require('./client_handshake.js');
|
||||
const CharsetToEncoding = require('../constants/charset_encodings.js');
|
||||
|
||||
class ChangeUser extends Command {
|
||||
constructor(options, callback) {
|
||||
super();
|
||||
this.onResult = callback;
|
||||
this.user = options.user;
|
||||
this.password = options.password;
|
||||
// "password1" is an alias of "password"
|
||||
this.password1 = options.password;
|
||||
this.password2 = options.password2;
|
||||
this.password3 = options.password3;
|
||||
this.database = options.database;
|
||||
this.passwordSha1 = options.passwordSha1;
|
||||
this.charsetNumber = options.charsetNumber;
|
||||
this.currentConfig = options.currentConfig;
|
||||
this.authenticationFactor = 0;
|
||||
}
|
||||
start(packet, connection) {
|
||||
const newPacket = new Packets.ChangeUser({
|
||||
flags: connection.config.clientFlags,
|
||||
user: this.user,
|
||||
database: this.database,
|
||||
charsetNumber: this.charsetNumber,
|
||||
password: this.password,
|
||||
passwordSha1: this.passwordSha1,
|
||||
authPluginData1: connection._handshakePacket.authPluginData1,
|
||||
authPluginData2: connection._handshakePacket.authPluginData2,
|
||||
});
|
||||
this.currentConfig.user = this.user;
|
||||
this.currentConfig.password = this.password;
|
||||
this.currentConfig.database = this.database;
|
||||
this.currentConfig.charsetNumber = this.charsetNumber;
|
||||
connection.clientEncoding = CharsetToEncoding[this.charsetNumber];
|
||||
// clear prepared statements cache as all statements become invalid after changeUser
|
||||
connection._statements.clear();
|
||||
connection.writePacket(newPacket.toPacket());
|
||||
// check if the server supports multi-factor authentication
|
||||
const multiFactorAuthentication =
|
||||
connection.serverCapabilityFlags &
|
||||
ClientConstants.MULTI_FACTOR_AUTHENTICATION;
|
||||
if (multiFactorAuthentication) {
|
||||
// if the server supports multi-factor authentication, we enable it in
|
||||
// the client
|
||||
this.authenticationFactor = 1;
|
||||
}
|
||||
return ChangeUser.prototype.handshakeResult;
|
||||
}
|
||||
}
|
||||
|
||||
ChangeUser.prototype.handshakeResult =
|
||||
ClientHandshake.prototype.handshakeResult;
|
||||
ChangeUser.prototype.calculateNativePasswordAuthToken =
|
||||
ClientHandshake.prototype.calculateNativePasswordAuthToken;
|
||||
|
||||
module.exports = ChangeUser;
|
241
backend/node_modules/mysql2/lib/commands/client_handshake.js
generated
vendored
Normal file
241
backend/node_modules/mysql2/lib/commands/client_handshake.js
generated
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
// This file was modified by Oracle on June 17, 2021.
|
||||
// Handshake errors are now maked as fatal and the corresponding events are
|
||||
// emitted in the command instance itself.
|
||||
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
|
||||
|
||||
// This file was modified by Oracle on September 21, 2021.
|
||||
// Handshake workflow now supports additional authentication factors requested
|
||||
// by the server.
|
||||
// Modifications copyright (c) 2021, Oracle and/or its affiliates.
|
||||
|
||||
'use strict';
|
||||
|
||||
const Command = require('./command.js');
|
||||
const Packets = require('../packets/index.js');
|
||||
const ClientConstants = require('../constants/client.js');
|
||||
const CharsetToEncoding = require('../constants/charset_encodings.js');
|
||||
const auth41 = require('../auth_41.js');
|
||||
|
||||
function flagNames(flags) {
|
||||
const res = [];
|
||||
for (const c in ClientConstants) {
|
||||
if (flags & ClientConstants[c]) {
|
||||
res.push(c.replace(/_/g, ' ').toLowerCase());
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
class ClientHandshake extends Command {
|
||||
constructor(clientFlags) {
|
||||
super();
|
||||
this.handshake = null;
|
||||
this.clientFlags = clientFlags;
|
||||
this.authenticationFactor = 0;
|
||||
}
|
||||
|
||||
start() {
|
||||
return ClientHandshake.prototype.handshakeInit;
|
||||
}
|
||||
|
||||
sendSSLRequest(connection) {
|
||||
const sslRequest = new Packets.SSLRequest(
|
||||
this.clientFlags,
|
||||
connection.config.charsetNumber
|
||||
);
|
||||
connection.writePacket(sslRequest.toPacket());
|
||||
}
|
||||
|
||||
sendCredentials(connection) {
|
||||
if (connection.config.debug) {
|
||||
// eslint-disable-next-line
|
||||
console.log(
|
||||
'Sending handshake packet: flags:%d=(%s)',
|
||||
this.clientFlags,
|
||||
flagNames(this.clientFlags).join(', ')
|
||||
);
|
||||
}
|
||||
this.user = connection.config.user;
|
||||
this.password = connection.config.password;
|
||||
// "password1" is an alias to the original "password" value
|
||||
// to make it easier to integrate multi-factor authentication
|
||||
this.password1 = connection.config.password;
|
||||
// "password2" and "password3" are the 2nd and 3rd factor authentication
|
||||
// passwords, which can be undefined depending on the authentication
|
||||
// plugin being used
|
||||
this.password2 = connection.config.password2;
|
||||
this.password3 = connection.config.password3;
|
||||
this.passwordSha1 = connection.config.passwordSha1;
|
||||
this.database = connection.config.database;
|
||||
this.authPluginName = this.handshake.authPluginName;
|
||||
const handshakeResponse = new Packets.HandshakeResponse({
|
||||
flags: this.clientFlags,
|
||||
user: this.user,
|
||||
database: this.database,
|
||||
password: this.password,
|
||||
passwordSha1: this.passwordSha1,
|
||||
charsetNumber: connection.config.charsetNumber,
|
||||
authPluginData1: this.handshake.authPluginData1,
|
||||
authPluginData2: this.handshake.authPluginData2,
|
||||
compress: connection.config.compress,
|
||||
connectAttributes: connection.config.connectAttributes,
|
||||
});
|
||||
connection.writePacket(handshakeResponse.toPacket());
|
||||
}
|
||||
|
||||
calculateNativePasswordAuthToken(authPluginData) {
|
||||
// TODO: dont split into authPluginData1 and authPluginData2, instead join when 1 & 2 received
|
||||
const authPluginData1 = authPluginData.slice(0, 8);
|
||||
const authPluginData2 = authPluginData.slice(8, 20);
|
||||
let authToken;
|
||||
if (this.passwordSha1) {
|
||||
authToken = auth41.calculateTokenFromPasswordSha(
|
||||
this.passwordSha1,
|
||||
authPluginData1,
|
||||
authPluginData2
|
||||
);
|
||||
} else {
|
||||
authToken = auth41.calculateToken(
|
||||
this.password,
|
||||
authPluginData1,
|
||||
authPluginData2
|
||||
);
|
||||
}
|
||||
return authToken;
|
||||
}
|
||||
|
||||
handshakeInit(helloPacket, connection) {
|
||||
this.on('error', (e) => {
|
||||
connection._fatalError = e;
|
||||
connection._protocolError = e;
|
||||
});
|
||||
this.handshake = Packets.Handshake.fromPacket(helloPacket);
|
||||
if (connection.config.debug) {
|
||||
// eslint-disable-next-line
|
||||
console.log(
|
||||
'Server hello packet: capability flags:%d=(%s)',
|
||||
this.handshake.capabilityFlags,
|
||||
flagNames(this.handshake.capabilityFlags).join(', ')
|
||||
);
|
||||
}
|
||||
connection.serverCapabilityFlags = this.handshake.capabilityFlags;
|
||||
connection.serverEncoding = CharsetToEncoding[this.handshake.characterSet];
|
||||
connection.connectionId = this.handshake.connectionId;
|
||||
const serverSSLSupport =
|
||||
this.handshake.capabilityFlags & ClientConstants.SSL;
|
||||
// multi factor authentication is enabled with the
|
||||
// "MULTI_FACTOR_AUTHENTICATION" capability and should only be used if it
|
||||
// is supported by the server
|
||||
const multiFactorAuthentication =
|
||||
this.handshake.capabilityFlags &
|
||||
ClientConstants.MULTI_FACTOR_AUTHENTICATION;
|
||||
this.clientFlags = this.clientFlags | multiFactorAuthentication;
|
||||
// use compression only if requested by client and supported by server
|
||||
connection.config.compress =
|
||||
connection.config.compress &&
|
||||
this.handshake.capabilityFlags & ClientConstants.COMPRESS;
|
||||
this.clientFlags = this.clientFlags | connection.config.compress;
|
||||
if (connection.config.ssl) {
|
||||
// client requires SSL but server does not support it
|
||||
if (!serverSSLSupport) {
|
||||
const err = new Error('Server does not support secure connection');
|
||||
err.code = 'HANDSHAKE_NO_SSL_SUPPORT';
|
||||
err.fatal = true;
|
||||
this.emit('error', err);
|
||||
return false;
|
||||
}
|
||||
// send ssl upgrade request and immediately upgrade connection to secure
|
||||
this.clientFlags |= ClientConstants.SSL;
|
||||
this.sendSSLRequest(connection);
|
||||
connection.startTLS((err) => {
|
||||
// after connection is secure
|
||||
if (err) {
|
||||
// SSL negotiation error are fatal
|
||||
err.code = 'HANDSHAKE_SSL_ERROR';
|
||||
err.fatal = true;
|
||||
this.emit('error', err);
|
||||
return;
|
||||
}
|
||||
// rest of communication is encrypted
|
||||
this.sendCredentials(connection);
|
||||
});
|
||||
} else {
|
||||
this.sendCredentials(connection);
|
||||
}
|
||||
if (multiFactorAuthentication) {
|
||||
// if the server supports multi-factor authentication, we enable it in
|
||||
// the client
|
||||
this.authenticationFactor = 1;
|
||||
}
|
||||
return ClientHandshake.prototype.handshakeResult;
|
||||
}
|
||||
|
||||
handshakeResult(packet, connection) {
|
||||
const marker = packet.peekByte();
|
||||
// packet can be OK_Packet, ERR_Packet, AuthSwitchRequest, AuthNextFactor
|
||||
// or AuthMoreData
|
||||
if (marker === 0xfe || marker === 1 || marker === 0x02) {
|
||||
const authSwitch = require('./auth_switch');
|
||||
try {
|
||||
if (marker === 1) {
|
||||
authSwitch.authSwitchRequestMoreData(packet, connection, this);
|
||||
} else {
|
||||
// if authenticationFactor === 0, it means the server does not support
|
||||
// the multi-factor authentication capability
|
||||
if (this.authenticationFactor !== 0) {
|
||||
// if we are past the first authentication factor, we should use the
|
||||
// corresponding password (if there is one)
|
||||
connection.config.password =
|
||||
this[`password${this.authenticationFactor}`];
|
||||
// update the current authentication factor
|
||||
this.authenticationFactor += 1;
|
||||
}
|
||||
// if marker === 0x02, it means it is an AuthNextFactor packet,
|
||||
// which is similar in structure to an AuthSwitchRequest packet,
|
||||
// so, we can use it directly
|
||||
authSwitch.authSwitchRequest(packet, connection, this);
|
||||
}
|
||||
return ClientHandshake.prototype.handshakeResult;
|
||||
} catch (err) {
|
||||
// Authentication errors are fatal
|
||||
err.code = 'AUTH_SWITCH_PLUGIN_ERROR';
|
||||
err.fatal = true;
|
||||
|
||||
if (this.onResult) {
|
||||
this.onResult(err);
|
||||
} else {
|
||||
this.emit('error', err);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (marker !== 0) {
|
||||
const err = new Error('Unexpected packet during handshake phase');
|
||||
// Unknown handshake errors are fatal
|
||||
err.code = 'HANDSHAKE_UNKNOWN_ERROR';
|
||||
err.fatal = true;
|
||||
|
||||
if (this.onResult) {
|
||||
this.onResult(err);
|
||||
} else {
|
||||
this.emit('error', err);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// this should be called from ClientHandshake command only
|
||||
// and skipped when called from ChangeUser command
|
||||
if (!connection.authorized) {
|
||||
connection.authorized = true;
|
||||
if (connection.config.compress) {
|
||||
const enableCompression =
|
||||
require('../compressed_protocol.js').enableCompression;
|
||||
enableCompression(connection);
|
||||
}
|
||||
}
|
||||
if (this.onResult) {
|
||||
this.onResult(null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
module.exports = ClientHandshake;
|
18
backend/node_modules/mysql2/lib/commands/close_statement.js
generated
vendored
Normal file
18
backend/node_modules/mysql2/lib/commands/close_statement.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
const Command = require('./command');
|
||||
const Packets = require('../packets/index.js');
|
||||
|
||||
class CloseStatement extends Command {
|
||||
constructor(id) {
|
||||
super();
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
start(packet, connection) {
|
||||
connection.writePacket(new Packets.CloseStatement(this.id).toPacket(1));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CloseStatement;
|
54
backend/node_modules/mysql2/lib/commands/command.js
generated
vendored
Normal file
54
backend/node_modules/mysql2/lib/commands/command.js
generated
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
'use strict';
|
||||
|
||||
const EventEmitter = require('events').EventEmitter;
|
||||
const Timers = require('timers');
|
||||
|
||||
class Command extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.next = null;
|
||||
}
|
||||
|
||||
// slow. debug only
|
||||
stateName() {
|
||||
const state = this.next;
|
||||
for (const i in this) {
|
||||
if (this[i] === state && i !== 'next') {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 'unknown name';
|
||||
}
|
||||
|
||||
execute(packet, connection) {
|
||||
if (!this.next) {
|
||||
this.next = this.start;
|
||||
connection._resetSequenceId();
|
||||
}
|
||||
if (packet && packet.isError()) {
|
||||
const err = packet.asError(connection.clientEncoding);
|
||||
err.sql = this.sql || this.query;
|
||||
if (this.queryTimeout) {
|
||||
Timers.clearTimeout(this.queryTimeout);
|
||||
this.queryTimeout = null;
|
||||
}
|
||||
if (this.onResult) {
|
||||
this.onResult(err);
|
||||
this.emit('end');
|
||||
} else {
|
||||
this.emit('error', err);
|
||||
this.emit('end');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// TODO: don't return anything from execute, it's ugly and error-prone. Listen for 'end' event in connection
|
||||
this.next = this.next(packet, connection);
|
||||
if (this.next) {
|
||||
return false;
|
||||
}
|
||||
this.emit('end');
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Command;
|
112
backend/node_modules/mysql2/lib/commands/execute.js
generated
vendored
Normal file
112
backend/node_modules/mysql2/lib/commands/execute.js
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
'use strict';
|
||||
|
||||
const Command = require('./command.js');
|
||||
const Query = require('./query.js');
|
||||
const Packets = require('../packets/index.js');
|
||||
|
||||
const getBinaryParser = require('../parsers/binary_parser.js');
|
||||
const getStaticBinaryParser = require('../parsers/static_binary_parser.js');
|
||||
|
||||
class Execute extends Command {
|
||||
constructor(options, callback) {
|
||||
super();
|
||||
this.statement = options.statement;
|
||||
this.sql = options.sql;
|
||||
this.values = options.values;
|
||||
this.onResult = callback;
|
||||
this.parameters = options.values;
|
||||
this.insertId = 0;
|
||||
this.timeout = options.timeout;
|
||||
this.queryTimeout = null;
|
||||
this._rows = [];
|
||||
this._fields = [];
|
||||
this._result = [];
|
||||
this._fieldCount = 0;
|
||||
this._rowParser = null;
|
||||
this._executeOptions = options;
|
||||
this._resultIndex = 0;
|
||||
this._localStream = null;
|
||||
this._unpipeStream = function () {};
|
||||
this._streamFactory = options.infileStreamFactory;
|
||||
this._connection = null;
|
||||
}
|
||||
|
||||
buildParserFromFields(fields, connection) {
|
||||
if (this.options.disableEval) {
|
||||
return getStaticBinaryParser(fields, this.options, connection.config);
|
||||
}
|
||||
|
||||
return getBinaryParser(fields, this.options, connection.config);
|
||||
}
|
||||
|
||||
start(packet, connection) {
|
||||
this._connection = connection;
|
||||
this.options = Object.assign({}, connection.config, this._executeOptions);
|
||||
this._setTimeout();
|
||||
const executePacket = new Packets.Execute(
|
||||
this.statement.id,
|
||||
this.parameters,
|
||||
connection.config.charsetNumber,
|
||||
connection.config.timezone
|
||||
);
|
||||
//For reasons why this try-catch is here, please see
|
||||
// https://github.com/sidorares/node-mysql2/pull/689
|
||||
//For additional discussion, see
|
||||
// 1. https://github.com/sidorares/node-mysql2/issues/493
|
||||
// 2. https://github.com/sidorares/node-mysql2/issues/187
|
||||
// 3. https://github.com/sidorares/node-mysql2/issues/480
|
||||
try {
|
||||
connection.writePacket(executePacket.toPacket(1));
|
||||
} catch (error) {
|
||||
this.onResult(error);
|
||||
}
|
||||
return Execute.prototype.resultsetHeader;
|
||||
}
|
||||
|
||||
readField(packet, connection) {
|
||||
let fields;
|
||||
// disabling for now, but would be great to find reliable way to parse fields only once
|
||||
// fields reported by prepare can be empty at all or just incorrect - see #169
|
||||
//
|
||||
// perfomance optimisation: if we already have this field parsed in statement header, use one from header
|
||||
// const field = this.statement.columns.length == this._fieldCount ?
|
||||
// this.statement.columns[this._receivedFieldsCount] : new Packets.ColumnDefinition(packet);
|
||||
const field = new Packets.ColumnDefinition(
|
||||
packet,
|
||||
connection.clientEncoding
|
||||
);
|
||||
this._receivedFieldsCount++;
|
||||
this._fields[this._resultIndex].push(field);
|
||||
if (this._receivedFieldsCount === this._fieldCount) {
|
||||
fields = this._fields[this._resultIndex];
|
||||
this.emit('fields', fields, this._resultIndex);
|
||||
return Execute.prototype.fieldsEOF;
|
||||
}
|
||||
return Execute.prototype.readField;
|
||||
}
|
||||
|
||||
fieldsEOF(packet, connection) {
|
||||
// check EOF
|
||||
if (!packet.isEOF()) {
|
||||
return connection.protocolError('Expected EOF packet');
|
||||
}
|
||||
this._rowParser = new (this.buildParserFromFields(
|
||||
this._fields[this._resultIndex],
|
||||
connection
|
||||
))();
|
||||
return Execute.prototype.row;
|
||||
}
|
||||
}
|
||||
|
||||
Execute.prototype.done = Query.prototype.done;
|
||||
Execute.prototype.doneInsert = Query.prototype.doneInsert;
|
||||
Execute.prototype.resultsetHeader = Query.prototype.resultsetHeader;
|
||||
Execute.prototype._findOrCreateReadStream =
|
||||
Query.prototype._findOrCreateReadStream;
|
||||
Execute.prototype._streamLocalInfile = Query.prototype._streamLocalInfile;
|
||||
Execute.prototype._setTimeout = Query.prototype._setTimeout;
|
||||
Execute.prototype._handleTimeoutError = Query.prototype._handleTimeoutError;
|
||||
Execute.prototype.row = Query.prototype.row;
|
||||
Execute.prototype.stream = Query.prototype.stream;
|
||||
|
||||
module.exports = Execute;
|
27
backend/node_modules/mysql2/lib/commands/index.js
generated
vendored
Normal file
27
backend/node_modules/mysql2/lib/commands/index.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
const ClientHandshake = require('./client_handshake.js');
|
||||
const ServerHandshake = require('./server_handshake.js');
|
||||
const Query = require('./query.js');
|
||||
const Prepare = require('./prepare.js');
|
||||
const CloseStatement = require('./close_statement.js');
|
||||
const Execute = require('./execute.js');
|
||||
const Ping = require('./ping.js');
|
||||
const RegisterSlave = require('./register_slave.js');
|
||||
const BinlogDump = require('./binlog_dump.js');
|
||||
const ChangeUser = require('./change_user.js');
|
||||
const Quit = require('./quit.js');
|
||||
|
||||
module.exports = {
|
||||
ClientHandshake,
|
||||
ServerHandshake,
|
||||
Query,
|
||||
Prepare,
|
||||
CloseStatement,
|
||||
Execute,
|
||||
Ping,
|
||||
RegisterSlave,
|
||||
BinlogDump,
|
||||
ChangeUser,
|
||||
Quit,
|
||||
};
|
36
backend/node_modules/mysql2/lib/commands/ping.js
generated
vendored
Normal file
36
backend/node_modules/mysql2/lib/commands/ping.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
'use strict';
|
||||
|
||||
const Command = require('./command');
|
||||
const CommandCode = require('../constants/commands');
|
||||
const Packet = require('../packets/packet');
|
||||
|
||||
// TODO: time statistics?
|
||||
// usefull for queue size and network latency monitoring
|
||||
// store created,sent,reply timestamps
|
||||
class Ping extends Command {
|
||||
constructor(callback) {
|
||||
super();
|
||||
this.onResult = callback;
|
||||
}
|
||||
|
||||
start(packet, connection) {
|
||||
const ping = new Packet(
|
||||
0,
|
||||
Buffer.from([1, 0, 0, 0, CommandCode.PING]),
|
||||
0,
|
||||
5
|
||||
);
|
||||
connection.writePacket(ping);
|
||||
return Ping.prototype.pingResponse;
|
||||
}
|
||||
|
||||
pingResponse() {
|
||||
// TODO: check it's OK packet. error check already done in caller
|
||||
if (this.onResult) {
|
||||
process.nextTick(this.onResult.bind(this));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Ping;
|
143
backend/node_modules/mysql2/lib/commands/prepare.js
generated
vendored
Normal file
143
backend/node_modules/mysql2/lib/commands/prepare.js
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
'use strict';
|
||||
|
||||
const Packets = require('../packets/index.js');
|
||||
const Command = require('./command.js');
|
||||
const CloseStatement = require('./close_statement.js');
|
||||
const Execute = require('./execute.js');
|
||||
|
||||
class PreparedStatementInfo {
|
||||
constructor(query, id, columns, parameters, connection) {
|
||||
this.query = query;
|
||||
this.id = id;
|
||||
this.columns = columns;
|
||||
this.parameters = parameters;
|
||||
this.rowParser = null;
|
||||
this._connection = connection;
|
||||
}
|
||||
|
||||
close() {
|
||||
return this._connection.addCommand(new CloseStatement(this.id));
|
||||
}
|
||||
|
||||
execute(parameters, callback) {
|
||||
if (typeof parameters === 'function') {
|
||||
callback = parameters;
|
||||
parameters = [];
|
||||
}
|
||||
return this._connection.addCommand(
|
||||
new Execute({ statement: this, values: parameters }, callback)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Prepare extends Command {
|
||||
constructor(options, callback) {
|
||||
super();
|
||||
this.query = options.sql;
|
||||
this.onResult = callback;
|
||||
this.id = 0;
|
||||
this.fieldCount = 0;
|
||||
this.parameterCount = 0;
|
||||
this.fields = [];
|
||||
this.parameterDefinitions = [];
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
start(packet, connection) {
|
||||
const Connection = connection.constructor;
|
||||
this.key = Connection.statementKey(this.options);
|
||||
const statement = connection._statements.get(this.key);
|
||||
if (statement) {
|
||||
if (this.onResult) {
|
||||
this.onResult(null, statement);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
const cmdPacket = new Packets.PrepareStatement(
|
||||
this.query,
|
||||
connection.config.charsetNumber,
|
||||
this.options.values
|
||||
);
|
||||
connection.writePacket(cmdPacket.toPacket(1));
|
||||
return Prepare.prototype.prepareHeader;
|
||||
}
|
||||
|
||||
prepareHeader(packet, connection) {
|
||||
const header = new Packets.PreparedStatementHeader(packet);
|
||||
this.id = header.id;
|
||||
this.fieldCount = header.fieldCount;
|
||||
this.parameterCount = header.parameterCount;
|
||||
if (this.parameterCount > 0) {
|
||||
return Prepare.prototype.readParameter;
|
||||
}
|
||||
if (this.fieldCount > 0) {
|
||||
return Prepare.prototype.readField;
|
||||
}
|
||||
return this.prepareDone(connection);
|
||||
}
|
||||
|
||||
readParameter(packet, connection) {
|
||||
// there might be scenarios when mysql server reports more parameters than
|
||||
// are actually present in the array of parameter definitions.
|
||||
// if EOF packet is received we switch to "read fields" state if there are
|
||||
// any fields reported by the server, otherwise we finish the command.
|
||||
if (packet.isEOF()) {
|
||||
if (this.fieldCount > 0) {
|
||||
return Prepare.prototype.readField;
|
||||
}
|
||||
return this.prepareDone(connection);
|
||||
}
|
||||
const def = new Packets.ColumnDefinition(packet, connection.clientEncoding);
|
||||
this.parameterDefinitions.push(def);
|
||||
if (this.parameterDefinitions.length === this.parameterCount) {
|
||||
return Prepare.prototype.parametersEOF;
|
||||
}
|
||||
return this.readParameter;
|
||||
}
|
||||
|
||||
readField(packet, connection) {
|
||||
if (packet.isEOF()) {
|
||||
return this.prepareDone(connection);
|
||||
}
|
||||
const def = new Packets.ColumnDefinition(packet, connection.clientEncoding);
|
||||
this.fields.push(def);
|
||||
if (this.fields.length === this.fieldCount) {
|
||||
return Prepare.prototype.fieldsEOF;
|
||||
}
|
||||
return Prepare.prototype.readField;
|
||||
}
|
||||
|
||||
parametersEOF(packet, connection) {
|
||||
if (!packet.isEOF()) {
|
||||
return connection.protocolError('Expected EOF packet after parameters');
|
||||
}
|
||||
if (this.fieldCount > 0) {
|
||||
return Prepare.prototype.readField;
|
||||
}
|
||||
return this.prepareDone(connection);
|
||||
}
|
||||
|
||||
fieldsEOF(packet, connection) {
|
||||
if (!packet.isEOF()) {
|
||||
return connection.protocolError('Expected EOF packet after fields');
|
||||
}
|
||||
return this.prepareDone(connection);
|
||||
}
|
||||
|
||||
prepareDone(connection) {
|
||||
const statement = new PreparedStatementInfo(
|
||||
this.query,
|
||||
this.id,
|
||||
this.fields,
|
||||
this.parameterDefinitions,
|
||||
connection
|
||||
);
|
||||
connection._statements.set(this.key, statement);
|
||||
if (this.onResult) {
|
||||
this.onResult(null, statement);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Prepare;
|
329
backend/node_modules/mysql2/lib/commands/query.js
generated
vendored
Normal file
329
backend/node_modules/mysql2/lib/commands/query.js
generated
vendored
Normal file
@@ -0,0 +1,329 @@
|
||||
'use strict';
|
||||
|
||||
const process = require('process');
|
||||
const Timers = require('timers');
|
||||
|
||||
const Readable = require('stream').Readable;
|
||||
|
||||
const Command = require('./command.js');
|
||||
const Packets = require('../packets/index.js');
|
||||
const getTextParser = require('../parsers/text_parser.js');
|
||||
const staticParser = require('../parsers/static_text_parser.js');
|
||||
const ServerStatus = require('../constants/server_status.js');
|
||||
|
||||
const EmptyPacket = new Packets.Packet(0, Buffer.allocUnsafe(4), 0, 4);
|
||||
|
||||
// http://dev.mysql.com/doc/internals/en/com-query.html
|
||||
class Query extends Command {
|
||||
constructor(options, callback) {
|
||||
super();
|
||||
this.sql = options.sql;
|
||||
this.values = options.values;
|
||||
this._queryOptions = options;
|
||||
this.namedPlaceholders = options.namedPlaceholders || false;
|
||||
this.onResult = callback;
|
||||
this.timeout = options.timeout;
|
||||
this.queryTimeout = null;
|
||||
this._fieldCount = 0;
|
||||
this._rowParser = null;
|
||||
this._fields = [];
|
||||
this._rows = [];
|
||||
this._receivedFieldsCount = 0;
|
||||
this._resultIndex = 0;
|
||||
this._localStream = null;
|
||||
this._unpipeStream = function () {};
|
||||
this._streamFactory = options.infileStreamFactory;
|
||||
this._connection = null;
|
||||
}
|
||||
|
||||
then() {
|
||||
const err =
|
||||
"You have tried to call .then(), .catch(), or invoked await on the result of query that is not a promise, which is a programming error. Try calling con.promise().query(), or require('mysql2/promise') instead of 'mysql2' for a promise-compatible version of the query interface. To learn how to use async/await or Promises check out documentation at https://sidorares.github.io/node-mysql2/docs#using-promise-wrapper, or the mysql2 documentation at https://sidorares.github.io/node-mysql2/docs/documentation/promise-wrapper";
|
||||
// eslint-disable-next-line
|
||||
console.log(err);
|
||||
throw new Error(err);
|
||||
}
|
||||
|
||||
/* eslint no-unused-vars: ["error", { "argsIgnorePattern": "^_" }] */
|
||||
start(_packet, connection) {
|
||||
if (connection.config.debug) {
|
||||
// eslint-disable-next-line
|
||||
console.log(' Sending query command: %s', this.sql);
|
||||
}
|
||||
this._connection = connection;
|
||||
this.options = Object.assign({}, connection.config, this._queryOptions);
|
||||
this._setTimeout();
|
||||
|
||||
const cmdPacket = new Packets.Query(
|
||||
this.sql,
|
||||
connection.config.charsetNumber
|
||||
);
|
||||
connection.writePacket(cmdPacket.toPacket(1));
|
||||
return Query.prototype.resultsetHeader;
|
||||
}
|
||||
|
||||
done() {
|
||||
this._unpipeStream();
|
||||
// if all ready timeout, return null directly
|
||||
if (this.timeout && !this.queryTimeout) {
|
||||
return null;
|
||||
}
|
||||
// else clear timer
|
||||
if (this.queryTimeout) {
|
||||
Timers.clearTimeout(this.queryTimeout);
|
||||
this.queryTimeout = null;
|
||||
}
|
||||
if (this.onResult) {
|
||||
let rows, fields;
|
||||
if (this._resultIndex === 0) {
|
||||
rows = this._rows[0];
|
||||
fields = this._fields[0];
|
||||
} else {
|
||||
rows = this._rows;
|
||||
fields = this._fields;
|
||||
}
|
||||
if (fields) {
|
||||
process.nextTick(() => {
|
||||
this.onResult(null, rows, fields);
|
||||
});
|
||||
} else {
|
||||
process.nextTick(() => {
|
||||
this.onResult(null, rows);
|
||||
});
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
doneInsert(rs) {
|
||||
if (this._localStreamError) {
|
||||
if (this.onResult) {
|
||||
this.onResult(this._localStreamError, rs);
|
||||
} else {
|
||||
this.emit('error', this._localStreamError);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
this._rows.push(rs);
|
||||
this._fields.push(void 0);
|
||||
this.emit('fields', void 0);
|
||||
this.emit('result', rs);
|
||||
if (rs.serverStatus & ServerStatus.SERVER_MORE_RESULTS_EXISTS) {
|
||||
this._resultIndex++;
|
||||
return this.resultsetHeader;
|
||||
}
|
||||
return this.done();
|
||||
}
|
||||
|
||||
resultsetHeader(packet, connection) {
|
||||
const rs = new Packets.ResultSetHeader(packet, connection);
|
||||
this._fieldCount = rs.fieldCount;
|
||||
if (connection.config.debug) {
|
||||
// eslint-disable-next-line
|
||||
console.log(
|
||||
` Resultset header received, expecting ${rs.fieldCount} column definition packets`
|
||||
);
|
||||
}
|
||||
if (this._fieldCount === 0) {
|
||||
return this.doneInsert(rs);
|
||||
}
|
||||
if (this._fieldCount === null) {
|
||||
return this._streamLocalInfile(connection, rs.infileName);
|
||||
}
|
||||
this._receivedFieldsCount = 0;
|
||||
this._rows.push([]);
|
||||
this._fields.push([]);
|
||||
return this.readField;
|
||||
}
|
||||
|
||||
_streamLocalInfile(connection, path) {
|
||||
if (this._streamFactory) {
|
||||
this._localStream = this._streamFactory(path);
|
||||
} else {
|
||||
this._localStreamError = new Error(
|
||||
`As a result of LOCAL INFILE command server wants to read ${path} file, but as of v2.0 you must provide streamFactory option returning ReadStream.`
|
||||
);
|
||||
connection.writePacket(EmptyPacket);
|
||||
return this.infileOk;
|
||||
}
|
||||
|
||||
const onConnectionError = () => {
|
||||
this._unpipeStream();
|
||||
};
|
||||
const onDrain = () => {
|
||||
this._localStream.resume();
|
||||
};
|
||||
const onPause = () => {
|
||||
this._localStream.pause();
|
||||
};
|
||||
const onData = function (data) {
|
||||
const dataWithHeader = Buffer.allocUnsafe(data.length + 4);
|
||||
data.copy(dataWithHeader, 4);
|
||||
connection.writePacket(
|
||||
new Packets.Packet(0, dataWithHeader, 0, dataWithHeader.length)
|
||||
);
|
||||
};
|
||||
const onEnd = () => {
|
||||
connection.removeListener('error', onConnectionError);
|
||||
connection.writePacket(EmptyPacket);
|
||||
};
|
||||
const onError = (err) => {
|
||||
this._localStreamError = err;
|
||||
connection.removeListener('error', onConnectionError);
|
||||
connection.writePacket(EmptyPacket);
|
||||
};
|
||||
this._unpipeStream = () => {
|
||||
connection.stream.removeListener('pause', onPause);
|
||||
connection.stream.removeListener('drain', onDrain);
|
||||
this._localStream.removeListener('data', onData);
|
||||
this._localStream.removeListener('end', onEnd);
|
||||
this._localStream.removeListener('error', onError);
|
||||
};
|
||||
connection.stream.on('pause', onPause);
|
||||
connection.stream.on('drain', onDrain);
|
||||
this._localStream.on('data', onData);
|
||||
this._localStream.on('end', onEnd);
|
||||
this._localStream.on('error', onError);
|
||||
connection.once('error', onConnectionError);
|
||||
return this.infileOk;
|
||||
}
|
||||
|
||||
readField(packet, connection) {
|
||||
this._receivedFieldsCount++;
|
||||
// Often there is much more data in the column definition than in the row itself
|
||||
// If you set manually _fields[0] to array of ColumnDefinition's (from previous call)
|
||||
// you can 'cache' result of parsing. Field packets still received, but ignored in that case
|
||||
// this is the reason _receivedFieldsCount exist (otherwise we could just use current length of fields array)
|
||||
if (this._fields[this._resultIndex].length !== this._fieldCount) {
|
||||
const field = new Packets.ColumnDefinition(
|
||||
packet,
|
||||
connection.clientEncoding
|
||||
);
|
||||
this._fields[this._resultIndex].push(field);
|
||||
if (connection.config.debug) {
|
||||
/* eslint-disable no-console */
|
||||
console.log(' Column definition:');
|
||||
console.log(` name: ${field.name}`);
|
||||
console.log(` type: ${field.columnType}`);
|
||||
console.log(` flags: ${field.flags}`);
|
||||
/* eslint-enable no-console */
|
||||
}
|
||||
}
|
||||
// last field received
|
||||
if (this._receivedFieldsCount === this._fieldCount) {
|
||||
const fields = this._fields[this._resultIndex];
|
||||
this.emit('fields', fields);
|
||||
if (this.options.disableEval) {
|
||||
this._rowParser = staticParser(fields, this.options, connection.config);
|
||||
} else {
|
||||
this._rowParser = new (getTextParser(
|
||||
fields,
|
||||
this.options,
|
||||
connection.config
|
||||
))(fields);
|
||||
}
|
||||
return Query.prototype.fieldsEOF;
|
||||
}
|
||||
return Query.prototype.readField;
|
||||
}
|
||||
|
||||
fieldsEOF(packet, connection) {
|
||||
// check EOF
|
||||
if (!packet.isEOF()) {
|
||||
return connection.protocolError('Expected EOF packet');
|
||||
}
|
||||
return this.row;
|
||||
}
|
||||
|
||||
/* eslint no-unused-vars: ["error", { "argsIgnorePattern": "^_" }] */
|
||||
row(packet, _connection) {
|
||||
if (packet.isEOF()) {
|
||||
const status = packet.eofStatusFlags();
|
||||
const moreResults = status & ServerStatus.SERVER_MORE_RESULTS_EXISTS;
|
||||
if (moreResults) {
|
||||
this._resultIndex++;
|
||||
return Query.prototype.resultsetHeader;
|
||||
}
|
||||
return this.done();
|
||||
}
|
||||
let row;
|
||||
try {
|
||||
row = this._rowParser.next(
|
||||
packet,
|
||||
this._fields[this._resultIndex],
|
||||
this.options
|
||||
);
|
||||
} catch (err) {
|
||||
this._localStreamError = err;
|
||||
return this.doneInsert(null);
|
||||
}
|
||||
if (this.onResult) {
|
||||
this._rows[this._resultIndex].push(row);
|
||||
} else {
|
||||
this.emit('result', row, this._resultIndex);
|
||||
}
|
||||
return Query.prototype.row;
|
||||
}
|
||||
|
||||
infileOk(packet, connection) {
|
||||
const rs = new Packets.ResultSetHeader(packet, connection);
|
||||
return this.doneInsert(rs);
|
||||
}
|
||||
|
||||
stream(options) {
|
||||
options = options || {};
|
||||
options.objectMode = true;
|
||||
const stream = new Readable(options);
|
||||
stream._read = () => {
|
||||
this._connection && this._connection.resume();
|
||||
};
|
||||
this.on('result', (row, resultSetIndex) => {
|
||||
if (!stream.push(row)) {
|
||||
this._connection.pause();
|
||||
}
|
||||
stream.emit('result', row, resultSetIndex); // replicate old emitter
|
||||
});
|
||||
this.on('error', (err) => {
|
||||
stream.emit('error', err); // Pass on any errors
|
||||
});
|
||||
this.on('end', () => {
|
||||
stream.push(null); // pushing null, indicating EOF
|
||||
});
|
||||
this.on('fields', (fields) => {
|
||||
stream.emit('fields', fields); // replicate old emitter
|
||||
});
|
||||
stream.on('end', () => {
|
||||
stream.emit('close');
|
||||
});
|
||||
return stream;
|
||||
}
|
||||
|
||||
_setTimeout() {
|
||||
if (this.timeout) {
|
||||
const timeoutHandler = this._handleTimeoutError.bind(this);
|
||||
this.queryTimeout = Timers.setTimeout(timeoutHandler, this.timeout);
|
||||
}
|
||||
}
|
||||
|
||||
_handleTimeoutError() {
|
||||
if (this.queryTimeout) {
|
||||
Timers.clearTimeout(this.queryTimeout);
|
||||
this.queryTimeout = null;
|
||||
}
|
||||
|
||||
const err = new Error('Query inactivity timeout');
|
||||
err.errorno = 'PROTOCOL_SEQUENCE_TIMEOUT';
|
||||
err.code = 'PROTOCOL_SEQUENCE_TIMEOUT';
|
||||
err.syscall = 'query';
|
||||
|
||||
if (this.onResult) {
|
||||
this.onResult(err);
|
||||
} else {
|
||||
this.emit('error', err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Query.prototype.catch = Query.prototype.then;
|
||||
|
||||
module.exports = Query;
|
29
backend/node_modules/mysql2/lib/commands/quit.js
generated
vendored
Normal file
29
backend/node_modules/mysql2/lib/commands/quit.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
const Command = require('./command.js');
|
||||
const CommandCode = require('../constants/commands.js');
|
||||
const Packet = require('../packets/packet.js');
|
||||
|
||||
class Quit extends Command {
|
||||
constructor(callback) {
|
||||
super();
|
||||
this.onResult = callback;
|
||||
}
|
||||
|
||||
start(packet, connection) {
|
||||
connection._closing = true;
|
||||
const quit = new Packet(
|
||||
0,
|
||||
Buffer.from([1, 0, 0, 0, CommandCode.QUIT]),
|
||||
0,
|
||||
5
|
||||
);
|
||||
if (this.onResult) {
|
||||
this.onResult();
|
||||
}
|
||||
connection.writePacket(quit);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Quit;
|
27
backend/node_modules/mysql2/lib/commands/register_slave.js
generated
vendored
Normal file
27
backend/node_modules/mysql2/lib/commands/register_slave.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
const Command = require('./command');
|
||||
const Packets = require('../packets');
|
||||
|
||||
class RegisterSlave extends Command {
|
||||
constructor(opts, callback) {
|
||||
super();
|
||||
this.onResult = callback;
|
||||
this.opts = opts;
|
||||
}
|
||||
|
||||
start(packet, connection) {
|
||||
const newPacket = new Packets.RegisterSlave(this.opts);
|
||||
connection.writePacket(newPacket.toPacket(1));
|
||||
return RegisterSlave.prototype.registerResponse;
|
||||
}
|
||||
|
||||
registerResponse() {
|
||||
if (this.onResult) {
|
||||
process.nextTick(this.onResult.bind(this));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RegisterSlave;
|
203
backend/node_modules/mysql2/lib/commands/server_handshake.js
generated
vendored
Normal file
203
backend/node_modules/mysql2/lib/commands/server_handshake.js
generated
vendored
Normal file
@@ -0,0 +1,203 @@
|
||||
'use strict';
|
||||
|
||||
const CommandCode = require('../constants/commands.js');
|
||||
const Errors = require('../constants/errors.js');
|
||||
|
||||
const Command = require('./command.js');
|
||||
const Packets = require('../packets/index.js');
|
||||
|
||||
class ServerHandshake extends Command {
|
||||
constructor(args) {
|
||||
super();
|
||||
this.args = args;
|
||||
/*
|
||||
this.protocolVersion = args.protocolVersion || 10;
|
||||
this.serverVersion = args.serverVersion;
|
||||
this.connectionId = args.connectionId,
|
||||
this.statusFlags = args.statusFlags,
|
||||
this.characterSet = args.characterSet,
|
||||
this.capabilityFlags = args.capabilityFlags || 512;
|
||||
*/
|
||||
}
|
||||
|
||||
start(packet, connection) {
|
||||
const serverHelloPacket = new Packets.Handshake(this.args);
|
||||
this.serverHello = serverHelloPacket;
|
||||
serverHelloPacket.setScrambleData((err) => {
|
||||
if (err) {
|
||||
connection.emit('error', new Error('Error generating random bytes'));
|
||||
return;
|
||||
}
|
||||
connection.writePacket(serverHelloPacket.toPacket(0));
|
||||
});
|
||||
return ServerHandshake.prototype.readClientReply;
|
||||
}
|
||||
|
||||
readClientReply(packet, connection) {
|
||||
// check auth here
|
||||
const clientHelloReply = Packets.HandshakeResponse.fromPacket(packet);
|
||||
// TODO check we don't have something similar already
|
||||
connection.clientHelloReply = clientHelloReply;
|
||||
if (this.args.authCallback) {
|
||||
this.args.authCallback(
|
||||
{
|
||||
user: clientHelloReply.user,
|
||||
database: clientHelloReply.database,
|
||||
address: connection.stream.remoteAddress,
|
||||
authPluginData1: this.serverHello.authPluginData1,
|
||||
authPluginData2: this.serverHello.authPluginData2,
|
||||
authToken: clientHelloReply.authToken,
|
||||
},
|
||||
(err, mysqlError) => {
|
||||
// if (err)
|
||||
if (!mysqlError) {
|
||||
connection.writeOk();
|
||||
} else {
|
||||
// TODO create constants / errorToCode
|
||||
// 1045 = ER_ACCESS_DENIED_ERROR
|
||||
connection.writeError({
|
||||
message: mysqlError.message || '',
|
||||
code: mysqlError.code || 1045,
|
||||
});
|
||||
connection.close();
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
connection.writeOk();
|
||||
}
|
||||
return ServerHandshake.prototype.dispatchCommands;
|
||||
}
|
||||
|
||||
_isStatement(query, name) {
|
||||
const firstWord = query.split(' ')[0].toUpperCase();
|
||||
return firstWord === name;
|
||||
}
|
||||
|
||||
dispatchCommands(packet, connection) {
|
||||
// command from client to server
|
||||
let knownCommand = true;
|
||||
const encoding = connection.clientHelloReply.encoding;
|
||||
const commandCode = packet.readInt8();
|
||||
switch (commandCode) {
|
||||
case CommandCode.STMT_PREPARE:
|
||||
if (connection.listeners('stmt_prepare').length) {
|
||||
const query = packet.readString(undefined, encoding);
|
||||
connection.emit('stmt_prepare', query);
|
||||
} else {
|
||||
connection.writeError({
|
||||
code: Errors.HA_ERR_INTERNAL_ERROR,
|
||||
message: 'No query handler for prepared statements.',
|
||||
});
|
||||
}
|
||||
break;
|
||||
case CommandCode.STMT_EXECUTE:
|
||||
if (connection.listeners('stmt_execute').length) {
|
||||
const { stmtId, flags, iterationCount, values } =
|
||||
Packets.Execute.fromPacket(packet, encoding);
|
||||
connection.emit(
|
||||
'stmt_execute',
|
||||
stmtId,
|
||||
flags,
|
||||
iterationCount,
|
||||
values
|
||||
);
|
||||
} else {
|
||||
connection.writeError({
|
||||
code: Errors.HA_ERR_INTERNAL_ERROR,
|
||||
message: 'No query handler for execute statements.',
|
||||
});
|
||||
}
|
||||
break;
|
||||
case CommandCode.QUIT:
|
||||
if (connection.listeners('quit').length) {
|
||||
connection.emit('quit');
|
||||
} else {
|
||||
connection.stream.end();
|
||||
}
|
||||
break;
|
||||
case CommandCode.INIT_DB:
|
||||
if (connection.listeners('init_db').length) {
|
||||
const schemaName = packet.readString(undefined, encoding);
|
||||
connection.emit('init_db', schemaName);
|
||||
} else {
|
||||
connection.writeOk();
|
||||
}
|
||||
break;
|
||||
case CommandCode.QUERY:
|
||||
if (connection.listeners('query').length) {
|
||||
const query = packet.readString(undefined, encoding);
|
||||
if (
|
||||
this._isStatement(query, 'PREPARE') ||
|
||||
this._isStatement(query, 'SET')
|
||||
) {
|
||||
connection.emit('stmt_prepare', query);
|
||||
} else if (this._isStatement(query, 'EXECUTE')) {
|
||||
connection.emit('stmt_execute', null, null, null, null, query);
|
||||
} else connection.emit('query', query);
|
||||
} else {
|
||||
connection.writeError({
|
||||
code: Errors.HA_ERR_INTERNAL_ERROR,
|
||||
message: 'No query handler',
|
||||
});
|
||||
}
|
||||
break;
|
||||
case CommandCode.FIELD_LIST:
|
||||
if (connection.listeners('field_list').length) {
|
||||
const table = packet.readNullTerminatedString(encoding);
|
||||
const fields = packet.readString(undefined, encoding);
|
||||
connection.emit('field_list', table, fields);
|
||||
} else {
|
||||
connection.writeError({
|
||||
code: Errors.ER_WARN_DEPRECATED_SYNTAX,
|
||||
message:
|
||||
'As of MySQL 5.7.11, COM_FIELD_LIST is deprecated and will be removed in a future version of MySQL.',
|
||||
});
|
||||
}
|
||||
break;
|
||||
case CommandCode.PING:
|
||||
if (connection.listeners('ping').length) {
|
||||
connection.emit('ping');
|
||||
} else {
|
||||
connection.writeOk();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
knownCommand = false;
|
||||
}
|
||||
if (connection.listeners('packet').length) {
|
||||
connection.emit('packet', packet.clone(), knownCommand, commandCode);
|
||||
} else if (!knownCommand) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Unknown command:', commandCode);
|
||||
}
|
||||
return ServerHandshake.prototype.dispatchCommands;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ServerHandshake;
|
||||
|
||||
// TODO: implement server-side 4.1 authentication
|
||||
/*
|
||||
4.1 authentication: (http://bazaar.launchpad.net/~mysql/mysql-server/5.5/view/head:/sql/password.c)
|
||||
|
||||
SERVER: public_seed=create_random_string()
|
||||
send(public_seed)
|
||||
|
||||
CLIENT: recv(public_seed)
|
||||
hash_stage1=sha1("password")
|
||||
hash_stage2=sha1(hash_stage1)
|
||||
reply=xor(hash_stage1, sha1(public_seed,hash_stage2)
|
||||
|
||||
// this three steps are done in scramble()
|
||||
|
||||
send(reply)
|
||||
|
||||
|
||||
SERVER: recv(reply)
|
||||
hash_stage1=xor(reply, sha1(public_seed,hash_stage2))
|
||||
candidate_hash2=sha1(hash_stage1)
|
||||
check(candidate_hash2==hash_stage2)
|
||||
|
||||
server stores sha1(sha1(password)) ( hash_stag2)
|
||||
*/
|
Reference in New Issue
Block a user