@@ -93,6 +93,8 @@ export function deserialize(
93
93
return deserializeObject ( buffer , index , options , isArray ) ;
94
94
}
95
95
96
+ const allowedDBRefKeys = / ^ \$ r e f $ | ^ \$ i d $ | ^ \$ d b $ / ;
97
+
96
98
function deserializeObject (
97
99
buffer : Buffer ,
98
100
index : number ,
@@ -134,6 +136,8 @@ function deserializeObject(
134
136
let arrayIndex = 0 ;
135
137
const done = false ;
136
138
139
+ let isPossibleDBRef = isArray ? false : null ;
140
+
137
141
// While we have more left data left keep parsing
138
142
while ( ! done ) {
139
143
// Read the type
@@ -152,6 +156,9 @@ function deserializeObject(
152
156
// If are at the end of the buffer there is a problem with the document
153
157
if ( i >= buffer . byteLength ) throw new Error ( 'Bad BSON Document: illegal CString' ) ;
154
158
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
+ }
155
162
let value ;
156
163
157
164
index = i + 1 ;
@@ -169,12 +176,17 @@ function deserializeObject(
169
176
)
170
177
throw new Error ( 'bad string length in bson' ) ;
171
178
172
- if ( ! validateUtf8 ( buffer , index , index + stringSize - 1 ) ) {
173
- throw new Error ( 'Invalid UTF-8 string in BSON document' ) ;
174
- }
175
-
176
179
value = buffer . toString ( 'utf8' , index , index + stringSize - 1 ) ;
177
180
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
+
178
190
index = index + stringSize ;
179
191
} else if ( elementType === constants . BSON_DATA_OID ) {
180
192
const oid = Buffer . alloc ( 12 ) ;
@@ -625,15 +637,8 @@ function deserializeObject(
625
637
throw new Error ( 'corrupt object bson' ) ;
626
638
}
627
639
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 ;
637
642
638
643
if ( isDBRefLike ( object ) ) {
639
644
const copy = Object . assign ( { } , object ) as Partial < DBRefLike > ;
0 commit comments