| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.DEFAULT_OPTIONS = exports.OPTIONS = void 0;
- exports.resolveSRVRecord = resolveSRVRecord;
- exports.parseOptions = parseOptions;
- const dns = require("dns");
- const mongodb_connection_string_url_1 = require("mongodb-connection-string-url");
- const url_1 = require("url");
- const mongo_credentials_1 = require("./cmap/auth/mongo_credentials");
- const providers_1 = require("./cmap/auth/providers");
- const compression_1 = require("./cmap/wire_protocol/compression");
- const encrypter_1 = require("./encrypter");
- const error_1 = require("./error");
- const mongo_client_1 = require("./mongo_client");
- const mongo_logger_1 = require("./mongo_logger");
- const read_concern_1 = require("./read_concern");
- const read_preference_1 = require("./read_preference");
- const monitor_1 = require("./sdam/monitor");
- const utils_1 = require("./utils");
- const write_concern_1 = require("./write_concern");
- const VALID_TXT_RECORDS = ['authSource', 'replicaSet', 'loadBalanced'];
- const LB_SINGLE_HOST_ERROR = 'loadBalanced option only supported with a single host in the URI';
- const LB_REPLICA_SET_ERROR = 'loadBalanced option not supported with a replicaSet option';
- const LB_DIRECT_CONNECTION_ERROR = 'loadBalanced option not supported when directConnection is provided';
- function retryDNSTimeoutFor(api) {
- return async function dnsReqRetryTimeout(lookupAddress) {
- try {
- return await dns.promises[api](lookupAddress);
- }
- catch (firstDNSError) {
- if (firstDNSError.code === dns.TIMEOUT) {
- return await dns.promises[api](lookupAddress);
- }
- else {
- throw firstDNSError;
- }
- }
- };
- }
- const resolveSrv = retryDNSTimeoutFor('resolveSrv');
- const resolveTxt = retryDNSTimeoutFor('resolveTxt');
- /**
- * Lookup a `mongodb+srv` connection string, combine the parts and reparse it as a normal
- * connection string.
- *
- * @param uri - The connection string to parse
- * @param options - Optional user provided connection string options
- */
- async function resolveSRVRecord(options) {
- if (typeof options.srvHost !== 'string') {
- throw new error_1.MongoAPIError('Option "srvHost" must not be empty');
- }
- // Asynchronously start TXT resolution so that we do not have to wait until
- // the SRV record is resolved before starting a second DNS query.
- const lookupAddress = options.srvHost;
- const txtResolutionPromise = resolveTxt(lookupAddress);
- txtResolutionPromise.then(undefined, utils_1.squashError); // rejections will be handled later
- const hostname = `_${options.srvServiceName}._tcp.${lookupAddress}`;
- // Resolve the SRV record and use the result as the list of hosts to connect to.
- const addresses = await resolveSrv(hostname);
- if (addresses.length === 0) {
- throw new error_1.MongoAPIError('No addresses found at host');
- }
- for (const { name } of addresses) {
- (0, utils_1.checkParentDomainMatch)(name, lookupAddress);
- }
- const hostAddresses = addresses.map(r => utils_1.HostAddress.fromString(`${r.name}:${r.port ?? 27017}`));
- validateLoadBalancedOptions(hostAddresses, options, true);
- // Use the result of resolving the TXT record and add options from there if they exist.
- let record;
- try {
- record = await txtResolutionPromise;
- }
- catch (error) {
- if (error.code !== 'ENODATA' && error.code !== 'ENOTFOUND') {
- throw error;
- }
- return hostAddresses;
- }
- if (record.length > 1) {
- throw new error_1.MongoParseError('Multiple text records not allowed');
- }
- const txtRecordOptions = new url_1.URLSearchParams(record[0].join(''));
- const txtRecordOptionKeys = [...txtRecordOptions.keys()];
- if (txtRecordOptionKeys.some(key => !VALID_TXT_RECORDS.includes(key))) {
- throw new error_1.MongoParseError(`Text record may only set any of: ${VALID_TXT_RECORDS.join(', ')}`);
- }
- if (VALID_TXT_RECORDS.some(option => txtRecordOptions.get(option) === '')) {
- throw new error_1.MongoParseError('Cannot have empty URI params in DNS TXT Record');
- }
- const source = txtRecordOptions.get('authSource') ?? undefined;
- const replicaSet = txtRecordOptions.get('replicaSet') ?? undefined;
- const loadBalanced = txtRecordOptions.get('loadBalanced') ?? undefined;
- if (!options.userSpecifiedAuthSource &&
- source &&
- options.credentials &&
- !providers_1.AUTH_MECHS_AUTH_SRC_EXTERNAL.has(options.credentials.mechanism)) {
- options.credentials = mongo_credentials_1.MongoCredentials.merge(options.credentials, { source });
- }
- if (!options.userSpecifiedReplicaSet && replicaSet) {
- options.replicaSet = replicaSet;
- }
- if (loadBalanced === 'true') {
- options.loadBalanced = true;
- }
- if (options.replicaSet && options.srvMaxHosts > 0) {
- throw new error_1.MongoParseError('Cannot combine replicaSet option with srvMaxHosts');
- }
- validateLoadBalancedOptions(hostAddresses, options, true);
- return hostAddresses;
- }
- /**
- * Checks if TLS options are valid
- *
- * @param allOptions - All options provided by user or included in default options map
- * @throws MongoAPIError if TLS options are invalid
- */
- function checkTLSOptions(allOptions) {
- if (!allOptions)
- return;
- const check = (a, b) => {
- if (allOptions.has(a) && allOptions.has(b)) {
- throw new error_1.MongoAPIError(`The '${a}' option cannot be used with the '${b}' option`);
- }
- };
- check('tlsInsecure', 'tlsAllowInvalidCertificates');
- check('tlsInsecure', 'tlsAllowInvalidHostnames');
- }
- function getBoolean(name, value) {
- if (typeof value === 'boolean')
- return value;
- switch (value) {
- case 'true':
- return true;
- case 'false':
- return false;
- default:
- throw new error_1.MongoParseError(`${name} must be either "true" or "false"`);
- }
- }
- function getIntFromOptions(name, value) {
- const parsedInt = (0, utils_1.parseInteger)(value);
- if (parsedInt != null) {
- return parsedInt;
- }
- throw new error_1.MongoParseError(`Expected ${name} to be stringified int value, got: ${value}`);
- }
- function getUIntFromOptions(name, value) {
- const parsedValue = getIntFromOptions(name, value);
- if (parsedValue < 0) {
- throw new error_1.MongoParseError(`${name} can only be a positive int value, got: ${value}`);
- }
- return parsedValue;
- }
- function* entriesFromString(value) {
- if (value === '') {
- return;
- }
- const keyValuePairs = value.split(',');
- for (const keyValue of keyValuePairs) {
- const [key, value] = keyValue.split(/:(.*)/);
- if (value == null) {
- throw new error_1.MongoParseError('Cannot have undefined values in key value pairs');
- }
- yield [key, value];
- }
- }
- class CaseInsensitiveMap extends Map {
- constructor(entries = []) {
- super(entries.map(([k, v]) => [k.toLowerCase(), v]));
- }
- has(k) {
- return super.has(k.toLowerCase());
- }
- get(k) {
- return super.get(k.toLowerCase());
- }
- set(k, v) {
- return super.set(k.toLowerCase(), v);
- }
- delete(k) {
- return super.delete(k.toLowerCase());
- }
- }
- function parseOptions(uri, mongoClient = undefined, options = {}) {
- if (mongoClient != null && !(mongoClient instanceof mongo_client_1.MongoClient)) {
- options = mongoClient;
- mongoClient = undefined;
- }
- // validate BSONOptions
- if (options.useBigInt64 && typeof options.promoteLongs === 'boolean' && !options.promoteLongs) {
- throw new error_1.MongoAPIError('Must request either bigint or Long for int64 deserialization');
- }
- if (options.useBigInt64 && typeof options.promoteValues === 'boolean' && !options.promoteValues) {
- throw new error_1.MongoAPIError('Must request either bigint or Long for int64 deserialization');
- }
- const url = new mongodb_connection_string_url_1.default(uri);
- const { hosts, isSRV } = url;
- const mongoOptions = Object.create(null);
- mongoOptions.hosts = isSRV ? [] : hosts.map(utils_1.HostAddress.fromString);
- const urlOptions = new CaseInsensitiveMap();
- if (url.pathname !== '/' && url.pathname !== '') {
- const dbName = decodeURIComponent(url.pathname[0] === '/' ? url.pathname.slice(1) : url.pathname);
- if (dbName) {
- urlOptions.set('dbName', [dbName]);
- }
- }
- if (url.username !== '') {
- const auth = {
- username: decodeURIComponent(url.username)
- };
- if (typeof url.password === 'string') {
- auth.password = decodeURIComponent(url.password);
- }
- urlOptions.set('auth', [auth]);
- }
- for (const key of url.searchParams.keys()) {
- const values = url.searchParams.getAll(key);
- const isReadPreferenceTags = /readPreferenceTags/i.test(key);
- if (!isReadPreferenceTags && values.length > 1) {
- throw new error_1.MongoInvalidArgumentError(`URI option "${key}" cannot appear more than once in the connection string`);
- }
- if (!isReadPreferenceTags && values.includes('')) {
- throw new error_1.MongoAPIError(`URI option "${key}" cannot be specified with no value`);
- }
- if (!urlOptions.has(key)) {
- urlOptions.set(key, values);
- }
- }
- const objectOptions = new CaseInsensitiveMap(Object.entries(options).filter(([, v]) => v != null));
- // Validate options that can only be provided by one of uri or object
- if (urlOptions.has('serverApi')) {
- throw new error_1.MongoParseError('URI cannot contain `serverApi`, it can only be passed to the client');
- }
- const uriMechanismProperties = urlOptions.get('authMechanismProperties');
- if (uriMechanismProperties) {
- for (const property of uriMechanismProperties) {
- if (/(^|,)ALLOWED_HOSTS:/.test(property)) {
- throw new error_1.MongoParseError('Auth mechanism property ALLOWED_HOSTS is not allowed in the connection string.');
- }
- }
- }
- if (objectOptions.has('loadBalanced')) {
- throw new error_1.MongoParseError('loadBalanced is only a valid option in the URI');
- }
- // All option collection
- const allProvidedOptions = new CaseInsensitiveMap();
- const allProvidedKeys = new Set([...urlOptions.keys(), ...objectOptions.keys()]);
- for (const key of allProvidedKeys) {
- const values = [];
- const objectOptionValue = objectOptions.get(key);
- if (objectOptionValue != null) {
- values.push(objectOptionValue);
- }
- const urlValues = urlOptions.get(key) ?? [];
- values.push(...urlValues);
- allProvidedOptions.set(key, values);
- }
- if (allProvidedOptions.has('tls') || allProvidedOptions.has('ssl')) {
- const tlsAndSslOpts = (allProvidedOptions.get('tls') || [])
- .concat(allProvidedOptions.get('ssl') || [])
- .map(getBoolean.bind(null, 'tls/ssl'));
- if (new Set(tlsAndSslOpts).size !== 1) {
- throw new error_1.MongoParseError('All values of tls/ssl must be the same.');
- }
- }
- checkTLSOptions(allProvidedOptions);
- const unsupportedOptions = (0, utils_1.setDifference)(allProvidedKeys, Array.from(Object.keys(exports.OPTIONS)).map(s => s.toLowerCase()));
- if (unsupportedOptions.size !== 0) {
- const optionWord = unsupportedOptions.size > 1 ? 'options' : 'option';
- const isOrAre = unsupportedOptions.size > 1 ? 'are' : 'is';
- throw new error_1.MongoParseError(`${optionWord} ${Array.from(unsupportedOptions).join(', ')} ${isOrAre} not supported`);
- }
- // Option parsing and setting
- for (const [key, descriptor] of Object.entries(exports.OPTIONS)) {
- const values = allProvidedOptions.get(key);
- if (!values || values.length === 0) {
- if (exports.DEFAULT_OPTIONS.has(key)) {
- setOption(mongoOptions, key, descriptor, [exports.DEFAULT_OPTIONS.get(key)]);
- }
- }
- else {
- const { deprecated } = descriptor;
- if (deprecated) {
- const deprecatedMsg = typeof deprecated === 'string' ? `: ${deprecated}` : '';
- (0, utils_1.emitWarning)(`${key} is a deprecated option${deprecatedMsg}`);
- }
- setOption(mongoOptions, key, descriptor, values);
- }
- }
- if (mongoOptions.credentials) {
- const isGssapi = mongoOptions.credentials.mechanism === providers_1.AuthMechanism.MONGODB_GSSAPI;
- const isX509 = mongoOptions.credentials.mechanism === providers_1.AuthMechanism.MONGODB_X509;
- const isAws = mongoOptions.credentials.mechanism === providers_1.AuthMechanism.MONGODB_AWS;
- const isOidc = mongoOptions.credentials.mechanism === providers_1.AuthMechanism.MONGODB_OIDC;
- if ((isGssapi || isX509) &&
- allProvidedOptions.has('authSource') &&
- mongoOptions.credentials.source !== '$external') {
- // If authSource was explicitly given and its incorrect, we error
- throw new error_1.MongoParseError(`authMechanism ${mongoOptions.credentials.mechanism} requires an authSource of '$external'`);
- }
- if (!(isGssapi || isX509 || isAws || isOidc) &&
- mongoOptions.dbName &&
- !allProvidedOptions.has('authSource')) {
- // inherit the dbName unless GSSAPI or X509, then silently ignore dbName
- // and there was no specific authSource given
- mongoOptions.credentials = mongo_credentials_1.MongoCredentials.merge(mongoOptions.credentials, {
- source: mongoOptions.dbName
- });
- }
- if (isAws) {
- const { username, password } = mongoOptions.credentials;
- if (username || password) {
- throw new error_1.MongoAPIError('username and password cannot be provided when using MONGODB-AWS. Credentials must be provided in a manner that can be read by the AWS SDK.');
- }
- if (mongoOptions.credentials.mechanismProperties.AWS_SESSION_TOKEN) {
- throw new error_1.MongoAPIError('AWS_SESSION_TOKEN cannot be provided when using MONGODB-AWS. Credentials must be provided in a manner that can be read by the AWS SDK.');
- }
- }
- mongoOptions.credentials.validate();
- // Check if the only auth related option provided was authSource, if so we can remove credentials
- if (mongoOptions.credentials.password === '' &&
- mongoOptions.credentials.username === '' &&
- mongoOptions.credentials.mechanism === providers_1.AuthMechanism.MONGODB_DEFAULT &&
- Object.keys(mongoOptions.credentials.mechanismProperties).length === 0) {
- delete mongoOptions.credentials;
- }
- }
- if (!mongoOptions.dbName) {
- // dbName default is applied here because of the credential validation above
- mongoOptions.dbName = 'test';
- }
- validateLoadBalancedOptions(hosts, mongoOptions, isSRV);
- if (mongoClient && mongoOptions.autoEncryption) {
- encrypter_1.Encrypter.checkForMongoCrypt();
- mongoOptions.encrypter = new encrypter_1.Encrypter(mongoClient, uri, options);
- mongoOptions.autoEncrypter = mongoOptions.encrypter.autoEncrypter;
- }
- // Potential SRV Overrides and SRV connection string validations
- mongoOptions.userSpecifiedAuthSource =
- objectOptions.has('authSource') || urlOptions.has('authSource');
- mongoOptions.userSpecifiedReplicaSet =
- objectOptions.has('replicaSet') || urlOptions.has('replicaSet');
- if (isSRV) {
- // SRV Record is resolved upon connecting
- mongoOptions.srvHost = hosts[0];
- if (mongoOptions.directConnection) {
- throw new error_1.MongoAPIError('SRV URI does not support directConnection');
- }
- if (mongoOptions.srvMaxHosts > 0 && typeof mongoOptions.replicaSet === 'string') {
- throw new error_1.MongoParseError('Cannot use srvMaxHosts option with replicaSet');
- }
- // SRV turns on TLS by default, but users can override and turn it off
- const noUserSpecifiedTLS = !objectOptions.has('tls') && !urlOptions.has('tls');
- const noUserSpecifiedSSL = !objectOptions.has('ssl') && !urlOptions.has('ssl');
- if (noUserSpecifiedTLS && noUserSpecifiedSSL) {
- mongoOptions.tls = true;
- }
- }
- else {
- const userSpecifiedSrvOptions = urlOptions.has('srvMaxHosts') ||
- objectOptions.has('srvMaxHosts') ||
- urlOptions.has('srvServiceName') ||
- objectOptions.has('srvServiceName');
- if (userSpecifiedSrvOptions) {
- throw new error_1.MongoParseError('Cannot use srvMaxHosts or srvServiceName with a non-srv connection string');
- }
- }
- if (mongoOptions.directConnection && mongoOptions.hosts.length !== 1) {
- throw new error_1.MongoParseError('directConnection option requires exactly one host');
- }
- if (!mongoOptions.proxyHost &&
- (mongoOptions.proxyPort || mongoOptions.proxyUsername || mongoOptions.proxyPassword)) {
- throw new error_1.MongoParseError('Must specify proxyHost if other proxy options are passed');
- }
- if ((mongoOptions.proxyUsername && !mongoOptions.proxyPassword) ||
- (!mongoOptions.proxyUsername && mongoOptions.proxyPassword)) {
- throw new error_1.MongoParseError('Can only specify both of proxy username/password or neither');
- }
- const proxyOptions = ['proxyHost', 'proxyPort', 'proxyUsername', 'proxyPassword'].map(key => urlOptions.get(key) ?? []);
- if (proxyOptions.some(options => options.length > 1)) {
- throw new error_1.MongoParseError('Proxy options cannot be specified multiple times in the connection string');
- }
- mongoOptions.mongoLoggerOptions = mongo_logger_1.MongoLogger.resolveOptions({
- MONGODB_LOG_COMMAND: process.env.MONGODB_LOG_COMMAND,
- MONGODB_LOG_TOPOLOGY: process.env.MONGODB_LOG_TOPOLOGY,
- MONGODB_LOG_SERVER_SELECTION: process.env.MONGODB_LOG_SERVER_SELECTION,
- MONGODB_LOG_CONNECTION: process.env.MONGODB_LOG_CONNECTION,
- MONGODB_LOG_CLIENT: process.env.MONGODB_LOG_CLIENT,
- MONGODB_LOG_ALL: process.env.MONGODB_LOG_ALL,
- MONGODB_LOG_MAX_DOCUMENT_LENGTH: process.env.MONGODB_LOG_MAX_DOCUMENT_LENGTH,
- MONGODB_LOG_PATH: process.env.MONGODB_LOG_PATH
- }, {
- mongodbLogPath: mongoOptions.mongodbLogPath,
- mongodbLogComponentSeverities: mongoOptions.mongodbLogComponentSeverities,
- mongodbLogMaxDocumentLength: mongoOptions.mongodbLogMaxDocumentLength
- });
- return mongoOptions;
- }
- /**
- * #### Throws if LB mode is true:
- * - hosts contains more than one host
- * - there is a replicaSet name set
- * - directConnection is set
- * - if srvMaxHosts is used when an srv connection string is passed in
- *
- * @throws MongoParseError
- */
- function validateLoadBalancedOptions(hosts, mongoOptions, isSrv) {
- if (mongoOptions.loadBalanced) {
- if (hosts.length > 1) {
- throw new error_1.MongoParseError(LB_SINGLE_HOST_ERROR);
- }
- if (mongoOptions.replicaSet) {
- throw new error_1.MongoParseError(LB_REPLICA_SET_ERROR);
- }
- if (mongoOptions.directConnection) {
- throw new error_1.MongoParseError(LB_DIRECT_CONNECTION_ERROR);
- }
- if (isSrv && mongoOptions.srvMaxHosts > 0) {
- throw new error_1.MongoParseError('Cannot limit srv hosts with loadBalanced enabled');
- }
- }
- return;
- }
- function setOption(mongoOptions, key, descriptor, values) {
- const { target, type, transform } = descriptor;
- const name = target ?? key;
- switch (type) {
- case 'boolean':
- mongoOptions[name] = getBoolean(name, values[0]);
- break;
- case 'int':
- mongoOptions[name] = getIntFromOptions(name, values[0]);
- break;
- case 'uint':
- mongoOptions[name] = getUIntFromOptions(name, values[0]);
- break;
- case 'string':
- if (values[0] == null) {
- break;
- }
- // The value should always be a string here, but since the array is typed as unknown
- // there still needs to be an explicit cast.
- // eslint-disable-next-line @typescript-eslint/no-base-to-string
- mongoOptions[name] = String(values[0]);
- break;
- case 'record':
- if (!(0, utils_1.isRecord)(values[0])) {
- throw new error_1.MongoParseError(`${name} must be an object`);
- }
- mongoOptions[name] = values[0];
- break;
- case 'any':
- mongoOptions[name] = values[0];
- break;
- default: {
- if (!transform) {
- throw new error_1.MongoParseError('Descriptors missing a type must define a transform');
- }
- const transformValue = transform({ name, options: mongoOptions, values });
- mongoOptions[name] = transformValue;
- break;
- }
- }
- }
- exports.OPTIONS = {
- appName: {
- type: 'string'
- },
- auth: {
- target: 'credentials',
- transform({ name, options, values: [value] }) {
- if (!(0, utils_1.isRecord)(value, ['username', 'password'])) {
- throw new error_1.MongoParseError(`${name} must be an object with 'username' and 'password' properties`);
- }
- return mongo_credentials_1.MongoCredentials.merge(options.credentials, {
- username: value.username,
- password: value.password
- });
- }
- },
- authMechanism: {
- target: 'credentials',
- transform({ options, values: [value] }) {
- const mechanisms = Object.values(providers_1.AuthMechanism);
- const [mechanism] = mechanisms.filter(m => m.match(RegExp(String.raw `\b${value}\b`, 'i')));
- if (!mechanism) {
- throw new error_1.MongoParseError(`authMechanism one of ${mechanisms}, got ${value}`);
- }
- let source = options.credentials?.source;
- if (mechanism === providers_1.AuthMechanism.MONGODB_PLAIN ||
- providers_1.AUTH_MECHS_AUTH_SRC_EXTERNAL.has(mechanism)) {
- // some mechanisms have '$external' as the Auth Source
- source = '$external';
- }
- let password = options.credentials?.password;
- if (mechanism === providers_1.AuthMechanism.MONGODB_X509 && password === '') {
- password = undefined;
- }
- return mongo_credentials_1.MongoCredentials.merge(options.credentials, {
- mechanism,
- source,
- password
- });
- }
- },
- // Note that if the authMechanismProperties contain a TOKEN_RESOURCE that has a
- // comma in it, it MUST be supplied as a MongoClient option instead of in the
- // connection string.
- authMechanismProperties: {
- target: 'credentials',
- transform({ options, values }) {
- // We can have a combination of options passed in the URI and options passed
- // as an object to the MongoClient. So we must transform the string options
- // as well as merge them together with a potentially provided object.
- let mechanismProperties = Object.create(null);
- for (const optionValue of values) {
- if (typeof optionValue === 'string') {
- for (const [key, value] of entriesFromString(optionValue)) {
- try {
- mechanismProperties[key] = getBoolean(key, value);
- }
- catch {
- mechanismProperties[key] = value;
- }
- }
- }
- else {
- if (!(0, utils_1.isRecord)(optionValue)) {
- throw new error_1.MongoParseError('AuthMechanismProperties must be an object');
- }
- mechanismProperties = { ...optionValue };
- }
- }
- return mongo_credentials_1.MongoCredentials.merge(options.credentials, {
- mechanismProperties
- });
- }
- },
- authSource: {
- target: 'credentials',
- transform({ options, values: [value] }) {
- const source = String(value);
- return mongo_credentials_1.MongoCredentials.merge(options.credentials, { source });
- }
- },
- autoEncryption: {
- type: 'record'
- },
- autoSelectFamily: {
- type: 'boolean',
- default: true
- },
- autoSelectFamilyAttemptTimeout: {
- type: 'uint'
- },
- bsonRegExp: {
- type: 'boolean'
- },
- serverApi: {
- target: 'serverApi',
- transform({ values: [version] }) {
- const serverApiToValidate = typeof version === 'string' ? { version } : version;
- const versionToValidate = serverApiToValidate && serverApiToValidate.version;
- if (!versionToValidate) {
- throw new error_1.MongoParseError(`Invalid \`serverApi\` property; must specify a version from the following enum: ["${Object.values(mongo_client_1.ServerApiVersion).join('", "')}"]`);
- }
- if (!Object.values(mongo_client_1.ServerApiVersion).some(v => v === versionToValidate)) {
- throw new error_1.MongoParseError(`Invalid server API version=${versionToValidate}; must be in the following enum: ["${Object.values(mongo_client_1.ServerApiVersion).join('", "')}"]`);
- }
- return serverApiToValidate;
- }
- },
- checkKeys: {
- type: 'boolean'
- },
- compressors: {
- default: 'none',
- target: 'compressors',
- transform({ values }) {
- const compressionList = new Set();
- for (const compVal of values) {
- const compValArray = typeof compVal === 'string' ? compVal.split(',') : compVal;
- if (!Array.isArray(compValArray)) {
- throw new error_1.MongoInvalidArgumentError('compressors must be an array or a comma-delimited list of strings');
- }
- for (const c of compValArray) {
- if (Object.keys(compression_1.Compressor).includes(String(c))) {
- compressionList.add(String(c));
- }
- else {
- throw new error_1.MongoInvalidArgumentError(`${c} is not a valid compression mechanism. Must be one of: ${Object.keys(compression_1.Compressor)}.`);
- }
- }
- }
- return [...compressionList];
- }
- },
- connectTimeoutMS: {
- default: 30000,
- type: 'uint'
- },
- dbName: {
- type: 'string'
- },
- directConnection: {
- default: false,
- type: 'boolean'
- },
- driverInfo: {
- default: {},
- type: 'record'
- },
- enableUtf8Validation: { type: 'boolean', default: true },
- family: {
- transform({ name, values: [value] }) {
- const transformValue = getIntFromOptions(name, value);
- if (transformValue === 4 || transformValue === 6) {
- return transformValue;
- }
- throw new error_1.MongoParseError(`Option 'family' must be 4 or 6 got ${transformValue}.`);
- }
- },
- fieldsAsRaw: {
- type: 'record'
- },
- forceServerObjectId: {
- default: false,
- type: 'boolean'
- },
- fsync: {
- deprecated: 'Please use journal instead',
- target: 'writeConcern',
- transform({ name, options, values: [value] }) {
- const wc = write_concern_1.WriteConcern.fromOptions({
- writeConcern: {
- ...options.writeConcern,
- fsync: getBoolean(name, value)
- }
- });
- if (!wc)
- throw new error_1.MongoParseError(`Unable to make a writeConcern from fsync=${value}`);
- return wc;
- }
- },
- heartbeatFrequencyMS: {
- default: 10000,
- type: 'uint'
- },
- ignoreUndefined: {
- type: 'boolean'
- },
- j: {
- deprecated: 'Please use journal instead',
- target: 'writeConcern',
- transform({ name, options, values: [value] }) {
- const wc = write_concern_1.WriteConcern.fromOptions({
- writeConcern: {
- ...options.writeConcern,
- journal: getBoolean(name, value)
- }
- });
- if (!wc)
- throw new error_1.MongoParseError(`Unable to make a writeConcern from journal=${value}`);
- return wc;
- }
- },
- journal: {
- target: 'writeConcern',
- transform({ name, options, values: [value] }) {
- const wc = write_concern_1.WriteConcern.fromOptions({
- writeConcern: {
- ...options.writeConcern,
- journal: getBoolean(name, value)
- }
- });
- if (!wc)
- throw new error_1.MongoParseError(`Unable to make a writeConcern from journal=${value}`);
- return wc;
- }
- },
- loadBalanced: {
- default: false,
- type: 'boolean'
- },
- localThresholdMS: {
- default: 15,
- type: 'uint'
- },
- maxConnecting: {
- default: 2,
- transform({ name, values: [value] }) {
- const maxConnecting = getUIntFromOptions(name, value);
- if (maxConnecting === 0) {
- throw new error_1.MongoInvalidArgumentError('maxConnecting must be > 0 if specified');
- }
- return maxConnecting;
- }
- },
- maxIdleTimeMS: {
- default: 0,
- type: 'uint'
- },
- maxPoolSize: {
- default: 100,
- type: 'uint'
- },
- maxStalenessSeconds: {
- target: 'readPreference',
- transform({ name, options, values: [value] }) {
- const maxStalenessSeconds = getUIntFromOptions(name, value);
- if (options.readPreference) {
- return read_preference_1.ReadPreference.fromOptions({
- readPreference: { ...options.readPreference, maxStalenessSeconds }
- });
- }
- else {
- return new read_preference_1.ReadPreference('secondary', undefined, { maxStalenessSeconds });
- }
- }
- },
- minInternalBufferSize: {
- type: 'uint'
- },
- minPoolSize: {
- default: 0,
- type: 'uint'
- },
- minHeartbeatFrequencyMS: {
- default: 500,
- type: 'uint'
- },
- monitorCommands: {
- default: false,
- type: 'boolean'
- },
- name: {
- target: 'driverInfo',
- transform({ values: [value], options }) {
- return { ...options.driverInfo, name: String(value) };
- }
- },
- noDelay: {
- default: true,
- type: 'boolean'
- },
- pkFactory: {
- default: utils_1.DEFAULT_PK_FACTORY,
- transform({ values: [value] }) {
- if ((0, utils_1.isRecord)(value, ['createPk']) && typeof value.createPk === 'function') {
- return value;
- }
- throw new error_1.MongoParseError(`Option pkFactory must be an object with a createPk function, got ${value}`);
- }
- },
- promoteBuffers: {
- type: 'boolean'
- },
- promoteLongs: {
- type: 'boolean'
- },
- promoteValues: {
- type: 'boolean'
- },
- useBigInt64: {
- type: 'boolean'
- },
- proxyHost: {
- type: 'string'
- },
- proxyPassword: {
- type: 'string'
- },
- proxyPort: {
- type: 'uint'
- },
- proxyUsername: {
- type: 'string'
- },
- raw: {
- default: false,
- type: 'boolean'
- },
- readConcern: {
- transform({ values: [value], options }) {
- if (value instanceof read_concern_1.ReadConcern || (0, utils_1.isRecord)(value, ['level'])) {
- return read_concern_1.ReadConcern.fromOptions({ ...options.readConcern, ...value });
- }
- throw new error_1.MongoParseError(`ReadConcern must be an object, got ${JSON.stringify(value)}`);
- }
- },
- readConcernLevel: {
- target: 'readConcern',
- transform({ values: [level], options }) {
- return read_concern_1.ReadConcern.fromOptions({
- ...options.readConcern,
- level: level
- });
- }
- },
- readPreference: {
- default: read_preference_1.ReadPreference.primary,
- transform({ values: [value], options }) {
- if (value instanceof read_preference_1.ReadPreference) {
- return read_preference_1.ReadPreference.fromOptions({
- readPreference: { ...options.readPreference, ...value },
- ...value
- });
- }
- if ((0, utils_1.isRecord)(value, ['mode'])) {
- const rp = read_preference_1.ReadPreference.fromOptions({
- readPreference: { ...options.readPreference, ...value },
- ...value
- });
- if (rp)
- return rp;
- else
- throw new error_1.MongoParseError(`Cannot make read preference from ${JSON.stringify(value)}`);
- }
- if (typeof value === 'string') {
- const rpOpts = {
- hedge: options.readPreference?.hedge,
- maxStalenessSeconds: options.readPreference?.maxStalenessSeconds
- };
- return new read_preference_1.ReadPreference(value, options.readPreference?.tags, rpOpts);
- }
- throw new error_1.MongoParseError(`Unknown ReadPreference value: ${value}`);
- }
- },
- readPreferenceTags: {
- target: 'readPreference',
- transform({ values, options }) {
- const tags = Array.isArray(values[0])
- ? values[0]
- : values;
- const readPreferenceTags = [];
- for (const tag of tags) {
- const readPreferenceTag = Object.create(null);
- if (typeof tag === 'string') {
- for (const [k, v] of entriesFromString(tag)) {
- readPreferenceTag[k] = v;
- }
- }
- if ((0, utils_1.isRecord)(tag)) {
- for (const [k, v] of Object.entries(tag)) {
- readPreferenceTag[k] = v;
- }
- }
- readPreferenceTags.push(readPreferenceTag);
- }
- return read_preference_1.ReadPreference.fromOptions({
- readPreference: options.readPreference,
- readPreferenceTags
- });
- }
- },
- replicaSet: {
- type: 'string'
- },
- retryReads: {
- default: true,
- type: 'boolean'
- },
- retryWrites: {
- default: true,
- type: 'boolean'
- },
- serializeFunctions: {
- type: 'boolean'
- },
- serverMonitoringMode: {
- default: 'auto',
- transform({ values: [value] }) {
- if (!Object.values(monitor_1.ServerMonitoringMode).includes(value)) {
- throw new error_1.MongoParseError('serverMonitoringMode must be one of `auto`, `poll`, or `stream`');
- }
- return value;
- }
- },
- serverSelectionTimeoutMS: {
- default: 30000,
- type: 'uint'
- },
- servername: {
- type: 'string'
- },
- socketTimeoutMS: {
- // TODO(NODE-6491): deprecated: 'Please use timeoutMS instead',
- default: 0,
- type: 'uint'
- },
- srvMaxHosts: {
- type: 'uint',
- default: 0
- },
- srvServiceName: {
- type: 'string',
- default: 'mongodb'
- },
- ssl: {
- target: 'tls',
- type: 'boolean'
- },
- timeoutMS: {
- type: 'uint'
- },
- tls: {
- type: 'boolean'
- },
- tlsAllowInvalidCertificates: {
- target: 'rejectUnauthorized',
- transform({ name, values: [value] }) {
- // allowInvalidCertificates is the inverse of rejectUnauthorized
- return !getBoolean(name, value);
- }
- },
- tlsAllowInvalidHostnames: {
- target: 'checkServerIdentity',
- transform({ name, values: [value] }) {
- // tlsAllowInvalidHostnames means setting the checkServerIdentity function to a noop
- return getBoolean(name, value) ? () => undefined : undefined;
- }
- },
- tlsCAFile: {
- type: 'string'
- },
- tlsCRLFile: {
- type: 'string'
- },
- tlsCertificateKeyFile: {
- type: 'string'
- },
- tlsCertificateKeyFilePassword: {
- target: 'passphrase',
- type: 'any'
- },
- tlsInsecure: {
- transform({ name, options, values: [value] }) {
- const tlsInsecure = getBoolean(name, value);
- if (tlsInsecure) {
- options.checkServerIdentity = () => undefined;
- options.rejectUnauthorized = false;
- }
- else {
- options.checkServerIdentity = options.tlsAllowInvalidHostnames
- ? () => undefined
- : undefined;
- options.rejectUnauthorized = options.tlsAllowInvalidCertificates ? false : true;
- }
- return tlsInsecure;
- }
- },
- w: {
- target: 'writeConcern',
- transform({ values: [value], options }) {
- return write_concern_1.WriteConcern.fromOptions({ writeConcern: { ...options.writeConcern, w: value } });
- }
- },
- waitQueueTimeoutMS: {
- // TODO(NODE-6491): deprecated: 'Please use timeoutMS instead',
- default: 0,
- type: 'uint'
- },
- writeConcern: {
- target: 'writeConcern',
- transform({ values: [value], options }) {
- if ((0, utils_1.isRecord)(value) || value instanceof write_concern_1.WriteConcern) {
- return write_concern_1.WriteConcern.fromOptions({
- writeConcern: {
- ...options.writeConcern,
- ...value
- }
- });
- }
- else if (value === 'majority' || typeof value === 'number') {
- return write_concern_1.WriteConcern.fromOptions({
- writeConcern: {
- ...options.writeConcern,
- w: value
- }
- });
- }
- throw new error_1.MongoParseError(`Invalid WriteConcern cannot parse: ${JSON.stringify(value)}`);
- }
- },
- wtimeout: {
- deprecated: 'Please use wtimeoutMS instead',
- target: 'writeConcern',
- transform({ values: [value], options }) {
- const wc = write_concern_1.WriteConcern.fromOptions({
- writeConcern: {
- ...options.writeConcern,
- wtimeout: getUIntFromOptions('wtimeout', value)
- }
- });
- if (wc)
- return wc;
- throw new error_1.MongoParseError(`Cannot make WriteConcern from wtimeout`);
- }
- },
- wtimeoutMS: {
- target: 'writeConcern',
- transform({ values: [value], options }) {
- const wc = write_concern_1.WriteConcern.fromOptions({
- writeConcern: {
- ...options.writeConcern,
- wtimeoutMS: getUIntFromOptions('wtimeoutMS', value)
- }
- });
- if (wc)
- return wc;
- throw new error_1.MongoParseError(`Cannot make WriteConcern from wtimeout`);
- }
- },
- zlibCompressionLevel: {
- default: 0,
- type: 'int'
- },
- mongodbLogPath: {
- transform({ values: [value] }) {
- if (!((typeof value === 'string' && ['stderr', 'stdout'].includes(value)) ||
- (value &&
- typeof value === 'object' &&
- 'write' in value &&
- typeof value.write === 'function'))) {
- throw new error_1.MongoAPIError(`Option 'mongodbLogPath' must be of type 'stderr' | 'stdout' | MongoDBLogWritable`);
- }
- return value;
- }
- },
- mongodbLogComponentSeverities: {
- transform({ values: [value] }) {
- if (typeof value !== 'object' || !value) {
- throw new error_1.MongoAPIError(`Option 'mongodbLogComponentSeverities' must be a non-null object`);
- }
- for (const [k, v] of Object.entries(value)) {
- if (typeof v !== 'string' || typeof k !== 'string') {
- throw new error_1.MongoAPIError(`User input for option 'mongodbLogComponentSeverities' object cannot include a non-string key or value`);
- }
- if (!Object.values(mongo_logger_1.MongoLoggableComponent).some(val => val === k) && k !== 'default') {
- throw new error_1.MongoAPIError(`User input for option 'mongodbLogComponentSeverities' contains invalid key: ${k}`);
- }
- if (!Object.values(mongo_logger_1.SeverityLevel).some(val => val === v)) {
- throw new error_1.MongoAPIError(`Option 'mongodbLogComponentSeverities' does not support ${v} as a value for ${k}`);
- }
- }
- return value;
- }
- },
- mongodbLogMaxDocumentLength: { type: 'uint' },
- // Custom types for modifying core behavior
- connectionType: { type: 'any' },
- srvPoller: { type: 'any' },
- // Accepted Node.js Options
- allowPartialTrustChain: { type: 'any' },
- minDHSize: { type: 'any' },
- pskCallback: { type: 'any' },
- secureContext: { type: 'any' },
- enableTrace: { type: 'any' },
- requestCert: { type: 'any' },
- rejectUnauthorized: { type: 'any' },
- checkServerIdentity: { type: 'any' },
- keepAliveInitialDelay: { type: 'any' },
- ALPNProtocols: { type: 'any' },
- SNICallback: { type: 'any' },
- session: { type: 'any' },
- requestOCSP: { type: 'any' },
- localAddress: { type: 'any' },
- localPort: { type: 'any' },
- hints: { type: 'any' },
- lookup: { type: 'any' },
- ca: { type: 'any' },
- cert: { type: 'any' },
- ciphers: { type: 'any' },
- crl: { type: 'any' },
- ecdhCurve: { type: 'any' },
- key: { type: 'any' },
- passphrase: { type: 'any' },
- pfx: { type: 'any' },
- secureProtocol: { type: 'any' },
- index: { type: 'any' },
- // Legacy options from v3 era
- __skipPingOnConnect: { type: 'boolean' }
- };
- exports.DEFAULT_OPTIONS = new CaseInsensitiveMap(Object.entries(exports.OPTIONS)
- .filter(([, descriptor]) => descriptor.default != null)
- .map(([k, d]) => [k, d.default]));
- //# sourceMappingURL=connection_string.js.map
|