@pasko70/pibo 1.3.1 → 1.3.2

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.
@@ -61,7 +61,23 @@ export function isLoopbackDevAuthRequest(request) {
61
61
  const forwardedHost = firstHeaderValue(request.headers.get("x-forwarded-host"));
62
62
  return isLoopbackHost(host) && (!forwardedHost || isLoopbackHost(forwardedHost));
63
63
  }
64
- function createDevAuthService() {
64
+ /**
65
+ * Headers-only variants of the loopback predicates so `getSession` can
66
+ * evaluate the same checks without holding on to the full `Request`
67
+ * object. `getSession` is part of the auth service contract and only
68
+ * receives `headers`, but the channel guarantees that the same
69
+ * `host`, `x-forwarded-host`, and `x-pibo-socket-peer` headers are
70
+ * present as they would be on a full `Request`.
71
+ */
72
+ export function isLoopbackDevAuthHeaders(headers) {
73
+ const host = firstHeaderValue(headers.get("host"));
74
+ const forwardedHost = firstHeaderValue(headers.get("x-forwarded-host"));
75
+ return isLoopbackHost(host) && (!forwardedHost || isLoopbackHost(forwardedHost));
76
+ }
77
+ export function isLoopbackSocketPeerForDevAuthHeaders(headers) {
78
+ return isLoopbackSocketAddress(firstHeaderValue(headers.get(SOCKET_PEER_HEADER)));
79
+ }
80
+ export function createDevAuthService() {
65
81
  const containerToken = generateToken();
66
82
  const debugSession = {
67
83
  identity: {
@@ -81,6 +97,16 @@ function createDevAuthService() {
81
97
  },
82
98
  stop() { },
83
99
  async getSession(headers) {
100
+ // In local auth mode the loopback bind is the real security
101
+ // boundary. Once the channel has confirmed that the request
102
+ // reached us from a loopback host and a loopback TCP socket
103
+ // peer, the caller is on the same host as the gateway and
104
+ // there is no cookie jar to share. Headless clients (VS Code
105
+ // extension, CLI scripts) can use the same dev identity as the
106
+ // browser without needing the HttpOnly session cookie.
107
+ if (isLoopbackDevAuthHeaders(headers) && isLoopbackSocketPeerForDevAuthHeaders(headers)) {
108
+ return debugSession;
109
+ }
84
110
  const token = getCookieValue(headers);
85
111
  if (token === containerToken)
86
112
  return debugSession;
@@ -188,7 +188,13 @@ export function createWebHostChannel(options = {}) {
188
188
  const handleRequest = async (nodeRequest, nodeResponse) => {
189
189
  try {
190
190
  const baseURL = createRequestBaseURL(nodeRequest, host, port);
191
- const request = await nodeRequestToWebRequest(nodeRequest, baseURL);
191
+ const baseRequest = await nodeRequestToWebRequest(nodeRequest, baseURL);
192
+ // Inject the TCP socket peer into every request so the local auth
193
+ // plugin can apply the same loopback predicate from `getSession`
194
+ // regardless of whether the call came from a browser cookie, the
195
+ // VS Code extension, or a CLI script. The header is stripped from
196
+ // any outgoing response by `stripSocketPeerHeaderFromResponse`.
197
+ const request = withSocketPeerHeader(baseRequest, nodeRequest.socket.remoteAddress);
192
198
  const url = new URL(request.url);
193
199
  const canonicalRedirect = createCanonicalRedirect(request, options.canonicalBaseURL);
194
200
  if (canonicalRedirect) {
@@ -207,8 +213,7 @@ export function createWebHostChannel(options = {}) {
207
213
  return;
208
214
  }
209
215
  if (url.pathname.startsWith("/api/auth/")) {
210
- const authRequest = withSocketPeerHeader(request, nodeRequest.socket.remoteAddress);
211
- const authResponse = stripSocketPeerHeaderFromResponse(await handleAuthRequest(authRequest));
216
+ const authResponse = stripSocketPeerHeaderFromResponse(await handleAuthRequest(request));
212
217
  await sendWebResponse(nodeResponse, authResponse);
213
218
  return;
214
219
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pasko70/pibo",
3
- "version": "1.3.1",
3
+ "version": "1.3.2",
4
4
  "type": "module",
5
5
  "description": "Minimal TypeScript wrapper around Pi Coding Agent.",
6
6
  "files": [