1616/// WebSocket client connection
1717struct Client {
1818 conn : @socket .Tcp
19+ rand : @random .Rand
1920 mut closed : CloseCode?
2021}
2122
@@ -37,12 +38,22 @@ pub async fn Client::connect(
3738 port ? : Int = 80 ,
3839 headers ? : Map [String , String ] = {},
3940) -> Client {
41+ let seed = FixedArray ::make (32 , b '\x00 ' )
42+ if @tls .rand_bytes (seed , 32 ) != 1 {
43+ fail ("Failed to get random bytes for WebSocket client" )
44+ }
45+ let rand = @random .Rand ::chacha8 (seed = seed .unsafe_reinterpret_as_bytes ())
4046 // Connect TCP socket
4147 let addr = @socket .Addr ::parse ("\{ host } :\{ port } " )
4248 let conn = @socket .Tcp ::connect (addr )
4349
4450 // Send WebSocket handshake request
45- let key = "dGhlIHNhbXBsZSBub25jZQ==" // In production, generate random key
51+ let nonce = FixedArray ::make (16 , b '\x00 ' )
52+ nonce .unsafe_write_uint32_le (0 , rand .uint ())
53+ nonce .unsafe_write_uint32_le (4 , rand .uint ())
54+ nonce .unsafe_write_uint32_le (8 , rand .uint ())
55+ nonce .unsafe_write_uint32_le (12 , rand .uint ())
56+ let key = base64_encode (nonce .unsafe_reinterpret_as_bytes ())
4657 let request = "GET \{ path } HTTP/1.1\r\n "
4758 conn .write (request )
4859 conn .write ("Host: \{ host } \r\n " )
@@ -79,7 +90,7 @@ pub async fn Client::connect(
7990 "Server response does not contain websocket upgrade confirmation" ,
8091 )
8192 }
82- { conn , closed : None }
93+ { conn , closed : None , rand }
8394}
8495
8596///|
@@ -98,7 +109,13 @@ pub async fn Client::send_text(self : Client, text : String) -> Unit {
98109 raise ConnectionClosed (code )
99110 }
100111 let payload = @encoding/utf8 .encode (text )
101- write_frame (self .conn, true , OpCode ::Text , payload , true )
112+ write_frame (
113+ self .conn,
114+ true ,
115+ OpCode ::Text ,
116+ payload ,
117+ self .rand.int ().to_le_bytes (),
118+ )
102119}
103120
104121///|
@@ -107,7 +124,13 @@ pub async fn Client::send_binary(self : Client, data : Bytes) -> Unit {
107124 if self .closed is Some (code ) {
108125 raise ConnectionClosed (code )
109126 }
110- write_frame (self .conn, true , OpCode ::Binary , data , true )
127+ write_frame (
128+ self .conn,
129+ true ,
130+ OpCode ::Binary ,
131+ data ,
132+ self .rand.int ().to_le_bytes (),
133+ )
111134}
112135
113136///|
@@ -119,7 +142,13 @@ async fn Client::_ping(self : Client, data? : Bytes = Bytes::new(0)) -> Unit {
119142 if self .closed is Some (code ) {
120143 raise ConnectionClosed (code )
121144 }
122- write_frame (self .conn, true , OpCode ::Ping , data , true )
145+ write_frame (
146+ self .conn,
147+ true ,
148+ OpCode ::Ping ,
149+ data ,
150+ self .rand.int ().to_le_bytes (),
151+ )
123152}
124153
125154///|
@@ -130,7 +159,13 @@ async fn Client::pong(self : Client, data? : Bytes = Bytes::new(0)) -> Unit {
130159 if self .closed is Some (code ) {
131160 raise ConnectionClosed (code )
132161 }
133- write_frame (self .conn, true , OpCode ::Pong , data , true )
162+ write_frame (
163+ self .conn,
164+ true ,
165+ OpCode ::Pong ,
166+ data ,
167+ self .rand.int ().to_be_bytes (),
168+ )
134169}
135170
136171///|
0 commit comments