@grackle-ai/auth 0.107.1 → 0.108.0

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.
@@ -1,9 +1,7 @@
1
1
  import type { ServerResponse } from "node:http";
2
2
  /**
3
- * Content Security Policy for the web handler.
4
- *
5
- * Covers the React SPA (served from 'self') and server-rendered pages
6
- * (pairing/authorize) which use inline styles.
3
+ * Full CSP string with `form-action 'self'` — used by tests and as a
4
+ * backwards-compatible export.
7
5
  */
8
6
  export declare const WEB_CONTENT_SECURITY_POLICY: string;
9
7
  /**
@@ -12,6 +10,12 @@ export declare const WEB_CONTENT_SECURITY_POLICY: string;
12
10
  * Called at the top of `createWebHandler`'s returned function so that all
13
11
  * response paths (static files, HTML pages, JSON APIs, redirects) are covered
14
12
  * without modifying each `writeHead` call individually.
13
+ *
14
+ * @param res - The HTTP response to set headers on.
15
+ * @param requestHost - The `Host` header from the incoming request. When
16
+ * provided, the CSP `form-action` directive explicitly includes the
17
+ * request origin to work around a Chromium bug where `'self'` does not
18
+ * match form submissions on non-standard ports.
15
19
  */
16
- export declare function setSecurityHeaders(res: ServerResponse): void;
20
+ export declare function setSecurityHeaders(res: ServerResponse, requestHost?: string): void;
17
21
  //# sourceMappingURL=security-headers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../src/security-headers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,EAAE,MAW9B,CAAC;AAEb;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,cAAc,GAAG,IAAI,CAI5D"}
