Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(NODE-6506): Add support for encrypted schemas #5

Open
wants to merge 3 commits into
base: 8.10
Choose a base branch
from
Open
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
3 changes: 2 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ module.exports = {
'!.*',
'node_modules',
'.git',
'data'
'data',
'.config'
Comment on lines +18 to +19
Copy link
Author

Choose a reason for hiding this comment

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

I added .config because I noticed lint failed after generating the docs locally, and data because otherwise the data for encrypted tests is linted.

Copy link
Member

Choose a reason for hiding this comment

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

Works for me

],
overrides: [
{
Expand Down
38 changes: 38 additions & 0 deletions docs/field-level-encryption.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,41 @@ With the above connection, if you create a model named 'Test' that uses the 'tes
const Model = mongoose.model('Test', mongoose.Schema({ name: String }));
await Model.create({ name: 'super secret' });
```

## Automatic FLE in Mongoose

Mongoose supports the declaration of encrypted schemas - schemas that, when connected to a model, utilize MongoDB's Client Side
Field Level Encryption or Queryable Encryption under the hood. Mongoose automatically generates either an `encryptedFieldsMap` or a
`schemaMap` when instantiating a MongoClient and encrypts fields on write and decrypts fields on reads.

### Encryption types

MongoDB has two different automatic encryption implementations: client side field level encryption (CSFLE) and queryable encryption (QE).
See [choosing an in-use encryption approach](https://www.mongodb.com/docs/v7.3/core/queryable-encryption/about-qe-csfle/#choosing-an-in-use-encryption-approach).

### Declaring Encrypted Schemas

The following schema declares two properties, `name` and `ssn`. `ssn` is encrypted using queryable encryption, and
is configured for equality queries:

```javascript
const encryptedUserSchema = new Schema({
name: String,
ssn: {
type: String,
// 1
encrypt: {
keyId: '<uuid string of key id>',
queries: 'equality'
}
}
// 2
}, { encryptionType: 'queryableEncryption' });
```

To declare a field as encrypted, you must:

1. Annotate the field with encryption metadata in the schema definition
2. Choose an encryption type for the schema and configure the schema for the encryption type

Not all schematypes are supported for CSFLE and QE. For an overview of valid schema types, refer to MongoDB's documentation.
72 changes: 72 additions & 0 deletions lib/encryptionUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
'use strict';

const schemaTypes = require('./schema/index.js');
const SchemaBigInt = require('./schema/bigint');
const SchemaBoolean = require('./schema/boolean');
const SchemaBuffer = require('./schema/buffer');
const SchemaDate = require('./schema/date');
const SchemaDecimal128 = require('./schema/decimal128');
const SchemaDouble = require('./schema/double');
const SchemaInt32 = require('./schema/int32');
const SchemaObjectId = require('./schema/objectId');
const SchemaString = require('./schema/string');

/**
* Given a schema and a path to a field in the schema, this returns the
* BSON type of the field, if it can be determined. This method specifically
* **only** handles BSON types that are used for CSFLE and QE - any other
* BSON types will return `null`. (example: MinKey and MaxKey).
*
* @param {import('.').Schema} schema
* @param {string} path
* @returns {string}
*/
function inferBSONType(schema, path) {
const type = schema.path(path);

if (type instanceof SchemaString) {
return 'string';
}

if (type instanceof SchemaInt32) {
return 'int';
}

if (type instanceof SchemaBigInt) {
return 'long';
}

if (type instanceof SchemaBoolean) {
return 'bool';
}

if (type instanceof SchemaDate) {
return 'date';
}

if (type instanceof SchemaBuffer) {
return 'binData';
}

if (type instanceof SchemaObjectId) {
return 'objectId';
}

if (type instanceof SchemaDecimal128) {
return 'decimal';
}

if (type instanceof SchemaDouble) {
return 'double';
}

if (type instanceof schemaTypes.Array) {
return 'array';
}

return null;
}

module.exports = {
inferBSONType
};
Loading
Loading