@@ -187,6 +187,18 @@ describe('getOggMetadata', () => {
187187 return buffer . buffer
188188 }
189189 } ,
190+ {
191+ name : 'segment data exceeds buffer boundary' ,
192+ createBuffer : ( ) => {
193+ // Page header declares 1 segment of length 200, but only 10 bytes of data follow
194+ const buffer = new Uint8Array ( 27 + 1 + 10 )
195+ buffer . set ( new TextEncoder ( ) . encode ( 'OggS' ) , 0 )
196+ buffer [ 26 ] = 1 // 1 segment
197+ buffer [ 27 ] = 200 // segment length = 200 (exceeds remaining 10 bytes)
198+ // Only 10 bytes of data follow; segment exceeds boundary
199+ return buffer . buffer
200+ }
201+ } ,
190202 {
191203 name : 'truncated user comment in OpusTags' ,
192204 createBuffer : ( ) => {
@@ -207,7 +219,6 @@ describe('getOggMetadata', () => {
207219 name : 'file smaller than the Ogg magic number' ,
208220 createBuffer : ( ) => new Uint8Array ( [ 1 , 2 ] ) . buffer
209221 } ,
210-
211222 {
212223 name : 'page has an invalid magic number (stop parsing)' ,
213224 createBuffer : ( ) => {
@@ -222,6 +233,73 @@ describe('getOggMetadata', () => {
222233 combined . set ( page2 , page1 . length )
223234 return combined . buffer
224235 }
236+ } ,
237+ {
238+ name : 'OpusTags packet truncated before vendorLength field' ,
239+ createBuffer : ( ) => {
240+ // Packet is only 10 bytes: 'OpusTags'(8) + 2 extra bytes (not enough for 4-byte vendorLength)
241+ const packet = new Uint8Array ( 10 )
242+ packet . set ( new TextEncoder ( ) . encode ( 'OpusTags' ) , 0 )
243+ const buffer = new Uint8Array ( 27 + 1 + packet . length )
244+ buffer . set ( new TextEncoder ( ) . encode ( 'OggS' ) , 0 )
245+ buffer [ 26 ] = 1
246+ buffer [ 27 ] = packet . length
247+ buffer . set ( packet , 28 )
248+ return buffer . buffer
249+ }
250+ } ,
251+ {
252+ name : 'OpusTags packet with oversized vendorLength' ,
253+ createBuffer : ( ) => {
254+ // Packet: 'OpusTags'(8) + vendorLength=9999(4) + no actual vendor bytes
255+ const packet = new Uint8Array ( 12 )
256+ packet . set ( new TextEncoder ( ) . encode ( 'OpusTags' ) , 0 )
257+ new DataView ( packet . buffer ) . setUint32 ( 8 , 9999 , true ) // vendor string claims 9999 bytes
258+ const buffer = new Uint8Array ( 27 + 1 + packet . length )
259+ buffer . set ( new TextEncoder ( ) . encode ( 'OggS' ) , 0 )
260+ buffer [ 26 ] = 1
261+ buffer [ 27 ] = packet . length
262+ buffer . set ( packet , 28 )
263+ return buffer . buffer
264+ }
265+ } ,
266+ {
267+ name : 'OpusTags packet truncated before userCommentListLength' ,
268+ createBuffer : ( ) => {
269+ // Packet: 'OpusTags'(8) + vendorLength=0(4) + no userCommentListLength
270+ const packet = new Uint8Array ( 12 ) // exactly 8 + 4, no bytes for userCommentListLength
271+ packet . set ( new TextEncoder ( ) . encode ( 'OpusTags' ) , 0 )
272+ new DataView ( packet . buffer ) . setUint32 ( 8 , 0 , true ) // vendorLength=0
273+ // packet ends here — no room for userCommentListLength (needs 4 more bytes)
274+ const buffer = new Uint8Array ( 27 + 1 + packet . length )
275+ buffer . set ( new TextEncoder ( ) . encode ( 'OggS' ) , 0 )
276+ buffer [ 26 ] = 1
277+ buffer [ 27 ] = packet . length
278+ buffer . set ( packet , 28 )
279+ return buffer . buffer
280+ }
281+ } ,
282+ {
283+ name : 'OpusTags packet truncated mid-comment-list (missing comment length field)' ,
284+ createBuffer : ( ) => {
285+ const commentBytes = new TextEncoder ( ) . encode ( 'key=value' )
286+ // Packet: 'OpusTags'(8) + vendorLength=0(4) + userCommentListLength=2(4) +
287+ // commentLength=9(4) + commentData(9) — second comment length field is missing
288+ const packet = new Uint8Array ( 8 + 4 + 4 + 4 + commentBytes . length )
289+ const view = new DataView ( packet . buffer )
290+ packet . set ( new TextEncoder ( ) . encode ( 'OpusTags' ) , 0 )
291+ view . setUint32 ( 8 , 0 , true ) // vendorLength = 0
292+ view . setUint32 ( 12 , 2 , true ) // userCommentListLength = 2 (but only 1 follows)
293+ view . setUint32 ( 16 , commentBytes . length , true ) // first comment length
294+ packet . set ( commentBytes , 20 ) // first comment data
295+ // second comment's length field is absent — packet ends here
296+ const buffer = new Uint8Array ( 27 + 1 + packet . length )
297+ buffer . set ( new TextEncoder ( ) . encode ( 'OggS' ) , 0 )
298+ buffer [ 26 ] = 1
299+ buffer [ 27 ] = packet . length
300+ buffer . set ( packet , 28 )
301+ return buffer . buffer
302+ }
225303 }
226304 ]
227305
@@ -231,14 +309,12 @@ describe('getOggMetadata', () => {
231309 [ createBuffer ( ) ] ,
232310 `test_${ name . replace ( / \s + / g, '_' ) } .ogg`
233311 )
234- try {
235- const result = await getOggMetadata ( file )
236- expect ( result . prompt ) . toBeUndefined ( )
237- expect ( result . workflow ) . toBeUndefined ( )
238- } catch ( e ) {
239- // If it throws (e.g. RangeError from DataView out of bounds), it's successfully handled gracefully by the caller
240- expect ( e ) . toBeInstanceOf ( Error )
241- }
312+ await expect (
313+ getOggMetadata ( file ) . then ( ( result ) => {
314+ expect ( result . prompt ) . toBeUndefined ( )
315+ expect ( result . workflow ) . toBeUndefined ( )
316+ } )
317+ ) . resolves . not . toThrow ( )
242318 } )
243319 }
244320 } )
@@ -247,7 +323,7 @@ describe('getOggMetadata', () => {
247323 const scenarios : {
248324 name : string
249325 createBuffer : ( ) => ArrayBuffer
250- expectedPrompt ?: any
326+ expectedPrompt ?: Record < string , unknown >
251327 } [ ] = [
252328 {
253329 name : 'unrelated Vorbis comments' ,
@@ -258,6 +334,14 @@ describe('getOggMetadata', () => {
258334 } ) ,
259335 expectedPrompt : { valid : true } // Workflow is undefined, Prompt is valid
260336 } ,
337+ {
338+ name : 'invalid JSON in prompt/workflow comments (plain text)' ,
339+ createBuffer : ( ) =>
340+ createOggWithOpusTags ( {
341+ prompt : 'hello world' ,
342+ workflow : 'plain text workflow'
343+ } )
344+ } ,
261345 {
262346 name : 'user comments without an equal sign' ,
263347 createBuffer : ( ) => {
@@ -287,18 +371,15 @@ describe('getOggMetadata', () => {
287371 [ createBuffer ( ) ] ,
288372 `test_${ name . replace ( / \s + / g, '_' ) } .ogg`
289373 )
290- try {
291- const result = await getOggMetadata ( file )
374+ await expect ( getOggMetadata ( file ) ) . resolves . toSatisfy ( ( result ) => {
292375 if ( expectedPrompt ) {
293- expect ( result . prompt ) . toEqual ( expectedPrompt ) // either undefined or { valid: true }
376+ expect ( result . prompt ) . toEqual ( expectedPrompt )
294377 } else {
295378 expect ( result . prompt ) . toBeUndefined ( )
296379 }
297380 expect ( result . workflow ) . toBeUndefined ( )
298- } catch ( e ) {
299- // Handled via thrown exception
300- expect ( e ) . toBeInstanceOf ( Error )
301- }
381+ return true
382+ } )
302383 } )
303384 }
304385 } )
0 commit comments