@mindfulauth/core 1.1.0 → 1.2.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.
package/dist/config.d.ts CHANGED
@@ -59,6 +59,11 @@ export declare function getMauthViteDefines(options?: {
59
59
  /**
60
60
  * Get security headers with CSP sources merged from defaults and build-time
61
61
  * custom values injected via vite.define (from getMauthViteDefines()).
62
+ *
63
+ * Pass the per-request `nonce` generated by `generateNonce()` so the
64
+ * Content-Security-Policy includes `'nonce-<value>'` in `script-src`.
65
+ * The same nonce must be set as the `nonce` attribute on every inline
66
+ * `<script>` tag (available via `Astro.locals.cspNonce` in layouts).
62
67
  */
63
- export declare function GET_SECURITY_HEADERS(): Record<string, string>;
68
+ export declare function GET_SECURITY_HEADERS(nonce?: string): Record<string, string>;
64
69
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,mBAAmB,gCAAgC,CAAC;AACjE,eAAO,MAAM,UAAU,gCAAgC,CAAC;AAGxD,eAAO,MAAM,oBAAoB,UAAkB,CAAC;AACpD,eAAO,MAAM,mBAAmB,UAAU,CAAC;AAC3C,eAAO,MAAM,qBAAqB,QAAQ,CAAC;AAC3C,eAAO,MAAM,6BAA6B,QAAQ,CAAC;AAenD;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C;AAID,eAAO,MAAM,aAAa,UAQzB,CAAC;AAIF,eAAO,MAAM,eAAe,UAO3B,CAAC;AAyCF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE;IAC1C,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,GAAG,CAAC,EAAE;QACF,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;KAC1B,CAAC;CACL,GAAG,OAAO,OAAO,CAEjB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE;IAC1C,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,GAAG,CAAC,EAAE;QACF,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;KAC1B,CAAC;CACL,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQzB;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA6C7D"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,mBAAmB,gCAAgC,CAAC;AACjE,eAAO,MAAM,UAAU,gCAAgC,CAAC;AAGxD,eAAO,MAAM,oBAAoB,UAAkB,CAAC;AACpD,eAAO,MAAM,mBAAmB,UAAU,CAAC;AAC3C,eAAO,MAAM,qBAAqB,QAAQ,CAAC;AAC3C,eAAO,MAAM,6BAA6B,QAAQ,CAAC;AAenD;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAE1C;AAID,eAAO,MAAM,aAAa,UAQzB,CAAC;AAIF,eAAO,MAAM,eAAe,UAO3B,CAAC;AA0CF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE;IAC1C,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,GAAG,CAAC,EAAE;QACF,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;KAC1B,CAAC;CACL,GAAG,OAAO,OAAO,CAEjB;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,CAAC,EAAE;IAC1C,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,GAAG,CAAC,EAAE;QACF,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;KAC1B,CAAC;CACL,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAiD3E"}
package/dist/config.js CHANGED
@@ -54,6 +54,7 @@ export const PUBLIC_PREFIXES = [
54
54
  const DEFAULT_SCRIPT_SOURCES = [
55
55
  "'self'",
56
56
  'https://*.cloudflare.com',
57
+ 'https://*.cloudflareinsights.com',
57
58
  'https://cdn.mindfulauth.com',
58
59
  'https://api.mindfulauth.com'
59
60
  ];
@@ -115,10 +116,19 @@ export function getMauthViteDefines(options) {
115
116
  /**
116
117
  * Get security headers with CSP sources merged from defaults and build-time
117
118
  * custom values injected via vite.define (from getMauthViteDefines()).
119
+ *
120
+ * Pass the per-request `nonce` generated by `generateNonce()` so the
121
+ * Content-Security-Policy includes `'nonce-<value>'` in `script-src`.
122
+ * The same nonce must be set as the `nonce` attribute on every inline
123
+ * `<script>` tag (available via `Astro.locals.cspNonce` in layouts).
118
124
  */
119
- export function GET_SECURITY_HEADERS() {
125
+ export function GET_SECURITY_HEADERS(nonce) {
120
126
  // Custom sources are baked in at build time via vite.define
121
- const SCRIPT_SOURCES = [...DEFAULT_SCRIPT_SOURCES, ...__MAUTH_SCRIPT_SOURCES__];
127
+ const SCRIPT_SOURCES = [
128
+ ...DEFAULT_SCRIPT_SOURCES,
129
+ ...__MAUTH_SCRIPT_SOURCES__,
130
+ ...(nonce ? [`'nonce-${nonce}'`] : []),
131
+ ];
122
132
  const CONNECT_SOURCES = [...DEFAULT_CONNECT_SOURCES, ...__MAUTH_CONNECT_SOURCES__];
123
133
  const FRAME_SOURCES = [...DEFAULT_FRAME_SOURCES, ...__MAUTH_FRAME_SOURCES__];
124
134
  const FONT_SOURCES = [...DEFAULT_FONT_SOURCES, ...__MAUTH_FONT_SOURCES__];
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAuBA,eAAO,MAAM,SAAS,mCA8DpB,CAAC"}
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAuBA,eAAO,MAAM,SAAS,mCAmEpB,CAAC"}
@@ -2,16 +2,16 @@
2
2
  // Runs before all route handlers to enforce authentication
3
3
  import { defineMiddleware } from 'astro:middleware';
4
4
  import { PUBLIC_ROUTES, PUBLIC_PREFIXES, GET_SECURITY_HEADERS, GET_SKIP_ASSETS } from './config';
5
- import { sanitizePath } from './security';
5
+ import { sanitizePath, generateNonce } from './security';
6
6
  import { validateSession, validateMemberIdInUrl } from './auth';
7
7
  /** Check if a path is a public route (no auth required) */
8
8
  function isPublicRoute(pathname) {
9
9
  return PUBLIC_ROUTES.includes(pathname) ||
10
10
  PUBLIC_PREFIXES.some(prefix => pathname.startsWith(prefix));
11
11
  }
12
- /** Add security headers to a response */
13
- function addSecurityHeaders(response) {
14
- Object.entries(GET_SECURITY_HEADERS()).forEach(([key, value]) => {
12
+ /** Add security headers (including CSP nonce) to a response */
13
+ function addSecurityHeaders(response, nonce) {
14
+ Object.entries(GET_SECURITY_HEADERS(nonce)).forEach(([key, value]) => {
15
15
  response.headers.set(key, value);
16
16
  });
17
17
  return response;
@@ -22,6 +22,10 @@ export const onRequest = defineMiddleware(async (context, next) => {
22
22
  const pathname = url.pathname;
23
23
  // Type assertion for locals (users should extend App.Locals in their project)
24
24
  const authLocals = locals;
25
+ // Generate a per-request nonce for CSP. Exposed as locals.cspNonce so
26
+ // layouts can add nonce={Astro.locals.cspNonce} to inline <script> tags.
27
+ const nonce = generateNonce();
28
+ authLocals.cspNonce = nonce;
25
29
  // Skip middleware for static assets FIRST (before dev mode)
26
30
  if (GET_SKIP_ASSETS().includes(pathname)) {
27
31
  return next();
@@ -46,7 +50,7 @@ export const onRequest = defineMiddleware(async (context, next) => {
46
50
  // Public routes - no auth needed
47
51
  if (isPublicRoute(safePath)) {
48
52
  authLocals.recordId = null;
49
- return addSecurityHeaders(await next());
53
+ return addSecurityHeaders(await next(), nonce);
50
54
  }
51
55
  // Protected route - validate session
52
56
  const internalApiKey = authLocals.runtime?.env?.INTERNAL_API_KEY || import.meta.env.INTERNAL_API_KEY;
@@ -68,5 +72,5 @@ export const onRequest = defineMiddleware(async (context, next) => {
68
72
  return new Response('Forbidden: Invalid user ID in URL', { status: 403 });
69
73
  }
70
74
  authLocals.recordId = session.recordId;
71
- return addSecurityHeaders(await next());
75
+ return addSecurityHeaders(await next(), nonce);
72
76
  });
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Generate a cryptographically secure random nonce for use in CSP headers.
3
+ * The same nonce must be added as a `nonce` attribute on every inline <script>
4
+ * tag so the browser allows it to execute.
5
+ */
6
+ export declare function generateNonce(): string;
1
7
  /** Sanitize endpoint path (prevents ../ traversal and encoded variants) */
2
8
  export declare function sanitizeEndpoint(endpoint: string): string | null;
3
9
  /** Sanitize URL path (prevents ../ traversal and encoded variants) */
@@ -1 +1 @@
1
- {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAkBA,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIhE;AAED,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI5D"}
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../src/security.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAItC;AAgBD,2EAA2E;AAC3E,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIhE;AAED,sEAAsE;AACtE,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI5D"}
package/dist/security.js CHANGED
@@ -1,5 +1,15 @@
1
- // Security utilities - path traversal prevention
1
+ // Security utilities - path traversal prevention, nonce generation
2
2
  const MAX_PATH_LENGTH = 2048;
3
+ /**
4
+ * Generate a cryptographically secure random nonce for use in CSP headers.
5
+ * The same nonce must be added as a `nonce` attribute on every inline <script>
6
+ * tag so the browser allows it to execute.
7
+ */
8
+ export function generateNonce() {
9
+ const bytes = new Uint8Array(16);
10
+ crypto.getRandomValues(bytes);
11
+ return btoa(String.fromCharCode(...bytes));
12
+ }
3
13
  /** Decode and check for traversal attacks */
4
14
  function decodeAndValidate(str) {
5
15
  if (!str || typeof str !== 'string' || str.length > MAX_PATH_LENGTH)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mindfulauth/core",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Mindful Auth core authentication library for Astro",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",