1919 EventEmitter = require ( "node:events" ) . EventEmitter ;
2020}
2121
22+ /** @type {import("@stablelib/xchacha20poly1305")? } */
2223let StableLib = null ;
24+ /** @type {import("@projectdysnomia/libsodium")? } */
2325let Sodium = null ;
26+ /** @type {import("node:crypto")? } */
2427let crypto = null ;
2528let aes256Available = false ;
2629
@@ -88,11 +91,11 @@ class VoiceConnection extends EventEmitter {
8891 ready = false ;
8992 reconnecting = false ;
9093 samplingRate = 48_000 ;
91- sendBuffer = Buffer . allocUnsafe ( 16 + 32 + MAX_FRAME_SIZE ) ;
92- sendHeader = Buffer . alloc ( 12 ) ;
9394
9495 #nonce = 0 ;
96+ /** @type {import("@projectdysnomia/libsodium").BufferPointer? } */
9597 #nonceBuffer = null ;
98+ /** @type {import("@stablelib/xchacha20poly1305").XChaCha20Poly1305? } */
9699 #stablelib = null ;
97100 sequence = 0 ;
98101 speaking = false ;
@@ -116,7 +119,7 @@ class VoiceConnection extends EventEmitter {
116119
117120 if ( ! Sodium && ! StableLib ) {
118121 try {
119- Sodium = require ( "sodium-native " ) ;
122+ Sodium = require ( "@projectdysnomia/libsodium " ) ;
120123 } catch {
121124 try {
122125 StableLib = require ( "@stablelib/xchacha20poly1305" ) ;
@@ -148,6 +151,9 @@ class VoiceConnection extends EventEmitter {
148151 this . opus = { } ;
149152 }
150153
154+ this . sendBuffer = this . #alloc( 16 + 32 + MAX_FRAME_SIZE , false ) ;
155+ this . sendHeader = this . #alloc( 12 ) ;
156+
151157 this . sendHeader [ 0 ] = 0x80 ;
152158 this . sendHeader [ 1 ] = 0x78 ;
153159
@@ -334,8 +340,8 @@ class VoiceConnection extends EventEmitter {
334340 }
335341 case VoiceOPCodes . SESSION_DESCRIPTION : {
336342 this . mode = packet . d . mode ;
337- this . secret = Buffer . from ( packet . d . secret_key ) ;
338- this . #nonceBuffer = Buffer . alloc ( this . mode === "aead_aes256_gcm_rtpsize" ? 12 : 24 ) ;
343+ this . secret = this . #transfer ( Buffer . from ( packet . d . secret_key ) ) ;
344+ this . #nonceBuffer = this . # alloc( this . mode === "aead_aes256_gcm_rtpsize" ? 12 : 24 ) ;
339345 if ( this . mode === "aead_xchacha20_poly1305_rtpsize" && StableLib ) {
340346 this . #stablelib = new StableLib . XChaCha20Poly1305 ( this . secret ) ;
341347 }
@@ -682,8 +688,8 @@ class VoiceConnection extends EventEmitter {
682688 const hasExtension = ! ! ( msg [ 0 ] & 0b10000 ) ;
683689 const hasPadding = ! ! ( msg [ 0 ] & 0b100000 ) ;
684690 const cc = msg [ 0 ] & 0b1111 ;
685- const nonce = Buffer . alloc ( this . mode === "aead_aes256_gcm_rtpsize" ? 12 : 24 ) ;
686- msg . copy ( nonce , 0 , msg . length - 4 , msg . length ) ;
691+ const nonce = this . # alloc( this . mode === "aead_aes256_gcm_rtpsize" ? 12 : 24 ) ;
692+ msg . copy ( nonce . buffer , 0 , msg . length - 4 , msg . length ) ;
687693
688694 // Header Size = Fixed Header Length + (CSRC Identifier Length * CSRC count) + Extension
689695 let headerSize = 12 + ( cc * 4 ) ;
@@ -693,23 +699,34 @@ class VoiceConnection extends EventEmitter {
693699
694700 let data ;
695701 if ( this . mode === "aead_aes256_gcm_rtpsize" ) {
696- const decipher = crypto . createDecipheriv ( "aes-256-gcm" , this . secret , nonce ) ;
702+ const decipher = crypto . createDecipheriv ( "aes-256-gcm" , this . secret . buffer , nonce . buffer ) ;
697703 decipher . setAAD ( msg . subarray ( 0 , headerSize ) ) ;
698704 decipher . setAuthTag ( msg . subarray ( msg . length - 20 , msg . length - 4 ) ) ;
699705 data = Buffer . concat ( [ decipher . update ( msg . subarray ( headerSize , msg . length - 20 ) ) , decipher . final ( ) ] ) ;
700706 } else if ( Sodium ) {
701- data = Buffer . alloc ( msg . length - ( headerSize + 4 ) - Sodium . crypto_aead_xchacha20poly1305_ietf_ABYTES ) ;
707+ const msgPtr = this . #transfer( msg ) ;
708+ const d = this . #alloc( msg . length - ( headerSize + 4 ) - Sodium . crypto_aead_xchacha20poly1305_ietf_ABYTES ) ;
702709 Sodium . crypto_aead_xchacha20poly1305_ietf_decrypt (
703- data ,
710+ d ,
704711 null ,
705- msg . subarray ( headerSize , msg . length - 4 ) ,
706- msg . subarray ( 0 , headerSize ) ,
712+ msgPtr . subarray ( headerSize , msg . length - 4 ) ,
713+ msgPtr . subarray ( 0 , headerSize ) ,
707714 nonce ,
708715 this . secret
709716 ) ;
717+
718+ if ( Sodium . native ) {
719+ data = d . buffer ;
720+ } else {
721+ // The Buffer instance isn't guaranteed to be stable when in WASM, therefore a full copy is needed
722+ data = Buffer . from ( d . buffer ) ;
723+ }
724+
725+ msgPtr . free ( ) ;
726+ d . free ( ) ;
710727 } else if ( this . #stablelib) {
711728 data = this . #stablelib. open (
712- nonce ,
729+ nonce . buffer ,
713730 msg . subarray ( headerSize , msg . length - 4 ) ,
714731 msg . subarray ( 0 , headerSize )
715732 ) ;
@@ -945,26 +962,26 @@ class VoiceConnection extends EventEmitter {
945962 }
946963
947964 _sendAudioFrame ( frame ) {
948- const headerSize = this . sendHeader . length ;
949- this . sendHeader . writeUInt16BE ( this . sequence , 2 ) ;
950- this . sendHeader . writeUInt32BE ( this . timestamp , 4 ) ;
965+ const headerSize = this . sendHeader . buffer ;
966+ this . sendHeader . buffer . writeUInt16BE ( this . sequence , 2 ) ;
967+ this . sendHeader . buffer . writeUInt32BE ( this . timestamp , 4 ) ;
951968
952969 this . #nonce = ( this . #nonce + 1 ) >>> 0 ;
953- this . #nonceBuffer. writeUInt32BE ( this . #nonce, 0 ) ;
970+ this . #nonceBuffer. buffer . writeUInt32BE ( this . #nonce, 0 ) ;
954971
955972 if ( this . mode === "aead_aes256_gcm_rtpsize" ) {
956- const cipher = crypto . createCipheriv ( "aes-256-gcm" , this . secret , this . #nonceBuffer) ;
957- cipher . setAAD ( this . sendHeader ) ;
973+ const cipher = crypto . createCipheriv ( "aes-256-gcm" , this . secret . buffer , this . #nonceBuffer. buffer ) ;
974+ cipher . setAAD ( this . sendHeader . buffer ) ;
958975 const result = Buffer . concat ( [ cipher . update ( frame ) , cipher . final ( ) , cipher . getAuthTag ( ) ] ) ;
959- this . sendHeader . copy ( this . sendBuffer , 0 , 0 , headerSize ) ;
960- result . copy ( this . sendBuffer , headerSize ) ;
961- this . #nonceBuffer. copy ( this . sendBuffer , headerSize + result . length , 0 , 4 ) ; // nonce padding
962- return this . sendUDPPacket ( this . sendBuffer . subarray ( 0 , headerSize + result . length + 4 ) ) ;
976+ this . sendHeader . buffer . copy ( this . sendBuffer . buffer , 0 , 0 , headerSize ) ;
977+ result . copy ( this . sendBuffer . buffer , headerSize ) ;
978+ this . #nonceBuffer. buffer . copy ( this . sendBuffer . buffer , headerSize + result . length , 0 , 4 ) ; // nonce padding
979+ return this . sendUDPPacket ( this . sendBuffer . subarray ( 0 , headerSize + result . length + 4 ) . buffer ) ;
963980 } else if ( Sodium ) {
964981 const ABYTES = Sodium . crypto_aead_xchacha20poly1305_ietf_ABYTES ;
965982 const length = frame . length + ABYTES ;
966- this . sendBuffer . fill ( 0 , headerSize + frame . length , headerSize + frame . length + ABYTES ) ;
967- frame . copy ( this . sendBuffer , headerSize ) ;
983+ this . sendBuffer . buffer . fill ( 0 , headerSize + frame . length , headerSize + frame . length + ABYTES ) ;
984+ frame . copy ( this . sendBuffer . buffer , headerSize ) ;
968985 Sodium . crypto_aead_xchacha20poly1305_ietf_encrypt (
969986 this . sendBuffer . subarray ( headerSize , headerSize + length ) ,
970987 this . sendBuffer . subarray ( headerSize , headerSize + frame . length ) ,
@@ -973,24 +990,57 @@ class VoiceConnection extends EventEmitter {
973990 this . #nonceBuffer,
974991 this . secret
975992 ) ;
976- this . sendHeader . copy ( this . sendBuffer , 0 , 0 , headerSize ) ;
977- this . #nonceBuffer. copy ( this . sendBuffer , headerSize + length , 0 , 4 ) ; // nonce padding
978- return this . sendUDPPacket ( this . sendBuffer . subarray ( 0 , headerSize + length + 4 ) ) ;
993+ this . sendHeader . buffer . copy ( this . sendBuffer , 0 , 0 , headerSize ) ;
994+ this . #nonceBuffer. buffer . copy ( this . sendBuffer , headerSize + length , 0 , 4 ) ; // nonce padding
995+ return this . sendUDPPacket ( this . sendBuffer . subarray ( 0 , headerSize + length + 4 ) . buffer ) ;
979996 } else if ( this . #stablelib) {
980997 const length = frame . length + StableLib . TAG_LENGTH ;
981998 this . sendBuffer . fill ( 0 , headerSize + frame . length , headerSize + length ) ;
982999 this . #stablelib. seal (
983- this . #nonceBuffer,
1000+ this . #nonceBuffer. buffer ,
9841001 frame ,
985- this . sendHeader ,
986- this . sendBuffer . subarray ( headerSize , headerSize + length )
1002+ this . sendHeader . buffer ,
1003+ this . sendBuffer . subarray ( headerSize , headerSize + length ) . buffer
9871004 ) ;
988- this . sendHeader . copy ( this . sendBuffer , 0 , 0 , headerSize ) ;
989- this . #nonceBuffer. copy ( this . sendBuffer , headerSize + length , 0 , 4 ) ; // nonce padding
990- return this . sendUDPPacket ( this . sendBuffer . subarray ( 0 , headerSize + length + 4 ) ) ;
1005+ this . sendHeader . buffer . copy ( this . sendBuffer . buffer , 0 , 0 , headerSize ) ;
1006+ this . #nonceBuffer. buffer . copy ( this . sendBuffer . buffer , headerSize + length , 0 , 4 ) ; // nonce padding
1007+ return this . sendUDPPacket ( this . sendBuffer . subarray ( 0 , headerSize + length + 4 ) . buffer ) ;
9911008 }
9921009 }
9931010
1011+ /** @param {Buffer } buf */
1012+ #transfer( buf ) {
1013+ if ( Sodium ) {
1014+ return Sodium . transfer ( buf ) ;
1015+ } else {
1016+ return this . #makeBufferPointer( buf ) ;
1017+ }
1018+ }
1019+
1020+ /**
1021+ * @param {Number } size
1022+ * @param {Boolean } safe
1023+ */
1024+ #alloc( size , safe = true ) {
1025+ if ( Sodium ) {
1026+ return Sodium . alloc ( size , safe ) ;
1027+ } else {
1028+ return this . #makeBufferPointer( Buffer [ safe ? "alloc" : "allocUnsafe" ] ( size ) ) ;
1029+ }
1030+ }
1031+
1032+ /** @param {Buffer } buf */
1033+ #makeBufferPointer( buf ) {
1034+ // Keep in sync with BufferPointer in @projectdysnomia /libsodium to maintain compatibility
1035+ return {
1036+ buffer : buf ,
1037+ free : ( ) => { } ,
1038+ subarray : ( start , end ) => {
1039+ return this . #makeBufferPointer( buf . subarray ( start , end ) ) ;
1040+ }
1041+ } ;
1042+ }
1043+
9941044 [ util . inspect . custom ] ( ) {
9951045 return Base . prototype [ util . inspect . custom ] . call ( this ) ;
9961046 }
0 commit comments