@@ -93,6 +93,8 @@ export function deserialize(
9393 return deserializeObject ( buffer , index , options , isArray ) ;
9494}
9595
96+ const allowedDBRefKeys = / ^ \$ r e f $ | ^ \$ i d $ | ^ \$ d b $ / ;
97+
9698function deserializeObject (
9799 buffer : Buffer ,
98100 index : number ,
@@ -134,6 +136,8 @@ function deserializeObject(
134136 let arrayIndex = 0 ;
135137 const done = false ;
136138
139+ let isPossibleDBRef = isArray ? false : null ;
140+
137141 // While we have more left data left keep parsing
138142 while ( ! done ) {
139143 // Read the type
@@ -152,6 +156,9 @@ function deserializeObject(
152156 // If are at the end of the buffer there is a problem with the document
153157 if ( i >= buffer . byteLength ) throw new Error ( 'Bad BSON Document: illegal CString' ) ;
154158 const name = isArray ? arrayIndex ++ : buffer . toString ( 'utf8' , index , i ) ;
159+ if ( isPossibleDBRef !== false && ( name as string ) [ 0 ] === '$' ) {
160+ isPossibleDBRef = allowedDBRefKeys . test ( name as string ) ;
161+ }
155162 let value ;
156163
157164 index = i + 1 ;
@@ -169,12 +176,17 @@ function deserializeObject(
169176 )
170177 throw new Error ( 'bad string length in bson' ) ;
171178
172- if ( ! validateUtf8 ( buffer , index , index + stringSize - 1 ) ) {
173- throw new Error ( 'Invalid UTF-8 string in BSON document' ) ;
174- }
175-
176179 value = buffer . toString ( 'utf8' , index , index + stringSize - 1 ) ;
177180
181+ for ( let i = 0 ; i < value . length ; i ++ ) {
182+ if ( value . charCodeAt ( i ) === 0xfffd ) {
183+ if ( ! validateUtf8 ( buffer , index , index + stringSize - 1 ) ) {
184+ throw new Error ( 'Invalid UTF-8 string in BSON document' ) ;
185+ }
186+ break ;
187+ }
188+ }
189+
178190 index = index + stringSize ;
179191 } else if ( elementType === constants . BSON_DATA_OID ) {
180192 const oid = Buffer . alloc ( 12 ) ;
@@ -625,15 +637,8 @@ function deserializeObject(
625637 throw new Error ( 'corrupt object bson' ) ;
626638 }
627639
628- // check if object's $ keys are those of a DBRef
629- const dollarKeys = Object . keys ( object ) . filter ( k => k . startsWith ( '$' ) ) ;
630- let valid = true ;
631- dollarKeys . forEach ( k => {
632- if ( [ '$ref' , '$id' , '$db' ] . indexOf ( k ) === - 1 ) valid = false ;
633- } ) ;
634-
635- // if a $key not in "$ref", "$id", "$db", don't make a DBRef
636- if ( ! valid ) return object ;
640+ // if we did not find "$ref", "$id", "$db", or found an extraneous $key, don't make a DBRef
641+ if ( ! isPossibleDBRef ) return object ;
637642
638643 if ( isDBRefLike ( object ) ) {
639644 const copy = Object . assign ( { } , object ) as Partial < DBRefLike > ;
0 commit comments