Skip to content

Commit f058acd

Browse files
fix(NODE-5516): allow undefined values for optional Uint8Arrays arguments (#683)
relax optional arguments for buffers
1 parent dea7bf8 commit f058acd

File tree

2 files changed

+159
-87
lines changed

2 files changed

+159
-87
lines changed

addon/mongocrypt.cc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ MongoCrypt::MongoCrypt(const CallbackInfo& info)
435435

436436
Object options = info[0].ToObject();
437437

438-
if (options.Has("kmsProviders")) {
438+
if (!options.Get("kmsProviders").IsUndefined()) {
439439
Uint8Array kmsProvidersOptions =
440440
Uint8ArrayFromValue(options["kmsProviders"], "options.kmsProviders");
441441

@@ -446,7 +446,7 @@ MongoCrypt::MongoCrypt(const CallbackInfo& info)
446446
}
447447
}
448448

449-
if (options.Has("schemaMap")) {
449+
if (!options.Get("schemaMap").IsUndefined()) {
450450
Uint8Array schemaMapBuffer = Uint8ArrayFromValue(options["schemaMap"], "options.schemaMap");
451451

452452
std::unique_ptr<mongocrypt_binary_t, MongoCryptBinaryDeleter> schemaMapBinary(
@@ -456,7 +456,7 @@ MongoCrypt::MongoCrypt(const CallbackInfo& info)
456456
}
457457
}
458458

459-
if (options.Has("encryptedFieldsMap")) {
459+
if (!options.Get("encryptedFieldsMap").IsUndefined()) {
460460
Uint8Array encryptedFieldsMapBuffer =
461461
Uint8ArrayFromValue(options["encryptedFieldsMap"], "options.encryptedFieldsMap");
462462

@@ -566,7 +566,7 @@ Value MongoCrypt::MakeExplicitEncryptionContext(const CallbackInfo& info) {
566566

567567
Object options = info.Length() > 1 ? info[1].ToObject() : Object::New(info.Env());
568568

569-
if (options.Has("keyId")) {
569+
if (!options.Get("keyId").IsUndefined()) {
570570
Uint8Array keyId = Uint8ArrayFromValue(options["keyId"], "keyId");
571571

572572
std::unique_ptr<mongocrypt_binary_t, MongoCryptBinaryDeleter> binary(
@@ -576,7 +576,7 @@ Value MongoCrypt::MakeExplicitEncryptionContext(const CallbackInfo& info) {
576576
}
577577
}
578578

579-
if (options.Has("keyAltName")) {
579+
if (!options.Get("keyAltName").IsUndefined()) {
580580
Uint8Array keyAltName = Uint8ArrayFromValue(options["keyAltName"], "keyAltName");
581581

582582
std::unique_ptr<mongocrypt_binary_t, MongoCryptBinaryDeleter> binary(
@@ -704,7 +704,7 @@ Value MongoCrypt::MakeDataKeyContext(const CallbackInfo& info) {
704704
}
705705
}
706706

707-
if (options.Has("keyMaterial")) {
707+
if (!options.Get("keyMaterial").IsUndefined()) {
708708
Uint8Array keyMaterial = Uint8ArrayFromValue(options["keyMaterial"], "options.keyMaterial");
709709

710710
std::unique_ptr<mongocrypt_binary_t, MongoCryptBinaryDeleter> binary(

test/bindings.test.ts

Lines changed: 153 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -63,30 +63,59 @@ describe('MongoCryptConstructor', () => {
6363
expect(MongoCrypt).to.have.property('libmongocryptVersion').that.is.a.string;
6464
});
6565

66-
it('throws if kmsProviders are not a buffer', () => {
67-
expect(() => new MongoCrypt({ kmsProviders: 3 })).to.throw(
68-
/Parameter `options.kmsProviders` must be a Uint8Array./
69-
);
66+
describe('options.kmsProviders', () => {
67+
it('throws if provided and are not a Uint8Array', () => {
68+
expect(() => new MongoCrypt({ kmsProviders: 3 })).to.throw(
69+
/Parameter `options.kmsProviders` must be a Uint8Array./
70+
);
71+
});
72+
73+
it('throws when explicitly set to undefined', () => {
74+
// the error is different because it is thrown from libmongocrypt
75+
expect(() => new MongoCrypt({ kmsProviders: undefined })).to.throw(/no kms provider set/);
76+
});
7077
});
7178

72-
it('throws when `schemaMap` is not a buffer', () => {
73-
expect(
74-
() =>
79+
describe('options.schemaMap', () => {
80+
it('throws when provided and not a Uint8Array', () => {
81+
expect(
82+
() =>
83+
new MongoCrypt({
84+
kmsProviders: serialize({ aws: {} }),
85+
schemaMap: 3
86+
})
87+
).to.throw(/Parameter `options.schemaMap` must be a Uint8Array./);
88+
});
89+
90+
it('can be explicitly set to `undefined`', () => {
91+
expect(
7592
new MongoCrypt({
7693
kmsProviders: serialize({ aws: {} }),
77-
schemaMap: 3
94+
schemaMap: undefined
7895
})
79-
).to.throw(/Parameter `options.schemaMap` must be a Uint8Array./);
96+
).to.be.instanceOf(MongoCrypt);
97+
});
8098
});
8199

82-
it('throws when `encryptedFieldsMap` is not a buffer', () => {
83-
expect(
84-
() =>
100+
describe('options.encryptedFieldsMap', () => {
101+
it('throws when provided and not a Uint8Array', () => {
102+
expect(
103+
() =>
104+
new MongoCrypt({
105+
kmsProviders: serialize({ aws: {} }),
106+
encryptedFieldsMap: 3
107+
})
108+
).to.throw(/Parameter `options.encryptedFieldsMap` must be a Uint8Array./);
109+
});
110+
111+
it('can be explicitly set to `undefined`', () => {
112+
expect(
85113
new MongoCrypt({
86114
kmsProviders: serialize({ aws: {} }),
87-
encryptedFieldsMap: 3
115+
encryptedFieldsMap: undefined
88116
})
89-
).to.throw(/Parameter `options.encryptedFieldsMap` must be a Uint8Array./);
117+
).to.be.instanceOf(MongoCrypt);
118+
});
90119
});
91120

92121
it('throws when cryptSharedLibSearchPaths is not an array', () => {
@@ -106,7 +135,7 @@ describe('MongoCryptConstructor', () => {
106135
});
107136

108137
describe('.makeEncryptionContext()', () => {
109-
it('throws if `command` is not a buffer', () => {
138+
it('throws if `command` is not a Uint8Array', () => {
110139
expect(() => mc.makeEncryptionContext('foo.bar', 'some non-buffer')).to.throw(
111140
/Parameter `command` must be a Uint8Array./
112141
);
@@ -120,7 +149,7 @@ describe('MongoCryptConstructor', () => {
120149
});
121150

122151
describe('.makeDecryptionContext()', () => {
123-
it('throws if not provided a buffer', () => {
152+
it('throws if not provided a Uint8Array', () => {
124153
expect(() => mc.makeDecryptionContext('foo.bar')).to.throw(
125154
/Parameter `value` must be a Uint8Array./
126155
);
@@ -134,7 +163,7 @@ describe('MongoCryptConstructor', () => {
134163
});
135164

136165
describe('.makeExplicitDecryptionContext()', () => {
137-
it('throws if not provided a buffer', () => {
166+
it('throws if not provided a Uint8Array', () => {
138167
expect(() => mc.makeExplicitDecryptionContext('foo.bar')).to.throw(
139168
/Parameter `value` must be a Uint8Array./
140169
);
@@ -154,65 +183,75 @@ describe('MongoCryptConstructor', () => {
154183
);
155184
});
156185

157-
it('throws when the filter is not a buffer', () => {
158-
expect(() => mc.makeRewrapManyDataKeyContext('foo.bar')).to.throw(
159-
/Parameter `filter` must be a Uint8Array./
160-
);
186+
describe('when a filter buffer is provided', () => {
187+
it('throws when the filter is not a Uint8Array', () => {
188+
expect(() => mc.makeRewrapManyDataKeyContext('foo.bar')).to.throw(
189+
/Parameter `filter` must be a Uint8Array./
190+
);
191+
});
192+
193+
it('can be explicitly passed `undefined`', () => {
194+
expect(mc.makeRewrapManyDataKeyContext(serialize({}), undefined)).to.be.instanceOf(
195+
MongoCryptContextCtor
196+
);
197+
});
161198
});
162199
});
163200

164201
describe('.makeDataKeyContext()', () => {
202+
const providers = serialize({
203+
provider: 'aws',
204+
region: 'region',
205+
key: 'key'
206+
});
165207
it('returns a MongoCryptContext', () => {
166-
expect(
167-
mc.makeDataKeyContext(
168-
serialize({
169-
provider: 'aws',
170-
region: 'region',
171-
key: 'key'
172-
}),
173-
{}
174-
)
175-
).to.be.instanceOf(MongoCryptContextCtor);
208+
expect(mc.makeDataKeyContext(providers, {})).to.be.instanceOf(MongoCryptContextCtor);
176209
});
177210

178-
it('throws when the first parameter is not a buffer', () => {
211+
it('throws when the first parameter is not a Uint8Array', () => {
179212
expect(() => mc.makeDataKeyContext('foo.bar', {})).to.throw(
180213
/Parameter `options` must be a Uint8Array./
181214
);
182215
});
183216

184-
it('throws a TypeError when options.keyAltNames includes values that are not buffers', () => {
185-
expect(() =>
186-
mc.makeDataKeyContext(
187-
serialize({
188-
provider: 'aws',
189-
region: 'region',
190-
key: 'key'
191-
}),
192-
{
217+
describe('options.keyAltNames', () => {
218+
it('can be explicitly set to `undefined`', () => {
219+
expect(
220+
mc.makeDataKeyContext(providers, {
221+
keyAltNames: undefined
222+
})
223+
).to.be.instanceOf(MongoCryptContextCtor);
224+
});
225+
226+
it('throws a TypeError when options.keyAltNames includes values that are not Uint8Arrays', () => {
227+
expect(() =>
228+
mc.makeDataKeyContext(providers, {
193229
keyAltNames: [1]
194-
}
230+
})
195231
)
196-
)
197-
.to.throw(/Parameter `options.keyAltName\[\]` must be a Uint8Array./)
198-
.to.be.instanceOf(TypeError);
232+
.to.throw(/Parameter `options.keyAltName\[\]` must be a Uint8Array./)
233+
.to.be.instanceOf(TypeError);
234+
});
199235
});
200236

201-
it('throws a TypeError when options.keyMaterial is not a buffer', () => {
202-
expect(() =>
203-
mc.makeDataKeyContext(
204-
serialize({
205-
provider: 'aws',
206-
region: 'region',
207-
key: 'key'
208-
}),
209-
{
237+
describe('options.keyMaterial', () => {
238+
it('can be explicitly set to `undefined`', () => {
239+
expect(
240+
mc.makeDataKeyContext(providers, {
241+
keyMaterial: undefined
242+
})
243+
).to.be.instanceOf(MongoCryptContextCtor);
244+
});
245+
246+
it('throws a TypeError when provided and is not a Uint8Array', () => {
247+
expect(() =>
248+
mc.makeDataKeyContext(providers, {
210249
keyMaterial: 'foo bar baz'
211-
}
250+
})
212251
)
213-
)
214-
.to.throw(/Parameter `options.keyMaterial` must be a Uint8Array./)
215-
.to.be.instanceOf(TypeError);
252+
.to.throw(/Parameter `options.keyMaterial` must be a Uint8Array./)
253+
.to.be.instanceOf(TypeError);
254+
});
216255
});
217256
});
218257

@@ -243,30 +282,63 @@ describe('MongoCryptConstructor', () => {
243282
.to.throw(/Parameter `value` must be a Uint8Array./)
244283
.to.be.instanceOf(TypeError);
245284
});
246-
it('throws a TypeError when `options.keyId` is not a Buffer', () => {
247-
expect(() =>
248-
mc.makeExplicitEncryptionContext(value, {
249-
// minimum required arguments from libmongocrypt
250-
keyId: 'asdf',
251-
expressionMode: false,
252-
algorithm: 'Unindexed'
253-
})
254-
)
255-
.to.throw(/Parameter `keyId` must be a Uint8Array./)
256-
.to.be.instanceOf(TypeError);
285+
286+
describe('options.keyId', () => {
287+
it('throws a TypeError when provided and is not a Uint8Array', () => {
288+
expect(() =>
289+
mc.makeExplicitEncryptionContext(value, {
290+
// minimum required arguments from libmongocrypt
291+
keyId: 'asdf',
292+
expressionMode: false,
293+
algorithm: 'Unindexed'
294+
})
295+
)
296+
.to.throw(/Parameter `keyId` must be a Uint8Array./)
297+
.to.be.instanceOf(TypeError);
298+
});
299+
300+
it('throws a TypeError when explicitly set to `undefined`', () => {
301+
expect(() =>
302+
mc.makeExplicitEncryptionContext(value, {
303+
// minimum required arguments from libmongocrypt
304+
keyId: undefined,
305+
expressionMode: false,
306+
algorithm: 'Unindexed'
307+
})
308+
)
309+
// error thrown from `libmongocrypt`
310+
.to.throw(/either key id or key alt name required/)
311+
.to.be.instanceOf(TypeError);
312+
});
257313
});
258314

259-
it('throws a TypeError when `options.keyAltName` is not a Buffer', () => {
260-
expect(() =>
261-
mc.makeExplicitEncryptionContext(value, {
262-
// minimum required arguments from libmongocrypt
263-
keyAltName: 'asdf',
264-
expressionMode: false,
265-
algorithm: 'Unindexed'
266-
})
267-
)
268-
.to.throw(/Parameter `keyAltName` must be a Uint8Array./)
269-
.to.be.instanceOf(TypeError);
315+
describe('options.keyAltName', () => {
316+
it('throws a TypeError provided and is not a Uint8Array', () => {
317+
expect(() =>
318+
mc.makeExplicitEncryptionContext(value, {
319+
// minimum required arguments from libmongocrypt
320+
keyAltName: 'asdf',
321+
expressionMode: false,
322+
algorithm: 'Unindexed'
323+
})
324+
)
325+
.to.throw(/Parameter `keyAltName` must be a Uint8Array./)
326+
.to.be.instanceOf(TypeError);
327+
});
328+
329+
it('throws a TypeError when explicitly set to `undefined`', () => {
330+
expect(() =>
331+
mc.makeExplicitEncryptionContext(value, {
332+
// minimum required arguments from libmongocrypt
333+
keyAltName: undefined,
334+
expressionMode: false,
335+
algorithm: 'Unindexed'
336+
})
337+
)
338+
// error thrown from `libmongocrypt`
339+
.to.throw(/either key id or key alt name required/)
340+
.to.be.instanceOf(TypeError);
341+
});
270342
});
271343

272344
context('when algorithm is `rangePreview', () => {
@@ -283,7 +355,7 @@ describe('MongoCryptConstructor', () => {
283355
.to.be.instanceOf(TypeError);
284356
});
285357

286-
it('throws a TypeError if `rangeOptions` is not a Buffer', () => {
358+
it('throws a TypeError if `rangeOptions` is not a Uint8Array', () => {
287359
expect(() =>
288360
mc.makeExplicitEncryptionContext(value, {
289361
// minimum required arguments from libmongocrypt

0 commit comments

Comments
 (0)