Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
Bedrock Non-Commercial License v1.0
===================================

Copyright (c) 2011-2017 Digital Bazaar, Inc.
Copyright (c) 2011-2024 Digital Bazaar, Inc.
All rights reserved.

Summary
Expand Down
23 changes: 10 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,10 @@ bedrock.start();
For documentation on database configuration, see [config.js](./lib/config.js).

### Connecting and Authenticating
MongoDB's documentation offers tons of great examples on how to authenticate
using a myriad number of connection strings.
MongoDB's documentation provides examples on how to authenticate using a myriad
number of connection strings.

[Mongo Node 3.5 Driver connect docs](http://mongodb.github.io/node-mongodb-native/3.5/tutorials/connect/)

[Mongo Node 3.5 Driver atlas docs](https://docs.mongodb.com/drivers/node#connect-to-mongodb-atlas)
[Mongo Node Driver connect docs](https://www.mongodb.com/docs/drivers/node/current/fundamentals/connection/connect/)

You can also connect to access-enabled mongo servers using some small changes to the
`config.mongodb.connectOptions`:
Expand Down Expand Up @@ -94,9 +92,9 @@ config.mongodb.url = 'mongodb://myDBReader:D1fficultP%[email protected].
## Requirements

* Linux or Mac OS X (also works on Windows with some coaxing)
* node.js >= 14.x
* npm >= 6.x
* mongodb ~= 4.x
* node.js >= 18.x
* npm >= 9.x
* mongodb >= 5.x
* libkrb5-dev >= 1.x.x

## Setup
Expand All @@ -105,7 +103,7 @@ config.mongodb.url = 'mongodb://myDBReader:D1fficultP%[email protected].
at [mongodb.org](http://docs.mongodb.org/manual/tutorial/add-user-administrator/)
for your version of MongoDB. Version 4.2.x is currently supported.
2. [optional] Tweak your project's configuration settings; see
[Configuration](#configuration) or [Quick Examples](#quickexamples).
[Configuration](#configuration) or [Quick Examples](#quick-examples).

## API

Expand All @@ -122,13 +120,12 @@ an error occurs, the returned promise rejects. If no error occurs, then once
the promise resolves, the `collections` object will have keys that match the
collection names and values that are instances of
[mongodb-native][]
[Collection](http://mongodb.github.io/node-mongodb-native/2.0/api/Collection.html).
[Collection](https://mongodb.github.io/node-mongodb-native/6.3/classes/Collection.html).

### createGridFSBucket(options)

Creates and returns a new `GridFSBucket` from the native driver. Options are
the same as for `GridFSBucket`. The current client is used and the
`writeConcern` option defaults to the `writeOptions` config value.
the same as for `GridFSBucket`. The current client is used.

## Test Mode
### Drop Collections on Initialization
Expand All @@ -152,4 +149,4 @@ bedrock.config.mongodb.dropCollections.collections = [];
```

[bedrock]: https://github.com/digitalbazaar/bedrock
[mongodb-native]: http://mongodb.github.io/node-mongodb-native/3.5/
[mongodb-native]: https://www.mongodb.com/docs/drivers/node/current/
43 changes: 15 additions & 28 deletions lib/authn.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2012-2024 Digital Bazaar, Inc. All rights reserved.
*/
import * as bedrock from '@bedrock/core';
import * as urls from './urls.js';
Expand All @@ -14,19 +14,19 @@ const {util: {BedrockError}} = bedrock;

export async function openDatabase(options) {
const config = bedrock.config.mongodb;
// copy the config stuff related to connecting

const opts = {
database: config.name,
authentication: {...config.authentication},
// authSource should be set in connectOptions
connectOptions: {...config.connectOptions},
writeOptions: {...config.writeOptions},
...options
};

// if a `url` was not specified, create one from the `config`
if(!opts.url) {
if(config.url) {
opts.url = config.url;
} else {
opts.url = urls.create(config);
opts.database = config.name;
opts.authentication = {...config.authentication};
}

// do unauthenticated connection to mongo server to check
Expand All @@ -35,21 +35,14 @@ export async function openDatabase(options) {
const serverInfo = await admin.serverInfo(null);
_checkServerVersion({serverInfo, config});

// check if server supports roles; if not, can't authenticate
if(!_usesRoles(serverInfo)) {
const stringVersion = serverInfo.versionArray.join('.');
throw new BedrockError(
`MongoDB server version "${stringVersion}" is unsupported.`,
'NotSupportedError');
}
// makes an unauthenticated call to the server
// to see if auth is required
const authRequired = await _isAuthnRequired({config, admin});

// if authRequired create an auth object for Mongo;
// otherwise `auth` will be passed as `null` and success will rely on other
// config options such as the url for the server
if(authRequired) {
if(!opts.url && authRequired) {
_addAuthOptions({options: opts, config});
}

Expand All @@ -69,8 +62,8 @@ async function _connect(options) {
if(!options.init) {
logger.info('connecting to database: ' + urls.sanitize(options.url));
}
const {writeConcern} = options.writeOptions;
let connectOptions = {...options.connectOptions, writeConcern};

let connectOptions = {...options.connectOptions};
// socket related options used to be an object
// they are now just general options in connectOptions
if('socketOptions' in options.connectOptions) {
Expand All @@ -80,20 +73,14 @@ async function _connect(options) {
};
delete connectOptions.socketOptions;
}

const client = await MongoClient.connect(options.url, connectOptions);

const db = client.db();
const ping = await db.admin().ping();
logger.debug(
'database connection succeeded: db=' + db.databaseName +
' username=' + connectOptions?.auth?.user, {ping});
return {client, db};
}
logger.debug('database connection succeeded: db=' + db.databaseName, {ping});

function _usesRoles(serverInfo) {
// >= Mongo 2.6 uses user roles
return (
(serverInfo.versionArray[0] == 2 && serverInfo.versionArray[1] >= 6) ||
(serverInfo.versionArray[0] > 2));
return {client, db};
}

/**
Expand Down Expand Up @@ -128,7 +115,7 @@ async function _isAuthnRequired({config, admin}) {

function _addAuthOptions({options, config}) {
options.connectOptions.auth = {
user: config.username,
username: config.username,
password: config.password
};
// authSource is the database to authenticate against
Expand Down
14 changes: 3 additions & 11 deletions lib/config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2012-2012 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2012-2024 Digital Bazaar, Inc. All rights reserved.
*/
import {config} from '@bedrock/core';

Expand Down Expand Up @@ -39,12 +39,8 @@ config.mongodb.authentication = {
};
// this is used when making connections to the database
config.mongodb.connectOptions = {
useUnifiedTopology: true,
serverSelectionTimeoutMS: 30000,
autoReconnect: false,
useNewUrlParser: true,
// promotes binary BSON values to native Node.js buffers
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did we mean to get rid of this comment? It's useful, IMO.

promoteBuffers: true,
serverSelectionTimeoutMS: 30000,
// it is recommended to set either ssl or tls to true in production
// ssl: true
// tls: true
Expand All @@ -55,16 +51,12 @@ config.mongodb.connectOptions = {

// this is used when writing to the database
config.mongodb.writeOptions = {
writeConcern: {
w: 'majority',
j: true,
},
forceServerObjectId: true,
};

config.mongodb.requirements = {};
// server version requirement with server-style string
config.mongodb.requirements.serverVersion = '>=4.2';
config.mongodb.requirements.serverVersion = '>=5';

// this is used by _createUser to add a user as an admin to a collection
// config.mongodb.collection = 'admin-collection';
6 changes: 4 additions & 2 deletions lib/exceptions.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
/*!
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2012-2024 Digital Bazaar, Inc. All rights reserved.
*/
export const MDBE_ERROR = 'MongoError';
export const WRITE_ERROR = 'WriteError';
export const BULK_WRITE_ERROR = 'BulkWriteError';
export const WRITE_CONCERN_ERROR = 'WriteConcernError';
export const MONGO_SERVER_ERROR = 'MongoServerError';
export const MDBE_ERRORS = [
MDBE_ERROR,
WRITE_ERROR,
BULK_WRITE_ERROR,
WRITE_CONCERN_ERROR
WRITE_CONCERN_ERROR,
MONGO_SERVER_ERROR,
];
export const MDBE_AUTHN_FAILED = 18;
export const MDBE_AUTHZ_FAILED = 13;
Expand Down
2 changes: 1 addition & 1 deletion lib/helpers.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2012-2024 Digital Bazaar, Inc. All rights reserved.
*/
import * as bedrock from '@bedrock/core';
import crypto from 'node:crypto';
Expand Down
11 changes: 2 additions & 9 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2012-2024 Digital Bazaar, Inc. All rights reserved.
*/
import * as bedrock from '@bedrock/core';
import * as urls from './urls.js';
Expand Down Expand Up @@ -81,12 +81,8 @@ export async function openCollections(names) {
// open the collections
logger.debug('opening collections', {collections: unopened});
const collections = {};
const {writeConcern} = _db.options;
await Promise.all(unopened.map(async name => {
// Note: We only pass `{writeConcern}` here to get around a bug in mongodb
// node driver 3.6.4 where `writeConcern` from `db` is not passed to
// collection
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably this bug has been fixed now.

collections[name] = await _db.collection(name, {writeConcern});
collections[name] = await _db.collection(name);
}));

// merge results into collection cache
Expand Down Expand Up @@ -115,9 +111,6 @@ export async function createIndexes(options) {
/**
* Creates a streaming GridFS bucket instance.
*
* By default the writeOptions config value is used for the GridFSBucket
* writeConcern option.
*
* @param {object} options - See GridFSBucket documentation.
*
* @returns {object} The new GridFSBucket instance.
Expand Down
2 changes: 1 addition & 1 deletion lib/logger.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2017-2022 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2017-2024 Digital Bazaar, Inc. All rights reserved.
*/
import {loggers} from '@bedrock/core';
export const logger = loggers.get('app').child('bedrock-mongodb');
2 changes: 1 addition & 1 deletion lib/test.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2012-2024 Digital Bazaar, Inc. All rights reserved.
*/
import {config} from '@bedrock/core';

Expand Down
2 changes: 1 addition & 1 deletion lib/urls.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2012-2022 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2012-2024 Digital Bazaar, Inc. All rights reserved.
*/
export function create(config) {
let url = `${config.protocol}://`;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"homepage": "https://github.com/digitalbazaar/bedrock-mongodb",
"dependencies": {
"klona": "^2.0.5",
"mongodb": "^3.7.3",
"mongodb": "^6.3.0",
"semver": "^7.3.7"
},
"peerDependencies": {
Expand Down
45 changes: 44 additions & 1 deletion test/mocha/10-api.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2017-2022 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2017-2024 Digital Bazaar, Inc. All rights reserved.
*/
import * as database from '@bedrock/mongodb';

Expand Down Expand Up @@ -406,6 +406,26 @@ describe('api', function() {
}
should.exist(result);
should.not.exist(error);
result.should.have.keys(['acknowledged', 'insertedId']);
});
it('should properly promote binary values to buffers', async function() {
let error;
let result = null;
const recordId = '06f336c0-7177-401b-a8ce-9a2e36331b8e';
try {
const record = {
id: recordId,
aBinaryField: Buffer.from(recordId)
};
await database.collections.test.insertOne(record);
result = await database.collections.test.findOne({id: recordId});
} catch(e) {
error = e;
}
should.not.exist(error);
should.exist(result);
result.aBinaryField.should.be.instanceof(Buffer);
result.aBinaryField.toString().should.equal(recordId);
});
it('should insertMany into a collection', async function() {
let error;
Expand Down Expand Up @@ -455,4 +475,27 @@ describe('api', function() {
result.length.should.equal(2);
});
});
describe('isDuplicateError helper', () => {
it('should properly detect a duplicate error', async function() {
await database.openCollections(['test']);
await database.createIndexes([{
collection: 'test',
fields: {id: 1},
options: {unique: true}
}]);
const record = {
id: 'f466586f-7006-474d-ae44-d16c96a7b5c3'
};
await database.collections.test.insertOne(record);

let error = null;
try {
await database.collections.test.insertOne(record);
} catch(e) {
error = e;
}
should.exist(error);
database.isDuplicateError(error).should.be.true;
});
});
});
2 changes: 1 addition & 1 deletion test/test.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2019-2022 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2019-2024 Digital Bazaar, Inc. All rights reserved.
*/
import {config} from '@bedrock/core';
import {fileURLToPath} from 'node:url';
Expand Down
2 changes: 1 addition & 1 deletion test/test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*!
* Copyright (c) 2019-2022 Digital Bazaar, Inc. All rights reserved.
* Copyright (c) 2019-2024 Digital Bazaar, Inc. All rights reserved.
*/
import * as bedrock from '@bedrock/core';
import '@bedrock/mongodb';
Expand Down