Skip to content

Commit

Permalink
fix(NODE-3629): correct corpus runner and add null checks (#464)
Browse files Browse the repository at this point in the history
  • Loading branch information
nbbeeken committed Sep 28, 2021
1 parent 80d7f03 commit d75102d
Show file tree
Hide file tree
Showing 19 changed files with 859 additions and 110 deletions.
582 changes: 582 additions & 0 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"@rollup/plugin-typescript": "^6.0.0",
"@typescript-eslint/eslint-plugin": "^3.10.1",
"@typescript-eslint/parser": "^3.10.1",
"array-includes": "^3.1.3",
"benchmark": "^2.1.4",
"chai": "^4.2.0",
"downlevel-dts": "^0.7.0",
Expand All @@ -54,6 +55,7 @@
"mocha": "5.2.0",
"node-fetch": "^2.6.1",
"nyc": "^15.1.0",
"object.entries": "^1.1.4",
"prettier": "^2.1.1",
"rimraf": "^3.0.2",
"rollup": "^2.26.5",
Expand Down
13 changes: 7 additions & 6 deletions src/binary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ensureBuffer } from './ensure_buffer';
import { uuidHexStringToBuffer } from './uuid_utils';
import { UUID, UUIDExtended } from './uuid';
import type { EJSONOptions } from './extended_json';
import { BSONError, BSONTypeError } from './error';

