iframe.io 1.0.6 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "iframe.io",
3
- "version": "1.0.6",
3
+ "version": "1.2.0",
4
4
  "description": "Easy and friendly API to connect and interact between content window and its containing iframe",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -45,5 +45,5 @@
45
45
  "events",
46
46
  "io"
47
47
  ],
48
- "author": "Fabrice K.M.E"
48
+ "author": "Fabrice K.E.M"
49
49
  }
package/src/index.ts CHANGED
@@ -12,6 +12,16 @@ export type Options = {
12
12
  maxMessagesPerSecond?: number
13
13
  autoReconnect?: boolean
14
14
  messageQueueSize?: number
15
+ /**
16
+ * Optional allowlist of incoming application-level events.
17
+ * Reserved internal events (ping/pong/heartbeats) are always allowed.
18
+ */
19
+ allowedIncomingEvents?: string[]
20
+ /**
21
+ * Optional custom validator for incoming messages.
22
+ * Return false to drop a message; an 'error' event will be emitted.
23
+ */
24
+ validateIncoming?: ( event: string, payload: any, origin: string ) => boolean
15
25
  }
16
26
 
17
27
  export interface RegisteredEvents {
@@ -68,13 +78,32 @@ function sanitizePayload( payload: any, maxSize: number ): any {
68
78
  }
69
79
 
70
80
  const ackId = () => {
81
+ // Prefer cryptographically strong randomness when available
82
+ try {
83
+ const globalCrypto = (typeof crypto !== 'undefined'
84
+ ? crypto
85
+ : (typeof window !== 'undefined' && (window as any).crypto)
86
+ || (typeof globalThis !== 'undefined' && (globalThis as any).crypto))
87
+
88
+ if( globalCrypto && typeof globalCrypto.getRandomValues === 'function' ){
89
+ const buffer = new Uint32Array(4)
90
+ globalCrypto.getRandomValues( buffer )
91
+
92
+ const randomPart = Array.from( buffer ).map( n => n.toString( 16 ) ).join('')
93
+ return `${Date.now()}_${randomPart}`
94
+ }
95
+ }
96
+ catch{
97
+ // Fall back to Math.random-based implementation below
98
+ }
99
+
71
100
  const
72
101
  rmin = 100000,
73
102
  rmax = 999999,
74
- timestamp = Date.now(),
75
- random = Math.floor( Math.random() * ( rmax - rmin + 1 ) + rmin )
103
+ timestampFallback = Date.now(),
104
+ randomFallback = Math.floor( Math.random() * ( rmax - rmin + 1 ) + rmin )
76
105
 
77
- return `${timestamp}_${random}`
106
+ return `${timestampFallback}_${randomFallback}`
78
107
  }
79
108
 
80
109
  const RESERVED_EVENTS = [
@@ -89,8 +118,8 @@ export default class IOF {
89
118
  peer: Peer
90
119
  options: Options
91
120
  private messageListener?: ( event: MessageEvent ) => void
92
- private heartbeatTimer?: NodeJS.Timeout
93
- private reconnectTimer?: NodeJS.Timeout
121
+ private heartbeatTimer?: number
122
+ private reconnectTimer?: number
94
123
  private messageQueue: QueuedMessage[] = []
95
124
  private messageRateTracker: number[] = []
96
125
  private reconnectAttempts: number = 0
@@ -312,11 +341,38 @@ export default class IOF {
312
341
  this.peer.connected = true
313
342
  this.reconnectAttempts = 0
314
343
  this.peer.lastHeartbeat = Date.now()
344
+
315
345
  this.startHeartbeat()
316
346
  this.fire('connect')
317
347
  this.processMessageQueue()
348
+ this.debug(`[${this.peer.type}] connected`)
318
349
 
319
- return this.debug(`[${this.peer.type}] connected`)
350
+ return
351
+ }
352
+
353
+ // Optional application-level incoming validation (non-reserved events only)
354
+ if( !RESERVED_EVENTS.includes( _event ) ){
355
+ if( this.options.allowedIncomingEvents
356
+ && !this.options.allowedIncomingEvents.includes( _event ) ){
357
+ this.fire('error', {
358
+ type: 'DISALLOWED_EVENT',
359
+ direction: 'incoming',
360
+ event: _event,
361
+ origin
362
+ })
363
+ return
364
+ }
365
+
366
+ if( this.options.validateIncoming
367
+ && !this.options.validateIncoming( _event, payload, origin ) ){
368
+ this.fire('error', {
369
+ type: 'INVALID_MESSAGE',
370
+ direction: 'incoming',
371
+ event: _event,
372
+ origin
373
+ })
374
+ return
375
+ }
320
376
  }
321
377
 
322
378
  // Fire available event listeners
@@ -347,6 +403,7 @@ export default class IOF {
347
403
  this.peer.type = 'IFRAME' // iframe.io connection listener is automatically set as IFRAME
348
404
  this.peer.connected = false
349
405
  this.reconnectAttempts = 0
406
+
350
407
  this.debug(`[${this.peer.type}] Listening to connect${hostOrigin ? `: Host <${hostOrigin}>` : ''}`)
351
408
 
352
409
  // Clean up existing listener if any
@@ -414,7 +471,8 @@ export default class IOF {
414
471
  this.fire('connect')
415
472
  this.processMessageQueue()
416
473
 
417
- return this.debug(`[${this.peer.type}] connected`)
474
+ this.debug(`[${this.peer.type}] connected`)
475
+ return
418
476
  }
419
477
 
420
478
  // Fire available event listeners
@@ -437,8 +495,10 @@ export default class IOF {
437
495
 
438
496
  fire( _event: string, payload?: MessageData['payload'], cid?: string ){
439
497
  // Volatile event - check if any listeners exist
440
- if( !this.Events[_event] && !this.Events[_event + '--@once'] )
441
- return this.debug(`[${this.peer.type}] No <${_event}> listener defined`)
498
+ if( !this.Events[_event] && !this.Events[_event + '--@once'] ){
499
+ this.debug(`[${this.peer.type}] No <${_event}> listener defined`)
500
+ return
501
+ }
442
502
 
443
503
  const ackFn = cid
444
504
  ? ( error: boolean | string, ...args: any[] ): void => {
@@ -590,7 +650,7 @@ export default class IOF {
590
650
  return new Promise(( resolve, reject ) => {
591
651
  const timeoutId = setTimeout(() => {
592
652
  reject( new Error(`Event '${_event}' acknowledgment timeout after ${timeout}ms`) )
593
- }, timeout)
653
+ }, timeout )
594
654
 
595
655
  try {
596
656
  this.emit( _event, payload, ( error, ...args ) => {
@@ -646,7 +706,7 @@ export default class IOF {
646
706
  }
647
707
 
648
708
  disconnect( fn?: () => void ){
649
- // Clean disconnect method
709
+ // Cleanup on disconnect
650
710
  this.cleanup()
651
711
 
652
712
  this.peer.connected = false
@@ -656,6 +716,7 @@ export default class IOF {
656
716
  this.messageQueue = []
657
717
  this.messageRateTracker = []
658
718
  this.reconnectAttempts = 0
719
+
659
720
  this.removeListeners()
660
721
 
661
722
  typeof fn == 'function' && fn()