First commit
This commit is contained in:
47
node_modules/mongodb/lib/cmap/auth/auth_provider.js
generated
vendored
Normal file
47
node_modules/mongodb/lib/cmap/auth/auth_provider.js
generated
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AuthProvider = exports.AuthContext = void 0;
|
||||
const error_1 = require("../../error");
|
||||
/**
|
||||
* Context used during authentication
|
||||
* @internal
|
||||
*/
|
||||
class AuthContext {
|
||||
constructor(connection, credentials, options) {
|
||||
/** If the context is for reauthentication. */
|
||||
this.reauthenticating = false;
|
||||
this.connection = connection;
|
||||
this.credentials = credentials;
|
||||
this.options = options;
|
||||
}
|
||||
}
|
||||
exports.AuthContext = AuthContext;
|
||||
class AuthProvider {
|
||||
/**
|
||||
* Prepare the handshake document before the initial handshake.
|
||||
*
|
||||
* @param handshakeDoc - The document used for the initial handshake on a connection
|
||||
* @param authContext - Context for authentication flow
|
||||
*/
|
||||
async prepare(handshakeDoc, _authContext) {
|
||||
return handshakeDoc;
|
||||
}
|
||||
/**
|
||||
* Reauthenticate.
|
||||
* @param context - The shared auth context.
|
||||
*/
|
||||
async reauth(context) {
|
||||
if (context.reauthenticating) {
|
||||
throw new error_1.MongoRuntimeError('Reauthentication already in progress.');
|
||||
}
|
||||
try {
|
||||
context.reauthenticating = true;
|
||||
await this.auth(context);
|
||||
}
|
||||
finally {
|
||||
context.reauthenticating = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.AuthProvider = AuthProvider;
|
||||
//# sourceMappingURL=auth_provider.js.map
|
||||
1
node_modules/mongodb/lib/cmap/auth/auth_provider.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/auth/auth_provider.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth_provider.js","sourceRoot":"","sources":["../../../src/cmap/auth/auth_provider.ts"],"names":[],"mappings":";;;AACA,uCAAgD;AAKhD;;;GAGG;AACH,MAAa,WAAW;IAetB,YACE,UAAsB,EACtB,WAAyC,EACzC,OAA0B;QAb5B,8CAA8C;QAC9C,qBAAgB,GAAG,KAAK,CAAC;QAcvB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CACF;AAxBD,kCAwBC;AAED,MAAsB,YAAY;IAChC;;;;;OAKG;IACH,KAAK,CAAC,OAAO,CACX,YAA+B,EAC/B,YAAyB;QAEzB,OAAO,YAAY,CAAC;IACtB,CAAC;IASD;;;OAGG;IACH,KAAK,CAAC,MAAM,CAAC,OAAoB;QAC/B,IAAI,OAAO,CAAC,gBAAgB,EAAE;YAC5B,MAAM,IAAI,yBAAiB,CAAC,uCAAuC,CAAC,CAAC;SACtE;QACD,IAAI;YACF,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;YAChC,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;SAC1B;gBAAS;YACR,OAAO,CAAC,gBAAgB,GAAG,KAAK,CAAC;SAClC;IACH,CAAC;CACF;AApCD,oCAoCC"}
|
||||
143
node_modules/mongodb/lib/cmap/auth/gssapi.js
generated
vendored
Normal file
143
node_modules/mongodb/lib/cmap/auth/gssapi.js
generated
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.resolveCname = exports.performGSSAPICanonicalizeHostName = exports.GSSAPI = exports.GSSAPICanonicalizationValue = void 0;
|
||||
const dns = require("dns");
|
||||
const deps_1 = require("../../deps");
|
||||
const error_1 = require("../../error");
|
||||
const utils_1 = require("../../utils");
|
||||
const auth_provider_1 = require("./auth_provider");
|
||||
/** @public */
|
||||
exports.GSSAPICanonicalizationValue = Object.freeze({
|
||||
on: true,
|
||||
off: false,
|
||||
none: 'none',
|
||||
forward: 'forward',
|
||||
forwardAndReverse: 'forwardAndReverse'
|
||||
});
|
||||
async function externalCommand(connection, command) {
|
||||
return connection.commandAsync((0, utils_1.ns)('$external.$cmd'), command, undefined);
|
||||
}
|
||||
class GSSAPI extends auth_provider_1.AuthProvider {
|
||||
async auth(authContext) {
|
||||
const { connection, credentials } = authContext;
|
||||
if (credentials == null) {
|
||||
throw new error_1.MongoMissingCredentialsError('Credentials required for GSSAPI authentication');
|
||||
}
|
||||
const { username } = credentials;
|
||||
const client = await makeKerberosClient(authContext);
|
||||
const payload = await client.step('');
|
||||
const saslStartResponse = await externalCommand(connection, saslStart(payload));
|
||||
const negotiatedPayload = await negotiate(client, 10, saslStartResponse.payload);
|
||||
const saslContinueResponse = await externalCommand(connection, saslContinue(negotiatedPayload, saslStartResponse.conversationId));
|
||||
const finalizePayload = await finalize(client, username, saslContinueResponse.payload);
|
||||
await externalCommand(connection, {
|
||||
saslContinue: 1,
|
||||
conversationId: saslContinueResponse.conversationId,
|
||||
payload: finalizePayload
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.GSSAPI = GSSAPI;
|
||||
async function makeKerberosClient(authContext) {
|
||||
const { hostAddress } = authContext.options;
|
||||
const { credentials } = authContext;
|
||||
if (!hostAddress || typeof hostAddress.host !== 'string' || !credentials) {
|
||||
throw new error_1.MongoInvalidArgumentError('Connection must have host and port and credentials defined.');
|
||||
}
|
||||
if ('kModuleError' in deps_1.Kerberos) {
|
||||
throw deps_1.Kerberos['kModuleError'];
|
||||
}
|
||||
const { initializeClient } = deps_1.Kerberos;
|
||||
const { username, password } = credentials;
|
||||
const mechanismProperties = credentials.mechanismProperties;
|
||||
const serviceName = mechanismProperties.SERVICE_NAME ?? 'mongodb';
|
||||
const host = await performGSSAPICanonicalizeHostName(hostAddress.host, mechanismProperties);
|
||||
const initOptions = {};
|
||||
if (password != null) {
|
||||
// TODO(NODE-5139): These do not match the typescript options in initializeClient
|
||||
Object.assign(initOptions, { user: username, password: password });
|
||||
}
|
||||
const spnHost = mechanismProperties.SERVICE_HOST ?? host;
|
||||
let spn = `${serviceName}${process.platform === 'win32' ? '/' : '@'}${spnHost}`;
|
||||
if ('SERVICE_REALM' in mechanismProperties) {
|
||||
spn = `${spn}@${mechanismProperties.SERVICE_REALM}`;
|
||||
}
|
||||
return initializeClient(spn, initOptions);
|
||||
}
|
||||
function saslStart(payload) {
|
||||
return {
|
||||
saslStart: 1,
|
||||
mechanism: 'GSSAPI',
|
||||
payload,
|
||||
autoAuthorize: 1
|
||||
};
|
||||
}
|
||||
function saslContinue(payload, conversationId) {
|
||||
return {
|
||||
saslContinue: 1,
|
||||
conversationId,
|
||||
payload
|
||||
};
|
||||
}
|
||||
async function negotiate(client, retries, payload) {
|
||||
try {
|
||||
const response = await client.step(payload);
|
||||
return response || '';
|
||||
}
|
||||
catch (error) {
|
||||
if (retries === 0) {
|
||||
// Retries exhausted, raise error
|
||||
throw error;
|
||||
}
|
||||
// Adjust number of retries and call step again
|
||||
return negotiate(client, retries - 1, payload);
|
||||
}
|
||||
}
|
||||
async function finalize(client, user, payload) {
|
||||
// GSS Client Unwrap
|
||||
const response = await client.unwrap(payload);
|
||||
return client.wrap(response || '', { user });
|
||||
}
|
||||
async function performGSSAPICanonicalizeHostName(host, mechanismProperties) {
|
||||
const mode = mechanismProperties.CANONICALIZE_HOST_NAME;
|
||||
if (!mode || mode === exports.GSSAPICanonicalizationValue.none) {
|
||||
return host;
|
||||
}
|
||||
// If forward and reverse or true
|
||||
if (mode === exports.GSSAPICanonicalizationValue.on ||
|
||||
mode === exports.GSSAPICanonicalizationValue.forwardAndReverse) {
|
||||
// Perform the lookup of the ip address.
|
||||
const { address } = await dns.promises.lookup(host);
|
||||
try {
|
||||
// Perform a reverse ptr lookup on the ip address.
|
||||
const results = await dns.promises.resolvePtr(address);
|
||||
// If the ptr did not error but had no results, return the host.
|
||||
return results.length > 0 ? results[0] : host;
|
||||
}
|
||||
catch (error) {
|
||||
// This can error as ptr records may not exist for all ips. In this case
|
||||
// fallback to a cname lookup as dns.lookup() does not return the
|
||||
// cname.
|
||||
return resolveCname(host);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// The case for forward is just to resolve the cname as dns.lookup()
|
||||
// will not return it.
|
||||
return resolveCname(host);
|
||||
}
|
||||
}
|
||||
exports.performGSSAPICanonicalizeHostName = performGSSAPICanonicalizeHostName;
|
||||
async function resolveCname(host) {
|
||||
// Attempt to resolve the host name
|
||||
try {
|
||||
const results = await dns.promises.resolveCname(host);
|
||||
// Get the first resolved host id
|
||||
return results.length > 0 ? results[0] : host;
|
||||
}
|
||||
catch {
|
||||
return host;
|
||||
}
|
||||
}
|
||||
exports.resolveCname = resolveCname;
|
||||
//# sourceMappingURL=gssapi.js.map
|
||||
1
node_modules/mongodb/lib/cmap/auth/gssapi.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/auth/gssapi.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"gssapi.js","sourceRoot":"","sources":["../../../src/cmap/auth/gssapi.ts"],"names":[],"mappings":"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"}
|
||||
170
node_modules/mongodb/lib/cmap/auth/mongo_credentials.js
generated
vendored
Normal file
170
node_modules/mongodb/lib/cmap/auth/mongo_credentials.js
generated
vendored
Normal file
@@ -0,0 +1,170 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.MongoCredentials = exports.DEFAULT_ALLOWED_HOSTS = void 0;
|
||||
const error_1 = require("../../error");
|
||||
const gssapi_1 = require("./gssapi");
|
||||
const providers_1 = require("./providers");
|
||||
// https://github.com/mongodb/specifications/blob/master/source/auth/auth.rst
|
||||
function getDefaultAuthMechanism(hello) {
|
||||
if (hello) {
|
||||
// If hello contains saslSupportedMechs, use scram-sha-256
|
||||
// if it is available, else scram-sha-1
|
||||
if (Array.isArray(hello.saslSupportedMechs)) {
|
||||
return hello.saslSupportedMechs.includes(providers_1.AuthMechanism.MONGODB_SCRAM_SHA256)
|
||||
? providers_1.AuthMechanism.MONGODB_SCRAM_SHA256
|
||||
: providers_1.AuthMechanism.MONGODB_SCRAM_SHA1;
|
||||
}
|
||||
// Fallback to legacy selection method. If wire version >= 3, use scram-sha-1
|
||||
if (hello.maxWireVersion >= 3) {
|
||||
return providers_1.AuthMechanism.MONGODB_SCRAM_SHA1;
|
||||
}
|
||||
}
|
||||
// Default for wireprotocol < 3
|
||||
return providers_1.AuthMechanism.MONGODB_CR;
|
||||
}
|
||||
const ALLOWED_HOSTS_ERROR = 'Auth mechanism property ALLOWED_HOSTS must be an array of strings.';
|
||||
/** @internal */
|
||||
exports.DEFAULT_ALLOWED_HOSTS = [
|
||||
'*.mongodb.net',
|
||||
'*.mongodb-dev.net',
|
||||
'*.mongodbgov.net',
|
||||
'localhost',
|
||||
'127.0.0.1',
|
||||
'::1'
|
||||
];
|
||||
/**
|
||||
* A representation of the credentials used by MongoDB
|
||||
* @public
|
||||
*/
|
||||
class MongoCredentials {
|
||||
constructor(options) {
|
||||
this.username = options.username ?? '';
|
||||
this.password = options.password;
|
||||
this.source = options.source;
|
||||
if (!this.source && options.db) {
|
||||
this.source = options.db;
|
||||
}
|
||||
this.mechanism = options.mechanism || providers_1.AuthMechanism.MONGODB_DEFAULT;
|
||||
this.mechanismProperties = options.mechanismProperties || {};
|
||||
if (this.mechanism.match(/MONGODB-AWS/i)) {
|
||||
if (!this.username && process.env.AWS_ACCESS_KEY_ID) {
|
||||
this.username = process.env.AWS_ACCESS_KEY_ID;
|
||||
}
|
||||
if (!this.password && process.env.AWS_SECRET_ACCESS_KEY) {
|
||||
this.password = process.env.AWS_SECRET_ACCESS_KEY;
|
||||
}
|
||||
if (this.mechanismProperties.AWS_SESSION_TOKEN == null &&
|
||||
process.env.AWS_SESSION_TOKEN != null) {
|
||||
this.mechanismProperties = {
|
||||
...this.mechanismProperties,
|
||||
AWS_SESSION_TOKEN: process.env.AWS_SESSION_TOKEN
|
||||
};
|
||||
}
|
||||
}
|
||||
if (this.mechanism === providers_1.AuthMechanism.MONGODB_OIDC && !this.mechanismProperties.ALLOWED_HOSTS) {
|
||||
this.mechanismProperties = {
|
||||
...this.mechanismProperties,
|
||||
ALLOWED_HOSTS: exports.DEFAULT_ALLOWED_HOSTS
|
||||
};
|
||||
}
|
||||
Object.freeze(this.mechanismProperties);
|
||||
Object.freeze(this);
|
||||
}
|
||||
/** Determines if two MongoCredentials objects are equivalent */
|
||||
equals(other) {
|
||||
return (this.mechanism === other.mechanism &&
|
||||
this.username === other.username &&
|
||||
this.password === other.password &&
|
||||
this.source === other.source);
|
||||
}
|
||||
/**
|
||||
* If the authentication mechanism is set to "default", resolves the authMechanism
|
||||
* based on the server version and server supported sasl mechanisms.
|
||||
*
|
||||
* @param hello - A hello response from the server
|
||||
*/
|
||||
resolveAuthMechanism(hello) {
|
||||
// If the mechanism is not "default", then it does not need to be resolved
|
||||
if (this.mechanism.match(/DEFAULT/i)) {
|
||||
return new MongoCredentials({
|
||||
username: this.username,
|
||||
password: this.password,
|
||||
source: this.source,
|
||||
mechanism: getDefaultAuthMechanism(hello),
|
||||
mechanismProperties: this.mechanismProperties
|
||||
});
|
||||
}
|
||||
return this;
|
||||
}
|
||||
validate() {
|
||||
if ((this.mechanism === providers_1.AuthMechanism.MONGODB_GSSAPI ||
|
||||
this.mechanism === providers_1.AuthMechanism.MONGODB_CR ||
|
||||
this.mechanism === providers_1.AuthMechanism.MONGODB_PLAIN ||
|
||||
this.mechanism === providers_1.AuthMechanism.MONGODB_SCRAM_SHA1 ||
|
||||
this.mechanism === providers_1.AuthMechanism.MONGODB_SCRAM_SHA256) &&
|
||||
!this.username) {
|
||||
throw new error_1.MongoMissingCredentialsError(`Username required for mechanism '${this.mechanism}'`);
|
||||
}
|
||||
if (this.mechanism === providers_1.AuthMechanism.MONGODB_OIDC) {
|
||||
if (this.username && this.mechanismProperties.PROVIDER_NAME) {
|
||||
throw new error_1.MongoInvalidArgumentError(`username and PROVIDER_NAME may not be used together for mechanism '${this.mechanism}'.`);
|
||||
}
|
||||
if (this.mechanismProperties.PROVIDER_NAME &&
|
||||
this.mechanismProperties.PROVIDER_NAME !== 'aws') {
|
||||
throw new error_1.MongoInvalidArgumentError(`Currently only a PROVIDER_NAME of 'aws' is supported for mechanism '${this.mechanism}'.`);
|
||||
}
|
||||
if (this.mechanismProperties.REFRESH_TOKEN_CALLBACK &&
|
||||
!this.mechanismProperties.REQUEST_TOKEN_CALLBACK) {
|
||||
throw new error_1.MongoInvalidArgumentError(`A REQUEST_TOKEN_CALLBACK must be provided when using a REFRESH_TOKEN_CALLBACK for mechanism '${this.mechanism}'`);
|
||||
}
|
||||
if (!this.mechanismProperties.PROVIDER_NAME &&
|
||||
!this.mechanismProperties.REQUEST_TOKEN_CALLBACK) {
|
||||
throw new error_1.MongoInvalidArgumentError(`Either a PROVIDER_NAME or a REQUEST_TOKEN_CALLBACK must be specified for mechanism '${this.mechanism}'.`);
|
||||
}
|
||||
if (this.mechanismProperties.ALLOWED_HOSTS) {
|
||||
const hosts = this.mechanismProperties.ALLOWED_HOSTS;
|
||||
if (!Array.isArray(hosts)) {
|
||||
throw new error_1.MongoInvalidArgumentError(ALLOWED_HOSTS_ERROR);
|
||||
}
|
||||
for (const host of hosts) {
|
||||
if (typeof host !== 'string') {
|
||||
throw new error_1.MongoInvalidArgumentError(ALLOWED_HOSTS_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (providers_1.AUTH_MECHS_AUTH_SRC_EXTERNAL.has(this.mechanism)) {
|
||||
if (this.source != null && this.source !== '$external') {
|
||||
// TODO(NODE-3485): Replace this with a MongoAuthValidationError
|
||||
throw new error_1.MongoAPIError(`Invalid source '${this.source}' for mechanism '${this.mechanism}' specified.`);
|
||||
}
|
||||
}
|
||||
if (this.mechanism === providers_1.AuthMechanism.MONGODB_PLAIN && this.source == null) {
|
||||
// TODO(NODE-3485): Replace this with a MongoAuthValidationError
|
||||
throw new error_1.MongoAPIError('PLAIN Authentication Mechanism needs an auth source');
|
||||
}
|
||||
if (this.mechanism === providers_1.AuthMechanism.MONGODB_X509 && this.password != null) {
|
||||
if (this.password === '') {
|
||||
Reflect.set(this, 'password', undefined);
|
||||
return;
|
||||
}
|
||||
// TODO(NODE-3485): Replace this with a MongoAuthValidationError
|
||||
throw new error_1.MongoAPIError(`Password not allowed for mechanism MONGODB-X509`);
|
||||
}
|
||||
const canonicalization = this.mechanismProperties.CANONICALIZE_HOST_NAME ?? false;
|
||||
if (!Object.values(gssapi_1.GSSAPICanonicalizationValue).includes(canonicalization)) {
|
||||
throw new error_1.MongoAPIError(`Invalid CANONICALIZE_HOST_NAME value: ${canonicalization}`);
|
||||
}
|
||||
}
|
||||
static merge(creds, options) {
|
||||
return new MongoCredentials({
|
||||
username: options.username ?? creds?.username ?? '',
|
||||
password: options.password ?? creds?.password ?? '',
|
||||
mechanism: options.mechanism ?? creds?.mechanism ?? providers_1.AuthMechanism.MONGODB_DEFAULT,
|
||||
mechanismProperties: options.mechanismProperties ?? creds?.mechanismProperties ?? {},
|
||||
source: options.source ?? options.db ?? creds?.source ?? 'admin'
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.MongoCredentials = MongoCredentials;
|
||||
//# sourceMappingURL=mongo_credentials.js.map
|
||||
1
node_modules/mongodb/lib/cmap/auth/mongo_credentials.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/auth/mongo_credentials.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
35
node_modules/mongodb/lib/cmap/auth/mongocr.js
generated
vendored
Normal file
35
node_modules/mongodb/lib/cmap/auth/mongocr.js
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.MongoCR = void 0;
|
||||
const crypto = require("crypto");
|
||||
const error_1 = require("../../error");
|
||||
const utils_1 = require("../../utils");
|
||||
const auth_provider_1 = require("./auth_provider");
|
||||
class MongoCR extends auth_provider_1.AuthProvider {
|
||||
async auth(authContext) {
|
||||
const { connection, credentials } = authContext;
|
||||
if (!credentials) {
|
||||
throw new error_1.MongoMissingCredentialsError('AuthContext must provide credentials.');
|
||||
}
|
||||
const { username, password, source } = credentials;
|
||||
const { nonce } = await connection.commandAsync((0, utils_1.ns)(`${source}.$cmd`), { getnonce: 1 }, undefined);
|
||||
const hashPassword = crypto
|
||||
.createHash('md5')
|
||||
.update(`${username}:mongo:${password}`, 'utf8')
|
||||
.digest('hex');
|
||||
// Final key
|
||||
const key = crypto
|
||||
.createHash('md5')
|
||||
.update(`${nonce}${username}${hashPassword}`, 'utf8')
|
||||
.digest('hex');
|
||||
const authenticateCommand = {
|
||||
authenticate: 1,
|
||||
user: username,
|
||||
nonce,
|
||||
key
|
||||
};
|
||||
await connection.commandAsync((0, utils_1.ns)(`${source}.$cmd`), authenticateCommand, undefined);
|
||||
}
|
||||
}
|
||||
exports.MongoCR = MongoCR;
|
||||
//# sourceMappingURL=mongocr.js.map
|
||||
1
node_modules/mongodb/lib/cmap/auth/mongocr.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/auth/mongocr.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"mongocr.js","sourceRoot":"","sources":["../../../src/cmap/auth/mongocr.ts"],"names":[],"mappings":";;;AAAA,iCAAiC;AAEjC,uCAA2D;AAC3D,uCAAiC;AACjC,mDAA4D;AAE5D,MAAa,OAAQ,SAAQ,4BAAY;IAC9B,KAAK,CAAC,IAAI,CAAC,WAAwB;QAC1C,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,WAAW,CAAC;QAChD,IAAI,CAAC,WAAW,EAAE;YAChB,MAAM,IAAI,oCAA4B,CAAC,uCAAuC,CAAC,CAAC;SACjF;QAED,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,WAAW,CAAC;QAEnD,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,UAAU,CAAC,YAAY,CAC7C,IAAA,UAAE,EAAC,GAAG,MAAM,OAAO,CAAC,EACpB,EAAE,QAAQ,EAAE,CAAC,EAAE,EACf,SAAS,CACV,CAAC;QAEF,MAAM,YAAY,GAAG,MAAM;aACxB,UAAU,CAAC,KAAK,CAAC;aACjB,MAAM,CAAC,GAAG,QAAQ,UAAU,QAAQ,EAAE,EAAE,MAAM,CAAC;aAC/C,MAAM,CAAC,KAAK,CAAC,CAAC;QAEjB,YAAY;QACZ,MAAM,GAAG,GAAG,MAAM;aACf,UAAU,CAAC,KAAK,CAAC;aACjB,MAAM,CAAC,GAAG,KAAK,GAAG,QAAQ,GAAG,YAAY,EAAE,EAAE,MAAM,CAAC;aACpD,MAAM,CAAC,KAAK,CAAC,CAAC;QAEjB,MAAM,mBAAmB,GAAG;YAC1B,YAAY,EAAE,CAAC;YACf,IAAI,EAAE,QAAQ;YACd,KAAK;YACL,GAAG;SACJ,CAAC;QAEF,MAAM,UAAU,CAAC,YAAY,CAAC,IAAA,UAAE,EAAC,GAAG,MAAM,OAAO,CAAC,EAAE,mBAAmB,EAAE,SAAS,CAAC,CAAC;IACtF,CAAC;CACF;AAnCD,0BAmCC"}
|
||||
223
node_modules/mongodb/lib/cmap/auth/mongodb_aws.js
generated
vendored
Normal file
223
node_modules/mongodb/lib/cmap/auth/mongodb_aws.js
generated
vendored
Normal file
@@ -0,0 +1,223 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.MongoDBAWS = void 0;
|
||||
const crypto = require("crypto");
|
||||
const http = require("http");
|
||||
const url = require("url");
|
||||
const util_1 = require("util");
|
||||
const BSON = require("../../bson");
|
||||
const deps_1 = require("../../deps");
|
||||
const error_1 = require("../../error");
|
||||
const utils_1 = require("../../utils");
|
||||
const auth_provider_1 = require("./auth_provider");
|
||||
const mongo_credentials_1 = require("./mongo_credentials");
|
||||
const providers_1 = require("./providers");
|
||||
const ASCII_N = 110;
|
||||
const AWS_RELATIVE_URI = 'http://169.254.170.2';
|
||||
const AWS_EC2_URI = 'http://169.254.169.254';
|
||||
const AWS_EC2_PATH = '/latest/meta-data/iam/security-credentials';
|
||||
const bsonOptions = {
|
||||
useBigInt64: false,
|
||||
promoteLongs: true,
|
||||
promoteValues: true,
|
||||
promoteBuffers: false,
|
||||
bsonRegExp: false
|
||||
};
|
||||
class MongoDBAWS extends auth_provider_1.AuthProvider {
|
||||
constructor() {
|
||||
super();
|
||||
this.randomBytesAsync = (0, util_1.promisify)(crypto.randomBytes);
|
||||
}
|
||||
async auth(authContext) {
|
||||
const { connection } = authContext;
|
||||
if (!authContext.credentials) {
|
||||
throw new error_1.MongoMissingCredentialsError('AuthContext must provide credentials.');
|
||||
}
|
||||
if ('kModuleError' in deps_1.aws4) {
|
||||
throw deps_1.aws4['kModuleError'];
|
||||
}
|
||||
const { sign } = deps_1.aws4;
|
||||
if ((0, utils_1.maxWireVersion)(connection) < 9) {
|
||||
throw new error_1.MongoCompatibilityError('MONGODB-AWS authentication requires MongoDB version 4.4 or later');
|
||||
}
|
||||
if (!authContext.credentials.username) {
|
||||
authContext.credentials = await makeTempCredentials(authContext.credentials);
|
||||
}
|
||||
const { credentials } = authContext;
|
||||
const accessKeyId = credentials.username;
|
||||
const secretAccessKey = credentials.password;
|
||||
const sessionToken = credentials.mechanismProperties.AWS_SESSION_TOKEN;
|
||||
// If all three defined, include sessionToken, else include username and pass, else no credentials
|
||||
const awsCredentials = accessKeyId && secretAccessKey && sessionToken
|
||||
? { accessKeyId, secretAccessKey, sessionToken }
|
||||
: accessKeyId && secretAccessKey
|
||||
? { accessKeyId, secretAccessKey }
|
||||
: undefined;
|
||||
const db = credentials.source;
|
||||
const nonce = await this.randomBytesAsync(32);
|
||||
const saslStart = {
|
||||
saslStart: 1,
|
||||
mechanism: 'MONGODB-AWS',
|
||||
payload: BSON.serialize({ r: nonce, p: ASCII_N }, bsonOptions)
|
||||
};
|
||||
const saslStartResponse = await connection.commandAsync((0, utils_1.ns)(`${db}.$cmd`), saslStart, undefined);
|
||||
const serverResponse = BSON.deserialize(saslStartResponse.payload.buffer, bsonOptions);
|
||||
const host = serverResponse.h;
|
||||
const serverNonce = serverResponse.s.buffer;
|
||||
if (serverNonce.length !== 64) {
|
||||
// TODO(NODE-3483)
|
||||
throw new error_1.MongoRuntimeError(`Invalid server nonce length ${serverNonce.length}, expected 64`);
|
||||
}
|
||||
if (!utils_1.ByteUtils.equals(serverNonce.subarray(0, nonce.byteLength), nonce)) {
|
||||
// throw because the serverNonce's leading 32 bytes must equal the client nonce's 32 bytes
|
||||
// https://github.com/mongodb/specifications/blob/875446db44aade414011731840831f38a6c668df/source/auth/auth.rst#id11
|
||||
// TODO(NODE-3483)
|
||||
throw new error_1.MongoRuntimeError('Server nonce does not begin with client nonce');
|
||||
}
|
||||
if (host.length < 1 || host.length > 255 || host.indexOf('..') !== -1) {
|
||||
// TODO(NODE-3483)
|
||||
throw new error_1.MongoRuntimeError(`Server returned an invalid host: "${host}"`);
|
||||
}
|
||||
const body = 'Action=GetCallerIdentity&Version=2011-06-15';
|
||||
const options = sign({
|
||||
method: 'POST',
|
||||
host,
|
||||
region: deriveRegion(serverResponse.h),
|
||||
service: 'sts',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Content-Length': body.length,
|
||||
'X-MongoDB-Server-Nonce': utils_1.ByteUtils.toBase64(serverNonce),
|
||||
'X-MongoDB-GS2-CB-Flag': 'n'
|
||||
},
|
||||
path: '/',
|
||||
body
|
||||
}, awsCredentials);
|
||||
const payload = {
|
||||
a: options.headers.Authorization,
|
||||
d: options.headers['X-Amz-Date']
|
||||
};
|
||||
if (sessionToken) {
|
||||
payload.t = sessionToken;
|
||||
}
|
||||
const saslContinue = {
|
||||
saslContinue: 1,
|
||||
conversationId: 1,
|
||||
payload: BSON.serialize(payload, bsonOptions)
|
||||
};
|
||||
await connection.commandAsync((0, utils_1.ns)(`${db}.$cmd`), saslContinue, undefined);
|
||||
}
|
||||
}
|
||||
exports.MongoDBAWS = MongoDBAWS;
|
||||
async function makeTempCredentials(credentials) {
|
||||
function makeMongoCredentialsFromAWSTemp(creds) {
|
||||
if (!creds.AccessKeyId || !creds.SecretAccessKey || !creds.Token) {
|
||||
throw new error_1.MongoMissingCredentialsError('Could not obtain temporary MONGODB-AWS credentials');
|
||||
}
|
||||
return new mongo_credentials_1.MongoCredentials({
|
||||
username: creds.AccessKeyId,
|
||||
password: creds.SecretAccessKey,
|
||||
source: credentials.source,
|
||||
mechanism: providers_1.AuthMechanism.MONGODB_AWS,
|
||||
mechanismProperties: {
|
||||
AWS_SESSION_TOKEN: creds.Token
|
||||
}
|
||||
});
|
||||
}
|
||||
const credentialProvider = (0, deps_1.getAwsCredentialProvider)();
|
||||
// Check if the AWS credential provider from the SDK is present. If not,
|
||||
// use the old method.
|
||||
if ('kModuleError' in credentialProvider) {
|
||||
// If the environment variable AWS_CONTAINER_CREDENTIALS_RELATIVE_URI
|
||||
// is set then drivers MUST assume that it was set by an AWS ECS agent
|
||||
if (process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI) {
|
||||
return makeMongoCredentialsFromAWSTemp(await request(`${AWS_RELATIVE_URI}${process.env.AWS_CONTAINER_CREDENTIALS_RELATIVE_URI}`));
|
||||
}
|
||||
// Otherwise assume we are on an EC2 instance
|
||||
// get a token
|
||||
const token = await request(`${AWS_EC2_URI}/latest/api/token`, {
|
||||
method: 'PUT',
|
||||
json: false,
|
||||
headers: { 'X-aws-ec2-metadata-token-ttl-seconds': 30 }
|
||||
});
|
||||
// get role name
|
||||
const roleName = await request(`${AWS_EC2_URI}/${AWS_EC2_PATH}`, {
|
||||
json: false,
|
||||
headers: { 'X-aws-ec2-metadata-token': token }
|
||||
});
|
||||
// get temp credentials
|
||||
const creds = await request(`${AWS_EC2_URI}/${AWS_EC2_PATH}/${roleName}`, {
|
||||
headers: { 'X-aws-ec2-metadata-token': token }
|
||||
});
|
||||
return makeMongoCredentialsFromAWSTemp(creds);
|
||||
}
|
||||
else {
|
||||
/*
|
||||
* Creates a credential provider that will attempt to find credentials from the
|
||||
* following sources (listed in order of precedence):
|
||||
*
|
||||
* - Environment variables exposed via process.env
|
||||
* - SSO credentials from token cache
|
||||
* - Web identity token credentials
|
||||
* - Shared credentials and config ini files
|
||||
* - The EC2/ECS Instance Metadata Service
|
||||
*/
|
||||
const { fromNodeProviderChain } = credentialProvider;
|
||||
const provider = fromNodeProviderChain();
|
||||
try {
|
||||
const creds = await provider();
|
||||
return makeMongoCredentialsFromAWSTemp({
|
||||
AccessKeyId: creds.accessKeyId,
|
||||
SecretAccessKey: creds.secretAccessKey,
|
||||
Token: creds.sessionToken,
|
||||
Expiration: creds.expiration
|
||||
});
|
||||
}
|
||||
catch (error) {
|
||||
throw new error_1.MongoAWSError(error.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
function deriveRegion(host) {
|
||||
const parts = host.split('.');
|
||||
if (parts.length === 1 || parts[1] === 'amazonaws') {
|
||||
return 'us-east-1';
|
||||
}
|
||||
return parts[1];
|
||||
}
|
||||
async function request(uri, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const requestOptions = {
|
||||
method: 'GET',
|
||||
timeout: 10000,
|
||||
json: true,
|
||||
...url.parse(uri),
|
||||
...options
|
||||
};
|
||||
const req = http.request(requestOptions, res => {
|
||||
res.setEncoding('utf8');
|
||||
let data = '';
|
||||
res.on('data', d => {
|
||||
data += d;
|
||||
});
|
||||
res.once('end', () => {
|
||||
if (options.json === false) {
|
||||
resolve(data);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const parsed = JSON.parse(data);
|
||||
resolve(parsed);
|
||||
}
|
||||
catch {
|
||||
// TODO(NODE-3483)
|
||||
reject(new error_1.MongoRuntimeError(`Invalid JSON response: "${data}"`));
|
||||
}
|
||||
});
|
||||
});
|
||||
req.once('timeout', () => req.destroy(new error_1.MongoAWSError(`AWS request to ${uri} timed out after ${options.timeout} ms`)));
|
||||
req.once('error', error => reject(error));
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=mongodb_aws.js.map
|
||||
1
node_modules/mongodb/lib/cmap/auth/mongodb_aws.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/auth/mongodb_aws.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
66
node_modules/mongodb/lib/cmap/auth/mongodb_oidc.js
generated
vendored
Normal file
66
node_modules/mongodb/lib/cmap/auth/mongodb_oidc.js
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.MongoDBOIDC = exports.OIDC_WORKFLOWS = void 0;
|
||||
const error_1 = require("../../error");
|
||||
const auth_provider_1 = require("./auth_provider");
|
||||
const aws_service_workflow_1 = require("./mongodb_oidc/aws_service_workflow");
|
||||
const callback_workflow_1 = require("./mongodb_oidc/callback_workflow");
|
||||
/** Error when credentials are missing. */
|
||||
const MISSING_CREDENTIALS_ERROR = 'AuthContext must provide credentials.';
|
||||
/** @internal */
|
||||
exports.OIDC_WORKFLOWS = new Map();
|
||||
exports.OIDC_WORKFLOWS.set('callback', new callback_workflow_1.CallbackWorkflow());
|
||||
exports.OIDC_WORKFLOWS.set('aws', new aws_service_workflow_1.AwsServiceWorkflow());
|
||||
/**
|
||||
* OIDC auth provider.
|
||||
* @experimental
|
||||
*/
|
||||
class MongoDBOIDC extends auth_provider_1.AuthProvider {
|
||||
/**
|
||||
* Instantiate the auth provider.
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
/**
|
||||
* Authenticate using OIDC
|
||||
*/
|
||||
async auth(authContext) {
|
||||
const { connection, reauthenticating, response } = authContext;
|
||||
const credentials = getCredentials(authContext);
|
||||
const workflow = getWorkflow(credentials);
|
||||
await workflow.execute(connection, credentials, reauthenticating, response);
|
||||
}
|
||||
/**
|
||||
* Add the speculative auth for the initial handshake.
|
||||
*/
|
||||
async prepare(handshakeDoc, authContext) {
|
||||
const credentials = getCredentials(authContext);
|
||||
const workflow = getWorkflow(credentials);
|
||||
const result = await workflow.speculativeAuth(credentials);
|
||||
return { ...handshakeDoc, ...result };
|
||||
}
|
||||
}
|
||||
exports.MongoDBOIDC = MongoDBOIDC;
|
||||
/**
|
||||
* Get credentials from the auth context, throwing if they do not exist.
|
||||
*/
|
||||
function getCredentials(authContext) {
|
||||
const { credentials } = authContext;
|
||||
if (!credentials) {
|
||||
throw new error_1.MongoMissingCredentialsError(MISSING_CREDENTIALS_ERROR);
|
||||
}
|
||||
return credentials;
|
||||
}
|
||||
/**
|
||||
* Gets either a device workflow or callback workflow.
|
||||
*/
|
||||
function getWorkflow(credentials) {
|
||||
const providerName = credentials.mechanismProperties.PROVIDER_NAME;
|
||||
const workflow = exports.OIDC_WORKFLOWS.get(providerName || 'callback');
|
||||
if (!workflow) {
|
||||
throw new error_1.MongoInvalidArgumentError(`Could not load workflow for provider ${credentials.mechanismProperties.PROVIDER_NAME}`);
|
||||
}
|
||||
return workflow;
|
||||
}
|
||||
//# sourceMappingURL=mongodb_oidc.js.map
|
||||
1
node_modules/mongodb/lib/cmap/auth/mongodb_oidc.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/auth/mongodb_oidc.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"mongodb_oidc.js","sourceRoot":"","sources":["../../../src/cmap/auth/mongodb_oidc.ts"],"names":[],"mappings":";;;AAEA,uCAAsF;AAGtF,mDAA4D;AAE5D,8EAAyE;AACzE,wEAAoE;AAEpE,0CAA0C;AAC1C,MAAM,yBAAyB,GAAG,uCAAuC,CAAC;AAuE1E,gBAAgB;AACH,QAAA,cAAc,GAAgC,IAAI,GAAG,EAAE,CAAC;AACrE,sBAAc,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,oCAAgB,EAAE,CAAC,CAAC;AACvD,sBAAc,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,yCAAkB,EAAE,CAAC,CAAC;AAEpD;;;GAGG;AACH,MAAa,WAAY,SAAQ,4BAAY;IAC3C;;OAEG;IACH;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED;;OAEG;IACM,KAAK,CAAC,IAAI,CAAC,WAAwB;QAC1C,MAAM,EAAE,UAAU,EAAE,gBAAgB,EAAE,QAAQ,EAAE,GAAG,WAAW,CAAC;QAC/D,MAAM,WAAW,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;QAC1C,MAAM,QAAQ,CAAC,OAAO,CAAC,UAAU,EAAE,WAAW,EAAE,gBAAgB,EAAE,QAAQ,CAAC,CAAC;IAC9E,CAAC;IAED;;OAEG;IACM,KAAK,CAAC,OAAO,CACpB,YAA+B,EAC/B,WAAwB;QAExB,MAAM,WAAW,GAAG,cAAc,CAAC,WAAW,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,eAAe,CAAC,WAAW,CAAC,CAAC;QAC3D,OAAO,EAAE,GAAG,YAAY,EAAE,GAAG,MAAM,EAAE,CAAC;IACxC,CAAC;CACF;AA9BD,kCA8BC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,WAAwB;IAC9C,MAAM,EAAE,WAAW,EAAE,GAAG,WAAW,CAAC;IACpC,IAAI,CAAC,WAAW,EAAE;QAChB,MAAM,IAAI,oCAA4B,CAAC,yBAAyB,CAAC,CAAC;KACnE;IACD,OAAO,WAAW,CAAC;AACrB,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,WAA6B;IAChD,MAAM,YAAY,GAAG,WAAW,CAAC,mBAAmB,CAAC,aAAa,CAAC;IACnE,MAAM,QAAQ,GAAG,sBAAc,CAAC,GAAG,CAAC,YAAY,IAAI,UAAU,CAAC,CAAC;IAChE,IAAI,CAAC,QAAQ,EAAE;QACb,MAAM,IAAI,iCAAyB,CACjC,wCAAwC,WAAW,CAAC,mBAAmB,CAAC,aAAa,EAAE,CACxF,CAAC;KACH;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
||||
30
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/aws_service_workflow.js
generated
vendored
Normal file
30
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/aws_service_workflow.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AwsServiceWorkflow = void 0;
|
||||
const fs = require("fs");
|
||||
const error_1 = require("../../../error");
|
||||
const service_workflow_1 = require("./service_workflow");
|
||||
/** Error for when the token is missing in the environment. */
|
||||
const TOKEN_MISSING_ERROR = 'AWS_WEB_IDENTITY_TOKEN_FILE must be set in the environment.';
|
||||
/**
|
||||
* Device workflow implementation for AWS.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class AwsServiceWorkflow extends service_workflow_1.ServiceWorkflow {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
/**
|
||||
* Get the token from the environment.
|
||||
*/
|
||||
async getToken() {
|
||||
const tokenFile = process.env.AWS_WEB_IDENTITY_TOKEN_FILE;
|
||||
if (!tokenFile) {
|
||||
throw new error_1.MongoAWSError(TOKEN_MISSING_ERROR);
|
||||
}
|
||||
return fs.promises.readFile(tokenFile, 'utf8');
|
||||
}
|
||||
}
|
||||
exports.AwsServiceWorkflow = AwsServiceWorkflow;
|
||||
//# sourceMappingURL=aws_service_workflow.js.map
|
||||
1
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/aws_service_workflow.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/aws_service_workflow.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"aws_service_workflow.js","sourceRoot":"","sources":["../../../../src/cmap/auth/mongodb_oidc/aws_service_workflow.ts"],"names":[],"mappings":";;;AAAA,yBAAyB;AAEzB,0CAA+C;AAC/C,yDAAqD;AAErD,8DAA8D;AAC9D,MAAM,mBAAmB,GAAG,6DAA6D,CAAC;AAE1F;;;;GAIG;AACH,MAAa,kBAAmB,SAAQ,kCAAe;IACrD;QACE,KAAK,EAAE,CAAC;IACV,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,QAAQ;QACZ,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC;QAC1D,IAAI,CAAC,SAAS,EAAE;YACd,MAAM,IAAI,qBAAa,CAAC,mBAAmB,CAAC,CAAC;SAC9C;QACD,OAAO,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACjD,CAAC;CACF;AAfD,gDAeC"}
|
||||
28
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/cache.js
generated
vendored
Normal file
28
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/cache.js
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Cache = void 0;
|
||||
/**
|
||||
* Base class for OIDC caches.
|
||||
*/
|
||||
class Cache {
|
||||
/**
|
||||
* Create a new cache.
|
||||
*/
|
||||
constructor() {
|
||||
this.entries = new Map();
|
||||
}
|
||||
/**
|
||||
* Clear the cache.
|
||||
*/
|
||||
clear() {
|
||||
this.entries.clear();
|
||||
}
|
||||
/**
|
||||
* Create a cache key from the address and username.
|
||||
*/
|
||||
cacheKey(address, username, callbackHash) {
|
||||
return JSON.stringify([address, username, callbackHash]);
|
||||
}
|
||||
}
|
||||
exports.Cache = Cache;
|
||||
//# sourceMappingURL=cache.js.map
|
||||
1
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/cache.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/cache.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../../src/cmap/auth/mongodb_oidc/cache.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,MAAsB,KAAK;IAGzB;;OAEG;IACH;QACE,IAAI,CAAC,OAAO,GAAG,IAAI,GAAG,EAAa,CAAC;IACtC,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,OAAe,EAAE,QAAgB,EAAE,YAAoB;QAC9D,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;IAC3D,CAAC;CACF;AAvBD,sBAuBC"}
|
||||
83
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/callback_lock_cache.js
generated
vendored
Normal file
83
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/callback_lock_cache.js
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.CallbackLockCache = void 0;
|
||||
const error_1 = require("../../../error");
|
||||
const cache_1 = require("./cache");
|
||||
/** Error message for when request callback is missing. */
|
||||
const REQUEST_CALLBACK_REQUIRED_ERROR = 'Auth mechanism property REQUEST_TOKEN_CALLBACK is required.';
|
||||
/* Counter for function "hashes".*/
|
||||
let FN_HASH_COUNTER = 0;
|
||||
/* No function present function */
|
||||
const NO_FUNCTION = async () => ({ accessToken: 'test' });
|
||||
/* The map of function hashes */
|
||||
const FN_HASHES = new WeakMap();
|
||||
/* Put the no function hash in the map. */
|
||||
FN_HASHES.set(NO_FUNCTION, FN_HASH_COUNTER);
|
||||
/**
|
||||
* A cache of request and refresh callbacks per server/user.
|
||||
*/
|
||||
class CallbackLockCache extends cache_1.Cache {
|
||||
/**
|
||||
* Get the callbacks for the connection and credentials. If an entry does not
|
||||
* exist a new one will get set.
|
||||
*/
|
||||
getCallbacks(connection, credentials) {
|
||||
const requestCallback = credentials.mechanismProperties.REQUEST_TOKEN_CALLBACK;
|
||||
const refreshCallback = credentials.mechanismProperties.REFRESH_TOKEN_CALLBACK;
|
||||
if (!requestCallback) {
|
||||
throw new error_1.MongoInvalidArgumentError(REQUEST_CALLBACK_REQUIRED_ERROR);
|
||||
}
|
||||
const callbackHash = hashFunctions(requestCallback, refreshCallback);
|
||||
const key = this.cacheKey(connection.address, credentials.username, callbackHash);
|
||||
const entry = this.entries.get(key);
|
||||
if (entry) {
|
||||
return entry;
|
||||
}
|
||||
return this.setCallbacks(key, callbackHash, requestCallback, refreshCallback);
|
||||
}
|
||||
/**
|
||||
* Set locked callbacks on for connection and credentials.
|
||||
*/
|
||||
setCallbacks(key, callbackHash, requestCallback, refreshCallback) {
|
||||
const entry = {
|
||||
requestCallback: withLock(requestCallback),
|
||||
refreshCallback: refreshCallback ? withLock(refreshCallback) : undefined,
|
||||
callbackHash: callbackHash
|
||||
};
|
||||
this.entries.set(key, entry);
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
exports.CallbackLockCache = CallbackLockCache;
|
||||
/**
|
||||
* Ensure the callback is only executed one at a time.
|
||||
*/
|
||||
function withLock(callback) {
|
||||
let lock = Promise.resolve();
|
||||
return async (info, context) => {
|
||||
await lock;
|
||||
lock = lock.then(() => callback(info, context));
|
||||
return lock;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Get the hash string for the request and refresh functions.
|
||||
*/
|
||||
function hashFunctions(requestFn, refreshFn) {
|
||||
let requestHash = FN_HASHES.get(requestFn);
|
||||
let refreshHash = FN_HASHES.get(refreshFn ?? NO_FUNCTION);
|
||||
if (requestHash == null) {
|
||||
// Create a new one for the function and put it in the map.
|
||||
FN_HASH_COUNTER++;
|
||||
requestHash = FN_HASH_COUNTER;
|
||||
FN_HASHES.set(requestFn, FN_HASH_COUNTER);
|
||||
}
|
||||
if (refreshHash == null && refreshFn) {
|
||||
// Create a new one for the function and put it in the map.
|
||||
FN_HASH_COUNTER++;
|
||||
refreshHash = FN_HASH_COUNTER;
|
||||
FN_HASHES.set(refreshFn, FN_HASH_COUNTER);
|
||||
}
|
||||
return `${requestHash}-${refreshHash}`;
|
||||
}
|
||||
//# sourceMappingURL=callback_lock_cache.js.map
|
||||
1
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/callback_lock_cache.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/callback_lock_cache.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"callback_lock_cache.js","sourceRoot":"","sources":["../../../../src/cmap/auth/mongodb_oidc/callback_lock_cache.ts"],"names":[],"mappings":"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"}
|
||||
204
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/callback_workflow.js
generated
vendored
Normal file
204
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/callback_workflow.js
generated
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.CallbackWorkflow = void 0;
|
||||
const bson_1 = require("bson");
|
||||
const error_1 = require("../../../error");
|
||||
const utils_1 = require("../../../utils");
|
||||
const providers_1 = require("../providers");
|
||||
const callback_lock_cache_1 = require("./callback_lock_cache");
|
||||
const token_entry_cache_1 = require("./token_entry_cache");
|
||||
/** The current version of OIDC implementation. */
|
||||
const OIDC_VERSION = 0;
|
||||
/** 5 minutes in seconds */
|
||||
const TIMEOUT_S = 300;
|
||||
/** Properties allowed on results of callbacks. */
|
||||
const RESULT_PROPERTIES = ['accessToken', 'expiresInSeconds', 'refreshToken'];
|
||||
/** Error message when the callback result is invalid. */
|
||||
const CALLBACK_RESULT_ERROR = 'User provided OIDC callbacks must return a valid object with an accessToken.';
|
||||
/**
|
||||
* OIDC implementation of a callback based workflow.
|
||||
* @internal
|
||||
*/
|
||||
class CallbackWorkflow {
|
||||
/**
|
||||
* Instantiate the workflow
|
||||
*/
|
||||
constructor() {
|
||||
this.cache = new token_entry_cache_1.TokenEntryCache();
|
||||
this.callbackCache = new callback_lock_cache_1.CallbackLockCache();
|
||||
}
|
||||
/**
|
||||
* Get the document to add for speculative authentication. This also needs
|
||||
* to add a db field from the credentials source.
|
||||
*/
|
||||
async speculativeAuth(credentials) {
|
||||
const document = startCommandDocument(credentials);
|
||||
document.db = credentials.source;
|
||||
return { speculativeAuthenticate: document };
|
||||
}
|
||||
/**
|
||||
* Execute the OIDC callback workflow.
|
||||
*/
|
||||
async execute(connection, credentials, reauthenticating, response) {
|
||||
// Get the callbacks with locks from the callback lock cache.
|
||||
const { requestCallback, refreshCallback, callbackHash } = this.callbackCache.getCallbacks(connection, credentials);
|
||||
// Look for an existing entry in the cache.
|
||||
const entry = this.cache.getEntry(connection.address, credentials.username, callbackHash);
|
||||
let result;
|
||||
if (entry) {
|
||||
// Reauthentication cannot use a token from the cache since the server has
|
||||
// stated it is invalid by the request for reauthentication.
|
||||
if (entry.isValid() && !reauthenticating) {
|
||||
// Presence of a valid cache entry means we can skip to the finishing step.
|
||||
result = await this.finishAuthentication(connection, credentials, entry.tokenResult, response?.speculativeAuthenticate?.conversationId);
|
||||
}
|
||||
else {
|
||||
// Presence of an expired cache entry means we must fetch a new one and
|
||||
// then execute the final step.
|
||||
const tokenResult = await this.fetchAccessToken(connection, credentials, entry.serverInfo, reauthenticating, callbackHash, requestCallback, refreshCallback);
|
||||
try {
|
||||
result = await this.finishAuthentication(connection, credentials, tokenResult, reauthenticating ? undefined : response?.speculativeAuthenticate?.conversationId);
|
||||
}
|
||||
catch (error) {
|
||||
// If we are reauthenticating and this errors with reauthentication
|
||||
// required, we need to do the entire process over again and clear
|
||||
// the cache entry.
|
||||
if (reauthenticating &&
|
||||
error instanceof error_1.MongoError &&
|
||||
error.code === error_1.MONGODB_ERROR_CODES.Reauthenticate) {
|
||||
this.cache.deleteEntry(connection.address, credentials.username, callbackHash);
|
||||
result = await this.execute(connection, credentials, reauthenticating);
|
||||
}
|
||||
else {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// No entry in the cache requires us to do all authentication steps
|
||||
// from start to finish, including getting a fresh token for the cache.
|
||||
const startDocument = await this.startAuthentication(connection, credentials, reauthenticating, response);
|
||||
const conversationId = startDocument.conversationId;
|
||||
const serverResult = bson_1.BSON.deserialize(startDocument.payload.buffer);
|
||||
const tokenResult = await this.fetchAccessToken(connection, credentials, serverResult, reauthenticating, callbackHash, requestCallback, refreshCallback);
|
||||
result = await this.finishAuthentication(connection, credentials, tokenResult, conversationId);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Starts the callback authentication process. If there is a speculative
|
||||
* authentication document from the initial handshake, then we will use that
|
||||
* value to get the issuer, otherwise we will send the saslStart command.
|
||||
*/
|
||||
async startAuthentication(connection, credentials, reauthenticating, response) {
|
||||
let result;
|
||||
if (!reauthenticating && response?.speculativeAuthenticate) {
|
||||
result = response.speculativeAuthenticate;
|
||||
}
|
||||
else {
|
||||
result = await connection.commandAsync((0, utils_1.ns)(credentials.source), startCommandDocument(credentials), undefined);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Finishes the callback authentication process.
|
||||
*/
|
||||
async finishAuthentication(connection, credentials, tokenResult, conversationId) {
|
||||
const result = await connection.commandAsync((0, utils_1.ns)(credentials.source), finishCommandDocument(tokenResult.accessToken, conversationId), undefined);
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* Fetches an access token using either the request or refresh callbacks and
|
||||
* puts it in the cache.
|
||||
*/
|
||||
async fetchAccessToken(connection, credentials, serverInfo, reauthenticating, callbackHash, requestCallback, refreshCallback) {
|
||||
// Get the token from the cache.
|
||||
const entry = this.cache.getEntry(connection.address, credentials.username, callbackHash);
|
||||
let result;
|
||||
const context = { timeoutSeconds: TIMEOUT_S, version: OIDC_VERSION };
|
||||
// Check if there's a token in the cache.
|
||||
if (entry) {
|
||||
// If the cache entry is valid, return the token result.
|
||||
if (entry.isValid() && !reauthenticating) {
|
||||
return entry.tokenResult;
|
||||
}
|
||||
// If the cache entry is not valid, remove it from the cache and first attempt
|
||||
// to use the refresh callback to get a new token. If no refresh callback
|
||||
// exists, then fallback to the request callback.
|
||||
if (refreshCallback) {
|
||||
context.refreshToken = entry.tokenResult.refreshToken;
|
||||
result = await refreshCallback(serverInfo, context);
|
||||
}
|
||||
else {
|
||||
result = await requestCallback(serverInfo, context);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// With no token in the cache we use the request callback.
|
||||
result = await requestCallback(serverInfo, context);
|
||||
}
|
||||
// Validate that the result returned by the callback is acceptable. If it is not
|
||||
// we must clear the token result from the cache.
|
||||
if (isCallbackResultInvalid(result)) {
|
||||
this.cache.deleteEntry(connection.address, credentials.username, callbackHash);
|
||||
throw new error_1.MongoMissingCredentialsError(CALLBACK_RESULT_ERROR);
|
||||
}
|
||||
// Cleanup the cache.
|
||||
this.cache.deleteExpiredEntries();
|
||||
// Put the new entry into the cache.
|
||||
this.cache.addEntry(connection.address, credentials.username || '', callbackHash, result, serverInfo);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
exports.CallbackWorkflow = CallbackWorkflow;
|
||||
/**
|
||||
* Generate the finishing command document for authentication. Will be a
|
||||
* saslStart or saslContinue depending on the presence of a conversation id.
|
||||
*/
|
||||
function finishCommandDocument(token, conversationId) {
|
||||
if (conversationId != null && typeof conversationId === 'number') {
|
||||
return {
|
||||
saslContinue: 1,
|
||||
conversationId: conversationId,
|
||||
payload: new bson_1.Binary(bson_1.BSON.serialize({ jwt: token }))
|
||||
};
|
||||
}
|
||||
// saslContinue requires a conversationId in the command to be valid so in this
|
||||
// case the server allows "step two" to actually be a saslStart with the token
|
||||
// as the jwt since the use of the cached value has no correlating conversating
|
||||
// on the particular connection.
|
||||
return {
|
||||
saslStart: 1,
|
||||
mechanism: providers_1.AuthMechanism.MONGODB_OIDC,
|
||||
payload: new bson_1.Binary(bson_1.BSON.serialize({ jwt: token }))
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Determines if a result returned from a request or refresh callback
|
||||
* function is invalid. This means the result is nullish, doesn't contain
|
||||
* the accessToken required field, and does not contain extra fields.
|
||||
*/
|
||||
function isCallbackResultInvalid(tokenResult) {
|
||||
if (tokenResult == null || typeof tokenResult !== 'object')
|
||||
return true;
|
||||
if (!('accessToken' in tokenResult))
|
||||
return true;
|
||||
return !Object.getOwnPropertyNames(tokenResult).every(prop => RESULT_PROPERTIES.includes(prop));
|
||||
}
|
||||
/**
|
||||
* Generate the saslStart command document.
|
||||
*/
|
||||
function startCommandDocument(credentials) {
|
||||
const payload = {};
|
||||
if (credentials.username) {
|
||||
payload.n = credentials.username;
|
||||
}
|
||||
return {
|
||||
saslStart: 1,
|
||||
autoAuthorize: 1,
|
||||
mechanism: providers_1.AuthMechanism.MONGODB_OIDC,
|
||||
payload: new bson_1.Binary(bson_1.BSON.serialize(payload))
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=callback_workflow.js.map
|
||||
1
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/callback_workflow.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/callback_workflow.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
43
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/service_workflow.js
generated
vendored
Normal file
43
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/service_workflow.js
generated
vendored
Normal file
@@ -0,0 +1,43 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.commandDocument = exports.ServiceWorkflow = void 0;
|
||||
const bson_1 = require("bson");
|
||||
const utils_1 = require("../../../utils");
|
||||
const providers_1 = require("../providers");
|
||||
/**
|
||||
* Common behaviour for OIDC device workflows.
|
||||
* @internal
|
||||
*/
|
||||
class ServiceWorkflow {
|
||||
/**
|
||||
* Execute the workflow. Looks for AWS_WEB_IDENTITY_TOKEN_FILE in the environment
|
||||
* and then attempts to read the token from that path.
|
||||
*/
|
||||
async execute(connection, credentials) {
|
||||
const token = await this.getToken();
|
||||
const command = commandDocument(token);
|
||||
return connection.commandAsync((0, utils_1.ns)(credentials.source), command, undefined);
|
||||
}
|
||||
/**
|
||||
* Get the document to add for speculative authentication.
|
||||
*/
|
||||
async speculativeAuth(credentials) {
|
||||
const token = await this.getToken();
|
||||
const document = commandDocument(token);
|
||||
document.db = credentials.source;
|
||||
return { speculativeAuthenticate: document };
|
||||
}
|
||||
}
|
||||
exports.ServiceWorkflow = ServiceWorkflow;
|
||||
/**
|
||||
* Create the saslStart command document.
|
||||
*/
|
||||
function commandDocument(token) {
|
||||
return {
|
||||
saslStart: 1,
|
||||
mechanism: providers_1.AuthMechanism.MONGODB_OIDC,
|
||||
payload: bson_1.BSON.serialize({ jwt: token })
|
||||
};
|
||||
}
|
||||
exports.commandDocument = commandDocument;
|
||||
//# sourceMappingURL=service_workflow.js.map
|
||||
1
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/service_workflow.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/service_workflow.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"service_workflow.js","sourceRoot":"","sources":["../../../../src/cmap/auth/mongodb_oidc/service_workflow.ts"],"names":[],"mappings":";;;AAAA,+BAA2C;AAE3C,0CAAoC;AAIpC,4CAA6C;AAE7C;;;GAGG;AACH,MAAsB,eAAe;IACnC;;;OAGG;IACH,KAAK,CAAC,OAAO,CAAC,UAAsB,EAAE,WAA6B;QACjE,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACpC,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QACvC,OAAO,UAAU,CAAC,YAAY,CAAC,IAAA,UAAE,EAAC,WAAW,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IAC7E,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,WAA6B;QACjD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;QACpC,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC;QACxC,QAAQ,CAAC,EAAE,GAAG,WAAW,CAAC,MAAM,CAAC;QACjC,OAAO,EAAE,uBAAuB,EAAE,QAAQ,EAAE,CAAC;IAC/C,CAAC;CAMF;AAzBD,0CAyBC;AAED;;GAEG;AACH,SAAgB,eAAe,CAAC,KAAa;IAC3C,OAAO;QACL,SAAS,EAAE,CAAC;QACZ,SAAS,EAAE,yBAAa,CAAC,YAAY;QACrC,OAAO,EAAE,WAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;KACxC,CAAC;AACJ,CAAC;AAND,0CAMC"}
|
||||
71
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/token_entry_cache.js
generated
vendored
Normal file
71
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/token_entry_cache.js
generated
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.TokenEntryCache = exports.TokenEntry = void 0;
|
||||
const cache_1 = require("./cache");
|
||||
/* 5 minutes in milliseconds */
|
||||
const EXPIRATION_BUFFER_MS = 300000;
|
||||
/* Default expiration is now for when no expiration provided */
|
||||
const DEFAULT_EXPIRATION_SECS = 0;
|
||||
/** @internal */
|
||||
class TokenEntry {
|
||||
/**
|
||||
* Instantiate the entry.
|
||||
*/
|
||||
constructor(tokenResult, serverInfo, expiration) {
|
||||
this.tokenResult = tokenResult;
|
||||
this.serverInfo = serverInfo;
|
||||
this.expiration = expiration;
|
||||
}
|
||||
/**
|
||||
* The entry is still valid if the expiration is more than
|
||||
* 5 minutes from the expiration time.
|
||||
*/
|
||||
isValid() {
|
||||
return this.expiration - Date.now() > EXPIRATION_BUFFER_MS;
|
||||
}
|
||||
}
|
||||
exports.TokenEntry = TokenEntry;
|
||||
/**
|
||||
* Cache of OIDC token entries.
|
||||
* @internal
|
||||
*/
|
||||
class TokenEntryCache extends cache_1.Cache {
|
||||
/**
|
||||
* Set an entry in the token cache.
|
||||
*/
|
||||
addEntry(address, username, callbackHash, tokenResult, serverInfo) {
|
||||
const entry = new TokenEntry(tokenResult, serverInfo, expirationTime(tokenResult.expiresInSeconds));
|
||||
this.entries.set(this.cacheKey(address, username, callbackHash), entry);
|
||||
return entry;
|
||||
}
|
||||
/**
|
||||
* Delete an entry from the cache.
|
||||
*/
|
||||
deleteEntry(address, username, callbackHash) {
|
||||
this.entries.delete(this.cacheKey(address, username, callbackHash));
|
||||
}
|
||||
/**
|
||||
* Get an entry from the cache.
|
||||
*/
|
||||
getEntry(address, username, callbackHash) {
|
||||
return this.entries.get(this.cacheKey(address, username, callbackHash));
|
||||
}
|
||||
/**
|
||||
* Delete all expired entries from the cache.
|
||||
*/
|
||||
deleteExpiredEntries() {
|
||||
for (const [key, entry] of this.entries) {
|
||||
if (!entry.isValid()) {
|
||||
this.entries.delete(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.TokenEntryCache = TokenEntryCache;
|
||||
/**
|
||||
* Get an expiration time in milliseconds past epoch. Defaults to immediate.
|
||||
*/
|
||||
function expirationTime(expiresInSeconds) {
|
||||
return Date.now() + (expiresInSeconds ?? DEFAULT_EXPIRATION_SECS) * 1000;
|
||||
}
|
||||
//# sourceMappingURL=token_entry_cache.js.map
|
||||
1
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/token_entry_cache.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/auth/mongodb_oidc/token_entry_cache.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"token_entry_cache.js","sourceRoot":"","sources":["../../../../src/cmap/auth/mongodb_oidc/token_entry_cache.ts"],"names":[],"mappings":";;;AACA,mCAAgC;AAEhC,+BAA+B;AAC/B,MAAM,oBAAoB,GAAG,MAAM,CAAC;AACpC,+DAA+D;AAC/D,MAAM,uBAAuB,GAAG,CAAC,CAAC;AAClC,gBAAgB;AAChB,MAAa,UAAU;IAKrB;;OAEG;IACH,YAAY,WAA8B,EAAE,UAAyB,EAAE,UAAkB;QACvF,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED;;;OAGG;IACH,OAAO;QACL,OAAO,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,oBAAoB,CAAC;IAC7D,CAAC;CACF;AArBD,gCAqBC;AAED;;;GAGG;AACH,MAAa,eAAgB,SAAQ,aAAiB;IACpD;;OAEG;IACH,QAAQ,CACN,OAAe,EACf,QAAgB,EAChB,YAAoB,EACpB,WAA8B,EAC9B,UAAyB;QAEzB,MAAM,KAAK,GAAG,IAAI,UAAU,CAC1B,WAAW,EACX,UAAU,EACV,cAAc,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAC7C,CAAC;QACF,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC,EAAE,KAAK,CAAC,CAAC;QACxE,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,OAAe,EAAE,QAAgB,EAAE,YAAoB;QACjE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;IACtE,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,OAAe,EAAE,QAAgB,EAAE,YAAoB;QAC9D,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED;;OAEG;IACH,oBAAoB;QAClB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,OAAO,EAAE;YACvC,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE;gBACpB,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;aAC1B;SACF;IACH,CAAC;CACF;AA5CD,0CA4CC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,gBAAyB;IAC/C,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,gBAAgB,IAAI,uBAAuB,CAAC,GAAG,IAAI,CAAC;AAC3E,CAAC"}
|
||||
26
node_modules/mongodb/lib/cmap/auth/plain.js
generated
vendored
Normal file
26
node_modules/mongodb/lib/cmap/auth/plain.js
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Plain = void 0;
|
||||
const bson_1 = require("../../bson");
|
||||
const error_1 = require("../../error");
|
||||
const utils_1 = require("../../utils");
|
||||
const auth_provider_1 = require("./auth_provider");
|
||||
class Plain extends auth_provider_1.AuthProvider {
|
||||
async auth(authContext) {
|
||||
const { connection, credentials } = authContext;
|
||||
if (!credentials) {
|
||||
throw new error_1.MongoMissingCredentialsError('AuthContext must provide credentials.');
|
||||
}
|
||||
const { username, password } = credentials;
|
||||
const payload = new bson_1.Binary(Buffer.from(`\x00${username}\x00${password}`));
|
||||
const command = {
|
||||
saslStart: 1,
|
||||
mechanism: 'PLAIN',
|
||||
payload: payload,
|
||||
autoAuthorize: 1
|
||||
};
|
||||
await connection.commandAsync((0, utils_1.ns)('$external.$cmd'), command, undefined);
|
||||
}
|
||||
}
|
||||
exports.Plain = Plain;
|
||||
//# sourceMappingURL=plain.js.map
|
||||
1
node_modules/mongodb/lib/cmap/auth/plain.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/auth/plain.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"plain.js","sourceRoot":"","sources":["../../../src/cmap/auth/plain.ts"],"names":[],"mappings":";;;AAAA,qCAAoC;AACpC,uCAA2D;AAC3D,uCAAiC;AACjC,mDAA4D;AAE5D,MAAa,KAAM,SAAQ,4BAAY;IAC5B,KAAK,CAAC,IAAI,CAAC,WAAwB;QAC1C,MAAM,EAAE,UAAU,EAAE,WAAW,EAAE,GAAG,WAAW,CAAC;QAChD,IAAI,CAAC,WAAW,EAAE;YAChB,MAAM,IAAI,oCAA4B,CAAC,uCAAuC,CAAC,CAAC;SACjF;QAED,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,WAAW,CAAC;QAE3C,MAAM,OAAO,GAAG,IAAI,aAAM,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,QAAQ,OAAO,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC1E,MAAM,OAAO,GAAG;YACd,SAAS,EAAE,CAAC;YACZ,SAAS,EAAE,OAAO;YAClB,OAAO,EAAE,OAAO;YAChB,aAAa,EAAE,CAAC;SACjB,CAAC;QAEF,MAAM,UAAU,CAAC,YAAY,CAAC,IAAA,UAAE,EAAC,gBAAgB,CAAC,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IAC1E,CAAC;CACF;AAnBD,sBAmBC"}
|
||||
24
node_modules/mongodb/lib/cmap/auth/providers.js
generated
vendored
Normal file
24
node_modules/mongodb/lib/cmap/auth/providers.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AUTH_MECHS_AUTH_SRC_EXTERNAL = exports.AuthMechanism = void 0;
|
||||
/** @public */
|
||||
exports.AuthMechanism = Object.freeze({
|
||||
MONGODB_AWS: 'MONGODB-AWS',
|
||||
MONGODB_CR: 'MONGODB-CR',
|
||||
MONGODB_DEFAULT: 'DEFAULT',
|
||||
MONGODB_GSSAPI: 'GSSAPI',
|
||||
MONGODB_PLAIN: 'PLAIN',
|
||||
MONGODB_SCRAM_SHA1: 'SCRAM-SHA-1',
|
||||
MONGODB_SCRAM_SHA256: 'SCRAM-SHA-256',
|
||||
MONGODB_X509: 'MONGODB-X509',
|
||||
/** @experimental */
|
||||
MONGODB_OIDC: 'MONGODB-OIDC'
|
||||
});
|
||||
/** @internal */
|
||||
exports.AUTH_MECHS_AUTH_SRC_EXTERNAL = new Set([
|
||||
exports.AuthMechanism.MONGODB_GSSAPI,
|
||||
exports.AuthMechanism.MONGODB_AWS,
|
||||
exports.AuthMechanism.MONGODB_OIDC,
|
||||
exports.AuthMechanism.MONGODB_X509
|
||||
]);
|
||||
//# sourceMappingURL=providers.js.map
|
||||
1
node_modules/mongodb/lib/cmap/auth/providers.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/auth/providers.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"providers.js","sourceRoot":"","sources":["../../../src/cmap/auth/providers.ts"],"names":[],"mappings":";;;AAAA,cAAc;AACD,QAAA,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC;IACzC,WAAW,EAAE,aAAa;IAC1B,UAAU,EAAE,YAAY;IACxB,eAAe,EAAE,SAAS;IAC1B,cAAc,EAAE,QAAQ;IACxB,aAAa,EAAE,OAAO;IACtB,kBAAkB,EAAE,aAAa;IACjC,oBAAoB,EAAE,eAAe;IACrC,YAAY,EAAE,cAAc;IAC5B,oBAAoB;IACpB,YAAY,EAAE,cAAc;CACpB,CAAC,CAAC;AAKZ,gBAAgB;AACH,QAAA,4BAA4B,GAAG,IAAI,GAAG,CAAgB;IACjE,qBAAa,CAAC,cAAc;IAC5B,qBAAa,CAAC,WAAW;IACzB,qBAAa,CAAC,YAAY;IAC1B,qBAAa,CAAC,YAAY;CAC3B,CAAC,CAAC"}
|
||||
260
node_modules/mongodb/lib/cmap/auth/scram.js
generated
vendored
Normal file
260
node_modules/mongodb/lib/cmap/auth/scram.js
generated
vendored
Normal file
@@ -0,0 +1,260 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ScramSHA256 = exports.ScramSHA1 = void 0;
|
||||
const crypto = require("crypto");
|
||||
const util_1 = require("util");
|
||||
const bson_1 = require("../../bson");
|
||||
const deps_1 = require("../../deps");
|
||||
const error_1 = require("../../error");
|
||||
const utils_1 = require("../../utils");
|
||||
const auth_provider_1 = require("./auth_provider");
|
||||
const providers_1 = require("./providers");
|
||||
class ScramSHA extends auth_provider_1.AuthProvider {
|
||||
constructor(cryptoMethod) {
|
||||
super();
|
||||
this.cryptoMethod = cryptoMethod || 'sha1';
|
||||
this.randomBytesAsync = (0, util_1.promisify)(crypto.randomBytes);
|
||||
}
|
||||
async prepare(handshakeDoc, authContext) {
|
||||
const cryptoMethod = this.cryptoMethod;
|
||||
const credentials = authContext.credentials;
|
||||
if (!credentials) {
|
||||
throw new error_1.MongoMissingCredentialsError('AuthContext must provide credentials.');
|
||||
}
|
||||
if (cryptoMethod === 'sha256' && deps_1.saslprep == null) {
|
||||
(0, utils_1.emitWarning)('Warning: no saslprep library specified. Passwords will not be sanitized');
|
||||
}
|
||||
const nonce = await this.randomBytesAsync(24);
|
||||
// store the nonce for later use
|
||||
authContext.nonce = nonce;
|
||||
const request = {
|
||||
...handshakeDoc,
|
||||
speculativeAuthenticate: {
|
||||
...makeFirstMessage(cryptoMethod, credentials, nonce),
|
||||
db: credentials.source
|
||||
}
|
||||
};
|
||||
return request;
|
||||
}
|
||||
async auth(authContext) {
|
||||
const { reauthenticating, response } = authContext;
|
||||
if (response?.speculativeAuthenticate && !reauthenticating) {
|
||||
return continueScramConversation(this.cryptoMethod, response.speculativeAuthenticate, authContext);
|
||||
}
|
||||
return executeScram(this.cryptoMethod, authContext);
|
||||
}
|
||||
}
|
||||
function cleanUsername(username) {
|
||||
return username.replace('=', '=3D').replace(',', '=2C');
|
||||
}
|
||||
function clientFirstMessageBare(username, nonce) {
|
||||
// NOTE: This is done b/c Javascript uses UTF-16, but the server is hashing in UTF-8.
|
||||
// Since the username is not sasl-prep-d, we need to do this here.
|
||||
return Buffer.concat([
|
||||
Buffer.from('n=', 'utf8'),
|
||||
Buffer.from(username, 'utf8'),
|
||||
Buffer.from(',r=', 'utf8'),
|
||||
Buffer.from(nonce.toString('base64'), 'utf8')
|
||||
]);
|
||||
}
|
||||
function makeFirstMessage(cryptoMethod, credentials, nonce) {
|
||||
const username = cleanUsername(credentials.username);
|
||||
const mechanism = cryptoMethod === 'sha1' ? providers_1.AuthMechanism.MONGODB_SCRAM_SHA1 : providers_1.AuthMechanism.MONGODB_SCRAM_SHA256;
|
||||
// NOTE: This is done b/c Javascript uses UTF-16, but the server is hashing in UTF-8.
|
||||
// Since the username is not sasl-prep-d, we need to do this here.
|
||||
return {
|
||||
saslStart: 1,
|
||||
mechanism,
|
||||
payload: new bson_1.Binary(Buffer.concat([Buffer.from('n,,', 'utf8'), clientFirstMessageBare(username, nonce)])),
|
||||
autoAuthorize: 1,
|
||||
options: { skipEmptyExchange: true }
|
||||
};
|
||||
}
|
||||
async function executeScram(cryptoMethod, authContext) {
|
||||
const { connection, credentials } = authContext;
|
||||
if (!credentials) {
|
||||
throw new error_1.MongoMissingCredentialsError('AuthContext must provide credentials.');
|
||||
}
|
||||
if (!authContext.nonce) {
|
||||
throw new error_1.MongoInvalidArgumentError('AuthContext must contain a valid nonce property');
|
||||
}
|
||||
const nonce = authContext.nonce;
|
||||
const db = credentials.source;
|
||||
const saslStartCmd = makeFirstMessage(cryptoMethod, credentials, nonce);
|
||||
const response = await connection.commandAsync((0, utils_1.ns)(`${db}.$cmd`), saslStartCmd, undefined);
|
||||
await continueScramConversation(cryptoMethod, response, authContext);
|
||||
}
|
||||
async function continueScramConversation(cryptoMethod, response, authContext) {
|
||||
const connection = authContext.connection;
|
||||
const credentials = authContext.credentials;
|
||||
if (!credentials) {
|
||||
throw new error_1.MongoMissingCredentialsError('AuthContext must provide credentials.');
|
||||
}
|
||||
if (!authContext.nonce) {
|
||||
throw new error_1.MongoInvalidArgumentError('Unable to continue SCRAM without valid nonce');
|
||||
}
|
||||
const nonce = authContext.nonce;
|
||||
const db = credentials.source;
|
||||
const username = cleanUsername(credentials.username);
|
||||
const password = credentials.password;
|
||||
let processedPassword;
|
||||
if (cryptoMethod === 'sha256') {
|
||||
processedPassword = 'kModuleError' in deps_1.saslprep ? password : (0, deps_1.saslprep)(password);
|
||||
}
|
||||
else {
|
||||
processedPassword = passwordDigest(username, password);
|
||||
}
|
||||
const payload = Buffer.isBuffer(response.payload)
|
||||
? new bson_1.Binary(response.payload)
|
||||
: response.payload;
|
||||
const dict = parsePayload(payload.value());
|
||||
const iterations = parseInt(dict.i, 10);
|
||||
if (iterations && iterations < 4096) {
|
||||
// TODO(NODE-3483)
|
||||
throw new error_1.MongoRuntimeError(`Server returned an invalid iteration count ${iterations}`);
|
||||
}
|
||||
const salt = dict.s;
|
||||
const rnonce = dict.r;
|
||||
if (rnonce.startsWith('nonce')) {
|
||||
// TODO(NODE-3483)
|
||||
throw new error_1.MongoRuntimeError(`Server returned an invalid nonce: ${rnonce}`);
|
||||
}
|
||||
// Set up start of proof
|
||||
const withoutProof = `c=biws,r=${rnonce}`;
|
||||
const saltedPassword = HI(processedPassword, Buffer.from(salt, 'base64'), iterations, cryptoMethod);
|
||||
const clientKey = HMAC(cryptoMethod, saltedPassword, 'Client Key');
|
||||
const serverKey = HMAC(cryptoMethod, saltedPassword, 'Server Key');
|
||||
const storedKey = H(cryptoMethod, clientKey);
|
||||
const authMessage = [clientFirstMessageBare(username, nonce), payload.value(), withoutProof].join(',');
|
||||
const clientSignature = HMAC(cryptoMethod, storedKey, authMessage);
|
||||
const clientProof = `p=${xor(clientKey, clientSignature)}`;
|
||||
const clientFinal = [withoutProof, clientProof].join(',');
|
||||
const serverSignature = HMAC(cryptoMethod, serverKey, authMessage);
|
||||
const saslContinueCmd = {
|
||||
saslContinue: 1,
|
||||
conversationId: response.conversationId,
|
||||
payload: new bson_1.Binary(Buffer.from(clientFinal))
|
||||
};
|
||||
const r = await connection.commandAsync((0, utils_1.ns)(`${db}.$cmd`), saslContinueCmd, undefined);
|
||||
const parsedResponse = parsePayload(r.payload.value());
|
||||
if (!compareDigest(Buffer.from(parsedResponse.v, 'base64'), serverSignature)) {
|
||||
throw new error_1.MongoRuntimeError('Server returned an invalid signature');
|
||||
}
|
||||
if (r.done !== false) {
|
||||
// If the server sends r.done === true we can save one RTT
|
||||
return;
|
||||
}
|
||||
const retrySaslContinueCmd = {
|
||||
saslContinue: 1,
|
||||
conversationId: r.conversationId,
|
||||
payload: Buffer.alloc(0)
|
||||
};
|
||||
await connection.commandAsync((0, utils_1.ns)(`${db}.$cmd`), retrySaslContinueCmd, undefined);
|
||||
}
|
||||
function parsePayload(payload) {
|
||||
const dict = {};
|
||||
const parts = payload.split(',');
|
||||
for (let i = 0; i < parts.length; i++) {
|
||||
const valueParts = parts[i].split('=');
|
||||
dict[valueParts[0]] = valueParts[1];
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
function passwordDigest(username, password) {
|
||||
if (typeof username !== 'string') {
|
||||
throw new error_1.MongoInvalidArgumentError('Username must be a string');
|
||||
}
|
||||
if (typeof password !== 'string') {
|
||||
throw new error_1.MongoInvalidArgumentError('Password must be a string');
|
||||
}
|
||||
if (password.length === 0) {
|
||||
throw new error_1.MongoInvalidArgumentError('Password cannot be empty');
|
||||
}
|
||||
let md5;
|
||||
try {
|
||||
md5 = crypto.createHash('md5');
|
||||
}
|
||||
catch (err) {
|
||||
if (crypto.getFips()) {
|
||||
// This error is (slightly) more helpful than what comes from OpenSSL directly, e.g.
|
||||
// 'Error: error:060800C8:digital envelope routines:EVP_DigestInit_ex:disabled for FIPS'
|
||||
throw new Error('Auth mechanism SCRAM-SHA-1 is not supported in FIPS mode');
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
md5.update(`${username}:mongo:${password}`, 'utf8');
|
||||
return md5.digest('hex');
|
||||
}
|
||||
// XOR two buffers
|
||||
function xor(a, b) {
|
||||
if (!Buffer.isBuffer(a)) {
|
||||
a = Buffer.from(a);
|
||||
}
|
||||
if (!Buffer.isBuffer(b)) {
|
||||
b = Buffer.from(b);
|
||||
}
|
||||
const length = Math.max(a.length, b.length);
|
||||
const res = [];
|
||||
for (let i = 0; i < length; i += 1) {
|
||||
res.push(a[i] ^ b[i]);
|
||||
}
|
||||
return Buffer.from(res).toString('base64');
|
||||
}
|
||||
function H(method, text) {
|
||||
return crypto.createHash(method).update(text).digest();
|
||||
}
|
||||
function HMAC(method, key, text) {
|
||||
return crypto.createHmac(method, key).update(text).digest();
|
||||
}
|
||||
let _hiCache = {};
|
||||
let _hiCacheCount = 0;
|
||||
function _hiCachePurge() {
|
||||
_hiCache = {};
|
||||
_hiCacheCount = 0;
|
||||
}
|
||||
const hiLengthMap = {
|
||||
sha256: 32,
|
||||
sha1: 20
|
||||
};
|
||||
function HI(data, salt, iterations, cryptoMethod) {
|
||||
// omit the work if already generated
|
||||
const key = [data, salt.toString('base64'), iterations].join('_');
|
||||
if (_hiCache[key] != null) {
|
||||
return _hiCache[key];
|
||||
}
|
||||
// generate the salt
|
||||
const saltedData = crypto.pbkdf2Sync(data, salt, iterations, hiLengthMap[cryptoMethod], cryptoMethod);
|
||||
// cache a copy to speed up the next lookup, but prevent unbounded cache growth
|
||||
if (_hiCacheCount >= 200) {
|
||||
_hiCachePurge();
|
||||
}
|
||||
_hiCache[key] = saltedData;
|
||||
_hiCacheCount += 1;
|
||||
return saltedData;
|
||||
}
|
||||
function compareDigest(lhs, rhs) {
|
||||
if (lhs.length !== rhs.length) {
|
||||
return false;
|
||||
}
|
||||
if (typeof crypto.timingSafeEqual === 'function') {
|
||||
return crypto.timingSafeEqual(lhs, rhs);
|
||||
}
|
||||
let result = 0;
|
||||
for (let i = 0; i < lhs.length; i++) {
|
||||
result |= lhs[i] ^ rhs[i];
|
||||
}
|
||||
return result === 0;
|
||||
}
|
||||
class ScramSHA1 extends ScramSHA {
|
||||
constructor() {
|
||||
super('sha1');
|
||||
}
|
||||
}
|
||||
exports.ScramSHA1 = ScramSHA1;
|
||||
class ScramSHA256 extends ScramSHA {
|
||||
constructor() {
|
||||
super('sha256');
|
||||
}
|
||||
}
|
||||
exports.ScramSHA256 = ScramSHA256;
|
||||
//# sourceMappingURL=scram.js.map
|
||||
1
node_modules/mongodb/lib/cmap/auth/scram.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/auth/scram.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
36
node_modules/mongodb/lib/cmap/auth/x509.js
generated
vendored
Normal file
36
node_modules/mongodb/lib/cmap/auth/x509.js
generated
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.X509 = void 0;
|
||||
const error_1 = require("../../error");
|
||||
const utils_1 = require("../../utils");
|
||||
const auth_provider_1 = require("./auth_provider");
|
||||
class X509 extends auth_provider_1.AuthProvider {
|
||||
async prepare(handshakeDoc, authContext) {
|
||||
const { credentials } = authContext;
|
||||
if (!credentials) {
|
||||
throw new error_1.MongoMissingCredentialsError('AuthContext must provide credentials.');
|
||||
}
|
||||
return { ...handshakeDoc, speculativeAuthenticate: x509AuthenticateCommand(credentials) };
|
||||
}
|
||||
async auth(authContext) {
|
||||
const connection = authContext.connection;
|
||||
const credentials = authContext.credentials;
|
||||
if (!credentials) {
|
||||
throw new error_1.MongoMissingCredentialsError('AuthContext must provide credentials.');
|
||||
}
|
||||
const response = authContext.response;
|
||||
if (response?.speculativeAuthenticate) {
|
||||
return;
|
||||
}
|
||||
await connection.commandAsync((0, utils_1.ns)('$external.$cmd'), x509AuthenticateCommand(credentials), undefined);
|
||||
}
|
||||
}
|
||||
exports.X509 = X509;
|
||||
function x509AuthenticateCommand(credentials) {
|
||||
const command = { authenticate: 1, mechanism: 'MONGODB-X509' };
|
||||
if (credentials.username) {
|
||||
command.user = credentials.username;
|
||||
}
|
||||
return command;
|
||||
}
|
||||
//# sourceMappingURL=x509.js.map
|
||||
1
node_modules/mongodb/lib/cmap/auth/x509.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/auth/x509.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"x509.js","sourceRoot":"","sources":["../../../src/cmap/auth/x509.ts"],"names":[],"mappings":";;;AACA,uCAA2D;AAC3D,uCAAiC;AAEjC,mDAA4D;AAG5D,MAAa,IAAK,SAAQ,4BAAY;IAC3B,KAAK,CAAC,OAAO,CACpB,YAA+B,EAC/B,WAAwB;QAExB,MAAM,EAAE,WAAW,EAAE,GAAG,WAAW,CAAC;QACpC,IAAI,CAAC,WAAW,EAAE;YAChB,MAAM,IAAI,oCAA4B,CAAC,uCAAuC,CAAC,CAAC;SACjF;QACD,OAAO,EAAE,GAAG,YAAY,EAAE,uBAAuB,EAAE,uBAAuB,CAAC,WAAW,CAAC,EAAE,CAAC;IAC5F,CAAC;IAEQ,KAAK,CAAC,IAAI,CAAC,WAAwB;QAC1C,MAAM,UAAU,GAAG,WAAW,CAAC,UAAU,CAAC;QAC1C,MAAM,WAAW,GAAG,WAAW,CAAC,WAAW,CAAC;QAC5C,IAAI,CAAC,WAAW,EAAE;YAChB,MAAM,IAAI,oCAA4B,CAAC,uCAAuC,CAAC,CAAC;SACjF;QACD,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC;QAEtC,IAAI,QAAQ,EAAE,uBAAuB,EAAE;YACrC,OAAO;SACR;QAED,MAAM,UAAU,CAAC,YAAY,CAC3B,IAAA,UAAE,EAAC,gBAAgB,CAAC,EACpB,uBAAuB,CAAC,WAAW,CAAC,EACpC,SAAS,CACV,CAAC;IACJ,CAAC;CACF;AA9BD,oBA8BC;AAED,SAAS,uBAAuB,CAAC,WAA6B;IAC5D,MAAM,OAAO,GAAa,EAAE,YAAY,EAAE,CAAC,EAAE,SAAS,EAAE,cAAc,EAAE,CAAC;IACzE,IAAI,WAAW,CAAC,QAAQ,EAAE;QACxB,OAAO,CAAC,IAAI,GAAG,WAAW,CAAC,QAAQ,CAAC;KACrC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
||||
251
node_modules/mongodb/lib/cmap/command_monitoring_events.js
generated
vendored
Normal file
251
node_modules/mongodb/lib/cmap/command_monitoring_events.js
generated
vendored
Normal file
@@ -0,0 +1,251 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.SENSITIVE_COMMANDS = exports.CommandFailedEvent = exports.CommandSucceededEvent = exports.CommandStartedEvent = void 0;
|
||||
const constants_1 = require("../constants");
|
||||
const utils_1 = require("../utils");
|
||||
const commands_1 = require("./commands");
|
||||
/**
|
||||
* An event indicating the start of a given
|
||||
* @public
|
||||
* @category Event
|
||||
*/
|
||||
class CommandStartedEvent {
|
||||
/**
|
||||
* Create a started event
|
||||
*
|
||||
* @internal
|
||||
* @param pool - the pool that originated the command
|
||||
* @param command - the command
|
||||
*/
|
||||
constructor(connection, command) {
|
||||
/** @internal */
|
||||
this.name = constants_1.COMMAND_STARTED;
|
||||
const cmd = extractCommand(command);
|
||||
const commandName = extractCommandName(cmd);
|
||||
const { address, connectionId, serviceId } = extractConnectionDetails(connection);
|
||||
// TODO: remove in major revision, this is not spec behavior
|
||||
if (exports.SENSITIVE_COMMANDS.has(commandName)) {
|
||||
this.commandObj = {};
|
||||
this.commandObj[commandName] = true;
|
||||
}
|
||||
this.address = address;
|
||||
this.connectionId = connectionId;
|
||||
this.serviceId = serviceId;
|
||||
this.requestId = command.requestId;
|
||||
this.databaseName = databaseName(command);
|
||||
this.commandName = commandName;
|
||||
this.command = maybeRedact(commandName, cmd, cmd);
|
||||
}
|
||||
/* @internal */
|
||||
get hasServiceId() {
|
||||
return !!this.serviceId;
|
||||
}
|
||||
}
|
||||
exports.CommandStartedEvent = CommandStartedEvent;
|
||||
/**
|
||||
* An event indicating the success of a given command
|
||||
* @public
|
||||
* @category Event
|
||||
*/
|
||||
class CommandSucceededEvent {
|
||||
/**
|
||||
* Create a succeeded event
|
||||
*
|
||||
* @internal
|
||||
* @param pool - the pool that originated the command
|
||||
* @param command - the command
|
||||
* @param reply - the reply for this command from the server
|
||||
* @param started - a high resolution tuple timestamp of when the command was first sent, to calculate duration
|
||||
*/
|
||||
constructor(connection, command, reply, started) {
|
||||
/** @internal */
|
||||
this.name = constants_1.COMMAND_SUCCEEDED;
|
||||
const cmd = extractCommand(command);
|
||||
const commandName = extractCommandName(cmd);
|
||||
const { address, connectionId, serviceId } = extractConnectionDetails(connection);
|
||||
this.address = address;
|
||||
this.connectionId = connectionId;
|
||||
this.serviceId = serviceId;
|
||||
this.requestId = command.requestId;
|
||||
this.commandName = commandName;
|
||||
this.duration = (0, utils_1.calculateDurationInMs)(started);
|
||||
this.reply = maybeRedact(commandName, cmd, extractReply(command, reply));
|
||||
}
|
||||
/* @internal */
|
||||
get hasServiceId() {
|
||||
return !!this.serviceId;
|
||||
}
|
||||
}
|
||||
exports.CommandSucceededEvent = CommandSucceededEvent;
|
||||
/**
|
||||
* An event indicating the failure of a given command
|
||||
* @public
|
||||
* @category Event
|
||||
*/
|
||||
class CommandFailedEvent {
|
||||
/**
|
||||
* Create a failure event
|
||||
*
|
||||
* @internal
|
||||
* @param pool - the pool that originated the command
|
||||
* @param command - the command
|
||||
* @param error - the generated error or a server error response
|
||||
* @param started - a high resolution tuple timestamp of when the command was first sent, to calculate duration
|
||||
*/
|
||||
constructor(connection, command, error, started) {
|
||||
/** @internal */
|
||||
this.name = constants_1.COMMAND_FAILED;
|
||||
const cmd = extractCommand(command);
|
||||
const commandName = extractCommandName(cmd);
|
||||
const { address, connectionId, serviceId } = extractConnectionDetails(connection);
|
||||
this.address = address;
|
||||
this.connectionId = connectionId;
|
||||
this.serviceId = serviceId;
|
||||
this.requestId = command.requestId;
|
||||
this.commandName = commandName;
|
||||
this.duration = (0, utils_1.calculateDurationInMs)(started);
|
||||
this.failure = maybeRedact(commandName, cmd, error);
|
||||
}
|
||||
/* @internal */
|
||||
get hasServiceId() {
|
||||
return !!this.serviceId;
|
||||
}
|
||||
}
|
||||
exports.CommandFailedEvent = CommandFailedEvent;
|
||||
/**
|
||||
* Commands that we want to redact because of the sensitive nature of their contents
|
||||
* @internal
|
||||
*/
|
||||
exports.SENSITIVE_COMMANDS = new Set([
|
||||
'authenticate',
|
||||
'saslStart',
|
||||
'saslContinue',
|
||||
'getnonce',
|
||||
'createUser',
|
||||
'updateUser',
|
||||
'copydbgetnonce',
|
||||
'copydbsaslstart',
|
||||
'copydb'
|
||||
]);
|
||||
const HELLO_COMMANDS = new Set(['hello', constants_1.LEGACY_HELLO_COMMAND, constants_1.LEGACY_HELLO_COMMAND_CAMEL_CASE]);
|
||||
// helper methods
|
||||
const extractCommandName = (commandDoc) => Object.keys(commandDoc)[0];
|
||||
const namespace = (command) => command.ns;
|
||||
const databaseName = (command) => command.ns.split('.')[0];
|
||||
const collectionName = (command) => command.ns.split('.')[1];
|
||||
const maybeRedact = (commandName, commandDoc, result) => exports.SENSITIVE_COMMANDS.has(commandName) ||
|
||||
(HELLO_COMMANDS.has(commandName) && commandDoc.speculativeAuthenticate)
|
||||
? {}
|
||||
: result;
|
||||
const LEGACY_FIND_QUERY_MAP = {
|
||||
$query: 'filter',
|
||||
$orderby: 'sort',
|
||||
$hint: 'hint',
|
||||
$comment: 'comment',
|
||||
$maxScan: 'maxScan',
|
||||
$max: 'max',
|
||||
$min: 'min',
|
||||
$returnKey: 'returnKey',
|
||||
$showDiskLoc: 'showRecordId',
|
||||
$maxTimeMS: 'maxTimeMS',
|
||||
$snapshot: 'snapshot'
|
||||
};
|
||||
const LEGACY_FIND_OPTIONS_MAP = {
|
||||
numberToSkip: 'skip',
|
||||
numberToReturn: 'batchSize',
|
||||
returnFieldSelector: 'projection'
|
||||
};
|
||||
const OP_QUERY_KEYS = [
|
||||
'tailable',
|
||||
'oplogReplay',
|
||||
'noCursorTimeout',
|
||||
'awaitData',
|
||||
'partial',
|
||||
'exhaust'
|
||||
];
|
||||
/** Extract the actual command from the query, possibly up-converting if it's a legacy format */
|
||||
function extractCommand(command) {
|
||||
if (command instanceof commands_1.Msg) {
|
||||
return (0, utils_1.deepCopy)(command.command);
|
||||
}
|
||||
if (command.query?.$query) {
|
||||
let result;
|
||||
if (command.ns === 'admin.$cmd') {
|
||||
// up-convert legacy command
|
||||
result = Object.assign({}, command.query.$query);
|
||||
}
|
||||
else {
|
||||
// up-convert legacy find command
|
||||
result = { find: collectionName(command) };
|
||||
Object.keys(LEGACY_FIND_QUERY_MAP).forEach(key => {
|
||||
if (command.query[key] != null) {
|
||||
result[LEGACY_FIND_QUERY_MAP[key]] = (0, utils_1.deepCopy)(command.query[key]);
|
||||
}
|
||||
});
|
||||
}
|
||||
Object.keys(LEGACY_FIND_OPTIONS_MAP).forEach(key => {
|
||||
const legacyKey = key;
|
||||
if (command[legacyKey] != null) {
|
||||
result[LEGACY_FIND_OPTIONS_MAP[legacyKey]] = (0, utils_1.deepCopy)(command[legacyKey]);
|
||||
}
|
||||
});
|
||||
OP_QUERY_KEYS.forEach(key => {
|
||||
if (command[key]) {
|
||||
result[key] = command[key];
|
||||
}
|
||||
});
|
||||
if (command.pre32Limit != null) {
|
||||
result.limit = command.pre32Limit;
|
||||
}
|
||||
if (command.query.$explain) {
|
||||
return { explain: result };
|
||||
}
|
||||
return result;
|
||||
}
|
||||
const clonedQuery = {};
|
||||
const clonedCommand = {};
|
||||
if (command.query) {
|
||||
for (const k in command.query) {
|
||||
clonedQuery[k] = (0, utils_1.deepCopy)(command.query[k]);
|
||||
}
|
||||
clonedCommand.query = clonedQuery;
|
||||
}
|
||||
for (const k in command) {
|
||||
if (k === 'query')
|
||||
continue;
|
||||
clonedCommand[k] = (0, utils_1.deepCopy)(command[k]);
|
||||
}
|
||||
return command.query ? clonedQuery : clonedCommand;
|
||||
}
|
||||
function extractReply(command, reply) {
|
||||
if (!reply) {
|
||||
return reply;
|
||||
}
|
||||
if (command instanceof commands_1.Msg) {
|
||||
return (0, utils_1.deepCopy)(reply.result ? reply.result : reply);
|
||||
}
|
||||
// is this a legacy find command?
|
||||
if (command.query && command.query.$query != null) {
|
||||
return {
|
||||
ok: 1,
|
||||
cursor: {
|
||||
id: (0, utils_1.deepCopy)(reply.cursorId),
|
||||
ns: namespace(command),
|
||||
firstBatch: (0, utils_1.deepCopy)(reply.documents)
|
||||
}
|
||||
};
|
||||
}
|
||||
return (0, utils_1.deepCopy)(reply.result ? reply.result : reply);
|
||||
}
|
||||
function extractConnectionDetails(connection) {
|
||||
let connectionId;
|
||||
if ('id' in connection) {
|
||||
connectionId = connection.id;
|
||||
}
|
||||
return {
|
||||
address: connection.address,
|
||||
serviceId: connection.serviceId,
|
||||
connectionId
|
||||
};
|
||||
}
|
||||
//# sourceMappingURL=command_monitoring_events.js.map
|
||||
1
node_modules/mongodb/lib/cmap/command_monitoring_events.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/command_monitoring_events.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
487
node_modules/mongodb/lib/cmap/commands.js
generated
vendored
Normal file
487
node_modules/mongodb/lib/cmap/commands.js
generated
vendored
Normal file
@@ -0,0 +1,487 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.BinMsg = exports.Msg = exports.Response = exports.Query = void 0;
|
||||
const BSON = require("../bson");
|
||||
const error_1 = require("../error");
|
||||
const read_preference_1 = require("../read_preference");
|
||||
const utils_1 = require("../utils");
|
||||
const constants_1 = require("./wire_protocol/constants");
|
||||
// Incrementing request id
|
||||
let _requestId = 0;
|
||||
// Query flags
|
||||
const OPTS_TAILABLE_CURSOR = 2;
|
||||
const OPTS_SECONDARY = 4;
|
||||
const OPTS_OPLOG_REPLAY = 8;
|
||||
const OPTS_NO_CURSOR_TIMEOUT = 16;
|
||||
const OPTS_AWAIT_DATA = 32;
|
||||
const OPTS_EXHAUST = 64;
|
||||
const OPTS_PARTIAL = 128;
|
||||
// Response flags
|
||||
const CURSOR_NOT_FOUND = 1;
|
||||
const QUERY_FAILURE = 2;
|
||||
const SHARD_CONFIG_STALE = 4;
|
||||
const AWAIT_CAPABLE = 8;
|
||||
/**************************************************************
|
||||
* QUERY
|
||||
**************************************************************/
|
||||
/** @internal */
|
||||
class Query {
|
||||
constructor(ns, query, options) {
|
||||
// Basic options needed to be passed in
|
||||
// TODO(NODE-3483): Replace with MongoCommandError
|
||||
if (ns == null)
|
||||
throw new error_1.MongoRuntimeError('Namespace must be specified for query');
|
||||
// TODO(NODE-3483): Replace with MongoCommandError
|
||||
if (query == null)
|
||||
throw new error_1.MongoRuntimeError('A query document must be specified for query');
|
||||
// Validate that we are not passing 0x00 in the collection name
|
||||
if (ns.indexOf('\x00') !== -1) {
|
||||
// TODO(NODE-3483): Use MongoNamespace static method
|
||||
throw new error_1.MongoRuntimeError('Namespace cannot contain a null character');
|
||||
}
|
||||
// Basic options
|
||||
this.ns = ns;
|
||||
this.query = query;
|
||||
// Additional options
|
||||
this.numberToSkip = options.numberToSkip || 0;
|
||||
this.numberToReturn = options.numberToReturn || 0;
|
||||
this.returnFieldSelector = options.returnFieldSelector || undefined;
|
||||
this.requestId = Query.getRequestId();
|
||||
// special case for pre-3.2 find commands, delete ASAP
|
||||
this.pre32Limit = options.pre32Limit;
|
||||
// Serialization option
|
||||
this.serializeFunctions =
|
||||
typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false;
|
||||
this.ignoreUndefined =
|
||||
typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : false;
|
||||
this.maxBsonSize = options.maxBsonSize || 1024 * 1024 * 16;
|
||||
this.checkKeys = typeof options.checkKeys === 'boolean' ? options.checkKeys : false;
|
||||
this.batchSize = this.numberToReturn;
|
||||
// Flags
|
||||
this.tailable = false;
|
||||
this.secondaryOk = typeof options.secondaryOk === 'boolean' ? options.secondaryOk : false;
|
||||
this.oplogReplay = false;
|
||||
this.noCursorTimeout = false;
|
||||
this.awaitData = false;
|
||||
this.exhaust = false;
|
||||
this.partial = false;
|
||||
}
|
||||
/** Assign next request Id. */
|
||||
incRequestId() {
|
||||
this.requestId = _requestId++;
|
||||
}
|
||||
/** Peek next request Id. */
|
||||
nextRequestId() {
|
||||
return _requestId + 1;
|
||||
}
|
||||
/** Increment then return next request Id. */
|
||||
static getRequestId() {
|
||||
return ++_requestId;
|
||||
}
|
||||
// Uses a single allocated buffer for the process, avoiding multiple memory allocations
|
||||
toBin() {
|
||||
const buffers = [];
|
||||
let projection = null;
|
||||
// Set up the flags
|
||||
let flags = 0;
|
||||
if (this.tailable) {
|
||||
flags |= OPTS_TAILABLE_CURSOR;
|
||||
}
|
||||
if (this.secondaryOk) {
|
||||
flags |= OPTS_SECONDARY;
|
||||
}
|
||||
if (this.oplogReplay) {
|
||||
flags |= OPTS_OPLOG_REPLAY;
|
||||
}
|
||||
if (this.noCursorTimeout) {
|
||||
flags |= OPTS_NO_CURSOR_TIMEOUT;
|
||||
}
|
||||
if (this.awaitData) {
|
||||
flags |= OPTS_AWAIT_DATA;
|
||||
}
|
||||
if (this.exhaust) {
|
||||
flags |= OPTS_EXHAUST;
|
||||
}
|
||||
if (this.partial) {
|
||||
flags |= OPTS_PARTIAL;
|
||||
}
|
||||
// If batchSize is different to this.numberToReturn
|
||||
if (this.batchSize !== this.numberToReturn)
|
||||
this.numberToReturn = this.batchSize;
|
||||
// Allocate write protocol header buffer
|
||||
const header = Buffer.alloc(4 * 4 + // Header
|
||||
4 + // Flags
|
||||
Buffer.byteLength(this.ns) +
|
||||
1 + // namespace
|
||||
4 + // numberToSkip
|
||||
4 // numberToReturn
|
||||
);
|
||||
// Add header to buffers
|
||||
buffers.push(header);
|
||||
// Serialize the query
|
||||
const query = BSON.serialize(this.query, {
|
||||
checkKeys: this.checkKeys,
|
||||
serializeFunctions: this.serializeFunctions,
|
||||
ignoreUndefined: this.ignoreUndefined
|
||||
});
|
||||
// Add query document
|
||||
buffers.push(query);
|
||||
if (this.returnFieldSelector && Object.keys(this.returnFieldSelector).length > 0) {
|
||||
// Serialize the projection document
|
||||
projection = BSON.serialize(this.returnFieldSelector, {
|
||||
checkKeys: this.checkKeys,
|
||||
serializeFunctions: this.serializeFunctions,
|
||||
ignoreUndefined: this.ignoreUndefined
|
||||
});
|
||||
// Add projection document
|
||||
buffers.push(projection);
|
||||
}
|
||||
// Total message size
|
||||
const totalLength = header.length + query.length + (projection ? projection.length : 0);
|
||||
// Set up the index
|
||||
let index = 4;
|
||||
// Write total document length
|
||||
header[3] = (totalLength >> 24) & 0xff;
|
||||
header[2] = (totalLength >> 16) & 0xff;
|
||||
header[1] = (totalLength >> 8) & 0xff;
|
||||
header[0] = totalLength & 0xff;
|
||||
// Write header information requestId
|
||||
header[index + 3] = (this.requestId >> 24) & 0xff;
|
||||
header[index + 2] = (this.requestId >> 16) & 0xff;
|
||||
header[index + 1] = (this.requestId >> 8) & 0xff;
|
||||
header[index] = this.requestId & 0xff;
|
||||
index = index + 4;
|
||||
// Write header information responseTo
|
||||
header[index + 3] = (0 >> 24) & 0xff;
|
||||
header[index + 2] = (0 >> 16) & 0xff;
|
||||
header[index + 1] = (0 >> 8) & 0xff;
|
||||
header[index] = 0 & 0xff;
|
||||
index = index + 4;
|
||||
// Write header information OP_QUERY
|
||||
header[index + 3] = (constants_1.OP_QUERY >> 24) & 0xff;
|
||||
header[index + 2] = (constants_1.OP_QUERY >> 16) & 0xff;
|
||||
header[index + 1] = (constants_1.OP_QUERY >> 8) & 0xff;
|
||||
header[index] = constants_1.OP_QUERY & 0xff;
|
||||
index = index + 4;
|
||||
// Write header information flags
|
||||
header[index + 3] = (flags >> 24) & 0xff;
|
||||
header[index + 2] = (flags >> 16) & 0xff;
|
||||
header[index + 1] = (flags >> 8) & 0xff;
|
||||
header[index] = flags & 0xff;
|
||||
index = index + 4;
|
||||
// Write collection name
|
||||
index = index + header.write(this.ns, index, 'utf8') + 1;
|
||||
header[index - 1] = 0;
|
||||
// Write header information flags numberToSkip
|
||||
header[index + 3] = (this.numberToSkip >> 24) & 0xff;
|
||||
header[index + 2] = (this.numberToSkip >> 16) & 0xff;
|
||||
header[index + 1] = (this.numberToSkip >> 8) & 0xff;
|
||||
header[index] = this.numberToSkip & 0xff;
|
||||
index = index + 4;
|
||||
// Write header information flags numberToReturn
|
||||
header[index + 3] = (this.numberToReturn >> 24) & 0xff;
|
||||
header[index + 2] = (this.numberToReturn >> 16) & 0xff;
|
||||
header[index + 1] = (this.numberToReturn >> 8) & 0xff;
|
||||
header[index] = this.numberToReturn & 0xff;
|
||||
index = index + 4;
|
||||
// Return the buffers
|
||||
return buffers;
|
||||
}
|
||||
}
|
||||
exports.Query = Query;
|
||||
/** @internal */
|
||||
class Response {
|
||||
constructor(message, msgHeader, msgBody, opts) {
|
||||
this.documents = new Array(0);
|
||||
this.parsed = false;
|
||||
this.raw = message;
|
||||
this.data = msgBody;
|
||||
this.opts = opts ?? {
|
||||
useBigInt64: false,
|
||||
promoteLongs: true,
|
||||
promoteValues: true,
|
||||
promoteBuffers: false,
|
||||
bsonRegExp: false
|
||||
};
|
||||
// Read the message header
|
||||
this.length = msgHeader.length;
|
||||
this.requestId = msgHeader.requestId;
|
||||
this.responseTo = msgHeader.responseTo;
|
||||
this.opCode = msgHeader.opCode;
|
||||
this.fromCompressed = msgHeader.fromCompressed;
|
||||
// Flag values
|
||||
this.useBigInt64 = typeof this.opts.useBigInt64 === 'boolean' ? this.opts.useBigInt64 : false;
|
||||
this.promoteLongs = typeof this.opts.promoteLongs === 'boolean' ? this.opts.promoteLongs : true;
|
||||
this.promoteValues =
|
||||
typeof this.opts.promoteValues === 'boolean' ? this.opts.promoteValues : true;
|
||||
this.promoteBuffers =
|
||||
typeof this.opts.promoteBuffers === 'boolean' ? this.opts.promoteBuffers : false;
|
||||
this.bsonRegExp = typeof this.opts.bsonRegExp === 'boolean' ? this.opts.bsonRegExp : false;
|
||||
}
|
||||
isParsed() {
|
||||
return this.parsed;
|
||||
}
|
||||
parse(options) {
|
||||
// Don't parse again if not needed
|
||||
if (this.parsed)
|
||||
return;
|
||||
options = options ?? {};
|
||||
// Allow the return of raw documents instead of parsing
|
||||
const raw = options.raw || false;
|
||||
const documentsReturnedIn = options.documentsReturnedIn || null;
|
||||
const useBigInt64 = options.useBigInt64 ?? this.opts.useBigInt64;
|
||||
const promoteLongs = options.promoteLongs ?? this.opts.promoteLongs;
|
||||
const promoteValues = options.promoteValues ?? this.opts.promoteValues;
|
||||
const promoteBuffers = options.promoteBuffers ?? this.opts.promoteBuffers;
|
||||
const bsonRegExp = options.bsonRegExp ?? this.opts.bsonRegExp;
|
||||
let bsonSize;
|
||||
// Set up the options
|
||||
const _options = {
|
||||
useBigInt64,
|
||||
promoteLongs,
|
||||
promoteValues,
|
||||
promoteBuffers,
|
||||
bsonRegExp
|
||||
};
|
||||
// Position within OP_REPLY at which documents start
|
||||
// (See https://www.mongodb.com/docs/manual/reference/mongodb-wire-protocol/#wire-op-reply)
|
||||
this.index = 20;
|
||||
// Read the message body
|
||||
this.responseFlags = this.data.readInt32LE(0);
|
||||
this.cursorId = new BSON.Long(this.data.readInt32LE(4), this.data.readInt32LE(8));
|
||||
this.startingFrom = this.data.readInt32LE(12);
|
||||
this.numberReturned = this.data.readInt32LE(16);
|
||||
// Preallocate document array
|
||||
this.documents = new Array(this.numberReturned);
|
||||
this.cursorNotFound = (this.responseFlags & CURSOR_NOT_FOUND) !== 0;
|
||||
this.queryFailure = (this.responseFlags & QUERY_FAILURE) !== 0;
|
||||
this.shardConfigStale = (this.responseFlags & SHARD_CONFIG_STALE) !== 0;
|
||||
this.awaitCapable = (this.responseFlags & AWAIT_CAPABLE) !== 0;
|
||||
// Parse Body
|
||||
for (let i = 0; i < this.numberReturned; i++) {
|
||||
bsonSize =
|
||||
this.data[this.index] |
|
||||
(this.data[this.index + 1] << 8) |
|
||||
(this.data[this.index + 2] << 16) |
|
||||
(this.data[this.index + 3] << 24);
|
||||
// If we have raw results specified slice the return document
|
||||
if (raw) {
|
||||
this.documents[i] = this.data.slice(this.index, this.index + bsonSize);
|
||||
}
|
||||
else {
|
||||
this.documents[i] = BSON.deserialize(this.data.slice(this.index, this.index + bsonSize), _options);
|
||||
}
|
||||
// Adjust the index
|
||||
this.index = this.index + bsonSize;
|
||||
}
|
||||
if (this.documents.length === 1 && documentsReturnedIn != null && raw) {
|
||||
const fieldsAsRaw = {};
|
||||
fieldsAsRaw[documentsReturnedIn] = true;
|
||||
_options.fieldsAsRaw = fieldsAsRaw;
|
||||
const doc = BSON.deserialize(this.documents[0], _options);
|
||||
this.documents = [doc];
|
||||
}
|
||||
// Set parsed
|
||||
this.parsed = true;
|
||||
}
|
||||
}
|
||||
exports.Response = Response;
|
||||
// Implementation of OP_MSG spec:
|
||||
// https://github.com/mongodb/specifications/blob/master/source/message/OP_MSG.rst
|
||||
//
|
||||
// struct Section {
|
||||
// uint8 payloadType;
|
||||
// union payload {
|
||||
// document document; // payloadType == 0
|
||||
// struct sequence { // payloadType == 1
|
||||
// int32 size;
|
||||
// cstring identifier;
|
||||
// document* documents;
|
||||
// };
|
||||
// };
|
||||
// };
|
||||
// struct OP_MSG {
|
||||
// struct MsgHeader {
|
||||
// int32 messageLength;
|
||||
// int32 requestID;
|
||||
// int32 responseTo;
|
||||
// int32 opCode = 2013;
|
||||
// };
|
||||
// uint32 flagBits;
|
||||
// Section+ sections;
|
||||
// [uint32 checksum;]
|
||||
// };
|
||||
// Msg Flags
|
||||
const OPTS_CHECKSUM_PRESENT = 1;
|
||||
const OPTS_MORE_TO_COME = 2;
|
||||
const OPTS_EXHAUST_ALLOWED = 1 << 16;
|
||||
/** @internal */
|
||||
class Msg {
|
||||
constructor(ns, command, options) {
|
||||
// Basic options needed to be passed in
|
||||
if (command == null)
|
||||
throw new error_1.MongoInvalidArgumentError('Query document must be specified for query');
|
||||
// Basic options
|
||||
this.ns = ns;
|
||||
this.command = command;
|
||||
this.command.$db = (0, utils_1.databaseNamespace)(ns);
|
||||
if (options.readPreference && options.readPreference.mode !== read_preference_1.ReadPreference.PRIMARY) {
|
||||
this.command.$readPreference = options.readPreference.toJSON();
|
||||
}
|
||||
// Ensure empty options
|
||||
this.options = options ?? {};
|
||||
// Additional options
|
||||
this.requestId = options.requestId ? options.requestId : Msg.getRequestId();
|
||||
// Serialization option
|
||||
this.serializeFunctions =
|
||||
typeof options.serializeFunctions === 'boolean' ? options.serializeFunctions : false;
|
||||
this.ignoreUndefined =
|
||||
typeof options.ignoreUndefined === 'boolean' ? options.ignoreUndefined : false;
|
||||
this.checkKeys = typeof options.checkKeys === 'boolean' ? options.checkKeys : false;
|
||||
this.maxBsonSize = options.maxBsonSize || 1024 * 1024 * 16;
|
||||
// flags
|
||||
this.checksumPresent = false;
|
||||
this.moreToCome = options.moreToCome || false;
|
||||
this.exhaustAllowed =
|
||||
typeof options.exhaustAllowed === 'boolean' ? options.exhaustAllowed : false;
|
||||
}
|
||||
toBin() {
|
||||
const buffers = [];
|
||||
let flags = 0;
|
||||
if (this.checksumPresent) {
|
||||
flags |= OPTS_CHECKSUM_PRESENT;
|
||||
}
|
||||
if (this.moreToCome) {
|
||||
flags |= OPTS_MORE_TO_COME;
|
||||
}
|
||||
if (this.exhaustAllowed) {
|
||||
flags |= OPTS_EXHAUST_ALLOWED;
|
||||
}
|
||||
const header = Buffer.alloc(4 * 4 + // Header
|
||||
4 // Flags
|
||||
);
|
||||
buffers.push(header);
|
||||
let totalLength = header.length;
|
||||
const command = this.command;
|
||||
totalLength += this.makeDocumentSegment(buffers, command);
|
||||
header.writeInt32LE(totalLength, 0); // messageLength
|
||||
header.writeInt32LE(this.requestId, 4); // requestID
|
||||
header.writeInt32LE(0, 8); // responseTo
|
||||
header.writeInt32LE(constants_1.OP_MSG, 12); // opCode
|
||||
header.writeUInt32LE(flags, 16); // flags
|
||||
return buffers;
|
||||
}
|
||||
makeDocumentSegment(buffers, document) {
|
||||
const payloadTypeBuffer = Buffer.alloc(1);
|
||||
payloadTypeBuffer[0] = 0;
|
||||
const documentBuffer = this.serializeBson(document);
|
||||
buffers.push(payloadTypeBuffer);
|
||||
buffers.push(documentBuffer);
|
||||
return payloadTypeBuffer.length + documentBuffer.length;
|
||||
}
|
||||
serializeBson(document) {
|
||||
return BSON.serialize(document, {
|
||||
checkKeys: this.checkKeys,
|
||||
serializeFunctions: this.serializeFunctions,
|
||||
ignoreUndefined: this.ignoreUndefined
|
||||
});
|
||||
}
|
||||
static getRequestId() {
|
||||
_requestId = (_requestId + 1) & 0x7fffffff;
|
||||
return _requestId;
|
||||
}
|
||||
}
|
||||
exports.Msg = Msg;
|
||||
/** @internal */
|
||||
class BinMsg {
|
||||
constructor(message, msgHeader, msgBody, opts) {
|
||||
this.parsed = false;
|
||||
this.raw = message;
|
||||
this.data = msgBody;
|
||||
this.opts = opts ?? {
|
||||
useBigInt64: false,
|
||||
promoteLongs: true,
|
||||
promoteValues: true,
|
||||
promoteBuffers: false,
|
||||
bsonRegExp: false
|
||||
};
|
||||
// Read the message header
|
||||
this.length = msgHeader.length;
|
||||
this.requestId = msgHeader.requestId;
|
||||
this.responseTo = msgHeader.responseTo;
|
||||
this.opCode = msgHeader.opCode;
|
||||
this.fromCompressed = msgHeader.fromCompressed;
|
||||
// Read response flags
|
||||
this.responseFlags = msgBody.readInt32LE(0);
|
||||
this.checksumPresent = (this.responseFlags & OPTS_CHECKSUM_PRESENT) !== 0;
|
||||
this.moreToCome = (this.responseFlags & OPTS_MORE_TO_COME) !== 0;
|
||||
this.exhaustAllowed = (this.responseFlags & OPTS_EXHAUST_ALLOWED) !== 0;
|
||||
this.useBigInt64 = typeof this.opts.useBigInt64 === 'boolean' ? this.opts.useBigInt64 : false;
|
||||
this.promoteLongs = typeof this.opts.promoteLongs === 'boolean' ? this.opts.promoteLongs : true;
|
||||
this.promoteValues =
|
||||
typeof this.opts.promoteValues === 'boolean' ? this.opts.promoteValues : true;
|
||||
this.promoteBuffers =
|
||||
typeof this.opts.promoteBuffers === 'boolean' ? this.opts.promoteBuffers : false;
|
||||
this.bsonRegExp = typeof this.opts.bsonRegExp === 'boolean' ? this.opts.bsonRegExp : false;
|
||||
this.documents = [];
|
||||
}
|
||||
isParsed() {
|
||||
return this.parsed;
|
||||
}
|
||||
parse(options) {
|
||||
// Don't parse again if not needed
|
||||
if (this.parsed)
|
||||
return;
|
||||
options = options ?? {};
|
||||
this.index = 4;
|
||||
// Allow the return of raw documents instead of parsing
|
||||
const raw = options.raw || false;
|
||||
const documentsReturnedIn = options.documentsReturnedIn || null;
|
||||
const useBigInt64 = options.useBigInt64 ?? this.opts.useBigInt64;
|
||||
const promoteLongs = options.promoteLongs ?? this.opts.promoteLongs;
|
||||
const promoteValues = options.promoteValues ?? this.opts.promoteValues;
|
||||
const promoteBuffers = options.promoteBuffers ?? this.opts.promoteBuffers;
|
||||
const bsonRegExp = options.bsonRegExp ?? this.opts.bsonRegExp;
|
||||
const validation = this.parseBsonSerializationOptions(options);
|
||||
// Set up the options
|
||||
const bsonOptions = {
|
||||
useBigInt64,
|
||||
promoteLongs,
|
||||
promoteValues,
|
||||
promoteBuffers,
|
||||
bsonRegExp,
|
||||
validation
|
||||
// Due to the strictness of the BSON libraries validation option we need this cast
|
||||
};
|
||||
while (this.index < this.data.length) {
|
||||
const payloadType = this.data.readUInt8(this.index++);
|
||||
if (payloadType === 0) {
|
||||
const bsonSize = this.data.readUInt32LE(this.index);
|
||||
const bin = this.data.slice(this.index, this.index + bsonSize);
|
||||
this.documents.push(raw ? bin : BSON.deserialize(bin, bsonOptions));
|
||||
this.index += bsonSize;
|
||||
}
|
||||
else if (payloadType === 1) {
|
||||
// It was decided that no driver makes use of payload type 1
|
||||
// TODO(NODE-3483): Replace with MongoDeprecationError
|
||||
throw new error_1.MongoRuntimeError('OP_MSG Payload Type 1 detected unsupported protocol');
|
||||
}
|
||||
}
|
||||
if (this.documents.length === 1 && documentsReturnedIn != null && raw) {
|
||||
const fieldsAsRaw = {};
|
||||
fieldsAsRaw[documentsReturnedIn] = true;
|
||||
bsonOptions.fieldsAsRaw = fieldsAsRaw;
|
||||
const doc = BSON.deserialize(this.documents[0], bsonOptions);
|
||||
this.documents = [doc];
|
||||
}
|
||||
this.parsed = true;
|
||||
}
|
||||
parseBsonSerializationOptions({ enableUtf8Validation }) {
|
||||
if (enableUtf8Validation === false) {
|
||||
return { utf8: false };
|
||||
}
|
||||
return { utf8: { writeErrors: false } };
|
||||
}
|
||||
}
|
||||
exports.BinMsg = BinMsg;
|
||||
//# sourceMappingURL=commands.js.map
|
||||
1
node_modules/mongodb/lib/cmap/commands.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/commands.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
381
node_modules/mongodb/lib/cmap/connect.js
generated
vendored
Normal file
381
node_modules/mongodb/lib/cmap/connect.js
generated
vendored
Normal file
@@ -0,0 +1,381 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.LEGAL_TCP_SOCKET_OPTIONS = exports.LEGAL_TLS_SOCKET_OPTIONS = exports.prepareHandshakeDocument = exports.connect = exports.AUTH_PROVIDERS = void 0;
|
||||
const net = require("net");
|
||||
const socks_1 = require("socks");
|
||||
const tls = require("tls");
|
||||
const bson_1 = require("../bson");
|
||||
const constants_1 = require("../constants");
|
||||
const error_1 = require("../error");
|
||||
const utils_1 = require("../utils");
|
||||
const auth_provider_1 = require("./auth/auth_provider");
|
||||
const gssapi_1 = require("./auth/gssapi");
|
||||
const mongocr_1 = require("./auth/mongocr");
|
||||
const mongodb_aws_1 = require("./auth/mongodb_aws");
|
||||
const mongodb_oidc_1 = require("./auth/mongodb_oidc");
|
||||
const plain_1 = require("./auth/plain");
|
||||
const providers_1 = require("./auth/providers");
|
||||
const scram_1 = require("./auth/scram");
|
||||
const x509_1 = require("./auth/x509");
|
||||
const connection_1 = require("./connection");
|
||||
const constants_2 = require("./wire_protocol/constants");
|
||||
/** @internal */
|
||||
exports.AUTH_PROVIDERS = new Map([
|
||||
[providers_1.AuthMechanism.MONGODB_AWS, new mongodb_aws_1.MongoDBAWS()],
|
||||
[providers_1.AuthMechanism.MONGODB_CR, new mongocr_1.MongoCR()],
|
||||
[providers_1.AuthMechanism.MONGODB_GSSAPI, new gssapi_1.GSSAPI()],
|
||||
[providers_1.AuthMechanism.MONGODB_OIDC, new mongodb_oidc_1.MongoDBOIDC()],
|
||||
[providers_1.AuthMechanism.MONGODB_PLAIN, new plain_1.Plain()],
|
||||
[providers_1.AuthMechanism.MONGODB_SCRAM_SHA1, new scram_1.ScramSHA1()],
|
||||
[providers_1.AuthMechanism.MONGODB_SCRAM_SHA256, new scram_1.ScramSHA256()],
|
||||
[providers_1.AuthMechanism.MONGODB_X509, new x509_1.X509()]
|
||||
]);
|
||||
function connect(options, callback) {
|
||||
makeConnection({ ...options, existingSocket: undefined }, (err, socket) => {
|
||||
if (err || !socket) {
|
||||
return callback(err);
|
||||
}
|
||||
let ConnectionType = options.connectionType ?? connection_1.Connection;
|
||||
if (options.autoEncrypter) {
|
||||
ConnectionType = connection_1.CryptoConnection;
|
||||
}
|
||||
const connection = new ConnectionType(socket, options);
|
||||
performInitialHandshake(connection, options).then(() => callback(undefined, connection), error => {
|
||||
connection.destroy({ force: false });
|
||||
callback(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
exports.connect = connect;
|
||||
function checkSupportedServer(hello, options) {
|
||||
const serverVersionHighEnough = hello &&
|
||||
(typeof hello.maxWireVersion === 'number' || hello.maxWireVersion instanceof bson_1.Int32) &&
|
||||
hello.maxWireVersion >= constants_2.MIN_SUPPORTED_WIRE_VERSION;
|
||||
const serverVersionLowEnough = hello &&
|
||||
(typeof hello.minWireVersion === 'number' || hello.minWireVersion instanceof bson_1.Int32) &&
|
||||
hello.minWireVersion <= constants_2.MAX_SUPPORTED_WIRE_VERSION;
|
||||
if (serverVersionHighEnough) {
|
||||
if (serverVersionLowEnough) {
|
||||
return null;
|
||||
}
|
||||
const message = `Server at ${options.hostAddress} reports minimum wire version ${JSON.stringify(hello.minWireVersion)}, but this version of the Node.js Driver requires at most ${constants_2.MAX_SUPPORTED_WIRE_VERSION} (MongoDB ${constants_2.MAX_SUPPORTED_SERVER_VERSION})`;
|
||||
return new error_1.MongoCompatibilityError(message);
|
||||
}
|
||||
const message = `Server at ${options.hostAddress} reports maximum wire version ${JSON.stringify(hello.maxWireVersion) ?? 0}, but this version of the Node.js Driver requires at least ${constants_2.MIN_SUPPORTED_WIRE_VERSION} (MongoDB ${constants_2.MIN_SUPPORTED_SERVER_VERSION})`;
|
||||
return new error_1.MongoCompatibilityError(message);
|
||||
}
|
||||
async function performInitialHandshake(conn, options) {
|
||||
const credentials = options.credentials;
|
||||
if (credentials) {
|
||||
if (!(credentials.mechanism === providers_1.AuthMechanism.MONGODB_DEFAULT) &&
|
||||
!exports.AUTH_PROVIDERS.get(credentials.mechanism)) {
|
||||
throw new error_1.MongoInvalidArgumentError(`AuthMechanism '${credentials.mechanism}' not supported`);
|
||||
}
|
||||
}
|
||||
const authContext = new auth_provider_1.AuthContext(conn, credentials, options);
|
||||
conn.authContext = authContext;
|
||||
const handshakeDoc = await prepareHandshakeDocument(authContext);
|
||||
// @ts-expect-error: TODO(NODE-5141): The options need to be filtered properly, Connection options differ from Command options
|
||||
const handshakeOptions = { ...options };
|
||||
if (typeof options.connectTimeoutMS === 'number') {
|
||||
// The handshake technically is a monitoring check, so its socket timeout should be connectTimeoutMS
|
||||
handshakeOptions.socketTimeoutMS = options.connectTimeoutMS;
|
||||
}
|
||||
const start = new Date().getTime();
|
||||
const response = await conn.commandAsync((0, utils_1.ns)('admin.$cmd'), handshakeDoc, handshakeOptions);
|
||||
if (!('isWritablePrimary' in response)) {
|
||||
// Provide hello-style response document.
|
||||
response.isWritablePrimary = response[constants_1.LEGACY_HELLO_COMMAND];
|
||||
}
|
||||
if (response.helloOk) {
|
||||
conn.helloOk = true;
|
||||
}
|
||||
const supportedServerErr = checkSupportedServer(response, options);
|
||||
if (supportedServerErr) {
|
||||
throw supportedServerErr;
|
||||
}
|
||||
if (options.loadBalanced) {
|
||||
if (!response.serviceId) {
|
||||
throw new error_1.MongoCompatibilityError('Driver attempted to initialize in load balancing mode, ' +
|
||||
'but the server does not support this mode.');
|
||||
}
|
||||
}
|
||||
// NOTE: This is metadata attached to the connection while porting away from
|
||||
// handshake being done in the `Server` class. Likely, it should be
|
||||
// relocated, or at very least restructured.
|
||||
conn.hello = response;
|
||||
conn.lastHelloMS = new Date().getTime() - start;
|
||||
if (!response.arbiterOnly && credentials) {
|
||||
// store the response on auth context
|
||||
authContext.response = response;
|
||||
const resolvedCredentials = credentials.resolveAuthMechanism(response);
|
||||
const provider = exports.AUTH_PROVIDERS.get(resolvedCredentials.mechanism);
|
||||
if (!provider) {
|
||||
throw new error_1.MongoInvalidArgumentError(`No AuthProvider for ${resolvedCredentials.mechanism} defined.`);
|
||||
}
|
||||
try {
|
||||
await provider.auth(authContext);
|
||||
}
|
||||
catch (error) {
|
||||
if (error instanceof error_1.MongoError) {
|
||||
error.addErrorLabel(error_1.MongoErrorLabel.HandshakeError);
|
||||
if ((0, error_1.needsRetryableWriteLabel)(error, response.maxWireVersion)) {
|
||||
error.addErrorLabel(error_1.MongoErrorLabel.RetryableWriteError);
|
||||
}
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @internal
|
||||
*
|
||||
* This function is only exposed for testing purposes.
|
||||
*/
|
||||
async function prepareHandshakeDocument(authContext) {
|
||||
const options = authContext.options;
|
||||
const compressors = options.compressors ? options.compressors : [];
|
||||
const { serverApi } = authContext.connection;
|
||||
const handshakeDoc = {
|
||||
[serverApi?.version ? 'hello' : constants_1.LEGACY_HELLO_COMMAND]: 1,
|
||||
helloOk: true,
|
||||
client: options.metadata,
|
||||
compression: compressors
|
||||
};
|
||||
if (options.loadBalanced === true) {
|
||||
handshakeDoc.loadBalanced = true;
|
||||
}
|
||||
const credentials = authContext.credentials;
|
||||
if (credentials) {
|
||||
if (credentials.mechanism === providers_1.AuthMechanism.MONGODB_DEFAULT && credentials.username) {
|
||||
handshakeDoc.saslSupportedMechs = `${credentials.source}.${credentials.username}`;
|
||||
const provider = exports.AUTH_PROVIDERS.get(providers_1.AuthMechanism.MONGODB_SCRAM_SHA256);
|
||||
if (!provider) {
|
||||
// This auth mechanism is always present.
|
||||
throw new error_1.MongoInvalidArgumentError(`No AuthProvider for ${providers_1.AuthMechanism.MONGODB_SCRAM_SHA256} defined.`);
|
||||
}
|
||||
return provider.prepare(handshakeDoc, authContext);
|
||||
}
|
||||
const provider = exports.AUTH_PROVIDERS.get(credentials.mechanism);
|
||||
if (!provider) {
|
||||
throw new error_1.MongoInvalidArgumentError(`No AuthProvider for ${credentials.mechanism} defined.`);
|
||||
}
|
||||
return provider.prepare(handshakeDoc, authContext);
|
||||
}
|
||||
return handshakeDoc;
|
||||
}
|
||||
exports.prepareHandshakeDocument = prepareHandshakeDocument;
|
||||
/** @public */
|
||||
exports.LEGAL_TLS_SOCKET_OPTIONS = [
|
||||
'ALPNProtocols',
|
||||
'ca',
|
||||
'cert',
|
||||
'checkServerIdentity',
|
||||
'ciphers',
|
||||
'crl',
|
||||
'ecdhCurve',
|
||||
'key',
|
||||
'minDHSize',
|
||||
'passphrase',
|
||||
'pfx',
|
||||
'rejectUnauthorized',
|
||||
'secureContext',
|
||||
'secureProtocol',
|
||||
'servername',
|
||||
'session'
|
||||
];
|
||||
/** @public */
|
||||
exports.LEGAL_TCP_SOCKET_OPTIONS = [
|
||||
'family',
|
||||
'hints',
|
||||
'localAddress',
|
||||
'localPort',
|
||||
'lookup'
|
||||
];
|
||||
function parseConnectOptions(options) {
|
||||
const hostAddress = options.hostAddress;
|
||||
if (!hostAddress)
|
||||
throw new error_1.MongoInvalidArgumentError('Option "hostAddress" is required');
|
||||
const result = {};
|
||||
for (const name of exports.LEGAL_TCP_SOCKET_OPTIONS) {
|
||||
if (options[name] != null) {
|
||||
result[name] = options[name];
|
||||
}
|
||||
}
|
||||
if (typeof hostAddress.socketPath === 'string') {
|
||||
result.path = hostAddress.socketPath;
|
||||
return result;
|
||||
}
|
||||
else if (typeof hostAddress.host === 'string') {
|
||||
result.host = hostAddress.host;
|
||||
result.port = hostAddress.port;
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
// This should never happen since we set up HostAddresses
|
||||
// But if we don't throw here the socket could hang until timeout
|
||||
// TODO(NODE-3483)
|
||||
throw new error_1.MongoRuntimeError(`Unexpected HostAddress ${JSON.stringify(hostAddress)}`);
|
||||
}
|
||||
}
|
||||
function parseSslOptions(options) {
|
||||
const result = parseConnectOptions(options);
|
||||
// Merge in valid SSL options
|
||||
for (const name of exports.LEGAL_TLS_SOCKET_OPTIONS) {
|
||||
if (options[name] != null) {
|
||||
result[name] = options[name];
|
||||
}
|
||||
}
|
||||
if (options.existingSocket) {
|
||||
result.socket = options.existingSocket;
|
||||
}
|
||||
// Set default sni servername to be the same as host
|
||||
if (result.servername == null && result.host && !net.isIP(result.host)) {
|
||||
result.servername = result.host;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
const SOCKET_ERROR_EVENT_LIST = ['error', 'close', 'timeout', 'parseError'];
|
||||
const SOCKET_ERROR_EVENTS = new Set(SOCKET_ERROR_EVENT_LIST);
|
||||
function makeConnection(options, _callback) {
|
||||
const useTLS = options.tls ?? false;
|
||||
const keepAlive = options.keepAlive ?? true;
|
||||
const socketTimeoutMS = options.socketTimeoutMS ?? Reflect.get(options, 'socketTimeout') ?? 0;
|
||||
const noDelay = options.noDelay ?? true;
|
||||
const connectTimeoutMS = options.connectTimeoutMS ?? 30000;
|
||||
const rejectUnauthorized = options.rejectUnauthorized ?? true;
|
||||
const keepAliveInitialDelay = ((options.keepAliveInitialDelay ?? 120000) > socketTimeoutMS
|
||||
? Math.round(socketTimeoutMS / 2)
|
||||
: options.keepAliveInitialDelay) ?? 120000;
|
||||
const existingSocket = options.existingSocket;
|
||||
let socket;
|
||||
const callback = function (err, ret) {
|
||||
if (err && socket) {
|
||||
socket.destroy();
|
||||
}
|
||||
_callback(err, ret);
|
||||
};
|
||||
if (options.proxyHost != null) {
|
||||
// Currently, only Socks5 is supported.
|
||||
return makeSocks5Connection({
|
||||
...options,
|
||||
connectTimeoutMS // Should always be present for Socks5
|
||||
}, callback);
|
||||
}
|
||||
if (useTLS) {
|
||||
const tlsSocket = tls.connect(parseSslOptions(options));
|
||||
if (typeof tlsSocket.disableRenegotiation === 'function') {
|
||||
tlsSocket.disableRenegotiation();
|
||||
}
|
||||
socket = tlsSocket;
|
||||
}
|
||||
else if (existingSocket) {
|
||||
// In the TLS case, parseSslOptions() sets options.socket to existingSocket,
|
||||
// so we only need to handle the non-TLS case here (where existingSocket
|
||||
// gives us all we need out of the box).
|
||||
socket = existingSocket;
|
||||
}
|
||||
else {
|
||||
socket = net.createConnection(parseConnectOptions(options));
|
||||
}
|
||||
socket.setKeepAlive(keepAlive, keepAliveInitialDelay);
|
||||
socket.setTimeout(connectTimeoutMS);
|
||||
socket.setNoDelay(noDelay);
|
||||
const connectEvent = useTLS ? 'secureConnect' : 'connect';
|
||||
let cancellationHandler;
|
||||
function errorHandler(eventName) {
|
||||
return (err) => {
|
||||
SOCKET_ERROR_EVENTS.forEach(event => socket.removeAllListeners(event));
|
||||
if (cancellationHandler && options.cancellationToken) {
|
||||
options.cancellationToken.removeListener('cancel', cancellationHandler);
|
||||
}
|
||||
socket.removeListener(connectEvent, connectHandler);
|
||||
callback(connectionFailureError(eventName, err));
|
||||
};
|
||||
}
|
||||
function connectHandler() {
|
||||
SOCKET_ERROR_EVENTS.forEach(event => socket.removeAllListeners(event));
|
||||
if (cancellationHandler && options.cancellationToken) {
|
||||
options.cancellationToken.removeListener('cancel', cancellationHandler);
|
||||
}
|
||||
if ('authorizationError' in socket) {
|
||||
if (socket.authorizationError && rejectUnauthorized) {
|
||||
// TODO(NODE-5192): wrap this with a MongoError subclass
|
||||
return callback(socket.authorizationError);
|
||||
}
|
||||
}
|
||||
socket.setTimeout(0);
|
||||
callback(undefined, socket);
|
||||
}
|
||||
SOCKET_ERROR_EVENTS.forEach(event => socket.once(event, errorHandler(event)));
|
||||
if (options.cancellationToken) {
|
||||
cancellationHandler = errorHandler('cancel');
|
||||
options.cancellationToken.once('cancel', cancellationHandler);
|
||||
}
|
||||
if (existingSocket) {
|
||||
process.nextTick(connectHandler);
|
||||
}
|
||||
else {
|
||||
socket.once(connectEvent, connectHandler);
|
||||
}
|
||||
}
|
||||
function makeSocks5Connection(options, callback) {
|
||||
const hostAddress = utils_1.HostAddress.fromHostPort(options.proxyHost ?? '', // proxyHost is guaranteed to set here
|
||||
options.proxyPort ?? 1080);
|
||||
// First, connect to the proxy server itself:
|
||||
makeConnection({
|
||||
...options,
|
||||
hostAddress,
|
||||
tls: false,
|
||||
proxyHost: undefined
|
||||
}, (err, rawSocket) => {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
const destination = parseConnectOptions(options);
|
||||
if (typeof destination.host !== 'string' || typeof destination.port !== 'number') {
|
||||
return callback(new error_1.MongoInvalidArgumentError('Can only make Socks5 connections to TCP hosts'));
|
||||
}
|
||||
// Then, establish the Socks5 proxy connection:
|
||||
socks_1.SocksClient.createConnection({
|
||||
existing_socket: rawSocket,
|
||||
timeout: options.connectTimeoutMS,
|
||||
command: 'connect',
|
||||
destination: {
|
||||
host: destination.host,
|
||||
port: destination.port
|
||||
},
|
||||
proxy: {
|
||||
// host and port are ignored because we pass existing_socket
|
||||
host: 'iLoveJavaScript',
|
||||
port: 0,
|
||||
type: 5,
|
||||
userId: options.proxyUsername || undefined,
|
||||
password: options.proxyPassword || undefined
|
||||
}
|
||||
}).then(({ socket }) => {
|
||||
// Finally, now treat the resulting duplex stream as the
|
||||
// socket over which we send and receive wire protocol messages:
|
||||
makeConnection({
|
||||
...options,
|
||||
existingSocket: socket,
|
||||
proxyHost: undefined
|
||||
}, callback);
|
||||
}, error => callback(connectionFailureError('error', error)));
|
||||
});
|
||||
}
|
||||
function connectionFailureError(type, err) {
|
||||
switch (type) {
|
||||
case 'error':
|
||||
return new error_1.MongoNetworkError(err);
|
||||
case 'timeout':
|
||||
return new error_1.MongoNetworkTimeoutError('connection timed out');
|
||||
case 'close':
|
||||
return new error_1.MongoNetworkError('connection closed');
|
||||
case 'cancel':
|
||||
return new error_1.MongoNetworkError('connection establishment was cancelled');
|
||||
default:
|
||||
return new error_1.MongoNetworkError('unknown network error');
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=connect.js.map
|
||||
1
node_modules/mongodb/lib/cmap/connect.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/connect.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
492
node_modules/mongodb/lib/cmap/connection.js
generated
vendored
Normal file
492
node_modules/mongodb/lib/cmap/connection.js
generated
vendored
Normal file
@@ -0,0 +1,492 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.hasSessionSupport = exports.CryptoConnection = exports.Connection = void 0;
|
||||
const timers_1 = require("timers");
|
||||
const util_1 = require("util");
|
||||
const constants_1 = require("../constants");
|
||||
const error_1 = require("../error");
|
||||
const mongo_types_1 = require("../mongo_types");
|
||||
const sessions_1 = require("../sessions");
|
||||
const utils_1 = require("../utils");
|
||||
const command_monitoring_events_1 = require("./command_monitoring_events");
|
||||
const commands_1 = require("./commands");
|
||||
const message_stream_1 = require("./message_stream");
|
||||
const stream_description_1 = require("./stream_description");
|
||||
const shared_1 = require("./wire_protocol/shared");
|
||||
/** @internal */
|
||||
const kStream = Symbol('stream');
|
||||
/** @internal */
|
||||
const kQueue = Symbol('queue');
|
||||
/** @internal */
|
||||
const kMessageStream = Symbol('messageStream');
|
||||
/** @internal */
|
||||
const kGeneration = Symbol('generation');
|
||||
/** @internal */
|
||||
const kLastUseTime = Symbol('lastUseTime');
|
||||
/** @internal */
|
||||
const kClusterTime = Symbol('clusterTime');
|
||||
/** @internal */
|
||||
const kDescription = Symbol('description');
|
||||
/** @internal */
|
||||
const kHello = Symbol('hello');
|
||||
/** @internal */
|
||||
const kAutoEncrypter = Symbol('autoEncrypter');
|
||||
/** @internal */
|
||||
const kDelayedTimeoutId = Symbol('delayedTimeoutId');
|
||||
const INVALID_QUEUE_SIZE = 'Connection internal queue contains more than 1 operation description';
|
||||
/** @internal */
|
||||
class Connection extends mongo_types_1.TypedEventEmitter {
|
||||
constructor(stream, options) {
|
||||
super();
|
||||
this.commandAsync = (0, util_1.promisify)((ns, cmd, options, callback) => this.command(ns, cmd, options, callback));
|
||||
this.id = options.id;
|
||||
this.address = streamIdentifier(stream, options);
|
||||
this.socketTimeoutMS = options.socketTimeoutMS ?? 0;
|
||||
this.monitorCommands = options.monitorCommands;
|
||||
this.serverApi = options.serverApi;
|
||||
this.closed = false;
|
||||
this[kHello] = null;
|
||||
this[kClusterTime] = null;
|
||||
this[kDescription] = new stream_description_1.StreamDescription(this.address, options);
|
||||
this[kGeneration] = options.generation;
|
||||
this[kLastUseTime] = (0, utils_1.now)();
|
||||
// setup parser stream and message handling
|
||||
this[kQueue] = new Map();
|
||||
this[kMessageStream] = new message_stream_1.MessageStream({
|
||||
...options,
|
||||
maxBsonMessageSize: this.hello?.maxBsonMessageSize
|
||||
});
|
||||
this[kStream] = stream;
|
||||
this[kDelayedTimeoutId] = null;
|
||||
this[kMessageStream].on('message', message => this.onMessage(message));
|
||||
this[kMessageStream].on('error', error => this.onError(error));
|
||||
this[kStream].on('close', () => this.onClose());
|
||||
this[kStream].on('timeout', () => this.onTimeout());
|
||||
this[kStream].on('error', () => {
|
||||
/* ignore errors, listen to `close` instead */
|
||||
});
|
||||
// hook the message stream up to the passed in stream
|
||||
this[kStream].pipe(this[kMessageStream]);
|
||||
this[kMessageStream].pipe(this[kStream]);
|
||||
}
|
||||
get description() {
|
||||
return this[kDescription];
|
||||
}
|
||||
get hello() {
|
||||
return this[kHello];
|
||||
}
|
||||
// the `connect` method stores the result of the handshake hello on the connection
|
||||
set hello(response) {
|
||||
this[kDescription].receiveResponse(response);
|
||||
this[kDescription] = Object.freeze(this[kDescription]);
|
||||
// TODO: remove this, and only use the `StreamDescription` in the future
|
||||
this[kHello] = response;
|
||||
}
|
||||
// Set the whether the message stream is for a monitoring connection.
|
||||
set isMonitoringConnection(value) {
|
||||
this[kMessageStream].isMonitoringConnection = value;
|
||||
}
|
||||
get isMonitoringConnection() {
|
||||
return this[kMessageStream].isMonitoringConnection;
|
||||
}
|
||||
get serviceId() {
|
||||
return this.hello?.serviceId;
|
||||
}
|
||||
get loadBalanced() {
|
||||
return this.description.loadBalanced;
|
||||
}
|
||||
get generation() {
|
||||
return this[kGeneration] || 0;
|
||||
}
|
||||
set generation(generation) {
|
||||
this[kGeneration] = generation;
|
||||
}
|
||||
get idleTime() {
|
||||
return (0, utils_1.calculateDurationInMs)(this[kLastUseTime]);
|
||||
}
|
||||
get clusterTime() {
|
||||
return this[kClusterTime];
|
||||
}
|
||||
get stream() {
|
||||
return this[kStream];
|
||||
}
|
||||
markAvailable() {
|
||||
this[kLastUseTime] = (0, utils_1.now)();
|
||||
}
|
||||
onError(error) {
|
||||
this.cleanup(true, error);
|
||||
}
|
||||
onClose() {
|
||||
const message = `connection ${this.id} to ${this.address} closed`;
|
||||
this.cleanup(true, new error_1.MongoNetworkError(message));
|
||||
}
|
||||
onTimeout() {
|
||||
this[kDelayedTimeoutId] = (0, timers_1.setTimeout)(() => {
|
||||
const message = `connection ${this.id} to ${this.address} timed out`;
|
||||
const beforeHandshake = this.hello == null;
|
||||
this.cleanup(true, new error_1.MongoNetworkTimeoutError(message, { beforeHandshake }));
|
||||
}, 1).unref(); // No need for this timer to hold the event loop open
|
||||
}
|
||||
onMessage(message) {
|
||||
const delayedTimeoutId = this[kDelayedTimeoutId];
|
||||
if (delayedTimeoutId != null) {
|
||||
(0, timers_1.clearTimeout)(delayedTimeoutId);
|
||||
this[kDelayedTimeoutId] = null;
|
||||
}
|
||||
const socketTimeoutMS = this[kStream].timeout ?? 0;
|
||||
this[kStream].setTimeout(0);
|
||||
// always emit the message, in case we are streaming
|
||||
this.emit('message', message);
|
||||
let operationDescription = this[kQueue].get(message.responseTo);
|
||||
if (!operationDescription && this.isMonitoringConnection) {
|
||||
// This is how we recover when the initial hello's requestId is not
|
||||
// the responseTo when hello responses have been skipped:
|
||||
// First check if the map is of invalid size
|
||||
if (this[kQueue].size > 1) {
|
||||
this.cleanup(true, new error_1.MongoRuntimeError(INVALID_QUEUE_SIZE));
|
||||
}
|
||||
else {
|
||||
// Get the first orphaned operation description.
|
||||
const entry = this[kQueue].entries().next();
|
||||
if (entry.value != null) {
|
||||
const [requestId, orphaned] = entry.value;
|
||||
// If the orphaned operation description exists then set it.
|
||||
operationDescription = orphaned;
|
||||
// Remove the entry with the bad request id from the queue.
|
||||
this[kQueue].delete(requestId);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!operationDescription) {
|
||||
return;
|
||||
}
|
||||
const callback = operationDescription.cb;
|
||||
// SERVER-45775: For exhaust responses we should be able to use the same requestId to
|
||||
// track response, however the server currently synthetically produces remote requests
|
||||
// making the `responseTo` change on each response
|
||||
this[kQueue].delete(message.responseTo);
|
||||
if ('moreToCome' in message && message.moreToCome) {
|
||||
// If the operation description check above does find an orphaned
|
||||
// description and sets the operationDescription then this line will put one
|
||||
// back in the queue with the correct requestId and will resolve not being able
|
||||
// to find the next one via the responseTo of the next streaming hello.
|
||||
this[kQueue].set(message.requestId, operationDescription);
|
||||
this[kStream].setTimeout(socketTimeoutMS);
|
||||
}
|
||||
try {
|
||||
// Pass in the entire description because it has BSON parsing options
|
||||
message.parse(operationDescription);
|
||||
}
|
||||
catch (err) {
|
||||
// If this error is generated by our own code, it will already have the correct class applied
|
||||
// if it is not, then it is coming from a catastrophic data parse failure or the BSON library
|
||||
// in either case, it should not be wrapped
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
if (message.documents[0]) {
|
||||
const document = message.documents[0];
|
||||
const session = operationDescription.session;
|
||||
if (session) {
|
||||
(0, sessions_1.updateSessionFromResponse)(session, document);
|
||||
}
|
||||
if (document.$clusterTime) {
|
||||
this[kClusterTime] = document.$clusterTime;
|
||||
this.emit(Connection.CLUSTER_TIME_RECEIVED, document.$clusterTime);
|
||||
}
|
||||
if (document.writeConcernError) {
|
||||
callback(new error_1.MongoWriteConcernError(document.writeConcernError, document), document);
|
||||
return;
|
||||
}
|
||||
if (document.ok === 0 || document.$err || document.errmsg || document.code) {
|
||||
callback(new error_1.MongoServerError(document));
|
||||
return;
|
||||
}
|
||||
}
|
||||
callback(undefined, message.documents[0]);
|
||||
}
|
||||
destroy(options, callback) {
|
||||
if (this.closed) {
|
||||
process.nextTick(() => callback?.());
|
||||
return;
|
||||
}
|
||||
if (typeof callback === 'function') {
|
||||
this.once('close', () => process.nextTick(() => callback()));
|
||||
}
|
||||
// load balanced mode requires that these listeners remain on the connection
|
||||
// after cleanup on timeouts, errors or close so we remove them before calling
|
||||
// cleanup.
|
||||
this.removeAllListeners(Connection.PINNED);
|
||||
this.removeAllListeners(Connection.UNPINNED);
|
||||
const message = `connection ${this.id} to ${this.address} closed`;
|
||||
this.cleanup(options.force, new error_1.MongoNetworkError(message));
|
||||
}
|
||||
/**
|
||||
* A method that cleans up the connection. When `force` is true, this method
|
||||
* forcibly destroys the socket.
|
||||
*
|
||||
* If an error is provided, any in-flight operations will be closed with the error.
|
||||
*
|
||||
* This method does nothing if the connection is already closed.
|
||||
*/
|
||||
cleanup(force, error) {
|
||||
if (this.closed) {
|
||||
return;
|
||||
}
|
||||
this.closed = true;
|
||||
const completeCleanup = () => {
|
||||
for (const op of this[kQueue].values()) {
|
||||
op.cb(error);
|
||||
}
|
||||
this[kQueue].clear();
|
||||
this.emit(Connection.CLOSE);
|
||||
};
|
||||
this[kStream].removeAllListeners();
|
||||
this[kMessageStream].removeAllListeners();
|
||||
this[kMessageStream].destroy();
|
||||
if (force) {
|
||||
this[kStream].destroy();
|
||||
completeCleanup();
|
||||
return;
|
||||
}
|
||||
if (!this[kStream].writableEnded) {
|
||||
this[kStream].end(() => {
|
||||
this[kStream].destroy();
|
||||
completeCleanup();
|
||||
});
|
||||
}
|
||||
else {
|
||||
completeCleanup();
|
||||
}
|
||||
}
|
||||
command(ns, command, options, callback) {
|
||||
let cmd = { ...command };
|
||||
const readPreference = (0, shared_1.getReadPreference)(options);
|
||||
const shouldUseOpMsg = supportsOpMsg(this);
|
||||
const session = options?.session;
|
||||
let clusterTime = this.clusterTime;
|
||||
if (this.serverApi) {
|
||||
const { version, strict, deprecationErrors } = this.serverApi;
|
||||
cmd.apiVersion = version;
|
||||
if (strict != null)
|
||||
cmd.apiStrict = strict;
|
||||
if (deprecationErrors != null)
|
||||
cmd.apiDeprecationErrors = deprecationErrors;
|
||||
}
|
||||
if (hasSessionSupport(this) && session) {
|
||||
if (session.clusterTime &&
|
||||
clusterTime &&
|
||||
session.clusterTime.clusterTime.greaterThan(clusterTime.clusterTime)) {
|
||||
clusterTime = session.clusterTime;
|
||||
}
|
||||
const err = (0, sessions_1.applySession)(session, cmd, options);
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
}
|
||||
else if (session?.explicit) {
|
||||
return callback(new error_1.MongoCompatibilityError('Current topology does not support sessions'));
|
||||
}
|
||||
// if we have a known cluster time, gossip it
|
||||
if (clusterTime) {
|
||||
cmd.$clusterTime = clusterTime;
|
||||
}
|
||||
if ((0, shared_1.isSharded)(this) && !shouldUseOpMsg && readPreference && readPreference.mode !== 'primary') {
|
||||
cmd = {
|
||||
$query: cmd,
|
||||
$readPreference: readPreference.toJSON()
|
||||
};
|
||||
}
|
||||
const commandOptions = Object.assign({
|
||||
numberToSkip: 0,
|
||||
numberToReturn: -1,
|
||||
checkKeys: false,
|
||||
// This value is not overridable
|
||||
secondaryOk: readPreference.secondaryOk()
|
||||
}, options);
|
||||
const cmdNs = `${ns.db}.$cmd`;
|
||||
const message = shouldUseOpMsg
|
||||
? new commands_1.Msg(cmdNs, cmd, commandOptions)
|
||||
: new commands_1.Query(cmdNs, cmd, commandOptions);
|
||||
try {
|
||||
write(this, message, commandOptions, callback);
|
||||
}
|
||||
catch (err) {
|
||||
callback(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.Connection = Connection;
|
||||
/** @event */
|
||||
Connection.COMMAND_STARTED = constants_1.COMMAND_STARTED;
|
||||
/** @event */
|
||||
Connection.COMMAND_SUCCEEDED = constants_1.COMMAND_SUCCEEDED;
|
||||
/** @event */
|
||||
Connection.COMMAND_FAILED = constants_1.COMMAND_FAILED;
|
||||
/** @event */
|
||||
Connection.CLUSTER_TIME_RECEIVED = constants_1.CLUSTER_TIME_RECEIVED;
|
||||
/** @event */
|
||||
Connection.CLOSE = constants_1.CLOSE;
|
||||
/** @event */
|
||||
Connection.MESSAGE = constants_1.MESSAGE;
|
||||
/** @event */
|
||||
Connection.PINNED = constants_1.PINNED;
|
||||
/** @event */
|
||||
Connection.UNPINNED = constants_1.UNPINNED;
|
||||
/** @internal */
|
||||
class CryptoConnection extends Connection {
|
||||
constructor(stream, options) {
|
||||
super(stream, options);
|
||||
this[kAutoEncrypter] = options.autoEncrypter;
|
||||
}
|
||||
/** @internal @override */
|
||||
command(ns, cmd, options, callback) {
|
||||
const autoEncrypter = this[kAutoEncrypter];
|
||||
if (!autoEncrypter) {
|
||||
return callback(new error_1.MongoMissingDependencyError('No AutoEncrypter available for encryption'));
|
||||
}
|
||||
const serverWireVersion = (0, utils_1.maxWireVersion)(this);
|
||||
if (serverWireVersion === 0) {
|
||||
// This means the initial handshake hasn't happened yet
|
||||
return super.command(ns, cmd, options, callback);
|
||||
}
|
||||
if (serverWireVersion < 8) {
|
||||
callback(new error_1.MongoCompatibilityError('Auto-encryption requires a minimum MongoDB version of 4.2'));
|
||||
return;
|
||||
}
|
||||
// Save sort or indexKeys based on the command being run
|
||||
// the encrypt API serializes our JS objects to BSON to pass to the native code layer
|
||||
// and then deserializes the encrypted result, the protocol level components
|
||||
// of the command (ex. sort) are then converted to JS objects potentially losing
|
||||
// import key order information. These fields are never encrypted so we can save the values
|
||||
// from before the encryption and replace them after encryption has been performed
|
||||
const sort = cmd.find || cmd.findAndModify ? cmd.sort : null;
|
||||
const indexKeys = cmd.createIndexes
|
||||
? cmd.indexes.map((index) => index.key)
|
||||
: null;
|
||||
autoEncrypter.encrypt(ns.toString(), cmd, options, (err, encrypted) => {
|
||||
if (err || encrypted == null) {
|
||||
callback(err, null);
|
||||
return;
|
||||
}
|
||||
// Replace the saved values
|
||||
if (sort != null && (cmd.find || cmd.findAndModify)) {
|
||||
encrypted.sort = sort;
|
||||
}
|
||||
if (indexKeys != null && cmd.createIndexes) {
|
||||
for (const [offset, index] of indexKeys.entries()) {
|
||||
encrypted.indexes[offset].key = index;
|
||||
}
|
||||
}
|
||||
super.command(ns, encrypted, options, (err, response) => {
|
||||
if (err || response == null) {
|
||||
callback(err, response);
|
||||
return;
|
||||
}
|
||||
autoEncrypter.decrypt(response, options, callback);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.CryptoConnection = CryptoConnection;
|
||||
/** @internal */
|
||||
function hasSessionSupport(conn) {
|
||||
const description = conn.description;
|
||||
return description.logicalSessionTimeoutMinutes != null;
|
||||
}
|
||||
exports.hasSessionSupport = hasSessionSupport;
|
||||
function supportsOpMsg(conn) {
|
||||
const description = conn.description;
|
||||
if (description == null) {
|
||||
return false;
|
||||
}
|
||||
return (0, utils_1.maxWireVersion)(conn) >= 6 && !description.__nodejs_mock_server__;
|
||||
}
|
||||
function streamIdentifier(stream, options) {
|
||||
if (options.proxyHost) {
|
||||
// If proxy options are specified, the properties of `stream` itself
|
||||
// will not accurately reflect what endpoint this is connected to.
|
||||
return options.hostAddress.toString();
|
||||
}
|
||||
const { remoteAddress, remotePort } = stream;
|
||||
if (typeof remoteAddress === 'string' && typeof remotePort === 'number') {
|
||||
return utils_1.HostAddress.fromHostPort(remoteAddress, remotePort).toString();
|
||||
}
|
||||
return (0, utils_1.uuidV4)().toString('hex');
|
||||
}
|
||||
function write(conn, command, options, callback) {
|
||||
options = options ?? {};
|
||||
const operationDescription = {
|
||||
requestId: command.requestId,
|
||||
cb: callback,
|
||||
session: options.session,
|
||||
noResponse: typeof options.noResponse === 'boolean' ? options.noResponse : false,
|
||||
documentsReturnedIn: options.documentsReturnedIn,
|
||||
// for BSON parsing
|
||||
useBigInt64: typeof options.useBigInt64 === 'boolean' ? options.useBigInt64 : false,
|
||||
promoteLongs: typeof options.promoteLongs === 'boolean' ? options.promoteLongs : true,
|
||||
promoteValues: typeof options.promoteValues === 'boolean' ? options.promoteValues : true,
|
||||
promoteBuffers: typeof options.promoteBuffers === 'boolean' ? options.promoteBuffers : false,
|
||||
bsonRegExp: typeof options.bsonRegExp === 'boolean' ? options.bsonRegExp : false,
|
||||
enableUtf8Validation: typeof options.enableUtf8Validation === 'boolean' ? options.enableUtf8Validation : true,
|
||||
raw: typeof options.raw === 'boolean' ? options.raw : false,
|
||||
started: 0
|
||||
};
|
||||
if (conn[kDescription] && conn[kDescription].compressor) {
|
||||
operationDescription.agreedCompressor = conn[kDescription].compressor;
|
||||
if (conn[kDescription].zlibCompressionLevel) {
|
||||
operationDescription.zlibCompressionLevel = conn[kDescription].zlibCompressionLevel;
|
||||
}
|
||||
}
|
||||
if (typeof options.socketTimeoutMS === 'number') {
|
||||
conn[kStream].setTimeout(options.socketTimeoutMS);
|
||||
}
|
||||
else if (conn.socketTimeoutMS !== 0) {
|
||||
conn[kStream].setTimeout(conn.socketTimeoutMS);
|
||||
}
|
||||
// if command monitoring is enabled we need to modify the callback here
|
||||
if (conn.monitorCommands) {
|
||||
conn.emit(Connection.COMMAND_STARTED, new command_monitoring_events_1.CommandStartedEvent(conn, command));
|
||||
operationDescription.started = (0, utils_1.now)();
|
||||
operationDescription.cb = (err, reply) => {
|
||||
// Command monitoring spec states that if ok is 1, then we must always emit
|
||||
// a command succeeded event, even if there's an error. Write concern errors
|
||||
// will have an ok: 1 in their reply.
|
||||
if (err && reply?.ok !== 1) {
|
||||
conn.emit(Connection.COMMAND_FAILED, new command_monitoring_events_1.CommandFailedEvent(conn, command, err, operationDescription.started));
|
||||
}
|
||||
else {
|
||||
if (reply && (reply.ok === 0 || reply.$err)) {
|
||||
conn.emit(Connection.COMMAND_FAILED, new command_monitoring_events_1.CommandFailedEvent(conn, command, reply, operationDescription.started));
|
||||
}
|
||||
else {
|
||||
conn.emit(Connection.COMMAND_SUCCEEDED, new command_monitoring_events_1.CommandSucceededEvent(conn, command, reply, operationDescription.started));
|
||||
}
|
||||
}
|
||||
if (typeof callback === 'function') {
|
||||
// Since we're passing through the reply with the write concern error now, we
|
||||
// need it not to be provided to the original callback in this case so
|
||||
// retryability does not get tricked into thinking the command actually
|
||||
// succeeded.
|
||||
callback(err, err instanceof error_1.MongoWriteConcernError ? undefined : reply);
|
||||
}
|
||||
};
|
||||
}
|
||||
if (!operationDescription.noResponse) {
|
||||
conn[kQueue].set(operationDescription.requestId, operationDescription);
|
||||
}
|
||||
try {
|
||||
conn[kMessageStream].writeCommand(command, operationDescription);
|
||||
}
|
||||
catch (e) {
|
||||
if (!operationDescription.noResponse) {
|
||||
conn[kQueue].delete(operationDescription.requestId);
|
||||
operationDescription.cb(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (operationDescription.noResponse) {
|
||||
operationDescription.cb();
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=connection.js.map
|
||||
1
node_modules/mongodb/lib/cmap/connection.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/connection.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
637
node_modules/mongodb/lib/cmap/connection_pool.js
generated
vendored
Normal file
637
node_modules/mongodb/lib/cmap/connection_pool.js
generated
vendored
Normal file
@@ -0,0 +1,637 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ConnectionPool = exports.PoolState = void 0;
|
||||
const timers_1 = require("timers");
|
||||
const constants_1 = require("../constants");
|
||||
const error_1 = require("../error");
|
||||
const mongo_types_1 = require("../mongo_types");
|
||||
const utils_1 = require("../utils");
|
||||
const connect_1 = require("./connect");
|
||||
const connection_1 = require("./connection");
|
||||
const connection_pool_events_1 = require("./connection_pool_events");
|
||||
const errors_1 = require("./errors");
|
||||
const metrics_1 = require("./metrics");
|
||||
/** @internal */
|
||||
const kServer = Symbol('server');
|
||||
/** @internal */
|
||||
const kConnections = Symbol('connections');
|
||||
/** @internal */
|
||||
const kPending = Symbol('pending');
|
||||
/** @internal */
|
||||
const kCheckedOut = Symbol('checkedOut');
|
||||
/** @internal */
|
||||
const kMinPoolSizeTimer = Symbol('minPoolSizeTimer');
|
||||
/** @internal */
|
||||
const kGeneration = Symbol('generation');
|
||||
/** @internal */
|
||||
const kServiceGenerations = Symbol('serviceGenerations');
|
||||
/** @internal */
|
||||
const kConnectionCounter = Symbol('connectionCounter');
|
||||
/** @internal */
|
||||
const kCancellationToken = Symbol('cancellationToken');
|
||||
/** @internal */
|
||||
const kWaitQueue = Symbol('waitQueue');
|
||||
/** @internal */
|
||||
const kCancelled = Symbol('cancelled');
|
||||
/** @internal */
|
||||
const kMetrics = Symbol('metrics');
|
||||
/** @internal */
|
||||
const kProcessingWaitQueue = Symbol('processingWaitQueue');
|
||||
/** @internal */
|
||||
const kPoolState = Symbol('poolState');
|
||||
/** @internal */
|
||||
exports.PoolState = Object.freeze({
|
||||
paused: 'paused',
|
||||
ready: 'ready',
|
||||
closed: 'closed'
|
||||
});
|
||||
/**
|
||||
* A pool of connections which dynamically resizes, and emit events related to pool activity
|
||||
* @internal
|
||||
*/
|
||||
class ConnectionPool extends mongo_types_1.TypedEventEmitter {
|
||||
constructor(server, options) {
|
||||
super();
|
||||
this.options = Object.freeze({
|
||||
...options,
|
||||
connectionType: connection_1.Connection,
|
||||
maxPoolSize: options.maxPoolSize ?? 100,
|
||||
minPoolSize: options.minPoolSize ?? 0,
|
||||
maxConnecting: options.maxConnecting ?? 2,
|
||||
maxIdleTimeMS: options.maxIdleTimeMS ?? 0,
|
||||
waitQueueTimeoutMS: options.waitQueueTimeoutMS ?? 0,
|
||||
minPoolSizeCheckFrequencyMS: options.minPoolSizeCheckFrequencyMS ?? 100,
|
||||
autoEncrypter: options.autoEncrypter,
|
||||
metadata: options.metadata
|
||||
});
|
||||
if (this.options.minPoolSize > this.options.maxPoolSize) {
|
||||
throw new error_1.MongoInvalidArgumentError('Connection pool minimum size must not be greater than maximum pool size');
|
||||
}
|
||||
this[kPoolState] = exports.PoolState.paused;
|
||||
this[kServer] = server;
|
||||
this[kConnections] = new utils_1.List();
|
||||
this[kPending] = 0;
|
||||
this[kCheckedOut] = new Set();
|
||||
this[kMinPoolSizeTimer] = undefined;
|
||||
this[kGeneration] = 0;
|
||||
this[kServiceGenerations] = new Map();
|
||||
this[kConnectionCounter] = (0, utils_1.makeCounter)(1);
|
||||
this[kCancellationToken] = new mongo_types_1.CancellationToken();
|
||||
this[kCancellationToken].setMaxListeners(Infinity);
|
||||
this[kWaitQueue] = new utils_1.List();
|
||||
this[kMetrics] = new metrics_1.ConnectionPoolMetrics();
|
||||
this[kProcessingWaitQueue] = false;
|
||||
this.mongoLogger = this[kServer].topology.client.mongoLogger;
|
||||
this.component = 'connection';
|
||||
process.nextTick(() => {
|
||||
this.emitAndLog(ConnectionPool.CONNECTION_POOL_CREATED, new connection_pool_events_1.ConnectionPoolCreatedEvent(this));
|
||||
});
|
||||
}
|
||||
/** The address of the endpoint the pool is connected to */
|
||||
get address() {
|
||||
return this.options.hostAddress.toString();
|
||||
}
|
||||
/**
|
||||
* Check if the pool has been closed
|
||||
*
|
||||
* TODO(NODE-3263): We can remove this property once shell no longer needs it
|
||||
*/
|
||||
get closed() {
|
||||
return this[kPoolState] === exports.PoolState.closed;
|
||||
}
|
||||
/** An integer representing the SDAM generation of the pool */
|
||||
get generation() {
|
||||
return this[kGeneration];
|
||||
}
|
||||
/** An integer expressing how many total connections (available + pending + in use) the pool currently has */
|
||||
get totalConnectionCount() {
|
||||
return (this.availableConnectionCount + this.pendingConnectionCount + this.currentCheckedOutCount);
|
||||
}
|
||||
/** An integer expressing how many connections are currently available in the pool. */
|
||||
get availableConnectionCount() {
|
||||
return this[kConnections].length;
|
||||
}
|
||||
get pendingConnectionCount() {
|
||||
return this[kPending];
|
||||
}
|
||||
get currentCheckedOutCount() {
|
||||
return this[kCheckedOut].size;
|
||||
}
|
||||
get waitQueueSize() {
|
||||
return this[kWaitQueue].length;
|
||||
}
|
||||
get loadBalanced() {
|
||||
return this.options.loadBalanced;
|
||||
}
|
||||
get serviceGenerations() {
|
||||
return this[kServiceGenerations];
|
||||
}
|
||||
get serverError() {
|
||||
return this[kServer].description.error;
|
||||
}
|
||||
/**
|
||||
* This is exposed ONLY for use in mongosh, to enable
|
||||
* killing all connections if a user quits the shell with
|
||||
* operations in progress.
|
||||
*
|
||||
* This property may be removed as a part of NODE-3263.
|
||||
*/
|
||||
get checkedOutConnections() {
|
||||
return this[kCheckedOut];
|
||||
}
|
||||
/**
|
||||
* Get the metrics information for the pool when a wait queue timeout occurs.
|
||||
*/
|
||||
waitQueueErrorMetrics() {
|
||||
return this[kMetrics].info(this.options.maxPoolSize);
|
||||
}
|
||||
/**
|
||||
* Set the pool state to "ready"
|
||||
*/
|
||||
ready() {
|
||||
if (this[kPoolState] !== exports.PoolState.paused) {
|
||||
return;
|
||||
}
|
||||
this[kPoolState] = exports.PoolState.ready;
|
||||
this.emitAndLog(ConnectionPool.CONNECTION_POOL_READY, new connection_pool_events_1.ConnectionPoolReadyEvent(this));
|
||||
(0, timers_1.clearTimeout)(this[kMinPoolSizeTimer]);
|
||||
this.ensureMinPoolSize();
|
||||
}
|
||||
/**
|
||||
* Check a connection out of this pool. The connection will continue to be tracked, but no reference to it
|
||||
* will be held by the pool. This means that if a connection is checked out it MUST be checked back in or
|
||||
* explicitly destroyed by the new owner.
|
||||
*/
|
||||
checkOut(callback) {
|
||||
this.emitAndLog(ConnectionPool.CONNECTION_CHECK_OUT_STARTED, new connection_pool_events_1.ConnectionCheckOutStartedEvent(this));
|
||||
const waitQueueMember = { callback };
|
||||
const waitQueueTimeoutMS = this.options.waitQueueTimeoutMS;
|
||||
if (waitQueueTimeoutMS) {
|
||||
waitQueueMember.timer = (0, timers_1.setTimeout)(() => {
|
||||
waitQueueMember[kCancelled] = true;
|
||||
waitQueueMember.timer = undefined;
|
||||
this.emitAndLog(ConnectionPool.CONNECTION_CHECK_OUT_FAILED, new connection_pool_events_1.ConnectionCheckOutFailedEvent(this, 'timeout'));
|
||||
waitQueueMember.callback(new errors_1.WaitQueueTimeoutError(this.loadBalanced
|
||||
? this.waitQueueErrorMetrics()
|
||||
: 'Timed out while checking out a connection from connection pool', this.address));
|
||||
}, waitQueueTimeoutMS);
|
||||
}
|
||||
this[kWaitQueue].push(waitQueueMember);
|
||||
process.nextTick(() => this.processWaitQueue());
|
||||
}
|
||||
/**
|
||||
* Check a connection into the pool.
|
||||
*
|
||||
* @param connection - The connection to check in
|
||||
*/
|
||||
checkIn(connection) {
|
||||
if (!this[kCheckedOut].has(connection)) {
|
||||
return;
|
||||
}
|
||||
const poolClosed = this.closed;
|
||||
const stale = this.connectionIsStale(connection);
|
||||
const willDestroy = !!(poolClosed || stale || connection.closed);
|
||||
if (!willDestroy) {
|
||||
connection.markAvailable();
|
||||
this[kConnections].unshift(connection);
|
||||
}
|
||||
this[kCheckedOut].delete(connection);
|
||||
this.emitAndLog(ConnectionPool.CONNECTION_CHECKED_IN, new connection_pool_events_1.ConnectionCheckedInEvent(this, connection));
|
||||
if (willDestroy) {
|
||||
const reason = connection.closed ? 'error' : poolClosed ? 'poolClosed' : 'stale';
|
||||
this.destroyConnection(connection, reason);
|
||||
}
|
||||
process.nextTick(() => this.processWaitQueue());
|
||||
}
|
||||
/**
|
||||
* Clear the pool
|
||||
*
|
||||
* Pool reset is handled by incrementing the pool's generation count. Any existing connection of a
|
||||
* previous generation will eventually be pruned during subsequent checkouts.
|
||||
*/
|
||||
clear(options = {}) {
|
||||
if (this.closed) {
|
||||
return;
|
||||
}
|
||||
// handle load balanced case
|
||||
if (this.loadBalanced) {
|
||||
const { serviceId } = options;
|
||||
if (!serviceId) {
|
||||
throw new error_1.MongoRuntimeError('ConnectionPool.clear() called in load balanced mode with no serviceId.');
|
||||
}
|
||||
const sid = serviceId.toHexString();
|
||||
const generation = this.serviceGenerations.get(sid);
|
||||
// Only need to worry if the generation exists, since it should
|
||||
// always be there but typescript needs the check.
|
||||
if (generation == null) {
|
||||
throw new error_1.MongoRuntimeError('Service generations are required in load balancer mode.');
|
||||
}
|
||||
else {
|
||||
// Increment the generation for the service id.
|
||||
this.serviceGenerations.set(sid, generation + 1);
|
||||
}
|
||||
this.emitAndLog(ConnectionPool.CONNECTION_POOL_CLEARED, new connection_pool_events_1.ConnectionPoolClearedEvent(this, { serviceId }));
|
||||
return;
|
||||
}
|
||||
// handle non load-balanced case
|
||||
const interruptInUseConnections = options.interruptInUseConnections ?? false;
|
||||
const oldGeneration = this[kGeneration];
|
||||
this[kGeneration] += 1;
|
||||
const alreadyPaused = this[kPoolState] === exports.PoolState.paused;
|
||||
this[kPoolState] = exports.PoolState.paused;
|
||||
this.clearMinPoolSizeTimer();
|
||||
if (!alreadyPaused) {
|
||||
this.emitAndLog(ConnectionPool.CONNECTION_POOL_CLEARED, new connection_pool_events_1.ConnectionPoolClearedEvent(this, {
|
||||
interruptInUseConnections
|
||||
}));
|
||||
}
|
||||
if (interruptInUseConnections) {
|
||||
process.nextTick(() => this.interruptInUseConnections(oldGeneration));
|
||||
}
|
||||
this.processWaitQueue();
|
||||
}
|
||||
/**
|
||||
* Closes all stale in-use connections in the pool with a resumable PoolClearedOnNetworkError.
|
||||
*
|
||||
* Only connections where `connection.generation <= minGeneration` are killed.
|
||||
*/
|
||||
interruptInUseConnections(minGeneration) {
|
||||
for (const connection of this[kCheckedOut]) {
|
||||
if (connection.generation <= minGeneration) {
|
||||
this.checkIn(connection);
|
||||
connection.onError(new errors_1.PoolClearedOnNetworkError(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
close(_options, _cb) {
|
||||
let options = _options;
|
||||
const callback = (_cb ?? _options);
|
||||
if (typeof options === 'function') {
|
||||
options = {};
|
||||
}
|
||||
options = Object.assign({ force: false }, options);
|
||||
if (this.closed) {
|
||||
return callback();
|
||||
}
|
||||
// immediately cancel any in-flight connections
|
||||
this[kCancellationToken].emit('cancel');
|
||||
// end the connection counter
|
||||
if (typeof this[kConnectionCounter].return === 'function') {
|
||||
this[kConnectionCounter].return(undefined);
|
||||
}
|
||||
this[kPoolState] = exports.PoolState.closed;
|
||||
this.clearMinPoolSizeTimer();
|
||||
this.processWaitQueue();
|
||||
(0, utils_1.eachAsync)(this[kConnections].toArray(), (conn, cb) => {
|
||||
this.emitAndLog(ConnectionPool.CONNECTION_CLOSED, new connection_pool_events_1.ConnectionClosedEvent(this, conn, 'poolClosed'));
|
||||
conn.destroy({ force: !!options.force }, cb);
|
||||
}, err => {
|
||||
this[kConnections].clear();
|
||||
this.emitAndLog(ConnectionPool.CONNECTION_POOL_CLOSED, new connection_pool_events_1.ConnectionPoolClosedEvent(this));
|
||||
callback(err);
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Runs a lambda with an implicitly checked out connection, checking that connection back in when the lambda
|
||||
* has completed by calling back.
|
||||
*
|
||||
* NOTE: please note the required signature of `fn`
|
||||
*
|
||||
* @remarks When in load balancer mode, connections can be pinned to cursors or transactions.
|
||||
* In these cases we pass the connection in to this method to ensure it is used and a new
|
||||
* connection is not checked out.
|
||||
*
|
||||
* @param conn - A pinned connection for use in load balancing mode.
|
||||
* @param fn - A function which operates on a managed connection
|
||||
* @param callback - The original callback
|
||||
*/
|
||||
withConnection(conn, fn, callback) {
|
||||
if (conn) {
|
||||
// use the provided connection, and do _not_ check it in after execution
|
||||
fn(undefined, conn, (fnErr, result) => {
|
||||
if (fnErr) {
|
||||
return this.withReauthentication(fnErr, conn, fn, callback);
|
||||
}
|
||||
callback(undefined, result);
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.checkOut((err, conn) => {
|
||||
// don't callback with `err` here, we might want to act upon it inside `fn`
|
||||
fn(err, conn, (fnErr, result) => {
|
||||
if (fnErr) {
|
||||
if (conn) {
|
||||
this.withReauthentication(fnErr, conn, fn, callback);
|
||||
}
|
||||
else {
|
||||
callback(fnErr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
callback(undefined, result);
|
||||
}
|
||||
if (conn) {
|
||||
this.checkIn(conn);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
withReauthentication(fnErr, conn, fn, callback) {
|
||||
if (fnErr instanceof error_1.MongoError && fnErr.code === error_1.MONGODB_ERROR_CODES.Reauthenticate) {
|
||||
this.reauthenticate(conn, fn, (error, res) => {
|
||||
if (error) {
|
||||
return callback(error);
|
||||
}
|
||||
callback(undefined, res);
|
||||
});
|
||||
}
|
||||
else {
|
||||
callback(fnErr);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Reauthenticate on the same connection and then retry the operation.
|
||||
*/
|
||||
reauthenticate(connection, fn, callback) {
|
||||
const authContext = connection.authContext;
|
||||
if (!authContext) {
|
||||
return callback(new error_1.MongoRuntimeError('No auth context found on connection.'));
|
||||
}
|
||||
const credentials = authContext.credentials;
|
||||
if (!credentials) {
|
||||
return callback(new error_1.MongoMissingCredentialsError('Connection is missing credentials when asked to reauthenticate'));
|
||||
}
|
||||
const resolvedCredentials = credentials.resolveAuthMechanism(connection.hello || undefined);
|
||||
const provider = connect_1.AUTH_PROVIDERS.get(resolvedCredentials.mechanism);
|
||||
if (!provider) {
|
||||
return callback(new error_1.MongoMissingCredentialsError(`Reauthenticate failed due to no auth provider for ${credentials.mechanism}`));
|
||||
}
|
||||
provider.reauth(authContext).then(() => {
|
||||
fn(undefined, connection, (fnErr, fnResult) => {
|
||||
if (fnErr) {
|
||||
return callback(fnErr);
|
||||
}
|
||||
callback(undefined, fnResult);
|
||||
});
|
||||
}, error => callback(error));
|
||||
}
|
||||
/** Clear the min pool size timer */
|
||||
clearMinPoolSizeTimer() {
|
||||
const minPoolSizeTimer = this[kMinPoolSizeTimer];
|
||||
if (minPoolSizeTimer) {
|
||||
(0, timers_1.clearTimeout)(minPoolSizeTimer);
|
||||
}
|
||||
}
|
||||
destroyConnection(connection, reason) {
|
||||
this.emitAndLog(ConnectionPool.CONNECTION_CLOSED, new connection_pool_events_1.ConnectionClosedEvent(this, connection, reason));
|
||||
// destroy the connection
|
||||
process.nextTick(() => connection.destroy({ force: false }));
|
||||
}
|
||||
connectionIsStale(connection) {
|
||||
const serviceId = connection.serviceId;
|
||||
if (this.loadBalanced && serviceId) {
|
||||
const sid = serviceId.toHexString();
|
||||
const generation = this.serviceGenerations.get(sid);
|
||||
return connection.generation !== generation;
|
||||
}
|
||||
return connection.generation !== this[kGeneration];
|
||||
}
|
||||
connectionIsIdle(connection) {
|
||||
return !!(this.options.maxIdleTimeMS && connection.idleTime > this.options.maxIdleTimeMS);
|
||||
}
|
||||
/**
|
||||
* Destroys a connection if the connection is perished.
|
||||
*
|
||||
* @returns `true` if the connection was destroyed, `false` otherwise.
|
||||
*/
|
||||
destroyConnectionIfPerished(connection) {
|
||||
const isStale = this.connectionIsStale(connection);
|
||||
const isIdle = this.connectionIsIdle(connection);
|
||||
if (!isStale && !isIdle && !connection.closed) {
|
||||
return false;
|
||||
}
|
||||
const reason = connection.closed ? 'error' : isStale ? 'stale' : 'idle';
|
||||
this.destroyConnection(connection, reason);
|
||||
return true;
|
||||
}
|
||||
createConnection(callback) {
|
||||
const connectOptions = {
|
||||
...this.options,
|
||||
id: this[kConnectionCounter].next().value,
|
||||
generation: this[kGeneration],
|
||||
cancellationToken: this[kCancellationToken]
|
||||
};
|
||||
this[kPending]++;
|
||||
// This is our version of a "virtual" no-I/O connection as the spec requires
|
||||
this.emitAndLog(ConnectionPool.CONNECTION_CREATED, new connection_pool_events_1.ConnectionCreatedEvent(this, { id: connectOptions.id }));
|
||||
(0, connect_1.connect)(connectOptions, (err, connection) => {
|
||||
if (err || !connection) {
|
||||
this[kPending]--;
|
||||
this.emitAndLog(ConnectionPool.CONNECTION_CLOSED, new connection_pool_events_1.ConnectionClosedEvent(this, { id: connectOptions.id, serviceId: undefined }, 'error',
|
||||
// TODO(NODE-5192): Remove this cast
|
||||
err));
|
||||
if (err instanceof error_1.MongoNetworkError || err instanceof error_1.MongoServerError) {
|
||||
err.connectionGeneration = connectOptions.generation;
|
||||
}
|
||||
callback(err ?? new error_1.MongoRuntimeError('Connection creation failed without error'));
|
||||
return;
|
||||
}
|
||||
// The pool might have closed since we started trying to create a connection
|
||||
if (this[kPoolState] !== exports.PoolState.ready) {
|
||||
this[kPending]--;
|
||||
connection.destroy({ force: true });
|
||||
callback(this.closed ? new errors_1.PoolClosedError(this) : new errors_1.PoolClearedError(this));
|
||||
return;
|
||||
}
|
||||
// forward all events from the connection to the pool
|
||||
for (const event of [...constants_1.APM_EVENTS, connection_1.Connection.CLUSTER_TIME_RECEIVED]) {
|
||||
connection.on(event, (e) => this.emit(event, e));
|
||||
}
|
||||
if (this.loadBalanced) {
|
||||
connection.on(connection_1.Connection.PINNED, pinType => this[kMetrics].markPinned(pinType));
|
||||
connection.on(connection_1.Connection.UNPINNED, pinType => this[kMetrics].markUnpinned(pinType));
|
||||
const serviceId = connection.serviceId;
|
||||
if (serviceId) {
|
||||
let generation;
|
||||
const sid = serviceId.toHexString();
|
||||
if ((generation = this.serviceGenerations.get(sid))) {
|
||||
connection.generation = generation;
|
||||
}
|
||||
else {
|
||||
this.serviceGenerations.set(sid, 0);
|
||||
connection.generation = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
connection.markAvailable();
|
||||
this.emitAndLog(ConnectionPool.CONNECTION_READY, new connection_pool_events_1.ConnectionReadyEvent(this, connection));
|
||||
this[kPending]--;
|
||||
callback(undefined, connection);
|
||||
return;
|
||||
});
|
||||
}
|
||||
ensureMinPoolSize() {
|
||||
const minPoolSize = this.options.minPoolSize;
|
||||
if (this[kPoolState] !== exports.PoolState.ready || minPoolSize === 0) {
|
||||
return;
|
||||
}
|
||||
this[kConnections].prune(connection => this.destroyConnectionIfPerished(connection));
|
||||
if (this.totalConnectionCount < minPoolSize &&
|
||||
this.pendingConnectionCount < this.options.maxConnecting) {
|
||||
// NOTE: ensureMinPoolSize should not try to get all the pending
|
||||
// connection permits because that potentially delays the availability of
|
||||
// the connection to a checkout request
|
||||
this.createConnection((err, connection) => {
|
||||
if (err) {
|
||||
this[kServer].handleError(err);
|
||||
}
|
||||
if (!err && connection) {
|
||||
this[kConnections].push(connection);
|
||||
process.nextTick(() => this.processWaitQueue());
|
||||
}
|
||||
if (this[kPoolState] === exports.PoolState.ready) {
|
||||
(0, timers_1.clearTimeout)(this[kMinPoolSizeTimer]);
|
||||
this[kMinPoolSizeTimer] = (0, timers_1.setTimeout)(() => this.ensureMinPoolSize(), this.options.minPoolSizeCheckFrequencyMS);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
(0, timers_1.clearTimeout)(this[kMinPoolSizeTimer]);
|
||||
this[kMinPoolSizeTimer] = (0, timers_1.setTimeout)(() => this.ensureMinPoolSize(), this.options.minPoolSizeCheckFrequencyMS);
|
||||
}
|
||||
}
|
||||
processWaitQueue() {
|
||||
if (this[kProcessingWaitQueue]) {
|
||||
return;
|
||||
}
|
||||
this[kProcessingWaitQueue] = true;
|
||||
while (this.waitQueueSize) {
|
||||
const waitQueueMember = this[kWaitQueue].first();
|
||||
if (!waitQueueMember) {
|
||||
this[kWaitQueue].shift();
|
||||
continue;
|
||||
}
|
||||
if (waitQueueMember[kCancelled]) {
|
||||
this[kWaitQueue].shift();
|
||||
continue;
|
||||
}
|
||||
if (this[kPoolState] !== exports.PoolState.ready) {
|
||||
const reason = this.closed ? 'poolClosed' : 'connectionError';
|
||||
const error = this.closed ? new errors_1.PoolClosedError(this) : new errors_1.PoolClearedError(this);
|
||||
this.emitAndLog(ConnectionPool.CONNECTION_CHECK_OUT_FAILED, new connection_pool_events_1.ConnectionCheckOutFailedEvent(this, reason, error));
|
||||
if (waitQueueMember.timer) {
|
||||
(0, timers_1.clearTimeout)(waitQueueMember.timer);
|
||||
}
|
||||
this[kWaitQueue].shift();
|
||||
waitQueueMember.callback(error);
|
||||
continue;
|
||||
}
|
||||
if (!this.availableConnectionCount) {
|
||||
break;
|
||||
}
|
||||
const connection = this[kConnections].shift();
|
||||
if (!connection) {
|
||||
break;
|
||||
}
|
||||
if (!this.destroyConnectionIfPerished(connection)) {
|
||||
this[kCheckedOut].add(connection);
|
||||
this.emitAndLog(ConnectionPool.CONNECTION_CHECKED_OUT, new connection_pool_events_1.ConnectionCheckedOutEvent(this, connection));
|
||||
if (waitQueueMember.timer) {
|
||||
(0, timers_1.clearTimeout)(waitQueueMember.timer);
|
||||
}
|
||||
this[kWaitQueue].shift();
|
||||
waitQueueMember.callback(undefined, connection);
|
||||
}
|
||||
}
|
||||
const { maxPoolSize, maxConnecting } = this.options;
|
||||
while (this.waitQueueSize > 0 &&
|
||||
this.pendingConnectionCount < maxConnecting &&
|
||||
(maxPoolSize === 0 || this.totalConnectionCount < maxPoolSize)) {
|
||||
const waitQueueMember = this[kWaitQueue].shift();
|
||||
if (!waitQueueMember || waitQueueMember[kCancelled]) {
|
||||
continue;
|
||||
}
|
||||
this.createConnection((err, connection) => {
|
||||
if (waitQueueMember[kCancelled]) {
|
||||
if (!err && connection) {
|
||||
this[kConnections].push(connection);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (err) {
|
||||
this.emitAndLog(ConnectionPool.CONNECTION_CHECK_OUT_FAILED,
|
||||
// TODO(NODE-5192): Remove this cast
|
||||
new connection_pool_events_1.ConnectionCheckOutFailedEvent(this, 'connectionError', err));
|
||||
}
|
||||
else if (connection) {
|
||||
this[kCheckedOut].add(connection);
|
||||
this.emitAndLog(ConnectionPool.CONNECTION_CHECKED_OUT, new connection_pool_events_1.ConnectionCheckedOutEvent(this, connection));
|
||||
}
|
||||
if (waitQueueMember.timer) {
|
||||
(0, timers_1.clearTimeout)(waitQueueMember.timer);
|
||||
}
|
||||
waitQueueMember.callback(err, connection);
|
||||
}
|
||||
process.nextTick(() => this.processWaitQueue());
|
||||
});
|
||||
}
|
||||
this[kProcessingWaitQueue] = false;
|
||||
}
|
||||
}
|
||||
exports.ConnectionPool = ConnectionPool;
|
||||
/**
|
||||
* Emitted when the connection pool is created.
|
||||
* @event
|
||||
*/
|
||||
ConnectionPool.CONNECTION_POOL_CREATED = constants_1.CONNECTION_POOL_CREATED;
|
||||
/**
|
||||
* Emitted once when the connection pool is closed
|
||||
* @event
|
||||
*/
|
||||
ConnectionPool.CONNECTION_POOL_CLOSED = constants_1.CONNECTION_POOL_CLOSED;
|
||||
/**
|
||||
* Emitted each time the connection pool is cleared and it's generation incremented
|
||||
* @event
|
||||
*/
|
||||
ConnectionPool.CONNECTION_POOL_CLEARED = constants_1.CONNECTION_POOL_CLEARED;
|
||||
/**
|
||||
* Emitted each time the connection pool is marked ready
|
||||
* @event
|
||||
*/
|
||||
ConnectionPool.CONNECTION_POOL_READY = constants_1.CONNECTION_POOL_READY;
|
||||
/**
|
||||
* Emitted when a connection is created.
|
||||
* @event
|
||||
*/
|
||||
ConnectionPool.CONNECTION_CREATED = constants_1.CONNECTION_CREATED;
|
||||
/**
|
||||
* Emitted when a connection becomes established, and is ready to use
|
||||
* @event
|
||||
*/
|
||||
ConnectionPool.CONNECTION_READY = constants_1.CONNECTION_READY;
|
||||
/**
|
||||
* Emitted when a connection is closed
|
||||
* @event
|
||||
*/
|
||||
ConnectionPool.CONNECTION_CLOSED = constants_1.CONNECTION_CLOSED;
|
||||
/**
|
||||
* Emitted when an attempt to check out a connection begins
|
||||
* @event
|
||||
*/
|
||||
ConnectionPool.CONNECTION_CHECK_OUT_STARTED = constants_1.CONNECTION_CHECK_OUT_STARTED;
|
||||
/**
|
||||
* Emitted when an attempt to check out a connection fails
|
||||
* @event
|
||||
*/
|
||||
ConnectionPool.CONNECTION_CHECK_OUT_FAILED = constants_1.CONNECTION_CHECK_OUT_FAILED;
|
||||
/**
|
||||
* Emitted each time a connection is successfully checked out of the connection pool
|
||||
* @event
|
||||
*/
|
||||
ConnectionPool.CONNECTION_CHECKED_OUT = constants_1.CONNECTION_CHECKED_OUT;
|
||||
/**
|
||||
* Emitted each time a connection is successfully checked into the connection pool
|
||||
* @event
|
||||
*/
|
||||
ConnectionPool.CONNECTION_CHECKED_IN = constants_1.CONNECTION_CHECKED_IN;
|
||||
//# sourceMappingURL=connection_pool.js.map
|
||||
1
node_modules/mongodb/lib/cmap/connection_pool.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/connection_pool.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
185
node_modules/mongodb/lib/cmap/connection_pool_events.js
generated
vendored
Normal file
185
node_modules/mongodb/lib/cmap/connection_pool_events.js
generated
vendored
Normal file
@@ -0,0 +1,185 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ConnectionPoolClearedEvent = exports.ConnectionCheckedInEvent = exports.ConnectionCheckedOutEvent = exports.ConnectionCheckOutFailedEvent = exports.ConnectionCheckOutStartedEvent = exports.ConnectionClosedEvent = exports.ConnectionReadyEvent = exports.ConnectionCreatedEvent = exports.ConnectionPoolClosedEvent = exports.ConnectionPoolReadyEvent = exports.ConnectionPoolCreatedEvent = exports.ConnectionPoolMonitoringEvent = void 0;
|
||||
const constants_1 = require("../constants");
|
||||
/**
|
||||
* The base export class for all monitoring events published from the connection pool
|
||||
* @public
|
||||
* @category Event
|
||||
*/
|
||||
class ConnectionPoolMonitoringEvent {
|
||||
/** @internal */
|
||||
constructor(pool) {
|
||||
this.time = new Date();
|
||||
this.address = pool.address;
|
||||
}
|
||||
}
|
||||
exports.ConnectionPoolMonitoringEvent = ConnectionPoolMonitoringEvent;
|
||||
/**
|
||||
* An event published when a connection pool is created
|
||||
* @public
|
||||
* @category Event
|
||||
*/
|
||||
class ConnectionPoolCreatedEvent extends ConnectionPoolMonitoringEvent {
|
||||
/** @internal */
|
||||
constructor(pool) {
|
||||
super(pool);
|
||||
/** @internal */
|
||||
this.name = constants_1.CONNECTION_POOL_CREATED;
|
||||
this.options = pool.options;
|
||||
}
|
||||
}
|
||||
exports.ConnectionPoolCreatedEvent = ConnectionPoolCreatedEvent;
|
||||
/**
|
||||
* An event published when a connection pool is ready
|
||||
* @public
|
||||
* @category Event
|
||||
*/
|
||||
class ConnectionPoolReadyEvent extends ConnectionPoolMonitoringEvent {
|
||||
/** @internal */
|
||||
constructor(pool) {
|
||||
super(pool);
|
||||
/** @internal */
|
||||
this.name = constants_1.CONNECTION_POOL_READY;
|
||||
}
|
||||
}
|
||||
exports.ConnectionPoolReadyEvent = ConnectionPoolReadyEvent;
|
||||
/**
|
||||
* An event published when a connection pool is closed
|
||||
* @public
|
||||
* @category Event
|
||||
*/
|
||||
class ConnectionPoolClosedEvent extends ConnectionPoolMonitoringEvent {
|
||||
/** @internal */
|
||||
constructor(pool) {
|
||||
super(pool);
|
||||
/** @internal */
|
||||
this.name = constants_1.CONNECTION_POOL_CLOSED;
|
||||
}
|
||||
}
|
||||
exports.ConnectionPoolClosedEvent = ConnectionPoolClosedEvent;
|
||||
/**
|
||||
* An event published when a connection pool creates a new connection
|
||||
* @public
|
||||
* @category Event
|
||||
*/
|
||||
class ConnectionCreatedEvent extends ConnectionPoolMonitoringEvent {
|
||||
/** @internal */
|
||||
constructor(pool, connection) {
|
||||
super(pool);
|
||||
/** @internal */
|
||||
this.name = constants_1.CONNECTION_CREATED;
|
||||
this.connectionId = connection.id;
|
||||
}
|
||||
}
|
||||
exports.ConnectionCreatedEvent = ConnectionCreatedEvent;
|
||||
/**
|
||||
* An event published when a connection is ready for use
|
||||
* @public
|
||||
* @category Event
|
||||
*/
|
||||
class ConnectionReadyEvent extends ConnectionPoolMonitoringEvent {
|
||||
/** @internal */
|
||||
constructor(pool, connection) {
|
||||
super(pool);
|
||||
/** @internal */
|
||||
this.name = constants_1.CONNECTION_READY;
|
||||
this.connectionId = connection.id;
|
||||
}
|
||||
}
|
||||
exports.ConnectionReadyEvent = ConnectionReadyEvent;
|
||||
/**
|
||||
* An event published when a connection is closed
|
||||
* @public
|
||||
* @category Event
|
||||
*/
|
||||
class ConnectionClosedEvent extends ConnectionPoolMonitoringEvent {
|
||||
/** @internal */
|
||||
constructor(pool, connection, reason, error) {
|
||||
super(pool);
|
||||
/** @internal */
|
||||
this.name = constants_1.CONNECTION_CLOSED;
|
||||
this.connectionId = connection.id;
|
||||
this.reason = reason;
|
||||
this.serviceId = connection.serviceId;
|
||||
this.error = error ?? null;
|
||||
}
|
||||
}
|
||||
exports.ConnectionClosedEvent = ConnectionClosedEvent;
|
||||
/**
|
||||
* An event published when a request to check a connection out begins
|
||||
* @public
|
||||
* @category Event
|
||||
*/
|
||||
class ConnectionCheckOutStartedEvent extends ConnectionPoolMonitoringEvent {
|
||||
/** @internal */
|
||||
constructor(pool) {
|
||||
super(pool);
|
||||
/** @internal */
|
||||
this.name = constants_1.CONNECTION_CHECK_OUT_STARTED;
|
||||
}
|
||||
}
|
||||
exports.ConnectionCheckOutStartedEvent = ConnectionCheckOutStartedEvent;
|
||||
/**
|
||||
* An event published when a request to check a connection out fails
|
||||
* @public
|
||||
* @category Event
|
||||
*/
|
||||
class ConnectionCheckOutFailedEvent extends ConnectionPoolMonitoringEvent {
|
||||
/** @internal */
|
||||
constructor(pool, reason, error) {
|
||||
super(pool);
|
||||
/** @internal */
|
||||
this.name = constants_1.CONNECTION_CHECK_OUT_FAILED;
|
||||
this.reason = reason;
|
||||
this.error = error;
|
||||
}
|
||||
}
|
||||
exports.ConnectionCheckOutFailedEvent = ConnectionCheckOutFailedEvent;
|
||||
/**
|
||||
* An event published when a connection is checked out of the connection pool
|
||||
* @public
|
||||
* @category Event
|
||||
*/
|
||||
class ConnectionCheckedOutEvent extends ConnectionPoolMonitoringEvent {
|
||||
/** @internal */
|
||||
constructor(pool, connection) {
|
||||
super(pool);
|
||||
/** @internal */
|
||||
this.name = constants_1.CONNECTION_CHECKED_OUT;
|
||||
this.connectionId = connection.id;
|
||||
}
|
||||
}
|
||||
exports.ConnectionCheckedOutEvent = ConnectionCheckedOutEvent;
|
||||
/**
|
||||
* An event published when a connection is checked into the connection pool
|
||||
* @public
|
||||
* @category Event
|
||||
*/
|
||||
class ConnectionCheckedInEvent extends ConnectionPoolMonitoringEvent {
|
||||
/** @internal */
|
||||
constructor(pool, connection) {
|
||||
super(pool);
|
||||
/** @internal */
|
||||
this.name = constants_1.CONNECTION_CHECKED_IN;
|
||||
this.connectionId = connection.id;
|
||||
}
|
||||
}
|
||||
exports.ConnectionCheckedInEvent = ConnectionCheckedInEvent;
|
||||
/**
|
||||
* An event published when a connection pool is cleared
|
||||
* @public
|
||||
* @category Event
|
||||
*/
|
||||
class ConnectionPoolClearedEvent extends ConnectionPoolMonitoringEvent {
|
||||
/** @internal */
|
||||
constructor(pool, options = {}) {
|
||||
super(pool);
|
||||
/** @internal */
|
||||
this.name = constants_1.CONNECTION_POOL_CLEARED;
|
||||
this.serviceId = options.serviceId;
|
||||
this.interruptInUseConnections = options.interruptInUseConnections;
|
||||
}
|
||||
}
|
||||
exports.ConnectionPoolClearedEvent = ConnectionPoolClearedEvent;
|
||||
//# sourceMappingURL=connection_pool_events.js.map
|
||||
1
node_modules/mongodb/lib/cmap/connection_pool_events.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/connection_pool_events.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"connection_pool_events.js","sourceRoot":"","sources":["../../src/cmap/connection_pool_events.ts"],"names":[],"mappings":"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"}
|
||||
64
node_modules/mongodb/lib/cmap/errors.js
generated
vendored
Normal file
64
node_modules/mongodb/lib/cmap/errors.js
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.WaitQueueTimeoutError = exports.PoolClearedOnNetworkError = exports.PoolClearedError = exports.PoolClosedError = void 0;
|
||||
const error_1 = require("../error");
|
||||
/**
|
||||
* An error indicating a connection pool is closed
|
||||
* @category Error
|
||||
*/
|
||||
class PoolClosedError extends error_1.MongoDriverError {
|
||||
constructor(pool) {
|
||||
super('Attempted to check out a connection from closed connection pool');
|
||||
this.address = pool.address;
|
||||
}
|
||||
get name() {
|
||||
return 'MongoPoolClosedError';
|
||||
}
|
||||
}
|
||||
exports.PoolClosedError = PoolClosedError;
|
||||
/**
|
||||
* An error indicating a connection pool is currently paused
|
||||
* @category Error
|
||||
*/
|
||||
class PoolClearedError extends error_1.MongoNetworkError {
|
||||
constructor(pool, message) {
|
||||
const errorMessage = message
|
||||
? message
|
||||
: `Connection pool for ${pool.address} was cleared because another operation failed with: "${pool.serverError?.message}"`;
|
||||
super(errorMessage);
|
||||
this.address = pool.address;
|
||||
this.addErrorLabel(error_1.MongoErrorLabel.RetryableWriteError);
|
||||
}
|
||||
get name() {
|
||||
return 'MongoPoolClearedError';
|
||||
}
|
||||
}
|
||||
exports.PoolClearedError = PoolClearedError;
|
||||
/**
|
||||
* An error indicating that a connection pool has been cleared after the monitor for that server timed out.
|
||||
* @category Error
|
||||
*/
|
||||
class PoolClearedOnNetworkError extends PoolClearedError {
|
||||
constructor(pool) {
|
||||
super(pool, `Connection to ${pool.address} interrupted due to server monitor timeout`);
|
||||
}
|
||||
get name() {
|
||||
return 'PoolClearedOnNetworkError';
|
||||
}
|
||||
}
|
||||
exports.PoolClearedOnNetworkError = PoolClearedOnNetworkError;
|
||||
/**
|
||||
* An error thrown when a request to check out a connection times out
|
||||
* @category Error
|
||||
*/
|
||||
class WaitQueueTimeoutError extends error_1.MongoDriverError {
|
||||
constructor(message, address) {
|
||||
super(message);
|
||||
this.address = address;
|
||||
}
|
||||
get name() {
|
||||
return 'MongoWaitQueueTimeoutError';
|
||||
}
|
||||
}
|
||||
exports.WaitQueueTimeoutError = WaitQueueTimeoutError;
|
||||
//# sourceMappingURL=errors.js.map
|
||||
1
node_modules/mongodb/lib/cmap/errors.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/errors.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/cmap/errors.ts"],"names":[],"mappings":";;;AAAA,oCAAgF;AAGhF;;;GAGG;AACH,MAAa,eAAgB,SAAQ,wBAAgB;IAInD,YAAY,IAAoB;QAC9B,KAAK,CAAC,iEAAiE,CAAC,CAAC;QACzE,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC9B,CAAC;IAED,IAAa,IAAI;QACf,OAAO,sBAAsB,CAAC;IAChC,CAAC;CACF;AAZD,0CAYC;AAED;;;GAGG;AACH,MAAa,gBAAiB,SAAQ,yBAAiB;IAIrD,YAAY,IAAoB,EAAE,OAAgB;QAChD,MAAM,YAAY,GAAG,OAAO;YAC1B,CAAC,CAAC,OAAO;YACT,CAAC,CAAC,uBAAuB,IAAI,CAAC,OAAO,wDAAwD,IAAI,CAAC,WAAW,EAAE,OAAO,GAAG,CAAC;QAC5H,KAAK,CAAC,YAAY,CAAC,CAAC;QACpB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;QAE5B,IAAI,CAAC,aAAa,CAAC,uBAAe,CAAC,mBAAmB,CAAC,CAAC;IAC1D,CAAC;IAED,IAAa,IAAI;QACf,OAAO,uBAAuB,CAAC;IACjC,CAAC;CACF;AAjBD,4CAiBC;AAED;;;GAGG;AACH,MAAa,yBAA0B,SAAQ,gBAAgB;IAC7D,YAAY,IAAoB;QAC9B,KAAK,CAAC,IAAI,EAAE,iBAAiB,IAAI,CAAC,OAAO,4CAA4C,CAAC,CAAC;IACzF,CAAC;IAED,IAAa,IAAI;QACf,OAAO,2BAA2B,CAAC;IACrC,CAAC;CACF;AARD,8DAQC;AAED;;;GAGG;AACH,MAAa,qBAAsB,SAAQ,wBAAgB;IAIzD,YAAY,OAAe,EAAE,OAAe;QAC1C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,IAAa,IAAI;QACf,OAAO,4BAA4B,CAAC;IACtC,CAAC;CACF;AAZD,sDAYC"}
|
||||
173
node_modules/mongodb/lib/cmap/handshake/client_metadata.js
generated
vendored
Normal file
173
node_modules/mongodb/lib/cmap/handshake/client_metadata.js
generated
vendored
Normal file
@@ -0,0 +1,173 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.getFAASEnv = exports.makeClientMetadata = exports.LimitedSizeDocument = void 0;
|
||||
const os = require("os");
|
||||
const process = require("process");
|
||||
const bson_1 = require("../../bson");
|
||||
const error_1 = require("../../error");
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
const NODE_DRIVER_VERSION = require('../../../package.json').version;
|
||||
/** @internal */
|
||||
class LimitedSizeDocument {
|
||||
constructor(maxSize) {
|
||||
this.maxSize = maxSize;
|
||||
this.document = new Map();
|
||||
/** BSON overhead: Int32 + Null byte */
|
||||
this.documentSize = 5;
|
||||
}
|
||||
/** Only adds key/value if the bsonByteLength is less than MAX_SIZE */
|
||||
ifItFitsItSits(key, value) {
|
||||
// The BSON byteLength of the new element is the same as serializing it to its own document
|
||||
// subtracting the document size int32 and the null terminator.
|
||||
const newElementSize = bson_1.BSON.serialize(new Map().set(key, value)).byteLength - 5;
|
||||
if (newElementSize + this.documentSize > this.maxSize) {
|
||||
return false;
|
||||
}
|
||||
this.documentSize += newElementSize;
|
||||
this.document.set(key, value);
|
||||
return true;
|
||||
}
|
||||
toObject() {
|
||||
return bson_1.BSON.deserialize(bson_1.BSON.serialize(this.document), {
|
||||
promoteLongs: false,
|
||||
promoteBuffers: false,
|
||||
promoteValues: false,
|
||||
useBigInt64: false
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.LimitedSizeDocument = LimitedSizeDocument;
|
||||
/**
|
||||
* From the specs:
|
||||
* Implementors SHOULD cumulatively update fields in the following order until the document is under the size limit:
|
||||
* 1. Omit fields from `env` except `env.name`.
|
||||
* 2. Omit fields from `os` except `os.type`.
|
||||
* 3. Omit the `env` document entirely.
|
||||
* 4. Truncate `platform`. -- special we do not truncate this field
|
||||
*/
|
||||
function makeClientMetadata(options) {
|
||||
const metadataDocument = new LimitedSizeDocument(512);
|
||||
const { appName = '' } = options;
|
||||
// Add app name first, it must be sent
|
||||
if (appName.length > 0) {
|
||||
const name = Buffer.byteLength(appName, 'utf8') <= 128
|
||||
? options.appName
|
||||
: Buffer.from(appName, 'utf8').subarray(0, 128).toString('utf8');
|
||||
metadataDocument.ifItFitsItSits('application', { name });
|
||||
}
|
||||
const { name = '', version = '', platform = '' } = options.driverInfo;
|
||||
const driverInfo = {
|
||||
name: name.length > 0 ? `nodejs|${name}` : 'nodejs',
|
||||
version: version.length > 0 ? `${NODE_DRIVER_VERSION}|${version}` : NODE_DRIVER_VERSION
|
||||
};
|
||||
if (!metadataDocument.ifItFitsItSits('driver', driverInfo)) {
|
||||
throw new error_1.MongoInvalidArgumentError('Unable to include driverInfo name and version, metadata cannot exceed 512 bytes');
|
||||
}
|
||||
let runtimeInfo = getRuntimeInfo();
|
||||
if (platform.length > 0) {
|
||||
runtimeInfo = `${runtimeInfo}|${platform}`;
|
||||
}
|
||||
if (!metadataDocument.ifItFitsItSits('platform', runtimeInfo)) {
|
||||
throw new error_1.MongoInvalidArgumentError('Unable to include driverInfo platform, metadata cannot exceed 512 bytes');
|
||||
}
|
||||
// Note: order matters, os.type is last so it will be removed last if we're at maxSize
|
||||
const osInfo = new Map()
|
||||
.set('name', process.platform)
|
||||
.set('architecture', process.arch)
|
||||
.set('version', os.release())
|
||||
.set('type', os.type());
|
||||
if (!metadataDocument.ifItFitsItSits('os', osInfo)) {
|
||||
for (const key of osInfo.keys()) {
|
||||
osInfo.delete(key);
|
||||
if (osInfo.size === 0)
|
||||
break;
|
||||
if (metadataDocument.ifItFitsItSits('os', osInfo))
|
||||
break;
|
||||
}
|
||||
}
|
||||
const faasEnv = getFAASEnv();
|
||||
if (faasEnv != null) {
|
||||
if (!metadataDocument.ifItFitsItSits('env', faasEnv)) {
|
||||
for (const key of faasEnv.keys()) {
|
||||
faasEnv.delete(key);
|
||||
if (faasEnv.size === 0)
|
||||
break;
|
||||
if (metadataDocument.ifItFitsItSits('env', faasEnv))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return metadataDocument.toObject();
|
||||
}
|
||||
exports.makeClientMetadata = makeClientMetadata;
|
||||
/**
|
||||
* Collects FaaS metadata.
|
||||
* - `name` MUST be the last key in the Map returned.
|
||||
*/
|
||||
function getFAASEnv() {
|
||||
const { AWS_EXECUTION_ENV = '', AWS_LAMBDA_RUNTIME_API = '', FUNCTIONS_WORKER_RUNTIME = '', K_SERVICE = '', FUNCTION_NAME = '', VERCEL = '', AWS_LAMBDA_FUNCTION_MEMORY_SIZE = '', AWS_REGION = '', FUNCTION_MEMORY_MB = '', FUNCTION_REGION = '', FUNCTION_TIMEOUT_SEC = '', VERCEL_REGION = '' } = process.env;
|
||||
const isAWSFaaS = AWS_EXECUTION_ENV.startsWith('AWS_Lambda_') || AWS_LAMBDA_RUNTIME_API.length > 0;
|
||||
const isAzureFaaS = FUNCTIONS_WORKER_RUNTIME.length > 0;
|
||||
const isGCPFaaS = K_SERVICE.length > 0 || FUNCTION_NAME.length > 0;
|
||||
const isVercelFaaS = VERCEL.length > 0;
|
||||
// Note: order matters, name must always be the last key
|
||||
const faasEnv = new Map();
|
||||
// When isVercelFaaS is true so is isAWSFaaS; Vercel inherits the AWS env
|
||||
if (isVercelFaaS && !(isAzureFaaS || isGCPFaaS)) {
|
||||
if (VERCEL_REGION.length > 0) {
|
||||
faasEnv.set('region', VERCEL_REGION);
|
||||
}
|
||||
faasEnv.set('name', 'vercel');
|
||||
return faasEnv;
|
||||
}
|
||||
if (isAWSFaaS && !(isAzureFaaS || isGCPFaaS || isVercelFaaS)) {
|
||||
if (AWS_REGION.length > 0) {
|
||||
faasEnv.set('region', AWS_REGION);
|
||||
}
|
||||
if (AWS_LAMBDA_FUNCTION_MEMORY_SIZE.length > 0 &&
|
||||
Number.isInteger(+AWS_LAMBDA_FUNCTION_MEMORY_SIZE)) {
|
||||
faasEnv.set('memory_mb', new bson_1.Int32(AWS_LAMBDA_FUNCTION_MEMORY_SIZE));
|
||||
}
|
||||
faasEnv.set('name', 'aws.lambda');
|
||||
return faasEnv;
|
||||
}
|
||||
if (isAzureFaaS && !(isGCPFaaS || isAWSFaaS || isVercelFaaS)) {
|
||||
faasEnv.set('name', 'azure.func');
|
||||
return faasEnv;
|
||||
}
|
||||
if (isGCPFaaS && !(isAzureFaaS || isAWSFaaS || isVercelFaaS)) {
|
||||
if (FUNCTION_REGION.length > 0) {
|
||||
faasEnv.set('region', FUNCTION_REGION);
|
||||
}
|
||||
if (FUNCTION_MEMORY_MB.length > 0 && Number.isInteger(+FUNCTION_MEMORY_MB)) {
|
||||
faasEnv.set('memory_mb', new bson_1.Int32(FUNCTION_MEMORY_MB));
|
||||
}
|
||||
if (FUNCTION_TIMEOUT_SEC.length > 0 && Number.isInteger(+FUNCTION_TIMEOUT_SEC)) {
|
||||
faasEnv.set('timeout_sec', new bson_1.Int32(FUNCTION_TIMEOUT_SEC));
|
||||
}
|
||||
faasEnv.set('name', 'gcp.func');
|
||||
return faasEnv;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
exports.getFAASEnv = getFAASEnv;
|
||||
/**
|
||||
* @internal
|
||||
* Get current JavaScript runtime platform
|
||||
*
|
||||
* NOTE: The version information fetching is intentionally written defensively
|
||||
* to avoid having a released driver version that becomes incompatible
|
||||
* with a future change to these global objects.
|
||||
*/
|
||||
function getRuntimeInfo() {
|
||||
if ('Deno' in globalThis) {
|
||||
const version = typeof Deno?.version?.deno === 'string' ? Deno?.version?.deno : '0.0.0-unknown';
|
||||
return `Deno v${version}, ${os.endianness()}`;
|
||||
}
|
||||
if ('Bun' in globalThis) {
|
||||
const version = typeof Bun?.version === 'string' ? Bun?.version : '0.0.0-unknown';
|
||||
return `Bun v${version}, ${os.endianness()}`;
|
||||
}
|
||||
return `Node.js ${process.version}, ${os.endianness()}`;
|
||||
}
|
||||
//# sourceMappingURL=client_metadata.js.map
|
||||
1
node_modules/mongodb/lib/cmap/handshake/client_metadata.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/handshake/client_metadata.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
156
node_modules/mongodb/lib/cmap/message_stream.js
generated
vendored
Normal file
156
node_modules/mongodb/lib/cmap/message_stream.js
generated
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.MessageStream = void 0;
|
||||
const stream_1 = require("stream");
|
||||
const error_1 = require("../error");
|
||||
const utils_1 = require("../utils");
|
||||
const commands_1 = require("./commands");
|
||||
const compression_1 = require("./wire_protocol/compression");
|
||||
const constants_1 = require("./wire_protocol/constants");
|
||||
const MESSAGE_HEADER_SIZE = 16;
|
||||
const COMPRESSION_DETAILS_SIZE = 9; // originalOpcode + uncompressedSize, compressorID
|
||||
const kDefaultMaxBsonMessageSize = 1024 * 1024 * 16 * 4;
|
||||
/** @internal */
|
||||
const kBuffer = Symbol('buffer');
|
||||
/**
|
||||
* A duplex stream that is capable of reading and writing raw wire protocol messages, with
|
||||
* support for optional compression
|
||||
* @internal
|
||||
*/
|
||||
class MessageStream extends stream_1.Duplex {
|
||||
constructor(options = {}) {
|
||||
super(options);
|
||||
/** @internal */
|
||||
this.isMonitoringConnection = false;
|
||||
this.maxBsonMessageSize = options.maxBsonMessageSize || kDefaultMaxBsonMessageSize;
|
||||
this[kBuffer] = new utils_1.BufferPool();
|
||||
}
|
||||
get buffer() {
|
||||
return this[kBuffer];
|
||||
}
|
||||
_write(chunk, _, callback) {
|
||||
this[kBuffer].append(chunk);
|
||||
processIncomingData(this, callback);
|
||||
}
|
||||
_read( /* size */) {
|
||||
// NOTE: This implementation is empty because we explicitly push data to be read
|
||||
// when `writeMessage` is called.
|
||||
return;
|
||||
}
|
||||
writeCommand(command, operationDescription) {
|
||||
const agreedCompressor = operationDescription.agreedCompressor ?? 'none';
|
||||
if (agreedCompressor === 'none' || !canCompress(command)) {
|
||||
const data = command.toBin();
|
||||
this.push(Array.isArray(data) ? Buffer.concat(data) : data);
|
||||
return;
|
||||
}
|
||||
// otherwise, compress the message
|
||||
const concatenatedOriginalCommandBuffer = Buffer.concat(command.toBin());
|
||||
const messageToBeCompressed = concatenatedOriginalCommandBuffer.slice(MESSAGE_HEADER_SIZE);
|
||||
// Extract information needed for OP_COMPRESSED from the uncompressed message
|
||||
const originalCommandOpCode = concatenatedOriginalCommandBuffer.readInt32LE(12);
|
||||
const options = {
|
||||
agreedCompressor,
|
||||
zlibCompressionLevel: operationDescription.zlibCompressionLevel ?? 0
|
||||
};
|
||||
// Compress the message body
|
||||
(0, compression_1.compress)(options, messageToBeCompressed).then(compressedMessage => {
|
||||
// Create the msgHeader of OP_COMPRESSED
|
||||
const msgHeader = Buffer.alloc(MESSAGE_HEADER_SIZE);
|
||||
msgHeader.writeInt32LE(MESSAGE_HEADER_SIZE + COMPRESSION_DETAILS_SIZE + compressedMessage.length, 0); // messageLength
|
||||
msgHeader.writeInt32LE(command.requestId, 4); // requestID
|
||||
msgHeader.writeInt32LE(0, 8); // responseTo (zero)
|
||||
msgHeader.writeInt32LE(constants_1.OP_COMPRESSED, 12); // opCode
|
||||
// Create the compression details of OP_COMPRESSED
|
||||
const compressionDetails = Buffer.alloc(COMPRESSION_DETAILS_SIZE);
|
||||
compressionDetails.writeInt32LE(originalCommandOpCode, 0); // originalOpcode
|
||||
compressionDetails.writeInt32LE(messageToBeCompressed.length, 4); // Size of the uncompressed compressedMessage, excluding the MsgHeader
|
||||
compressionDetails.writeUInt8(compression_1.Compressor[agreedCompressor], 8); // compressorID
|
||||
this.push(Buffer.concat([msgHeader, compressionDetails, compressedMessage]));
|
||||
}, error => {
|
||||
operationDescription.cb(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
exports.MessageStream = MessageStream;
|
||||
// Return whether a command contains an uncompressible command term
|
||||
// Will return true if command contains no uncompressible command terms
|
||||
function canCompress(command) {
|
||||
const commandDoc = command instanceof commands_1.Msg ? command.command : command.query;
|
||||
const commandName = Object.keys(commandDoc)[0];
|
||||
return !compression_1.uncompressibleCommands.has(commandName);
|
||||
}
|
||||
function processIncomingData(stream, callback) {
|
||||
const buffer = stream[kBuffer];
|
||||
const sizeOfMessage = buffer.getInt32();
|
||||
if (sizeOfMessage == null) {
|
||||
return callback();
|
||||
}
|
||||
if (sizeOfMessage < 0) {
|
||||
return callback(new error_1.MongoParseError(`Invalid message size: ${sizeOfMessage}`));
|
||||
}
|
||||
if (sizeOfMessage > stream.maxBsonMessageSize) {
|
||||
return callback(new error_1.MongoParseError(`Invalid message size: ${sizeOfMessage}, max allowed: ${stream.maxBsonMessageSize}`));
|
||||
}
|
||||
if (sizeOfMessage > buffer.length) {
|
||||
return callback();
|
||||
}
|
||||
const message = buffer.read(sizeOfMessage);
|
||||
const messageHeader = {
|
||||
length: message.readInt32LE(0),
|
||||
requestId: message.readInt32LE(4),
|
||||
responseTo: message.readInt32LE(8),
|
||||
opCode: message.readInt32LE(12)
|
||||
};
|
||||
const monitorHasAnotherHello = () => {
|
||||
if (stream.isMonitoringConnection) {
|
||||
// Can we read the next message size?
|
||||
const sizeOfMessage = buffer.getInt32();
|
||||
if (sizeOfMessage != null && sizeOfMessage <= buffer.length) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
let ResponseType = messageHeader.opCode === constants_1.OP_MSG ? commands_1.BinMsg : commands_1.Response;
|
||||
if (messageHeader.opCode !== constants_1.OP_COMPRESSED) {
|
||||
const messageBody = message.subarray(MESSAGE_HEADER_SIZE);
|
||||
// If we are a monitoring connection message stream and
|
||||
// there is more in the buffer that can be read, skip processing since we
|
||||
// want the last hello command response that is in the buffer.
|
||||
if (monitorHasAnotherHello()) {
|
||||
return processIncomingData(stream, callback);
|
||||
}
|
||||
stream.emit('message', new ResponseType(message, messageHeader, messageBody));
|
||||
if (buffer.length >= 4) {
|
||||
return processIncomingData(stream, callback);
|
||||
}
|
||||
return callback();
|
||||
}
|
||||
messageHeader.fromCompressed = true;
|
||||
messageHeader.opCode = message.readInt32LE(MESSAGE_HEADER_SIZE);
|
||||
messageHeader.length = message.readInt32LE(MESSAGE_HEADER_SIZE + 4);
|
||||
const compressorID = message[MESSAGE_HEADER_SIZE + 8];
|
||||
const compressedBuffer = message.slice(MESSAGE_HEADER_SIZE + 9);
|
||||
// recalculate based on wrapped opcode
|
||||
ResponseType = messageHeader.opCode === constants_1.OP_MSG ? commands_1.BinMsg : commands_1.Response;
|
||||
(0, compression_1.decompress)(compressorID, compressedBuffer).then(messageBody => {
|
||||
if (messageBody.length !== messageHeader.length) {
|
||||
return callback(new error_1.MongoDecompressionError('Message body and message header must be the same length'));
|
||||
}
|
||||
// If we are a monitoring connection message stream and
|
||||
// there is more in the buffer that can be read, skip processing since we
|
||||
// want the last hello command response that is in the buffer.
|
||||
if (monitorHasAnotherHello()) {
|
||||
return processIncomingData(stream, callback);
|
||||
}
|
||||
stream.emit('message', new ResponseType(message, messageHeader, messageBody));
|
||||
if (buffer.length >= 4) {
|
||||
return processIncomingData(stream, callback);
|
||||
}
|
||||
return callback();
|
||||
}, error => {
|
||||
return callback(error);
|
||||
});
|
||||
}
|
||||
//# sourceMappingURL=message_stream.js.map
|
||||
1
node_modules/mongodb/lib/cmap/message_stream.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/message_stream.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
62
node_modules/mongodb/lib/cmap/metrics.js
generated
vendored
Normal file
62
node_modules/mongodb/lib/cmap/metrics.js
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.ConnectionPoolMetrics = void 0;
|
||||
/** @internal */
|
||||
class ConnectionPoolMetrics {
|
||||
constructor() {
|
||||
this.txnConnections = 0;
|
||||
this.cursorConnections = 0;
|
||||
this.otherConnections = 0;
|
||||
}
|
||||
/**
|
||||
* Mark a connection as pinned for a specific operation.
|
||||
*/
|
||||
markPinned(pinType) {
|
||||
if (pinType === ConnectionPoolMetrics.TXN) {
|
||||
this.txnConnections += 1;
|
||||
}
|
||||
else if (pinType === ConnectionPoolMetrics.CURSOR) {
|
||||
this.cursorConnections += 1;
|
||||
}
|
||||
else {
|
||||
this.otherConnections += 1;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Unmark a connection as pinned for an operation.
|
||||
*/
|
||||
markUnpinned(pinType) {
|
||||
if (pinType === ConnectionPoolMetrics.TXN) {
|
||||
this.txnConnections -= 1;
|
||||
}
|
||||
else if (pinType === ConnectionPoolMetrics.CURSOR) {
|
||||
this.cursorConnections -= 1;
|
||||
}
|
||||
else {
|
||||
this.otherConnections -= 1;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Return information about the cmap metrics as a string.
|
||||
*/
|
||||
info(maxPoolSize) {
|
||||
return ('Timed out while checking out a connection from connection pool: ' +
|
||||
`maxPoolSize: ${maxPoolSize}, ` +
|
||||
`connections in use by cursors: ${this.cursorConnections}, ` +
|
||||
`connections in use by transactions: ${this.txnConnections}, ` +
|
||||
`connections in use by other operations: ${this.otherConnections}`);
|
||||
}
|
||||
/**
|
||||
* Reset the metrics to the initial values.
|
||||
*/
|
||||
reset() {
|
||||
this.txnConnections = 0;
|
||||
this.cursorConnections = 0;
|
||||
this.otherConnections = 0;
|
||||
}
|
||||
}
|
||||
exports.ConnectionPoolMetrics = ConnectionPoolMetrics;
|
||||
ConnectionPoolMetrics.TXN = 'txn';
|
||||
ConnectionPoolMetrics.CURSOR = 'cursor';
|
||||
ConnectionPoolMetrics.OTHER = 'other';
|
||||
//# sourceMappingURL=metrics.js.map
|
||||
1
node_modules/mongodb/lib/cmap/metrics.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/metrics.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/cmap/metrics.ts"],"names":[],"mappings":";;;AAAA,gBAAgB;AAChB,MAAa,qBAAqB;IAAlC;QAKE,mBAAc,GAAG,CAAC,CAAC;QACnB,sBAAiB,GAAG,CAAC,CAAC;QACtB,qBAAgB,GAAG,CAAC,CAAC;IAiDvB,CAAC;IA/CC;;OAEG;IACH,UAAU,CAAC,OAAe;QACxB,IAAI,OAAO,KAAK,qBAAqB,CAAC,GAAG,EAAE;YACzC,IAAI,CAAC,cAAc,IAAI,CAAC,CAAC;SAC1B;aAAM,IAAI,OAAO,KAAK,qBAAqB,CAAC,MAAM,EAAE;YACnD,IAAI,CAAC,iBAAiB,IAAI,CAAC,CAAC;SAC7B;aAAM;YACL,IAAI,CAAC,gBAAgB,IAAI,CAAC,CAAC;SAC5B;IACH,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,OAAe;QAC1B,IAAI,OAAO,KAAK,qBAAqB,CAAC,GAAG,EAAE;YACzC,IAAI,CAAC,cAAc,IAAI,CAAC,CAAC;SAC1B;aAAM,IAAI,OAAO,KAAK,qBAAqB,CAAC,MAAM,EAAE;YACnD,IAAI,CAAC,iBAAiB,IAAI,CAAC,CAAC;SAC7B;aAAM;YACL,IAAI,CAAC,gBAAgB,IAAI,CAAC,CAAC;SAC5B;IACH,CAAC;IAED;;OAEG;IACH,IAAI,CAAC,WAAmB;QACtB,OAAO,CACL,kEAAkE;YAClE,gBAAgB,WAAW,IAAI;YAC/B,kCAAkC,IAAI,CAAC,iBAAiB,IAAI;YAC5D,uCAAuC,IAAI,CAAC,cAAc,IAAI;YAC9D,2CAA2C,IAAI,CAAC,gBAAgB,EAAE,CACnE,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,cAAc,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;QAC3B,IAAI,CAAC,gBAAgB,GAAG,CAAC,CAAC;IAC5B,CAAC;;AAvDH,sDAwDC;AAvDiB,yBAAG,GAAG,KAAc,CAAC;AACrB,4BAAM,GAAG,QAAiB,CAAC;AAC3B,2BAAK,GAAG,OAAgB,CAAC"}
|
||||
51
node_modules/mongodb/lib/cmap/stream_description.js
generated
vendored
Normal file
51
node_modules/mongodb/lib/cmap/stream_description.js
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.StreamDescription = void 0;
|
||||
const common_1 = require("../sdam/common");
|
||||
const server_description_1 = require("../sdam/server_description");
|
||||
const RESPONSE_FIELDS = [
|
||||
'minWireVersion',
|
||||
'maxWireVersion',
|
||||
'maxBsonObjectSize',
|
||||
'maxMessageSizeBytes',
|
||||
'maxWriteBatchSize',
|
||||
'logicalSessionTimeoutMinutes'
|
||||
];
|
||||
/** @public */
|
||||
class StreamDescription {
|
||||
constructor(address, options) {
|
||||
this.address = address;
|
||||
this.type = common_1.ServerType.Unknown;
|
||||
this.minWireVersion = undefined;
|
||||
this.maxWireVersion = undefined;
|
||||
this.maxBsonObjectSize = 16777216;
|
||||
this.maxMessageSizeBytes = 48000000;
|
||||
this.maxWriteBatchSize = 100000;
|
||||
this.logicalSessionTimeoutMinutes = options?.logicalSessionTimeoutMinutes;
|
||||
this.loadBalanced = !!options?.loadBalanced;
|
||||
this.compressors =
|
||||
options && options.compressors && Array.isArray(options.compressors)
|
||||
? options.compressors
|
||||
: [];
|
||||
}
|
||||
receiveResponse(response) {
|
||||
if (response == null) {
|
||||
return;
|
||||
}
|
||||
this.type = (0, server_description_1.parseServerType)(response);
|
||||
for (const field of RESPONSE_FIELDS) {
|
||||
if (response[field] != null) {
|
||||
this[field] = response[field];
|
||||
}
|
||||
// testing case
|
||||
if ('__nodejs_mock_server__' in response) {
|
||||
this.__nodejs_mock_server__ = response['__nodejs_mock_server__'];
|
||||
}
|
||||
}
|
||||
if (response.compression) {
|
||||
this.compressor = this.compressors.filter(c => response.compression?.includes(c))[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.StreamDescription = StreamDescription;
|
||||
//# sourceMappingURL=stream_description.js.map
|
||||
1
node_modules/mongodb/lib/cmap/stream_description.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/stream_description.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"stream_description.js","sourceRoot":"","sources":["../../src/cmap/stream_description.ts"],"names":[],"mappings":";;;AACA,2CAA4C;AAC5C,mEAA6D;AAG7D,MAAM,eAAe,GAAG;IACtB,gBAAgB;IAChB,gBAAgB;IAChB,mBAAmB;IACnB,qBAAqB;IACrB,mBAAmB;IACnB,8BAA8B;CACtB,CAAC;AASX,cAAc;AACd,MAAa,iBAAiB;IAiB5B,YAAY,OAAe,EAAE,OAAkC;QAC7D,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,mBAAU,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,cAAc,GAAG,SAAS,CAAC;QAChC,IAAI,CAAC,cAAc,GAAG,SAAS,CAAC;QAChC,IAAI,CAAC,iBAAiB,GAAG,QAAQ,CAAC;QAClC,IAAI,CAAC,mBAAmB,GAAG,QAAQ,CAAC;QACpC,IAAI,CAAC,iBAAiB,GAAG,MAAM,CAAC;QAChC,IAAI,CAAC,4BAA4B,GAAG,OAAO,EAAE,4BAA4B,CAAC;QAC1E,IAAI,CAAC,YAAY,GAAG,CAAC,CAAC,OAAO,EAAE,YAAY,CAAC;QAC5C,IAAI,CAAC,WAAW;YACd,OAAO,IAAI,OAAO,CAAC,WAAW,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC;gBAClE,CAAC,CAAC,OAAO,CAAC,WAAW;gBACrB,CAAC,CAAC,EAAE,CAAC;IACX,CAAC;IAED,eAAe,CAAC,QAAyB;QACvC,IAAI,QAAQ,IAAI,IAAI,EAAE;YACpB,OAAO;SACR;QACD,IAAI,CAAC,IAAI,GAAG,IAAA,oCAAe,EAAC,QAAQ,CAAC,CAAC;QACtC,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE;YACnC,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE;gBAC3B,IAAI,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;aAC/B;YAED,eAAe;YACf,IAAI,wBAAwB,IAAI,QAAQ,EAAE;gBACxC,IAAI,CAAC,sBAAsB,GAAG,QAAQ,CAAC,wBAAwB,CAAC,CAAC;aAClE;SACF;QAED,IAAI,QAAQ,CAAC,WAAW,EAAE;YACxB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SACtF;IACH,CAAC;CACF;AArDD,8CAqDC"}
|
||||
81
node_modules/mongodb/lib/cmap/wire_protocol/compression.js
generated
vendored
Normal file
81
node_modules/mongodb/lib/cmap/wire_protocol/compression.js
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.decompress = exports.compress = exports.uncompressibleCommands = exports.Compressor = void 0;
|
||||
const util_1 = require("util");
|
||||
const zlib = require("zlib");
|
||||
const constants_1 = require("../../constants");
|
||||
const deps_1 = require("../../deps");
|
||||
const error_1 = require("../../error");
|
||||
/** @public */
|
||||
exports.Compressor = Object.freeze({
|
||||
none: 0,
|
||||
snappy: 1,
|
||||
zlib: 2,
|
||||
zstd: 3
|
||||
});
|
||||
exports.uncompressibleCommands = new Set([
|
||||
constants_1.LEGACY_HELLO_COMMAND,
|
||||
'saslStart',
|
||||
'saslContinue',
|
||||
'getnonce',
|
||||
'authenticate',
|
||||
'createUser',
|
||||
'updateUser',
|
||||
'copydbSaslStart',
|
||||
'copydbgetnonce',
|
||||
'copydb'
|
||||
]);
|
||||
const ZSTD_COMPRESSION_LEVEL = 3;
|
||||
const zlibInflate = (0, util_1.promisify)(zlib.inflate.bind(zlib));
|
||||
const zlibDeflate = (0, util_1.promisify)(zlib.deflate.bind(zlib));
|
||||
// Facilitate compressing a message using an agreed compressor
|
||||
async function compress(options, dataToBeCompressed) {
|
||||
const zlibOptions = {};
|
||||
switch (options.agreedCompressor) {
|
||||
case 'snappy':
|
||||
if ('kModuleError' in deps_1.Snappy) {
|
||||
throw deps_1.Snappy['kModuleError'];
|
||||
}
|
||||
return deps_1.Snappy.compress(dataToBeCompressed);
|
||||
case 'zstd':
|
||||
if ('kModuleError' in deps_1.ZStandard) {
|
||||
throw deps_1.ZStandard['kModuleError'];
|
||||
}
|
||||
return deps_1.ZStandard.compress(dataToBeCompressed, ZSTD_COMPRESSION_LEVEL);
|
||||
case 'zlib':
|
||||
if (options.zlibCompressionLevel) {
|
||||
zlibOptions.level = options.zlibCompressionLevel;
|
||||
}
|
||||
return zlibDeflate(dataToBeCompressed, zlibOptions);
|
||||
default:
|
||||
throw new error_1.MongoInvalidArgumentError(`Unknown compressor ${options.agreedCompressor} failed to compress`);
|
||||
}
|
||||
}
|
||||
exports.compress = compress;
|
||||
// Decompress a message using the given compressor
|
||||
async function decompress(compressorID, compressedData) {
|
||||
if (compressorID !== exports.Compressor.snappy &&
|
||||
compressorID !== exports.Compressor.zstd &&
|
||||
compressorID !== exports.Compressor.zlib &&
|
||||
compressorID !== exports.Compressor.none) {
|
||||
throw new error_1.MongoDecompressionError(`Server sent message compressed using an unsupported compressor. (Received compressor ID ${compressorID})`);
|
||||
}
|
||||
switch (compressorID) {
|
||||
case exports.Compressor.snappy:
|
||||
if ('kModuleError' in deps_1.Snappy) {
|
||||
throw deps_1.Snappy['kModuleError'];
|
||||
}
|
||||
return deps_1.Snappy.uncompress(compressedData, { asBuffer: true });
|
||||
case exports.Compressor.zstd:
|
||||
if ('kModuleError' in deps_1.ZStandard) {
|
||||
throw deps_1.ZStandard['kModuleError'];
|
||||
}
|
||||
return deps_1.ZStandard.decompress(compressedData);
|
||||
case exports.Compressor.zlib:
|
||||
return zlibInflate(compressedData);
|
||||
default:
|
||||
return compressedData;
|
||||
}
|
||||
}
|
||||
exports.decompress = decompress;
|
||||
//# sourceMappingURL=compression.js.map
|
||||
1
node_modules/mongodb/lib/cmap/wire_protocol/compression.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/wire_protocol/compression.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"compression.js","sourceRoot":"","sources":["../../../src/cmap/wire_protocol/compression.ts"],"names":[],"mappings":";;;AAAA,+BAAiC;AACjC,6BAA6B;AAE7B,+CAAuD;AACvD,qCAA+C;AAC/C,uCAAiF;AAEjF,cAAc;AACD,QAAA,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC;IACtC,IAAI,EAAE,CAAC;IACP,MAAM,EAAE,CAAC;IACT,IAAI,EAAE,CAAC;IACP,IAAI,EAAE,CAAC;CACC,CAAC,CAAC;AAQC,QAAA,sBAAsB,GAAG,IAAI,GAAG,CAAC;IAC5C,gCAAoB;IACpB,WAAW;IACX,cAAc;IACd,UAAU;IACV,cAAc;IACd,YAAY;IACZ,YAAY;IACZ,iBAAiB;IACjB,gBAAgB;IAChB,QAAQ;CACT,CAAC,CAAC;AAEH,MAAM,sBAAsB,GAAG,CAAC,CAAC;AAEjC,MAAM,WAAW,GAAG,IAAA,gBAAS,EAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACvD,MAAM,WAAW,GAAG,IAAA,gBAAS,EAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAEvD,8DAA8D;AACvD,KAAK,UAAU,QAAQ,CAC5B,OAA2E,EAC3E,kBAA0B;IAE1B,MAAM,WAAW,GAAG,EAAsB,CAAC;IAC3C,QAAQ,OAAO,CAAC,gBAAgB,EAAE;QAChC,KAAK,QAAQ;YACX,IAAI,cAAc,IAAI,aAAM,EAAE;gBAC5B,MAAM,aAAM,CAAC,cAAc,CAAC,CAAC;aAC9B;YACD,OAAO,aAAM,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAC;QAE7C,KAAK,MAAM;YACT,IAAI,cAAc,IAAI,gBAAS,EAAE;gBAC/B,MAAM,gBAAS,CAAC,cAAc,CAAC,CAAC;aACjC;YACD,OAAO,gBAAS,CAAC,QAAQ,CAAC,kBAAkB,EAAE,sBAAsB,CAAC,CAAC;QAExE,KAAK,MAAM;YACT,IAAI,OAAO,CAAC,oBAAoB,EAAE;gBAChC,WAAW,CAAC,KAAK,GAAG,OAAO,CAAC,oBAAoB,CAAC;aAClD;YACD,OAAO,WAAW,CAAC,kBAAkB,EAAE,WAAW,CAAC,CAAC;QAEtD;YACE,MAAM,IAAI,iCAAyB,CACjC,sBAAsB,OAAO,CAAC,gBAAgB,qBAAqB,CACpE,CAAC;KACL;AACH,CAAC;AA7BD,4BA6BC;AAED,kDAAkD;AAC3C,KAAK,UAAU,UAAU,CAAC,YAAoB,EAAE,cAAsB;IAC3E,IACE,YAAY,KAAK,kBAAU,CAAC,MAAM;QAClC,YAAY,KAAK,kBAAU,CAAC,IAAI;QAChC,YAAY,KAAK,kBAAU,CAAC,IAAI;QAChC,YAAY,KAAK,kBAAU,CAAC,IAAI,EAChC;QACA,MAAM,IAAI,+BAAuB,CAC/B,2FAA2F,YAAY,GAAG,CAC3G,CAAC;KACH;IAED,QAAQ,YAAY,EAAE;QACpB,KAAK,kBAAU,CAAC,MAAM;YACpB,IAAI,cAAc,IAAI,aAAM,EAAE;gBAC5B,MAAM,aAAM,CAAC,cAAc,CAAC,CAAC;aAC9B;YACD,OAAO,aAAM,CAAC,UAAU,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;QAE/D,KAAK,kBAAU,CAAC,IAAI;YAClB,IAAI,cAAc,IAAI,gBAAS,EAAE;gBAC/B,MAAM,gBAAS,CAAC,cAAc,CAAC,CAAC;aACjC;YACD,OAAO,gBAAS,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;QAE9C,KAAK,kBAAU,CAAC,IAAI;YAClB,OAAO,WAAW,CAAC,cAAc,CAAC,CAAC;QAErC;YACE,OAAO,cAAc,CAAC;KACzB;AACH,CAAC;AA/BD,gCA+BC"}
|
||||
17
node_modules/mongodb/lib/cmap/wire_protocol/constants.js
generated
vendored
Normal file
17
node_modules/mongodb/lib/cmap/wire_protocol/constants.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.OP_MSG = exports.OP_COMPRESSED = exports.OP_DELETE = exports.OP_QUERY = exports.OP_INSERT = exports.OP_UPDATE = exports.OP_REPLY = exports.MIN_SUPPORTED_QE_SERVER_VERSION = exports.MIN_SUPPORTED_QE_WIRE_VERSION = exports.MAX_SUPPORTED_WIRE_VERSION = exports.MIN_SUPPORTED_WIRE_VERSION = exports.MAX_SUPPORTED_SERVER_VERSION = exports.MIN_SUPPORTED_SERVER_VERSION = void 0;
|
||||
exports.MIN_SUPPORTED_SERVER_VERSION = '3.6';
|
||||
exports.MAX_SUPPORTED_SERVER_VERSION = '7.0';
|
||||
exports.MIN_SUPPORTED_WIRE_VERSION = 6;
|
||||
exports.MAX_SUPPORTED_WIRE_VERSION = 21;
|
||||
exports.MIN_SUPPORTED_QE_WIRE_VERSION = 21;
|
||||
exports.MIN_SUPPORTED_QE_SERVER_VERSION = '7.0';
|
||||
exports.OP_REPLY = 1;
|
||||
exports.OP_UPDATE = 2001;
|
||||
exports.OP_INSERT = 2002;
|
||||
exports.OP_QUERY = 2004;
|
||||
exports.OP_DELETE = 2006;
|
||||
exports.OP_COMPRESSED = 2012;
|
||||
exports.OP_MSG = 2013;
|
||||
//# sourceMappingURL=constants.js.map
|
||||
1
node_modules/mongodb/lib/cmap/wire_protocol/constants.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/wire_protocol/constants.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/cmap/wire_protocol/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,4BAA4B,GAAG,KAAK,CAAC;AACrC,QAAA,4BAA4B,GAAG,KAAK,CAAC;AACrC,QAAA,0BAA0B,GAAG,CAAC,CAAC;AAC/B,QAAA,0BAA0B,GAAG,EAAE,CAAC;AAChC,QAAA,6BAA6B,GAAG,EAAE,CAAC;AACnC,QAAA,+BAA+B,GAAG,KAAK,CAAC;AACxC,QAAA,QAAQ,GAAG,CAAC,CAAC;AACb,QAAA,SAAS,GAAG,IAAI,CAAC;AACjB,QAAA,SAAS,GAAG,IAAI,CAAC;AACjB,QAAA,QAAQ,GAAG,IAAI,CAAC;AAChB,QAAA,SAAS,GAAG,IAAI,CAAC;AACjB,QAAA,aAAa,GAAG,IAAI,CAAC;AACrB,QAAA,MAAM,GAAG,IAAI,CAAC"}
|
||||
40
node_modules/mongodb/lib/cmap/wire_protocol/shared.js
generated
vendored
Normal file
40
node_modules/mongodb/lib/cmap/wire_protocol/shared.js
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.isSharded = exports.getReadPreference = void 0;
|
||||
const error_1 = require("../../error");
|
||||
const read_preference_1 = require("../../read_preference");
|
||||
const common_1 = require("../../sdam/common");
|
||||
const topology_description_1 = require("../../sdam/topology_description");
|
||||
function getReadPreference(options) {
|
||||
// Default to command version of the readPreference
|
||||
let readPreference = options?.readPreference ?? read_preference_1.ReadPreference.primary;
|
||||
// If we have an option readPreference override the command one
|
||||
if (options?.readPreference) {
|
||||
readPreference = options.readPreference;
|
||||
}
|
||||
if (typeof readPreference === 'string') {
|
||||
readPreference = read_preference_1.ReadPreference.fromString(readPreference);
|
||||
}
|
||||
if (!(readPreference instanceof read_preference_1.ReadPreference)) {
|
||||
throw new error_1.MongoInvalidArgumentError('Option "readPreference" must be a ReadPreference instance');
|
||||
}
|
||||
return readPreference;
|
||||
}
|
||||
exports.getReadPreference = getReadPreference;
|
||||
function isSharded(topologyOrServer) {
|
||||
if (topologyOrServer == null) {
|
||||
return false;
|
||||
}
|
||||
if (topologyOrServer.description && topologyOrServer.description.type === common_1.ServerType.Mongos) {
|
||||
return true;
|
||||
}
|
||||
// NOTE: This is incredibly inefficient, and should be removed once command construction
|
||||
// happens based on `Server` not `Topology`.
|
||||
if (topologyOrServer.description && topologyOrServer.description instanceof topology_description_1.TopologyDescription) {
|
||||
const servers = Array.from(topologyOrServer.description.servers.values());
|
||||
return servers.some((server) => server.type === common_1.ServerType.Mongos);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
exports.isSharded = isSharded;
|
||||
//# sourceMappingURL=shared.js.map
|
||||
1
node_modules/mongodb/lib/cmap/wire_protocol/shared.js.map
generated
vendored
Normal file
1
node_modules/mongodb/lib/cmap/wire_protocol/shared.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/cmap/wire_protocol/shared.ts"],"names":[],"mappings":";;;AAAA,uCAAwD;AAExD,2DAAuD;AACvD,8CAA+C;AAI/C,0EAAsE;AAOtE,SAAgB,iBAAiB,CAAC,OAA8B;IAC9D,mDAAmD;IACnD,IAAI,cAAc,GAAG,OAAO,EAAE,cAAc,IAAI,gCAAc,CAAC,OAAO,CAAC;IACvE,+DAA+D;IAC/D,IAAI,OAAO,EAAE,cAAc,EAAE;QAC3B,cAAc,GAAG,OAAO,CAAC,cAAc,CAAC;KACzC;IAED,IAAI,OAAO,cAAc,KAAK,QAAQ,EAAE;QACtC,cAAc,GAAG,gCAAc,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;KAC5D;IAED,IAAI,CAAC,CAAC,cAAc,YAAY,gCAAc,CAAC,EAAE;QAC/C,MAAM,IAAI,iCAAyB,CACjC,2DAA2D,CAC5D,CAAC;KACH;IAED,OAAO,cAAc,CAAC;AACxB,CAAC;AAnBD,8CAmBC;AAED,SAAgB,SAAS,CAAC,gBAAiD;IACzE,IAAI,gBAAgB,IAAI,IAAI,EAAE;QAC5B,OAAO,KAAK,CAAC;KACd;IAED,IAAI,gBAAgB,CAAC,WAAW,IAAI,gBAAgB,CAAC,WAAW,CAAC,IAAI,KAAK,mBAAU,CAAC,MAAM,EAAE;QAC3F,OAAO,IAAI,CAAC;KACb;IAED,wFAAwF;IACxF,kDAAkD;IAClD,IAAI,gBAAgB,CAAC,WAAW,IAAI,gBAAgB,CAAC,WAAW,YAAY,0CAAmB,EAAE;QAC/F,MAAM,OAAO,GAAwB,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QAC/F,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,MAAyB,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,mBAAU,CAAC,MAAM,CAAC,CAAC;KACvF;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAjBD,8BAiBC"}
|
||||
Reference in New Issue
Block a user