Skip to content

Commit 4613763

Browse files
authored
fix: accept Uint8Array where Buffer is accepted (#432)
1 parent 3ffc44f commit 4613763

File tree

6 files changed

+35
-28
lines changed

6 files changed

+35
-28
lines changed

src/ensure_buffer.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { Buffer } from 'buffer';
2-
import { isBuffer, isAnyArrayBuffer } from './parser/utils';
2+
import { isAnyArrayBuffer } from './parser/utils';
33

44
/**
55
* Makes sure that, if a Uint8Array is passed in, it is wrapped in a Buffer.
@@ -10,12 +10,12 @@ import { isBuffer, isAnyArrayBuffer } from './parser/utils';
1010
* @throws TypeError If anything other than a Buffer or Uint8Array is passed in
1111
*/
1212
export function ensureBuffer(potentialBuffer: Buffer | ArrayBufferView | ArrayBuffer): Buffer {
13-
if (isBuffer(potentialBuffer)) {
14-
return potentialBuffer;
15-
}
16-
1713
if (ArrayBuffer.isView(potentialBuffer)) {
18-
return Buffer.from(potentialBuffer.buffer);
14+
return Buffer.from(
15+
potentialBuffer.buffer,
16+
potentialBuffer.byteOffset,
17+
potentialBuffer.byteLength
18+
);
1919
}
2020

2121
if (isAnyArrayBuffer(potentialBuffer)) {

src/objectid.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Buffer } from 'buffer';
22
import { ensureBuffer } from './ensure_buffer';
3-
import { deprecate, randomBytes } from './parser/utils';
3+
import { deprecate, isUint8Array, randomBytes } from './parser/utils';
44

55
// constants
66
const PROCESS_UNIQUE = randomBytes(5);
@@ -229,9 +229,9 @@ export class ObjectId {
229229
typeof otherId === 'string' &&
230230
ObjectId.isValid(otherId) &&
231231
otherId.length === 12 &&
232-
Buffer.isBuffer(this.id)
232+
isUint8Array(this.id)
233233
) {
234-
return otherId === this.id.toString('binary');
234+
return otherId === Buffer.prototype.toString.call(this.id, 'latin1');
235235
}
236236

237237
if (typeof otherId === 'string' && ObjectId.isValid(otherId) && otherId.length === 24) {
@@ -300,7 +300,7 @@ export class ObjectId {
300300
*
301301
* @param id - ObjectId instance to validate.
302302
*/
303-
static isValid(id: number | string | ObjectId | Buffer | ObjectIdLike): boolean {
303+
static isValid(id: number | string | ObjectId | Uint8Array | ObjectIdLike): boolean {
304304
if (id == null) return false;
305305

306306
if (typeof id === 'number') {
@@ -315,7 +315,7 @@ export class ObjectId {
315315
return true;
316316
}
317317

318-
if (Buffer.isBuffer(id) && id.length === 12) {
318+
if (isUint8Array(id) && id.length === 12) {
319319
return true;
320320
}
321321

src/parser/serializer.ts

+3-4
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import type { BSONRegExp } from '../regexp';
1818
import {
1919
isBigInt64Array,
2020
isBigUInt64Array,
21-
isBuffer,
2221
isDate,
2322
isMap,
2423
isRegExp,
@@ -784,7 +783,7 @@ export function serializeInto(
784783
index = serializeNull(buffer, key, value, index, true);
785784
} else if (value['_bsontype'] === 'ObjectId' || value['_bsontype'] === 'ObjectID') {
786785
index = serializeObjectId(buffer, key, value, index, true);
787-
} else if (isBuffer(value) || isUint8Array(value)) {
786+
} else if (isUint8Array(value)) {
788787
index = serializeBuffer(buffer, key, value, index, true);
789788
} else if (value instanceof RegExp || isRegExp(value)) {
790789
index = serializeRegExp(buffer, key, value, index, true);
@@ -890,7 +889,7 @@ export function serializeInto(
890889
index = serializeNull(buffer, key, value, index);
891890
} else if (value['_bsontype'] === 'ObjectId' || value['_bsontype'] === 'ObjectID') {
892891
index = serializeObjectId(buffer, key, value, index);
893-
} else if (isBuffer(value) || isUint8Array(value)) {
892+
} else if (isUint8Array(value)) {
894893
index = serializeBuffer(buffer, key, value, index);
895894
} else if (value instanceof RegExp || isRegExp(value)) {
896895
index = serializeRegExp(buffer, key, value, index);
@@ -996,7 +995,7 @@ export function serializeInto(
996995
index = serializeNull(buffer, key, value, index);
997996
} else if (value['_bsontype'] === 'ObjectId' || value['_bsontype'] === 'ObjectID') {
998997
index = serializeObjectId(buffer, key, value, index);
999-
} else if (isBuffer(value) || isUint8Array(value)) {
998+
} else if (isUint8Array(value)) {
1000999
index = serializeBuffer(buffer, key, value, index);
10011000
} else if (value instanceof RegExp || isRegExp(value)) {
10021001
index = serializeRegExp(buffer, key, value, index);

src/parser/utils.ts

-5
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,6 @@ export function haveBuffer(): boolean {
9393
return typeof global !== 'undefined' && typeof global.Buffer !== 'undefined';
9494
}
9595

96-
/** Callable in any environment to check if value is a Buffer */
97-
export function isBuffer(value: unknown): value is Buffer {
98-
return typeof value === 'object' && value?.constructor?.name === 'Buffer';
99-
}
100-
10196
// To ensure that 0.4 of node works correctly
10297
export function isDate(d: unknown): d is Date {
10398
return isObjectLike(d) && Object.prototype.toString.call(d) === '[object Date]';

src/uuid.ts

+3-6
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Buffer } from 'buffer';
22
import { ensureBuffer } from './ensure_buffer';
33
import { Binary } from './binary';
44
import { bufferToUuidHexString, uuidHexStringToBuffer, uuidValidateString } from './uuid_utils';
5-
import { randomBytes } from './parser/utils';
5+
import { isUint8Array, randomBytes } from './parser/utils';
66

77
/** @public */
88
export type UUIDExtended = {
@@ -40,10 +40,7 @@ export class UUID {
4040
} else if (input instanceof UUID) {
4141
this[kId] = Buffer.from(input.id);
4242
this.__id = input.__id;
43-
} else if (
44-
(Buffer.isBuffer(input) || ArrayBuffer.isView(input)) &&
45-
input.byteLength === BYTE_LENGTH
46-
) {
43+
} else if (ArrayBuffer.isView(input) && input.byteLength === BYTE_LENGTH) {
4744
this.id = ensureBuffer(input);
4845
} else if (typeof input === 'string') {
4946
this.id = uuidHexStringToBuffer(input);
@@ -167,7 +164,7 @@ export class UUID {
167164
return uuidValidateString(input);
168165
}
169166

170-
if (Buffer.isBuffer(input)) {
167+
if (isUint8Array(input)) {
171168
// check for length & uuid version (https://tools.ietf.org/html/rfc4122#section-4.1.3)
172169
if (input.length !== BYTE_LENGTH) {
173170
return false;

test/node/ensure_buffer_test.js

+18-2
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,18 @@ describe('ensureBuffer tests', function () {
99
expect(ensureBuffer).to.be.a('function');
1010
});
1111

12-
it('should return the exact same buffer if a buffer is passed in', function () {
12+
it('should return a view over the exact same memory when a Buffer is passed in', function () {
1313
const bufferIn = Buffer.alloc(10);
1414
let bufferOut;
1515

1616
expect(function () {
1717
bufferOut = ensureBuffer(bufferIn);
1818
}).to.not.throw(Error);
1919

20-
expect(bufferOut).to.equal(bufferIn);
20+
expect(bufferOut).to.be.an.instanceOf(Buffer);
21+
expect(bufferOut.buffer).to.equal(bufferIn.buffer);
22+
expect(bufferOut.byteLength).to.equal(bufferIn.byteLength);
23+
expect(bufferOut.byteOffset).to.equal(bufferIn.byteOffset);
2124
});
2225

2326
it('should wrap a Uint8Array with a buffer', function () {
@@ -60,6 +63,19 @@ describe('ensureBuffer tests', function () {
6063
expect(bufferOut.buffer).to.equal(arrayBufferIn);
6164
});
6265

66+
it('should account for the input view byteLength and byteOffset', function () {
67+
const input = new Uint8Array(new Uint8Array([1, 2, 3, 4, 5]).buffer, 1, 3);
68+
let bufferOut;
69+
70+
expect(function () {
71+
bufferOut = ensureBuffer(input);
72+
}).to.not.throw(Error);
73+
74+
expect(bufferOut).to.be.an.instanceOf(Buffer);
75+
expect(bufferOut.byteLength).to.equal(3);
76+
expect(bufferOut.byteOffset).to.equal(1);
77+
});
78+
6379
[0, 12, -1, '', 'foo', null, undefined, ['list'], {}, /x/].forEach(function (item) {
6480
it(`should throw if input is ${typeof item}: ${item}`, function () {
6581
expect(function () {

0 commit comments

Comments
 (0)