From 05cf04b3da34442fab69ed9c51ff927c59f1fda9 Mon Sep 17 00:00:00 2001 From: Bailey Pearson Date: Tue, 8 Aug 2023 07:36:44 -0600 Subject: [PATCH] docs(NODE-5423): export all public FLE types and classes (#3794) Co-authored-by: Durran Jordan --- src/client-side-encryption/auto_encrypter.ts | 8 +-- .../client_encryption.ts | 68 +++++++++++++------ src/client-side-encryption/errors.ts | 4 +- src/client-side-encryption/providers/index.ts | 7 +- src/client-side-encryption/state_machine.ts | 27 +++++--- src/index.ts | 28 +++++++- test/readme.md | 3 +- test/unit/error.test.ts | 6 +- test/unit/index.test.ts | 7 ++ 9 files changed, 113 insertions(+), 45 deletions(-) diff --git a/src/client-side-encryption/auto_encrypter.ts b/src/client-side-encryption/auto_encrypter.ts index 5bcbd1c683..6de294b63a 100644 --- a/src/client-side-encryption/auto_encrypter.ts +++ b/src/client-side-encryption/auto_encrypter.ts @@ -14,11 +14,7 @@ import * as cryptoCallbacks from './crypto_callbacks'; import { MongoCryptInvalidArgumentError } from './errors'; import { MongocryptdManager } from './mongocryptd_manager'; import { type KMSProviders, refreshKMSCredentials } from './providers'; -import { - type CSFLEKMSTlsOptions, - StateMachine, - type StateMachineExecutable -} from './state_machine'; +import { type CSFLEKMSTlsOptions, StateMachine } from './state_machine'; /** @public */ export interface AutoEncryptionOptions { @@ -229,7 +225,7 @@ const kDecoratedKeys = Symbol.for('@@mdb.decryptedKeys'); * @internal An internal class to be used by the driver for auto encryption * **NOTE**: Not meant to be instantiated directly, this is for internal use only. */ -export class AutoEncrypter implements StateMachineExecutable { +export class AutoEncrypter { _client: MongoClient; _bypassEncryption: boolean; _keyVaultNamespace: string; diff --git a/src/client-side-encryption/client_encryption.ts b/src/client-side-encryption/client_encryption.ts index 391659d874..641ffbcd6f 100644 --- a/src/client-side-encryption/client_encryption.ts +++ b/src/client-side-encryption/client_encryption.ts @@ -24,14 +24,15 @@ import { MongoCryptCreateEncryptedCollectionError, MongoCryptInvalidArgumentError } from './errors'; -import { type KMSProvider, type KMSProviders, refreshKMSCredentials } from './providers/index'; import { - type CSFLEKMSTlsOptions, - StateMachine, - type StateMachineExecutable -} from './state_machine'; + type ClientEncryptionDataKeyProvider, + type KMSProviders, + refreshKMSCredentials +} from './providers/index'; +import { type CSFLEKMSTlsOptions, StateMachine } from './state_machine'; /** + * @public * The schema for a DataKey in the key vault collection. */ export interface DataKey { @@ -46,14 +47,21 @@ export interface DataKey { } /** + * @public * The public interface for explicit in-use encryption */ -export class ClientEncryption implements StateMachineExecutable { +export class ClientEncryption { + /** @internal */ _client: MongoClient; + /** @internal */ _keyVaultNamespace: string; + /** @internal */ _keyVaultClient: MongoClient; + /** @internal */ _proxyOptions: ProxyOptions; + /** @internal */ _tlsOptions: CSFLEKMSTlsOptions; + /** @internal */ _kmsProviders: KMSProviders; /** @internal */ @@ -165,7 +173,7 @@ export class ClientEncryption implements StateMachineExecutable { * ``` */ createDataKey( - provider: KMSProvider, + provider: ClientEncryptionDataKeyProvider, options?: ClientEncryptionCreateDataKeyProviderOptions, callback?: Callback ) { @@ -268,7 +276,10 @@ export class ClientEncryption implements StateMachineExecutable { * } * ``` */ - async rewrapManyDataKey(filter: Filter, options: RewrapManyDataKeyOptions) { + async rewrapManyDataKey( + filter: Filter, + options: ClientEncryptionRewrapManyDataKeyProviderOptions + ) { let keyEncryptionKeyBson = undefined; if (options) { const keyEncryptionKey = Object.assign({ provider: options.provider }, options.masterKey); @@ -533,7 +544,7 @@ export class ClientEncryption implements StateMachineExecutable { db: Db, name: string, options: { - provider: KMSProvider; + provider: ClientEncryptionDataKeyProvider; createCollectionOptions: Omit & { encryptedFields: Document; }; @@ -569,7 +580,7 @@ export class ClientEncryption implements StateMachineExecutable { (result): result is PromiseRejectedResult => result.status === 'rejected' ); if (rejection != null) { - throw new MongoCryptCreateDataKeyError({ encryptedFields, cause: rejection.reason }); + throw new MongoCryptCreateDataKeyError(encryptedFields, { cause: rejection.reason }); } } @@ -580,7 +591,7 @@ export class ClientEncryption implements StateMachineExecutable { }); return { collection, encryptedFields }; } catch (cause) { - throw new MongoCryptCreateEncryptedCollectionError({ encryptedFields, cause }); + throw new MongoCryptCreateEncryptedCollectionError(encryptedFields, { cause }); } } @@ -703,6 +714,7 @@ export class ClientEncryption implements StateMachineExecutable { } /** + * @internal * Ask the user for KMS credentials. * * This returns anything that looks like the kmsProviders original input @@ -718,6 +730,7 @@ export class ClientEncryption implements StateMachineExecutable { } /** + * @internal * A helper that perform explicit encryption of values and expressions. * Explicitly encrypt a provided value. Note that either `options.keyId` or `options.keyAltName` must * be specified. Specifying both `options.keyId` and `options.keyAltName` is considered an error. @@ -780,6 +793,7 @@ export class ClientEncryption implements StateMachineExecutable { } /** + * @public * Options to provide when encrypting data. */ export interface ClientEncryptionEncryptOptions { @@ -817,9 +831,12 @@ export interface ClientEncryptionEncryptOptions { rangeOptions?: RangeOptions; } -/** @experimental */ -export interface RewrapManyDataKeyOptions { - provider: KMSProvider; +/** + * @public + * @experimental + */ +export interface ClientEncryptionRewrapManyDataKeyProviderOptions { + provider: ClientEncryptionDataKeyProvider; masterKey?: | AWSEncryptionKeyOptions | AzureEncryptionKeyOptions @@ -828,6 +845,7 @@ export interface RewrapManyDataKeyOptions { } /** + * @public * Additional settings to provide when creating a new `ClientEncryption` instance. */ export interface ClientEncryptionOptions { @@ -858,6 +876,7 @@ export interface ClientEncryptionOptions { } /** + * @public * Configuration options for making an AWS encryption key */ export interface AWSEncryptionKeyOptions { @@ -878,6 +897,7 @@ export interface AWSEncryptionKeyOptions { } /** + * @public * Configuration options for making an AWS encryption key */ export interface GCPEncryptionKeyOptions { @@ -913,6 +933,7 @@ export interface GCPEncryptionKeyOptions { } /** + * @public * Configuration options for making an Azure encryption key */ export interface AzureEncryptionKeyOptions { @@ -933,6 +954,7 @@ export interface AzureEncryptionKeyOptions { } /** + * @public * Options to provide when creating a new data key. */ export interface ClientEncryptionCreateDataKeyProviderOptions { @@ -955,9 +977,12 @@ export interface ClientEncryptionCreateDataKeyProviderOptions { keyMaterial?: Buffer | Binary; } -/** @experimental */ -export interface RewrapManyDataKeyOptions { - provider: KMSProvider; +/** + * @public + * @experimental + */ +export interface ClientEncryptionRewrapManyDataKeyProviderOptions { + provider: ClientEncryptionDataKeyProvider; masterKey?: | AWSEncryptionKeyOptions | AzureEncryptionKeyOptions @@ -965,18 +990,22 @@ export interface RewrapManyDataKeyOptions { | undefined; } -/** @experimental */ +/** + * @public + * @experimental + */ export interface ClientEncryptionRewrapManyDataKeyResult { /** The result of rewrapping data keys. If unset, no keys matched the filter. */ bulkWriteResult?: BulkWriteResult; } /** + * @public * RangeOptions specifies index options for a Queryable Encryption field supporting "rangePreview" queries. * min, max, sparsity, and range must match the values set in the encryptedFields of the destination collection. * For double and decimal128, min/max/precision must all be set, or all be unset. */ -interface RangeOptions { +export interface RangeOptions { min?: any; max?: any; sparsity: Long; @@ -984,6 +1013,7 @@ interface RangeOptions { } /** + * @public * Options to provide when encrypting data. */ export interface ClientEncryptionEncryptOptions { diff --git a/src/client-side-encryption/errors.ts b/src/client-side-encryption/errors.ts index d187bac0d9..9df2b8beb4 100644 --- a/src/client-side-encryption/errors.ts +++ b/src/client-side-encryption/errors.ts @@ -37,7 +37,7 @@ export class MongoCryptInvalidArgumentError extends MongoCryptError { export class MongoCryptCreateDataKeyError extends MongoCryptError { encryptedFields: Document; /** @internal */ - constructor({ encryptedFields, cause }: { encryptedFields: Document; cause: Error }) { + constructor(encryptedFields: Document, { cause }: { cause: Error }) { super(`Unable to complete creating data keys: ${cause.message}`, { cause }); this.encryptedFields = encryptedFields; } @@ -54,7 +54,7 @@ export class MongoCryptCreateDataKeyError extends MongoCryptError { export class MongoCryptCreateEncryptedCollectionError extends MongoCryptError { encryptedFields: Document; /** @internal */ - constructor({ encryptedFields, cause }: { encryptedFields: Document; cause: Error }) { + constructor(encryptedFields: Document, { cause }: { cause: Error }) { super(`Unable to create collection: ${cause.message}`, { cause }); this.encryptedFields = encryptedFields; } diff --git a/src/client-side-encryption/providers/index.ts b/src/client-side-encryption/providers/index.ts index d44f9d4127..fb83e7b912 100644 --- a/src/client-side-encryption/providers/index.ts +++ b/src/client-side-encryption/providers/index.ts @@ -5,7 +5,7 @@ import { loadGCPCredentials } from './gcp'; /** * @public */ -export type KMSProvider = 'aws' | 'azure' | 'gcp' | 'local'; +export type ClientEncryptionDataKeyProvider = 'aws' | 'azure' | 'gcp' | 'local' | 'kmip'; /** * @public @@ -132,7 +132,10 @@ export interface KMSProviders { * * @internal - exposed for testing purposes only */ -export function isEmptyCredentials(providerName: KMSProvider, kmsProviders: KMSProviders): boolean { +export function isEmptyCredentials( + providerName: ClientEncryptionDataKeyProvider, + kmsProviders: KMSProviders +): boolean { const provider = kmsProviders[providerName]; if (provider == null) { return false; diff --git a/src/client-side-encryption/state_machine.ts b/src/client-side-encryption/state_machine.ts index 121ee3fe8f..bf3963ffb1 100644 --- a/src/client-side-encryption/state_machine.ts +++ b/src/client-side-encryption/state_machine.ts @@ -19,7 +19,7 @@ import { BufferPool, type Callback, MongoDBCollectionNamespace } from '../utils' import { type DataKey } from './client_encryption'; import { MongoCryptError } from './errors'; import { type MongocryptdManager } from './mongocryptd_manager'; -import { type KMSProvider, type KMSProviders } from './providers'; +import { type ClientEncryptionDataKeyProvider, type KMSProviders } from './providers'; let socks: SocksLib | null = null; function loadSocks(): SocksLib { @@ -97,19 +97,21 @@ declare module 'mongodb-client-encryption' { * - tlsAllowInvalidCertificates * - tlsAllowInvalidHostnames * - tlsInsecure + * + * These options are not included in the type, and are ignored if provided. */ -export type CSFLETlsOptions = Pick< +export type ClientEncryptionTlsOptions = Pick< MongoClientOptions, 'tlsCAFile' | 'tlsCertificateKeyFile' | 'tlsCertificateKeyFilePassword' >; /** @public */ export type CSFLEKMSTlsOptions = { - aws?: CSFLETlsOptions; - gcp?: CSFLETlsOptions; - kmip?: CSFLETlsOptions; - local?: CSFLETlsOptions; - azure?: CSFLETlsOptions; + aws?: ClientEncryptionTlsOptions; + gcp?: ClientEncryptionTlsOptions; + kmip?: ClientEncryptionTlsOptions; + local?: ClientEncryptionTlsOptions; + azure?: ClientEncryptionTlsOptions; }; /** @@ -122,6 +124,7 @@ export type CSFLEKMSTlsOptions = { export interface StateMachineExecutable { _keyVaultNamespace: string; _keyVaultClient: MongoClient; + askForKMSCredentials: () => Promise; /** only used for auto encryption */ _metaDataClient?: MongoClient; @@ -129,7 +132,6 @@ export interface StateMachineExecutable { _mongocryptdClient?: MongoClient; /** only used for auto encryption */ _mongocryptdManager?: MongocryptdManager; - askForKMSCredentials: () => Promise; } export type StateMachineOptions = { @@ -402,7 +404,7 @@ export class StateMachine { const tlsOptions = this.options.tlsOptions; if (tlsOptions) { - const kmsProvider = request.kmsProvider as KMSProvider; + const kmsProvider = request.kmsProvider as ClientEncryptionDataKeyProvider; const providerTlsOptions = tlsOptions[kmsProvider]; if (providerTlsOptions) { const error = this.validateTlsOptions(kmsProvider, providerTlsOptions); @@ -441,7 +443,10 @@ export class StateMachine { * * @returns An error if any option is invalid. */ - validateTlsOptions(kmsProvider: string, tlsOptions: CSFLETlsOptions): MongoCryptError | void { + validateTlsOptions( + kmsProvider: string, + tlsOptions: ClientEncryptionTlsOptions + ): MongoCryptError | void { const tlsOptionNames = Object.keys(tlsOptions); for (const option of INSECURE_TLS_OPTIONS) { if (tlsOptionNames.includes(option)) { @@ -456,7 +461,7 @@ export class StateMachine { * @param tlsOptions - The client TLS options for the provider. * @param options - The existing connection options. */ - setTlsOptions(tlsOptions: CSFLETlsOptions, options: tls.ConnectionOptions) { + setTlsOptions(tlsOptions: ClientEncryptionTlsOptions, options: tls.ConnectionOptions) { if (tlsOptions.tlsCertificateKeyFile) { const cert = fs.readFileSync(tlsOptions.tlsCertificateKeyFile); options.cert = options.key = cert; diff --git a/src/index.ts b/src/index.ts index 5589702252..11ac502fce 100644 --- a/src/index.ts +++ b/src/index.ts @@ -36,6 +36,7 @@ export { Timestamp } from './bson'; export { AnyBulkWriteOperation, BulkWriteOptions, MongoBulkWriteError } from './bulk/common'; +export { ClientEncryption } from './client-side-encryption/client_encryption'; export { ChangeStreamCursor } from './cursor/change_stream_cursor'; export { MongoAPIError, @@ -204,11 +205,34 @@ export type { export type { AutoEncrypter } from './client-side-encryption/auto_encrypter'; export type { AutoEncryptionOptions } from './client-side-encryption/auto_encrypter'; export type { AutoEncryptionExtraOptions } from './client-side-encryption/auto_encrypter'; +export type { + AWSEncryptionKeyOptions, + AzureEncryptionKeyOptions, + ClientEncryptionCreateDataKeyProviderOptions, + ClientEncryptionEncryptOptions, + ClientEncryptionOptions, + ClientEncryptionRewrapManyDataKeyProviderOptions, + ClientEncryptionRewrapManyDataKeyResult, + DataKey, + GCPEncryptionKeyOptions, + RangeOptions +} from './client-side-encryption/client_encryption'; +export { + MongoCryptAzureKMSRequestError, + MongoCryptCreateDataKeyError, + MongoCryptCreateEncryptedCollectionError, + MongoCryptError, + MongoCryptInvalidArgumentError, + MongoCryptKMSRequestNetworkTimeoutError +} from './client-side-encryption/errors'; export type { MongocryptdManager } from './client-side-encryption/mongocryptd_manager'; -export type { KMSProviders } from './client-side-encryption/providers/index'; export type { + ClientEncryptionDataKeyProvider, + KMSProviders +} from './client-side-encryption/providers/index'; +export type { + ClientEncryptionTlsOptions, CSFLEKMSTlsOptions, - CSFLETlsOptions, StateMachineExecutable } from './client-side-encryption/state_machine'; export type { AuthContext } from './cmap/auth/auth_provider'; diff --git a/test/readme.md b/test/readme.md index f7abfd7d3e..392055bae5 100644 --- a/test/readme.md +++ b/test/readme.md @@ -328,7 +328,8 @@ The following steps will walk you through how to start and test a load balancer. The following steps will walk you through how to run the tests for CSFLE. 1. Install [MongoDB Client Encryption][npm-csfle] if you haven't already: - `npm install mongodb-client-encryption` + `npm install mongodb-client-encryption`. Note: if developing changes in `mongodb-client-encryption`, + you can link it locally using `etc/tooling/fle.sh`. 1. Create the following environment variables using a command like `export AWS_REGION="us-east-1"`. diff --git a/test/unit/error.test.ts b/test/unit/error.test.ts index cfeb854b6e..f995a8ff62 100644 --- a/test/unit/error.test.ts +++ b/test/unit/error.test.ts @@ -57,7 +57,7 @@ describe('MongoErrors', () => { it('all defined errors should be public', () => { expect( setDifference(Object.keys(errorClassesFromEntryPoint), Object.keys(errorClassesFromErrorSrc)) - ).to.have.property('size', 3); + ).to.have.property('size', 9); expect( setDifference(Object.keys(errorClassesFromErrorSrc), Object.keys(errorClassesFromEntryPoint)) @@ -68,7 +68,9 @@ describe('MongoErrors', () => { for (const [errorName, errorClass] of Object.entries(errorClassesFromEntryPoint)) { it(`${errorName} should be read-only`, () => { // Dynamically create error class with message - const error = new (errorClass as any)('generated by test', {}); + const error = new (errorClass as any)('generated by test', { + cause: new Error('something went wrong') + }); // expect name property to be class name expect(error).to.have.property('name', errorName); diff --git a/test/unit/index.test.ts b/test/unit/index.test.ts index fc5cfec41f..8a2ef6ee59 100644 --- a/test/unit/index.test.ts +++ b/test/unit/index.test.ts @@ -27,6 +27,7 @@ const EXPECTED_EXPORTS = [ 'CancellationToken', 'ChangeStream', 'ChangeStreamCursor', + 'ClientEncryption', 'ClientSession', 'Code', 'Collection', @@ -71,6 +72,12 @@ const EXPECTED_EXPORTS = [ 'MongoChangeStreamError', 'MongoClient', 'MongoCompatibilityError', + 'MongoCryptAzureKMSRequestError', + 'MongoCryptCreateDataKeyError', + 'MongoCryptCreateEncryptedCollectionError', + 'MongoCryptError', + 'MongoCryptInvalidArgumentError', + 'MongoCryptKMSRequestNetworkTimeoutError', 'MongoCursorExhaustedError', 'MongoCursorInUseError', 'MongoDecompressionError',