1
+ {"version":3,"file":"security-headers.d.ts","sourceRoot":"","sources":["../src/security-headers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAyBhD;;;GAGG;AACH,eAAO,MAAM,2BAA2B,EAAE,MAG9B,CAAC;AAEb;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,cAAc,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAoBlF"}
@@ -1,10 +1,15 @@
1
1
  /**
2
- * Content Security Policy for the web handler.
2
+ * Base Content Security Policy directives for the web handler.
3
3
  *
4
4
  * Covers the React SPA (served from 'self') and server-rendered pages
5
5
  * (pairing/authorize) which use inline styles.
6
+ *
7
+ * Note: `form-action` is intentionally omitted here and appended dynamically
8
+ * by {@link setSecurityHeaders} using the request's Host header, because
9
+ * Chromium does not reliably match `'self'` for form submissions on
10
+ * non-standard ports.
6
11
  */
7
- export const WEB_CONTENT_SECURITY_POLICY = [
12
+ const BASE_CSP_DIRECTIVES = [
8
13
  "default-src 'self'",
9
14
  "script-src 'self'",
10
15
  "style-src 'self' 'unsafe-inline'",
@@ -12,9 +17,16 @@ export const WEB_CONTENT_SECURITY_POLICY = [
12
17
  "font-src 'self'",
13
18
  "connect-src 'self'",
14
19
  "object-src 'none'",
15
- "form-action 'self'",
16
20
  "frame-ancestors 'none'",
17
21
  "base-uri 'self'",
22
+ ];
23
+ /**
24
+ * Full CSP string with `form-action 'self'` — used by tests and as a
25
+ * backwards-compatible export.
26
+ */
27
+ export const WEB_CONTENT_SECURITY_POLICY = [
28
+ ...BASE_CSP_DIRECTIVES,
29
+ "form-action 'self'",
18
30
  ].join("; ");
19
31
  /**
20
32
  * Set defense-in-depth security headers on every web response.
@@ -22,10 +34,33 @@ export const WEB_CONTENT_SECURITY_POLICY = [
22
34
  * Called at the top of `createWebHandler`'s returned function so that all
23
35
  * response paths (static files, HTML pages, JSON APIs, redirects) are covered
24
36
  * without modifying each `writeHead` call individually.
37
+ *
38
+ * @param res - The HTTP response to set headers on.
39
+ * @param requestHost - The `Host` header from the incoming request. When
40
+ * provided, the CSP `form-action` directive explicitly includes the
41
+ * request origin to work around a Chromium bug where `'self'` does not
42
+ * match form submissions on non-standard ports.
25
43
  */
26
- export function setSecurityHeaders(res) {
44
+ export function setSecurityHeaders(res, requestHost) {
27
45
  res.setHeader("X-Content-Type-Options", "nosniff");
28
46
  res.setHeader("X-Frame-Options", "DENY");
29
- res.setHeader("Content-Security-Policy", WEB_CONTENT_SECURITY_POLICY);
47
+ // Chromium does not reliably match 'self' or explicit origin+port for
48
+ // form-action on non-standard ports. Use the request hostname with a
49
+ // wildcard port so the form POST is allowed regardless of port.
50
+ // Validate via URL constructor to prevent CSP header injection (e.g. Host
51
+ // containing ';' could splice directives).
52
+ let formAction = "form-action 'self'";
53
+ if (requestHost) {
54
+ try {
55
+ const parsed = new URL(`http://${requestHost}`);
56
+ const hostname = parsed.hostname;
57
+ formAction = `form-action 'self' http://${hostname}:* https://${hostname}:*`;
58
+ }
59
+ catch {
60
+ // Malformed Host header — fall back to 'self' only
61
+ }
62
+ }
63
+ const csp = [...BASE_CSP_DIRECTIVES, formAction].join("; ");
64
+ res.setHeader("Content-Security-Policy", csp);
30
65
  }
31
66
  //# sourceMappingURL=security-headers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"security-headers.js","sourceRoot":"","sources":["../src/security-headers.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAW;IACjD,oBAAoB;IACpB,mBAAmB;IACnB,kCAAkC;IAClC,sBAAsB;IACtB,iBAAiB;IACjB,oBAAoB;IACpB,mBAAmB;IACnB,oBAAoB;IACpB,wBAAwB;IACxB,iBAAiB;CAClB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAmB;IACpD,GAAG,CAAC,SAAS,CAAC,wBAAwB,EAAE,SAAS,CAAC,CAAC;IACnD,GAAG,CAAC,SAAS,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;IACzC,GAAG,CAAC,SAAS,CAAC,yBAAyB,EAAE,2BAA2B,CAAC,CAAC;AACxE,CAAC"}
1
+ {"version":3,"file":"security-headers.js","sourceRoot":"","sources":["../src/security-headers.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;GAUG;AACH,MAAM,mBAAmB,GAAsB;IAC7C,oBAAoB;IACpB,mBAAmB;IACnB,kCAAkC;IAClC,sBAAsB;IACtB,iBAAiB;IACjB,oBAAoB;IACpB,mBAAmB;IACnB,wBAAwB;IACxB,iBAAiB;CAClB,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAW;IACjD,GAAG,mBAAmB;IACtB,oBAAoB;CACrB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAmB,EAAE,WAAoB;IAC1E,GAAG,CAAC,SAAS,CAAC,wBAAwB,EAAE,SAAS,CAAC,CAAC;IACnD,GAAG,CAAC,SAAS,CAAC,iBAAiB,EAAE,MAAM,CAAC,CAAC;IACzC,sEAAsE;IACtE,qEAAqE;IACrE,gEAAgE;IAChE,0EAA0E;IAC1E,2CAA2C;IAC3C,IAAI,UAAU,GAAG,oBAAoB,CAAC;IACtC,IAAI,WAAW,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,UAAU,WAAW,EAAE,CAAC,CAAC;YAChD,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;YACjC,UAAU,GAAG,6BAA6B,QAAQ,cAAc,QAAQ,IAAI,CAAC;QAC/E,CAAC;QAAC,MAAM,CAAC;YACP,mDAAmD;QACrD,CAAC;IACH,CAAC;IACD,MAAM,GAAG,GAAG,CAAC,GAAG,mBAAmB,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5D,GAAG,CAAC,SAAS,CAAC,yBAAyB,EAAE,GAAG,CAAC,CAAC;AAChD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grackle-ai/auth",
3
- "version": "0.107.1",
3
+ "version": "0.108.0",
4
4
  "description": "Authentication and authorization primitives for Grackle",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -29,7 +29,7 @@
29
29
  "dist/"
30
30
  ],
31
31
  "dependencies": {
32
- "@grackle-ai/common": "0.107.1"
32
+ "@grackle-ai/common": "0.108.0"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@rushstack/heft": "1.2.7",