@expo/serve-sim 0.3.2 → 0.3.3

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": "@expo/serve-sim",
3
- "version": "0.3.2",
3
+ "version": "0.3.3",
4
4
  "type": "module",
5
5
  "author": {
6
6
  "name": "Evan Bacon",
package/src/middleware.ts CHANGED
@@ -24,7 +24,12 @@ import {
24
24
  peekDeviceSession,
25
25
  type HidSocket,
26
26
  } from "./device-session";
27
- import { assertPreviewAccess, assertUpgradeAccess } from "./session-auth";
27
+ import {
28
+ acceptedTokenSubprotocol,
29
+ assertPreviewAccess,
30
+ assertUpgradeAccess,
31
+ upgradeAuthHeaders,
32
+ } from "./session-auth";
28
33
  import {
29
34
  eventLogEventForAction,
30
35
  readEventLog,
@@ -654,26 +659,35 @@ function webSocketBinary(payload: Buffer<ArrayBufferLike>): Uint8Array<ArrayBuff
654
659
  * handshake doesn't flush under Bun). Writes the 101 response and resumes the
655
660
  * socket on success; on a missing key writes 400 and returns false.
656
661
  */
657
- function writeWebSocketAccept(req: SimReq, socket: Socket): boolean {
662
+ function writeWebSocketAccept(req: SimReq, socket: Socket, execToken: string): boolean {
658
663
  const key = req.headers["sec-websocket-key"];
659
664
  if (typeof key !== "string") {
660
665
  socket.end("HTTP/1.1 400 Bad Request\r\n\r\n");
661
666
  return false;
662
667
  }
663
668
  const accept = createHash("sha1").update(key + WS_ACCEPT_GUID).digest("base64");
669
+ // A client that offered subprotocols fails the handshake unless one is named back.
670
+ const subprotocol = acceptedTokenSubprotocol(req.headers, execToken);
664
671
  socket.write(
665
672
  "HTTP/1.1 101 Switching Protocols\r\n" +
666
673
  "Upgrade: websocket\r\n" +
667
674
  "Connection: Upgrade\r\n" +
668
675
  `Sec-WebSocket-Accept: ${accept}\r\n` +
676
+ (subprotocol ? `Sec-WebSocket-Protocol: ${subprotocol}\r\n` : "") +
669
677
  "\r\n",
670
678
  );
671
679
  socket.resume();
672
680
  return true;
673
681
  }
674
682
 
675
- function bridgeWebSocketFrames(req: SimReq, socket: Socket, head: Buffer, upstreamUrl: string): void {
676
- if (!writeWebSocketAccept(req, socket)) return;
683
+ function bridgeWebSocketFrames(
684
+ req: SimReq,
685
+ socket: Socket,
686
+ head: Buffer,
687
+ upstreamUrl: string,
688
+ execToken: string,
689
+ ): void {
690
+ if (!writeWebSocketAccept(req, socket, execToken)) return;
677
691
 
678
692
  const upstream = new WebSocket(upstreamUrl);
679
693
  upstream.binaryType = "arraybuffer";
@@ -971,6 +985,7 @@ function rawHidSocket(socket: Socket, head: Buffer): HidSocket {
971
985
  function attachHidInProcess(
972
986
  req: SimReq,
973
987
  socket: Socket,
988
+ execToken: string,
974
989
  head: Buffer,
975
990
  device: string | null,
976
991
  initialStreamSettings?: StreamSettings,
@@ -982,7 +997,7 @@ function attachHidInProcess(
982
997
  } catch {
983
998
  return false;
984
999
  }
985
- if (!writeWebSocketAccept(req, socket)) return true; // bad request handled
1000
+ if (!writeWebSocketAccept(req, socket, execToken)) return true; // bad request handled
986
1001
  session.attachHidSocket(rawHidSocket(socket, head));
987
1002
  return true;
988
1003
  }
@@ -2665,13 +2680,7 @@ export function simMiddleware(options?: SimMiddlewareOptions): SimMiddleware {
2665
2680
  // their own, so gate them here too.
2666
2681
  if (
2667
2682
  !assertUpgradeAccess(
2668
- {
2669
- authorization: req.headers.authorization,
2670
- cookie: req.headers.cookie,
2671
- origin: req.headers.origin,
2672
- host: req.headers.host,
2673
- "sec-fetch-site": req.headers["sec-fetch-site"],
2674
- },
2683
+ upgradeAuthHeaders(req.headers),
2675
2684
  execToken,
2676
2685
  { required: requirePreviewToken },
2677
2686
  )
@@ -2687,7 +2696,13 @@ export function simMiddleware(options?: SimMiddlewareOptions): SimMiddleware {
2687
2696
  (async () => {
2688
2697
  try {
2689
2698
  const bridge = await getInspectWebKitBridge();
2690
- bridgeWebSocketFrames(req, socket, head, `ws://127.0.0.1:${bridge.port}${devtoolsTarget.upstreamPath}`);
2699
+ bridgeWebSocketFrames(
2700
+ req,
2701
+ socket,
2702
+ head,
2703
+ `ws://127.0.0.1:${bridge.port}${devtoolsTarget.upstreamPath}`,
2704
+ execToken,
2705
+ );
2691
2706
  } catch (err) {
2692
2707
  const message = err instanceof Error ? err.message : "Failed to start inspect-webkit";
2693
2708
  socket.end(`HTTP/1.1 502 Bad Gateway\r\nContent-Type: text/plain; charset=utf-8\r\n\r\n${message}`);
@@ -2702,7 +2717,7 @@ export function simMiddleware(options?: SimMiddlewareOptions): SimMiddleware {
2702
2717
  const device = helperTarget.device ?? selectedDevice;
2703
2718
  if (helperTarget.upstreamPath === "/ws") {
2704
2719
  // HID input is delivered to the in-process DeviceSession.
2705
- if (attachHidInProcess(req, socket, head, device, streamSettings)) return;
2720
+ if (attachHidInProcess(req, socket, execToken, head, device, streamSettings)) return;
2706
2721
  socket.end("HTTP/1.1 404 Not Found\r\n\r\n");
2707
2722
  return;
2708
2723
  }
@@ -2717,6 +2732,7 @@ export function simMiddleware(options?: SimMiddlewareOptions): SimMiddleware {
2717
2732
  const execWebSocketHandler = createExecWebSocketHandler({
2718
2733
  path: `${base}/exec-ws`,
2719
2734
  execToken,
2735
+ corsOrigins,
2720
2736
  ssePrefixes: [
2721
2737
  `${base}/api/events`,
2722
2738
  `${base}/api/event-log/events`,
@@ -2740,17 +2756,14 @@ export function simMiddleware(options?: SimMiddlewareOptions): SimMiddleware {
2740
2756
  });
2741
2757
 
2742
2758
  fetchMiddleware.handleWebSocket = (request: Request, websocket: UpgradeHandlerWebSocket): boolean => {
2759
+ // Before any refusal below can close it: an unhandled error from a peer that keeps sending
2760
+ // would exit the process.
2761
+ websocket.on("error", () => websocket.close());
2743
2762
  // Embedded hosts forward accepted sockets and bypass the request gate. The exec channel
2744
- // re-checks the token in its first frame; the helper HID socket does not.
2763
+ // re-checks the token itself; the helper HID socket does not.
2745
2764
  if (
2746
2765
  !assertUpgradeAccess(
2747
- {
2748
- authorization: request.headers.get("authorization") ?? undefined,
2749
- cookie: request.headers.get("cookie") ?? undefined,
2750
- origin: request.headers.get("origin") ?? undefined,
2751
- host: request.headers.get("host") ?? undefined,
2752
- "sec-fetch-site": request.headers.get("sec-fetch-site") ?? undefined,
2753
- },
2766
+ upgradeAuthHeaders(request),
2754
2767
  execToken,
2755
2768
  { required: requirePreviewToken },
2756
2769
  )