Skip to content

Commit 3eaf05b

Browse files
committed
feat(NODE-5513)!: remove callbacks from ClientEncryption encrypt, decrypt, and createDataKey
1 parent 844aa52 commit 3eaf05b

File tree

4 files changed

+86
-187
lines changed

4 files changed

+86
-187
lines changed

src/client-side-encryption/client_encryption.ts

Lines changed: 16 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import type {
44
MongoCryptConstructor,
55
MongoCryptOptions
66
} from 'mongodb-client-encryption';
7+
import { promisify } from 'util';
78

89
import { type Binary, type Document, type Long, serialize } from '../bson';
910
import { type AnyBulkWriteOperation, type BulkWriteResult } from '../bulk/common';
@@ -16,8 +17,7 @@ import { type MongoClient } from '../mongo_client';
1617
import { type Filter } from '../mongo_types';
1718
import { type CreateCollectionOptions } from '../operations/create_collection';
1819
import { type DeleteResult } from '../operations/delete';
19-
import { type Callback, MongoDBCollectionNamespace } from '../utils';
20-
import { maybeCallback, promiseOrCallback } from './common';
20+
import { MongoDBCollectionNamespace } from '../utils';
2121
import * as cryptoCallbacks from './crypto_callbacks';
2222
import {
2323
MongoCryptCreateDataKeyError,
@@ -125,18 +125,6 @@ export class ClientEncryption implements StateMachineExecutable {
125125
*
126126
* @example
127127
* ```ts
128-
* // Using callbacks to create a local key
129-
* clientEncryption.createDataKey('local', (err, dataKey) => {
130-
* if (err) {
131-
* // This means creating the key failed.
132-
* } else {
133-
* // key creation succeeded
134-
* }
135-
* });
136-
* ```
137-
*
138-
* @example
139-
* ```ts
140128
* // Using async/await to create a local key
141129
* const dataKeyId = await clientEncryption.createDataKey('local');
142130
* ```
@@ -164,19 +152,10 @@ export class ClientEncryption implements StateMachineExecutable {
164152
* });
165153
* ```
166154
*/
167-
createDataKey(
155+
async createDataKey(
168156
provider: KMSProvider,
169-
options?: ClientEncryptionCreateDataKeyProviderOptions,
170-
callback?: Callback<DataKey>
171-
) {
172-
if (typeof options === 'function') {
173-
callback = options;
174-
options = {};
175-
}
176-
if (options == null) {
177-
options = {};
178-
}
179-
157+
options: ClientEncryptionCreateDataKeyProviderOptions = {}
158+
): Promise<Binary> {
180159
const dataKey = Object.assign({ provider }, options.masterKey);
181160

182161
if (options.keyAltNames && !Array.isArray(options.keyAltNames)) {
@@ -213,8 +192,8 @@ export class ClientEncryption implements StateMachineExecutable {
213192
tlsOptions: this._tlsOptions
214193
});
215194

216-
// @ts-expect-error We did not convert promiseOrCallback to TS
217-
return promiseOrCallback(callback, cb => {
195+
return promisify<Binary>(callback => {
196+
const cb: (err: any, result: Binary | null) => void = callback as any;
218197
stateMachine.execute<DataKey>(this, context, (err, dataKey) => {
219198
if (err || !dataKey) {
220199
cb(err, null);
@@ -238,7 +217,7 @@ export class ClientEncryption implements StateMachineExecutable {
238217
}
239218
);
240219
});
241-
});
220+
})();
242221
}
243222

244223
/**
@@ -590,21 +569,7 @@ export class ClientEncryption implements StateMachineExecutable {
590569
*
591570
* @param value - The value that you wish to serialize. Must be of a type that can be serialized into BSON
592571
* @param options -
593-
* @param callback - Optional callback to invoke when value is encrypted
594-
* @returns If no callback is provided, returns a Promise that either resolves with the encrypted value, or rejects with an error. If a callback is provided, returns nothing.
595-
*
596-
* @example
597-
* ```ts
598-
* // Encryption with callback API
599-
* function encryptMyData(value, callback) {
600-
* clientEncryption.createDataKey('local', (err, keyId) => {
601-
* if (err) {
602-
* return callback(err);
603-
* }
604-
* clientEncryption.encrypt(value, { keyId, algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic' }, callback);
605-
* });
606-
* }
607-
* ```
572+
* @returns a Promise that either resolves with the encrypted value, or rejects with an error.
608573
*
609574
* @example
610575
* ```ts
@@ -624,12 +589,8 @@ export class ClientEncryption implements StateMachineExecutable {
624589
* }
625590
* ```
626591
*/
627-
encrypt(
628-
value: unknown,
629-
options: ClientEncryptionEncryptOptions,
630-
callback: Callback<Binary>
631-
): Promise<Binary> | void {
632-
return maybeCallback(() => this._encrypt(value, false, options), callback);
592+
async encrypt(value: unknown, options: ClientEncryptionEncryptOptions): Promise<Binary> {
593+
return this._encrypt(value, false, options);
633594
}
634595

635596
/**
@@ -661,16 +622,7 @@ export class ClientEncryption implements StateMachineExecutable {
661622
* Explicitly decrypt a provided encrypted value
662623
*
663624
* @param value - An encrypted value
664-
* @param callback - Optional callback to invoke when value is decrypted
665-
* @returns If no callback is provided, returns a Promise that either resolves with the decrypted value, or rejects with an error. If a callback is provided, returns nothing.
666-
*
667-
* ```ts
668-
* @example
669-
* // Decrypting value with callback API
670-
* function decryptMyValue(value, callback) {
671-
* clientEncryption.decrypt(value, callback);
672-
* }
673-
* ```
625+
* @returns a Promise that either resolves with the decrypted value, or rejects with an error
674626
*
675627
* @example
676628
* ```ts
@@ -680,7 +632,7 @@ export class ClientEncryption implements StateMachineExecutable {
680632
* }
681633
* ```
682634
*/
683-
decrypt<T = any>(value: Binary, callback?: Callback<T>): Promise<T> | void {
635+
async decrypt<T = any>(value: Binary): Promise<T> {
684636
const valueBuffer = serialize({ v: value });
685637
const context = this._mongoCrypt.makeExplicitDecryptionContext(valueBuffer);
686638

@@ -689,8 +641,8 @@ export class ClientEncryption implements StateMachineExecutable {
689641
tlsOptions: this._tlsOptions
690642
});
691643

692-
// @ts-expect-error We did not convert promiseOrCallback to TS
693-
return promiseOrCallback(callback, cb => {
644+
return promisify<T>(callback => {
645+
const cb: (error: Error | null | undefined, v: T | null) => void = callback as any;
694646
stateMachine.execute<{ v: T }>(this, context, (err, result) => {
695647
if (err || !result) {
696648
cb(err, null);
@@ -699,7 +651,7 @@ export class ClientEncryption implements StateMachineExecutable {
699651

700652
cb(null, result.v);
701653
});
702-
});
654+
})();
703655
}
704656

705657
/**

test/integration/client-side-encryption/client_side_encryption.prose.12.deadlock.test.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,8 @@ describe('Connection Pool Deadlock Prevention', function () {
138138
keyVaultClient: this.keyVaultClient,
139139
extraOptions: getEncryptExtraOptions()
140140
});
141-
this.clientEncryption.encryptPromisified = util.promisify(
142-
this.clientEncryption.encrypt.bind(this.clientEncryption)
143-
);
144141

145-
this.ciphertext = await this.clientEncryption.encryptPromisified('string0', {
142+
this.ciphertext = await this.clientEncryption.encrypt('string0', {
146143
algorithm: 'AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic',
147144
keyAltName: 'local'
148145
});

test/integration/node-specific/client_encryption.test.ts

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ describe('ClientEncryption integration tests', function () {
157157
}
158158
);
159159

160-
it('should fail to create a data key if keyMaterial is wrong', metadata, function (done) {
160+
it('should fail to create a data key if keyMaterial is wrong', metadata, async function () {
161161
const encryption = new ClientEncryption(client, {
162162
keyVaultNamespace: 'client.encryption',
163163
kmsProviders: { local: { key: 'A'.repeat(128) } }
@@ -166,13 +166,8 @@ describe('ClientEncryption integration tests', function () {
166166
const dataKeyOptions = {
167167
keyMaterial: new Binary(Buffer.alloc(97))
168168
};
169-
try {
170-
encryption.createDataKey('local', dataKeyOptions);
171-
expect.fail('missed exception');
172-
} catch (err) {
173-
expect(err.message).to.equal('keyMaterial should have length 96, but has length 97');
174-
done();
175-
}
169+
const error = await encryption.createDataKey('local', dataKeyOptions).catch(error => error);
170+
expect(error.message).to.equal('keyMaterial should have length 96, but has length 97');
176171
});
177172

178173
it(
@@ -536,23 +531,21 @@ describe('ClientEncryption integration tests', function () {
536531
}
537532

538533
describe('errors', function () {
539-
[42, 'hello', { keyAltNames: 'foobar' }, /foobar/].forEach(val => {
540-
it(`should fail if typeof keyAltNames = ${typeof val}`, metadata, function () {
534+
for (const val of [42, 'hello', { keyAltNames: 'foobar' }, /foobar/]) {
535+
it(`should fail if typeof keyAltNames = ${typeof val}`, metadata, async function () {
541536
const options = makeOptions(val);
542-
expect(() => clientEncryption.createDataKey('aws', options, () => undefined)).to.throw(
543-
MongoCryptInvalidArgumentError
544-
);
537+
const error = await clientEncryption.createDataKey('aws', options).catch(error => error);
538+
expect(error).to.be.instanceOf(MongoCryptInvalidArgumentError);
545539
});
546-
});
540+
}
547541

548-
[undefined, null, 42, { keyAltNames: 'foobar' }, ['foobar'], /foobar/].forEach(val => {
549-
it(`should fail if typeof keyAltNames[x] = ${typeof val}`, metadata, function () {
542+
for (const val of [undefined, null, 42, { keyAltNames: 'foobar' }, ['foobar'], /foobar/]) {
543+
it(`should fail if typeof keyAltNames[x] = ${typeof val}`, metadata, async function () {
550544
const options = makeOptions([val]);
551-
expect(() => clientEncryption.createDataKey('aws', options, () => undefined)).to.throw(
552-
MongoCryptInvalidArgumentError
553-
);
545+
const error = await clientEncryption.createDataKey('aws', options).catch(error => error);
546+
expect(error).to.be.instanceOf(MongoCryptInvalidArgumentError);
554547
});
555-
});
548+
}
556549
});
557550

558551
it('should create a key with keyAltNames', metadata, async function () {

0 commit comments

Comments
 (0)