@@ -115,6 +115,34 @@ async function withTrustedProxyBrowserWs(origin: string, run: (ws: WebSocket) =>
115115 } ) ;
116116}
117117
118+ async function expectBrowserOriginConnectRejected ( params : {
119+ client ?: {
120+ id : string ;
121+ version : string ;
122+ platform : string ;
123+ mode : string ;
124+ } ;
125+ } ) {
126+ testState . gatewayAuth = { mode : "token" , token : "secret" } ;
127+ await withGatewayServer ( async ( { port } ) => {
128+ const ws = await openWs ( port , { origin : "https://attacker.example" } ) ;
129+ try {
130+ const res = await connectReq ( ws , {
131+ token : "secret" ,
132+ client : params . client ?? TEST_OPERATOR_CLIENT ,
133+ ...( params . client ? { device : null } : { } ) ,
134+ } ) ;
135+ expect ( res . ok ) . toBe ( false ) ;
136+ expect ( res . error ?. message ?? "" ) . toContain ( "origin not allowed" ) ;
137+ expect ( ( res . error ?. details as { code ?: string } | undefined ) ?. code ) . toBe (
138+ ConnectErrorDetailCodes . CONTROL_UI_ORIGIN_NOT_ALLOWED ,
139+ ) ;
140+ } finally {
141+ ws . close ( ) ;
142+ }
143+ } ) ;
144+ }
145+
118146describe ( "gateway auth browser hardening" , ( ) => {
119147 test ( "rejects trusted-proxy browser connects from origins outside the allowlist" , async ( ) => {
120148 await withTrustedProxyBrowserWs ( "https://evil.example" , async ( ws ) => {
@@ -205,48 +233,17 @@ describe("gateway auth browser hardening", () => {
205233 ) ;
206234
207235 test ( "rejects non-local browser origins for non-control-ui clients" , async ( ) => {
208- testState . gatewayAuth = { mode : "token" , token : "secret" } ;
209- await withGatewayServer ( async ( { port } ) => {
210- const ws = await openWs ( port , { origin : "https://attacker.example" } ) ;
211- try {
212- const res = await connectReq ( ws , {
213- token : "secret" ,
214- client : TEST_OPERATOR_CLIENT ,
215- } ) ;
216- expect ( res . ok ) . toBe ( false ) ;
217- expect ( res . error ?. message ?? "" ) . toContain ( "origin not allowed" ) ;
218- expect ( ( res . error ?. details as { code ?: string } | undefined ) ?. code ) . toBe (
219- ConnectErrorDetailCodes . CONTROL_UI_ORIGIN_NOT_ALLOWED ,
220- ) ;
221- } finally {
222- ws . close ( ) ;
223- }
224- } ) ;
236+ await expectBrowserOriginConnectRejected ( { } ) ;
225237 } ) ;
226238
227239 test ( "rejects browser-origin connects that claim to be tui clients" , async ( ) => {
228- testState . gatewayAuth = { mode : "token" , token : "secret" } ;
229- await withGatewayServer ( async ( { port } ) => {
230- const ws = await openWs ( port , { origin : "https://attacker.example" } ) ;
231- try {
232- const res = await connectReq ( ws , {
233- token : "secret" ,
234- client : {
235- id : GATEWAY_CLIENT_NAMES . TUI ,
236- version : "1.0.0" ,
237- platform : "darwin" ,
238- mode : GATEWAY_CLIENT_MODES . UI ,
239- } ,
240- device : null ,
241- } ) ;
242- expect ( res . ok ) . toBe ( false ) ;
243- expect ( res . error ?. message ?? "" ) . toContain ( "origin not allowed" ) ;
244- expect ( ( res . error ?. details as { code ?: string } | undefined ) ?. code ) . toBe (
245- ConnectErrorDetailCodes . CONTROL_UI_ORIGIN_NOT_ALLOWED ,
246- ) ;
247- } finally {
248- ws . close ( ) ;
249- }
240+ await expectBrowserOriginConnectRejected ( {
241+ client : {
242+ id : GATEWAY_CLIENT_NAMES . TUI ,
243+ version : "1.0.0" ,
244+ platform : "darwin" ,
245+ mode : GATEWAY_CLIENT_MODES . UI ,
246+ } ,
250247 } ) ;
251248 } ) ;
252249
0 commit comments