@@ -69,7 +69,6 @@ const sandbox = vm.createContext({
6969 performance : global . performance ,
7070
7171 process : process ,
72- Buffer : Buffer ,
7372
7473 context : global . context ,
7574 describe : global . describe ,
@@ -114,12 +113,32 @@ function loadInSandbox(filepath: string) {
114113 }
115114
116115 // clientmetadata requires package.json to fetch driver's version
117- if ( realPath . endsWith ( '.json' ) ) {
116+ if ( realPath . endsWith ( 'package .json' ) ) {
118117 const jsonContent = JSON . parse ( fs . readFileSync ( realPath , 'utf8' ) ) ;
119118 moduleCache . set ( realPath , jsonContent ) ;
120119 return jsonContent ;
121120 }
122121
122+ // js-bson is allowed to use Buffer, only ./src/ is not
123+ const isSourceFile = realPath . includes ( '/src/' ) || ! realPath . includes ( 'node_modules' ) ;
124+ const isTestFile = realPath . includes ( '.test.ts' ) || realPath . includes ( '.test.js' ) ;
125+
126+ let localBuffer = Buffer ;
127+ if ( isSourceFile && ! isTestFile ) {
128+ localBuffer = new Proxy ( Buffer , {
129+ get ( ) {
130+ throw new Error (
131+ `Forbidden: 'Buffer' usage is not allowed in source files. Use Uint8Array instead. File: ${ realPath } `
132+ ) ;
133+ } ,
134+ construct ( ) {
135+ throw new Error (
136+ `Forbidden: 'Buffer' usage is not allowed in source files. Use Uint8Array instead. File: ${ realPath } `
137+ ) ;
138+ }
139+ } ) as any ;
140+ }
141+
123142 const content = fs . readFileSync ( realPath , 'utf8' ) ;
124143 let executableCode : string ;
125144 if ( realPath . endsWith ( '.ts' ) ) {
@@ -142,28 +161,29 @@ function loadInSandbox(filepath: string) {
142161 moduleCache . set ( realPath , localModule . exports ) ;
143162
144163 try {
145- const wrapper = `(function(exports, require, module, __filename, __dirname) {
164+ const wrapper = `(function(exports, require, module, __filename, __dirname, Buffer ) {
146165 ${ executableCode }
147166 })` ;
148167 const script = new vm . Script ( wrapper , { filename : realPath } ) ;
149168 const fn = script . runInContext ( sandbox ) ;
150169
151- fn ( localModule . exports , localRequire , localModule , filename , dirname ) ;
170+ fn ( localModule . exports , localRequire , localModule , filename , dirname , localBuffer ) ;
152171
153172 const result = localModule . exports ;
154- if ( realPath . includes ( 'src/error.ts' ) ) {
155- for ( const [ key , value ] of Object . entries ( result ) ) {
156- if ( typeof value === 'function' && value . name ?. startsWith ( 'Mongo' ) ) {
157- ( sandbox as any ) [ key ] = value ;
158173
174+ const isBSON = realPath . includes ( 'node_modules/bson' ) ;
175+ const isError = realPath . includes ( 'src/error.ts' ) ;
176+
177+ if ( isBSON || isError ) {
178+ for ( const [ key , value ] of Object . entries ( result ) ) {
179+ if ( typeof value === 'function' && value . name ) {
159180 // force instanceof to work across contexts by defining custom `instanceof` function
160181 Object . defineProperty ( value , Symbol . hasInstance , {
161- value : ( instance : any ) => {
162- return (
163- instance && ( instance . constructor . name === value . name || instance instanceof value )
164- ) ;
165- }
182+ value : ( i : any ) => i && ( i . constructor . name === value . name || i instanceof value )
166183 } ) ;
184+
185+ // also inject into global for easier access in tests
186+ ( sandbox as any ) [ key ] = value ;
167187 }
168188 }
169189 }
@@ -173,7 +193,7 @@ function loadInSandbox(filepath: string) {
173193 return result ;
174194 } catch ( err : any ) {
175195 moduleCache . delete ( realPath ) ;
176- console . error ( `Error running ${ realPath } in sandbox:` , err . stack ) ;
196+ console . error ( `Error running ${ realPath } in sandbox:` , err ) ;
177197 throw err ;
178198 }
179199}
0 commit comments