/** @public */
export type BinarySequence = Uint8Array | Buffer | number[];
Expand Down Expand Up @@ -73,7 +74,7 @@ export class Binary {
!(buffer instanceof ArrayBuffer) &&
!Array.isArray(buffer)
) {
throw new TypeError(
throw new BSONTypeError(
'Binary can only be constructed from string, Buffer, TypedArray, or Array<number>'
);
}
Expand Down Expand Up @@ -108,9 +109,9 @@ export class Binary {
put(byteValue: string | number | Uint8Array | Buffer | number[]): void {
// If it's a string and a has more than one character throw an error
if (typeof byteValue === 'string' && byteValue.length !== 1) {
throw new TypeError('only accepts single character String');
throw new BSONTypeError('only accepts single character String');
} else if (typeof byteValue !== 'number' && byteValue.length !== 1)
throw new TypeError('only accepts single character Uint8Array or Array');
throw new BSONTypeError('only accepts single character Uint8Array or Array');

// Decode the byte value once
let decodedByte: number;
Expand All @@ -123,7 +124,7 @@ export class Binary {
}

if (decodedByte < 0 || decodedByte > 255) {
throw new TypeError('only accepts number in a valid unsigned byte range 0-255');
throw new BSONTypeError('only accepts number in a valid unsigned byte range 0-255');
}

if (this.buffer.length > this.position) {
Expand Down Expand Up @@ -238,7 +239,7 @@ export class Binary {
return new UUID(this.buffer.slice(0, this.position));
}

throw new Error(
throw new BSONError(
`Binary sub_type "${this.sub_type}" is not supported for converting to UUID. Only "${Binary.SUBTYPE_UUID}" is currently supported.`
);
}
Expand Down Expand Up @@ -266,7 +267,7 @@ export class Binary {
data = uuidHexStringToBuffer(doc.$uuid);
}
if (!data) {
throw new TypeError(`Unexpected Binary Extended JSON format ${JSON.stringify(doc)}`);
throw new BSONTypeError(`Unexpected Binary Extended JSON format ${JSON.stringify(doc)}`);
}
return new Binary(data, type);
}
Expand Down
6 changes: 5 additions & 1 deletion src/bson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Map } from './map';
import { MaxKey } from './max_key';
import { MinKey } from './min_key';
import { ObjectId } from './objectid';
import { BSONError, BSONTypeError } from './error';
import { calculateObjectSize as internalCalculateObjectSize } from './parser/calculate_size';
// Parts of the parser
import { deserialize as internalDeserialize, DeserializeOptions } from './parser/deserializer';
Expand Down Expand Up @@ -98,6 +99,7 @@ export {
// later builds we changed it back to ObjectID (capital D) to match legacy implementations.
ObjectId as ObjectID
};
export { BSONError, BSONTypeError } from './error';

/** @public */
export interface Document {
Expand Down Expand Up @@ -326,6 +328,8 @@ const BSON = {
serializeWithBufferAndIndex,
deserialize,
calculateObjectSize,
deserializeStream
deserializeStream,
BSONError,
BSONTypeError
};
export default BSON;
9 changes: 5 additions & 4 deletions src/decimal128.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Buffer } from 'buffer';
import { BSONTypeError } from './error';
import { Long } from './long';

const PARSE_STRING_REGEXP = /^(\+|-)?(\d+|(\d*\.\d*))?(E|e)?([-+])?(\d+)?$/;
Expand Down Expand Up @@ -105,7 +106,7 @@ function lessThan(left: Long, right: Long): boolean {
}

function invalidErr(string: string, message: string) {
throw new TypeError(`"${string}" is not a valid Decimal128 string - ${message}`);
throw new BSONTypeError(`"${string}" is not a valid Decimal128 string - ${message}`);
}

/** @public */
Expand Down Expand Up @@ -187,7 +188,7 @@ export class Decimal128 {
// TODO: implementing a custom parsing for this, or refactoring the regex would yield
// further gains.
if (representation.length >= 7000) {
throw new TypeError('' + representation + ' not a valid Decimal128 string');
throw new BSONTypeError('' + representation + ' not a valid Decimal128 string');
}

// Results
Expand All @@ -197,7 +198,7 @@ export class Decimal128 {

// Validate the string
if ((!stringMatch && !infMatch && !nanMatch) || representation.length === 0) {
throw new TypeError('' + representation + ' not a valid Decimal128 string');
throw new BSONTypeError('' + representation + ' not a valid Decimal128 string');
}

if (stringMatch) {
Expand Down Expand Up @@ -269,7 +270,7 @@ export class Decimal128 {
}

if (sawRadix && !nDigitsRead)
throw new TypeError('' + representation + ' not a valid Decimal128 string');
throw new BSONTypeError('' + representation + ' not a valid Decimal128 string');

// Read exponent if exists
if (representation[index] === 'e' || representation[index] === 'E') {
Expand Down
3 changes: 2 additions & 1 deletion src/ensure_buffer.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Buffer } from 'buffer';
import { BSONTypeError } from './error';
import { isAnyArrayBuffer } from './parser/utils';

/**
Expand All @@ -22,5 +23,5 @@ export function ensureBuffer(potentialBuffer: Buffer | ArrayBufferView | ArrayBu
return Buffer.from(potentialBuffer);
}

throw new TypeError('Must use either Buffer or TypedArray');
throw new BSONTypeError('Must use either Buffer or TypedArray');
}
13 changes: 13 additions & 0 deletions src/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/** @public */
export class BSONError extends Error {
get name(): string {
return 'BSONError';
}
}

/** @public */
export class BSONTypeError extends TypeError {
get name(): string {
return 'BSONTypeError';
}
}
18 changes: 13 additions & 5 deletions src/extended_json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { Code } from './code';
import { DBRef, isDBRefLike } from './db_ref';
import { Decimal128 } from './decimal128';
import { Double } from './double';
import { BSONError, BSONTypeError } from './error';
import { Int32 } from './int_32';
import { Long } from './long';
import { MaxKey } from './max_key';
Expand Down Expand Up @@ -185,7 +186,7 @@ function serializeValue(value: any, options: EJSONSerializeOptions): any {
circularPart.length + (alreadySeen.length + current.length) / 2 - 1
);

throw new TypeError(
throw new BSONTypeError(
'Converting circular structure to EJSON:\n' +
` ${leadingPart}${alreadySeen}${circularPart}${current}\n` +
` ${leadingSpace}\\${dashes}/`
Expand Down Expand Up @@ -274,7 +275,7 @@ const BSON_TYPE_MAPPINGS = {

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function serializeDocument(doc: any, options: EJSONSerializeOptions) {
if (doc == null || typeof doc !== 'object') throw new Error('not an object instance');
if (doc == null || typeof doc !== 'object') throw new BSONError('not an object instance');

const bsontype: BSONType['_bsontype'] = doc._bsontype;
if (typeof bsontype === 'undefined') {
Expand All @@ -300,7 +301,7 @@ function serializeDocument(doc: any, options: EJSONSerializeOptions) {
// Copy the object into this library's version of that type.
const mapper = BSON_TYPE_MAPPINGS[doc._bsontype];
if (!mapper) {
throw new TypeError('Unrecognized or invalid _bsontype: ' + doc._bsontype);
throw new BSONTypeError('Unrecognized or invalid _bsontype: ' + doc._bsontype);
}
outDoc = mapper(outDoc);
}
Expand All @@ -319,7 +320,7 @@ function serializeDocument(doc: any, options: EJSONSerializeOptions) {

return outDoc.toExtendedJSON(options);
} else {
throw new Error('_bsontype must be a string, but was: ' + typeof bsontype);
throw new BSONError('_bsontype must be a string, but was: ' + typeof bsontype);
}
}

Expand Down Expand Up @@ -366,7 +367,14 @@ export namespace EJSON {
if (typeof finalOptions.relaxed === 'boolean') finalOptions.strict = !finalOptions.relaxed;
if (typeof finalOptions.strict === 'boolean') finalOptions.relaxed = !finalOptions.strict;

return JSON.parse(text, (_key, value) => deserializeValue(value, finalOptions));
return JSON.parse(text, (key, value) => {
if (key.indexOf('\x00') !== -1) {
throw new BSONError(
`BSON Document field names cannot contain null bytes, found: ${JSON.stringify(key)}`
);
}
return deserializeValue(value, finalOptions);
});
}

export type JSONPrimitive = string | number | boolean | null;
Expand Down
5 changes: 3 additions & 2 deletions src/objectid.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Buffer } from 'buffer';
import { ensureBuffer } from './ensure_buffer';
import { BSONTypeError } from './error';
import { deprecate, isUint8Array, randomBytes } from './parser/utils';

// Regular expression that checks for hex value
Expand Down Expand Up @@ -84,7 +85,7 @@ export class ObjectId {
} else if (id.length === 24 && checkForHexRegExp.test(id)) {
this[kId] = Buffer.from(id, 'hex');
} else {
throw new TypeError(
throw new BSONTypeError(
'Argument passed in must be a Buffer or string of 12 bytes or a string of 24 hex characters'
);
}
Expand Down Expand Up @@ -276,7 +277,7 @@ export class ObjectId {
static createFromHexString(hexString: string): ObjectId {
// Throw an error if it's not a valid setup
if (typeof hexString === 'undefined' || (hexString != null && hexString.length !== 24)) {
throw new TypeError(
throw new BSONTypeError(
'Argument passed in must be a single String of 12 bytes or a string of 24 hex characters'
);
}
Expand Down

0 comments on commit d75102d

Please sign in to comment.