@mindfulauth/core 1.2.1 → 2.0.0-beta.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/README.md +2 -14
- package/dist/auth-handler.d.ts.map +1 -1
- package/dist/auth-handler.js +9 -2
- package/dist/config.d.ts +29 -10
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +90 -25
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/middleware.d.ts.map +1 -1
- package/dist/middleware.js +49 -14
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/package.json +6 -5
package/README.md
CHANGED
|
@@ -1,18 +1,6 @@
|
|
|
1
|
-
# @mindful-auth/core
|
|
1
|
+
# @mindful-auth/core - ASTRO 6 Beta
|
|
2
2
|
|
|
3
|
-
Core authentication library for Mindful Auth, designed for Astro applications.
|
|
4
|
-
|
|
5
|
-
Install Mindful Auth Astro template here https://docs.mindfulauth.com/guides/frontend/astro/astro-setup/
|
|
6
|
-
|
|
7
|
-
## Features
|
|
8
|
-
|
|
9
|
-
- 🔐 Session validation and management
|
|
10
|
-
- 🛡️ Security headers (CSP, HSTS, etc.)
|
|
11
|
-
- 🚦 Public/protected route handling
|
|
12
|
-
- 🔄 Auth proxy for login, registration, 2FA, etc.
|
|
13
|
-
- 🛠️ Path traversal protection
|
|
14
|
-
- ⚡ Built for Cloudflare Workers & Astro SSR
|
|
3
|
+
Core authentication library for Mindful Auth, designed for Astro 6 applications.
|
|
15
4
|
|
|
16
5
|
## License
|
|
17
|
-
|
|
18
6
|
MIT
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-handler.d.ts","sourceRoot":"","sources":["../src/auth-handler.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"auth-handler.d.ts","sourceRoot":"","sources":["../src/auth-handler.ts"],"names":[],"mappings":"AAwEA,2EAA2E;AAC3E,wBAAsB,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CA6BpH;AAED,gEAAgE;AAChE,wBAAsB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,CAyDrH"}
|
package/dist/auth-handler.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
// Auth proxy handler for Mindful Auth
|
|
2
2
|
// Forwards authentication requests to the central Mindful Auth service
|
|
3
|
+
//
|
|
4
|
+
// ASTRO 6 MIGRATION:
|
|
5
|
+
// - Astro v6 removed context.locals.runtime.env. Env vars now import from 'cloudflare:workers'.
|
|
6
|
+
// - Note: @cloudflare/workers-types must be installed and referenced in env.d.ts.
|
|
7
|
+
import { env } from 'cloudflare:workers';
|
|
3
8
|
import { CENTRAL_AUTH_ORIGIN, ALLOWED_AUTH_METHODS, MAX_BODY_SIZE_BYTES, AUTH_PROXY_TIMEOUT_MS } from './config';
|
|
4
9
|
import { sanitizeEndpoint } from './security';
|
|
5
10
|
const JSON_HEADERS = { 'Content-Type': 'application/json' };
|
|
@@ -60,7 +65,8 @@ function buildResponse(data, status, cookie) {
|
|
|
60
65
|
}
|
|
61
66
|
/** Handle GET requests (email verification, password reset links, etc.) */
|
|
62
67
|
export async function handleAuthGet(rawEndpoint, request, url, locals) {
|
|
63
|
-
|
|
68
|
+
// ASTRO 6 CHANGE: Environment variables accessed from 'cloudflare:workers' env directly.
|
|
69
|
+
const internalApiKey = env.INTERNAL_API_KEY || import.meta.env.INTERNAL_API_KEY;
|
|
64
70
|
if (!internalApiKey)
|
|
65
71
|
console.error('[auth-handler] INTERNAL_API_KEY not configured');
|
|
66
72
|
const endpoint = sanitizeEndpoint(rawEndpoint);
|
|
@@ -94,7 +100,8 @@ export async function handleAuthPost(rawEndpoint, request, url, locals) {
|
|
|
94
100
|
const contentLength = request.headers.get('content-length');
|
|
95
101
|
if (contentLength && parseInt(contentLength) > MAX_BODY_SIZE_BYTES)
|
|
96
102
|
return jsonError('Payload too large', 413);
|
|
97
|
-
|
|
103
|
+
// ASTRO 6 CHANGE: Environment variables accessed from 'cloudflare:workers' env directly.
|
|
104
|
+
const internalApiKey = env.INTERNAL_API_KEY || import.meta.env.INTERNAL_API_KEY;
|
|
98
105
|
if (!internalApiKey)
|
|
99
106
|
console.error('[auth-handler] INTERNAL_API_KEY not configured');
|
|
100
107
|
const endpoint = sanitizeEndpoint(rawEndpoint);
|
package/dist/config.d.ts
CHANGED
|
@@ -15,6 +15,10 @@ export declare const PUBLIC_PREFIXES: string[];
|
|
|
15
15
|
* Configure Mindful Auth security settings including CSP sources and static
|
|
16
16
|
* assets to skip. Returns the options to be passed to getMauthViteDefines().
|
|
17
17
|
*
|
|
18
|
+
* IMPORTANT: A nonce must be provided for inline styles to work. Without a nonce, inline styles will be blocked by CSP. If you need 'unsafe-inline' for development or testing, explicitly add it to styleSources in mauthSecurityConfig().
|
|
19
|
+
*
|
|
20
|
+
* IMPORTANT: Do not use Astro 6 security.csp in astro.config.mjs alongside this function. Astro's CSP will override these headers. Use mauthSecurityConfig() exclusively.
|
|
21
|
+
*
|
|
18
22
|
* Call in astro.config.mjs and pass the result to vite.define:
|
|
19
23
|
*
|
|
20
24
|
* @example
|
|
@@ -25,7 +29,15 @@ export declare const PUBLIC_PREFIXES: string[];
|
|
|
25
29
|
* scriptSources: ['https://analytics.example.com'],
|
|
26
30
|
* connectSources: ['https://api.example.com'],
|
|
27
31
|
* frameSources: ['https://stripe.com'],
|
|
28
|
-
* fontSources: ['https://fonts.googleapis.com']
|
|
32
|
+
* fontSources: ['https://fonts.googleapis.com'],
|
|
33
|
+
* styleSources: ['https://cdn.example.com/styles'],
|
|
34
|
+
* imageSources: ['https://images.example.com'],
|
|
35
|
+
* frameAncestors: ["'self'"],
|
|
36
|
+
* workerSources: ["'self'"],
|
|
37
|
+
* manifestSources: ["'self'"],
|
|
38
|
+
* objectSources: ["'none'"],
|
|
39
|
+
* baseUris: ["'self'"],
|
|
40
|
+
* formActions: ["'self'"]
|
|
29
41
|
* }
|
|
30
42
|
* });
|
|
31
43
|
*
|
|
@@ -40,6 +52,14 @@ export declare function mauthSecurityConfig(options?: {
|
|
|
40
52
|
connectSources?: string[];
|
|
41
53
|
frameSources?: string[];
|
|
42
54
|
fontSources?: string[];
|
|
55
|
+
styleSources?: string[];
|
|
56
|
+
imageSources?: string[];
|
|
57
|
+
frameAncestors?: string[];
|
|
58
|
+
workerSources?: string[];
|
|
59
|
+
manifestSources?: string[];
|
|
60
|
+
objectSources?: string[];
|
|
61
|
+
baseUris?: string[];
|
|
62
|
+
formActions?: string[];
|
|
43
63
|
};
|
|
44
64
|
}): typeof options;
|
|
45
65
|
/**
|
|
@@ -54,16 +74,15 @@ export declare function getMauthViteDefines(options?: {
|
|
|
54
74
|
connectSources?: string[];
|
|
55
75
|
frameSources?: string[];
|
|
56
76
|
fontSources?: string[];
|
|
77
|
+
styleSources?: string[];
|
|
78
|
+
imageSources?: string[];
|
|
79
|
+
frameAncestors?: string[];
|
|
80
|
+
workerSources?: string[];
|
|
81
|
+
manifestSources?: string[];
|
|
82
|
+
objectSources?: string[];
|
|
83
|
+
baseUris?: string[];
|
|
84
|
+
formActions?: string[];
|
|
57
85
|
};
|
|
58
86
|
}): Record<string, string>;
|
|
59
|
-
/**
|
|
60
|
-
* Get security headers with CSP sources merged from defaults and build-time
|
|
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).
|
|
67
|
-
*/
|
|
68
87
|
export declare function GET_SECURITY_HEADERS(nonce?: string): Record<string, string>;
|
|
69
88
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -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;
|
|
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;AA2FF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,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;QACvB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;QAC3B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,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;QACvB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;QACxB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;QAC3B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;QACzB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;QACpB,WAAW,CAAC,EAAE,MAAM,EAAE,CAAC;KAC1B,CAAC;CACL,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAgBzB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA2E3E"}
|
package/dist/config.js
CHANGED
|
@@ -74,10 +74,47 @@ const DEFAULT_FONT_SOURCES = [
|
|
|
74
74
|
"'self'",
|
|
75
75
|
'data:'
|
|
76
76
|
];
|
|
77
|
+
// Default allowed style sources for CSP
|
|
78
|
+
const DEFAULT_STYLE_SOURCES = [
|
|
79
|
+
"'self'",
|
|
80
|
+
];
|
|
81
|
+
// Default allowed image sources for CSP
|
|
82
|
+
const DEFAULT_IMAGE_SOURCES = [
|
|
83
|
+
"'self'",
|
|
84
|
+
'https:'
|
|
85
|
+
];
|
|
86
|
+
// Default allowed frame ancestors for CSP (clickjacking protection)
|
|
87
|
+
const DEFAULT_FRAME_ANCESTORS = [
|
|
88
|
+
"'self'"
|
|
89
|
+
];
|
|
90
|
+
// Default allowed worker sources for CSP (Web Workers, Service Workers)
|
|
91
|
+
const DEFAULT_WORKER_SOURCES = [
|
|
92
|
+
"'self'"
|
|
93
|
+
];
|
|
94
|
+
// Default allowed manifest sources for CSP (web app manifest)
|
|
95
|
+
const DEFAULT_MANIFEST_SOURCES = [
|
|
96
|
+
"'self'"
|
|
97
|
+
];
|
|
98
|
+
// Default allowed object sources for CSP (disallow plugins like Flash/Java)
|
|
99
|
+
const DEFAULT_OBJECT_SOURCES = [
|
|
100
|
+
"'none'"
|
|
101
|
+
];
|
|
102
|
+
// Default allowed base URIs for CSP
|
|
103
|
+
const DEFAULT_BASE_URIS = [
|
|
104
|
+
"'self'"
|
|
105
|
+
];
|
|
106
|
+
// Default allowed form actions for CSP
|
|
107
|
+
const DEFAULT_FORM_ACTIONS = [
|
|
108
|
+
"'self'"
|
|
109
|
+
];
|
|
77
110
|
/**
|
|
78
111
|
* Configure Mindful Auth security settings including CSP sources and static
|
|
79
112
|
* assets to skip. Returns the options to be passed to getMauthViteDefines().
|
|
80
113
|
*
|
|
114
|
+
* IMPORTANT: A nonce must be provided for inline styles to work. Without a nonce, inline styles will be blocked by CSP. If you need 'unsafe-inline' for development or testing, explicitly add it to styleSources in mauthSecurityConfig().
|
|
115
|
+
*
|
|
116
|
+
* IMPORTANT: Do not use Astro 6 security.csp in astro.config.mjs alongside this function. Astro's CSP will override these headers. Use mauthSecurityConfig() exclusively.
|
|
117
|
+
*
|
|
81
118
|
* Call in astro.config.mjs and pass the result to vite.define:
|
|
82
119
|
*
|
|
83
120
|
* @example
|
|
@@ -88,7 +125,15 @@ const DEFAULT_FONT_SOURCES = [
|
|
|
88
125
|
* scriptSources: ['https://analytics.example.com'],
|
|
89
126
|
* connectSources: ['https://api.example.com'],
|
|
90
127
|
* frameSources: ['https://stripe.com'],
|
|
91
|
-
* fontSources: ['https://fonts.googleapis.com']
|
|
128
|
+
* fontSources: ['https://fonts.googleapis.com'],
|
|
129
|
+
* styleSources: ['https://cdn.example.com/styles'],
|
|
130
|
+
* imageSources: ['https://images.example.com'],
|
|
131
|
+
* frameAncestors: ["'self'"],
|
|
132
|
+
* workerSources: ["'self'"],
|
|
133
|
+
* manifestSources: ["'self'"],
|
|
134
|
+
* objectSources: ["'none'"],
|
|
135
|
+
* baseUris: ["'self'"],
|
|
136
|
+
* formActions: ["'self'"]
|
|
92
137
|
* }
|
|
93
138
|
* });
|
|
94
139
|
*
|
|
@@ -111,27 +156,39 @@ export function getMauthViteDefines(options) {
|
|
|
111
156
|
__MAUTH_CONNECT_SOURCES__: JSON.stringify(options?.csp?.connectSources ?? []),
|
|
112
157
|
__MAUTH_FRAME_SOURCES__: JSON.stringify(options?.csp?.frameSources ?? []),
|
|
113
158
|
__MAUTH_FONT_SOURCES__: JSON.stringify(options?.csp?.fontSources ?? []),
|
|
159
|
+
__MAUTH_STYLE_SOURCES__: JSON.stringify(options?.csp?.styleSources ?? []),
|
|
160
|
+
__MAUTH_IMAGE_SOURCES__: JSON.stringify(options?.csp?.imageSources ?? []),
|
|
161
|
+
__MAUTH_FRAME_ANCESTORS__: JSON.stringify(options?.csp?.frameAncestors ?? []),
|
|
162
|
+
__MAUTH_WORKER_SOURCES__: JSON.stringify(options?.csp?.workerSources ?? []),
|
|
163
|
+
__MAUTH_MANIFEST_SOURCES__: JSON.stringify(options?.csp?.manifestSources ?? []),
|
|
164
|
+
__MAUTH_OBJECT_SOURCES__: JSON.stringify(options?.csp?.objectSources ?? []),
|
|
165
|
+
__MAUTH_BASE_URIS__: JSON.stringify(options?.csp?.baseUris ?? []),
|
|
166
|
+
__MAUTH_FORM_ACTIONS__: JSON.stringify(options?.csp?.formActions ?? []),
|
|
114
167
|
};
|
|
115
168
|
}
|
|
116
|
-
/**
|
|
117
|
-
* Get security headers with CSP sources merged from defaults and build-time
|
|
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).
|
|
124
|
-
*/
|
|
125
169
|
export function GET_SECURITY_HEADERS(nonce) {
|
|
126
170
|
// Custom sources are baked in at build time via vite.define
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
const
|
|
134
|
-
|
|
171
|
+
// Using Set to deduplicate sources while preserving order
|
|
172
|
+
const SCRIPT_SOURCES = [...new Set([
|
|
173
|
+
...DEFAULT_SCRIPT_SOURCES,
|
|
174
|
+
...__MAUTH_SCRIPT_SOURCES__,
|
|
175
|
+
...(nonce ? [`'nonce-${nonce}'`] : []),
|
|
176
|
+
])];
|
|
177
|
+
const STYLE_SOURCES = [...new Set([
|
|
178
|
+
...DEFAULT_STYLE_SOURCES,
|
|
179
|
+
...__MAUTH_STYLE_SOURCES__,
|
|
180
|
+
...(nonce ? [`'nonce-${nonce}'`] : []),
|
|
181
|
+
])];
|
|
182
|
+
const CONNECT_SOURCES = [...new Set([...DEFAULT_CONNECT_SOURCES, ...__MAUTH_CONNECT_SOURCES__])];
|
|
183
|
+
const FRAME_SOURCES = [...new Set([...DEFAULT_FRAME_SOURCES, ...__MAUTH_FRAME_SOURCES__])];
|
|
184
|
+
const FONT_SOURCES = [...new Set([...DEFAULT_FONT_SOURCES, ...__MAUTH_FONT_SOURCES__])];
|
|
185
|
+
const IMAGE_SOURCES = [...new Set([...DEFAULT_IMAGE_SOURCES, ...__MAUTH_IMAGE_SOURCES__])];
|
|
186
|
+
const FRAME_ANCESTORS = [...new Set([...DEFAULT_FRAME_ANCESTORS, ...__MAUTH_FRAME_ANCESTORS__])];
|
|
187
|
+
const WORKER_SOURCES = [...new Set([...DEFAULT_WORKER_SOURCES, ...__MAUTH_WORKER_SOURCES__])];
|
|
188
|
+
const MANIFEST_SOURCES = [...new Set([...DEFAULT_MANIFEST_SOURCES, ...__MAUTH_MANIFEST_SOURCES__])];
|
|
189
|
+
const OBJECT_SOURCES = [...new Set([...DEFAULT_OBJECT_SOURCES, ...__MAUTH_OBJECT_SOURCES__])];
|
|
190
|
+
const BASE_URIS = [...new Set([...DEFAULT_BASE_URIS, ...__MAUTH_BASE_URIS__])];
|
|
191
|
+
const FORM_ACTIONS = [...new Set([...DEFAULT_FORM_ACTIONS, ...__MAUTH_FORM_ACTIONS__])];
|
|
135
192
|
return {
|
|
136
193
|
'X-Content-Type-Options': 'nosniff',
|
|
137
194
|
'X-Frame-Options': 'SAMEORIGIN',
|
|
@@ -139,25 +196,33 @@ export function GET_SECURITY_HEADERS(nonce) {
|
|
|
139
196
|
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
|
|
140
197
|
'Permissions-Policy': 'geolocation=(), microphone=(), camera=()',
|
|
141
198
|
'Content-Security-Policy': [
|
|
142
|
-
//
|
|
143
|
-
"default-src '
|
|
199
|
+
// Deny by default - only allow explicitly defined sources
|
|
200
|
+
"default-src 'none'",
|
|
144
201
|
// Scripts
|
|
145
202
|
`script-src ${SCRIPT_SOURCES.join(' ')}`,
|
|
146
203
|
// Styles
|
|
147
|
-
|
|
204
|
+
`style-src ${STYLE_SOURCES.join(' ')}`,
|
|
148
205
|
// Images
|
|
149
|
-
|
|
206
|
+
`img-src ${IMAGE_SOURCES.join(' ')}`,
|
|
150
207
|
// Connections
|
|
151
208
|
`connect-src ${CONNECT_SOURCES.join(' ')}`,
|
|
152
209
|
// Frames
|
|
153
210
|
`frame-src ${FRAME_SOURCES.join(' ')}`,
|
|
211
|
+
// Frame ancestors (clickjacking protection)
|
|
212
|
+
`frame-ancestors ${FRAME_ANCESTORS.join(' ')}`,
|
|
154
213
|
// Fonts
|
|
155
214
|
`font-src ${FONT_SOURCES.join(' ')}`,
|
|
215
|
+
// Web Workers and Service Workers
|
|
216
|
+
`worker-src ${WORKER_SOURCES.join(' ')}`,
|
|
217
|
+
// Web app manifest
|
|
218
|
+
`manifest-src ${MANIFEST_SOURCES.join(' ')}`,
|
|
156
219
|
// Disallow object/embed tags (Flash, Java, etc.)
|
|
157
|
-
|
|
220
|
+
`object-src ${OBJECT_SOURCES.join(' ')}`,
|
|
221
|
+
// Base URI
|
|
222
|
+
`base-uri ${BASE_URIS.join(' ')}`,
|
|
223
|
+
// Form action
|
|
224
|
+
`form-action ${FORM_ACTIONS.join(' ')}`,
|
|
158
225
|
// Security directives
|
|
159
|
-
"base-uri 'self'",
|
|
160
|
-
"form-action 'self'",
|
|
161
226
|
"upgrade-insecure-requests",
|
|
162
227
|
"block-all-mixed-content"
|
|
163
228
|
].join('; ')
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,SAAS,CAAC;AAGxB,cAAc,UAAU,CAAC;AAGzB,cAAc,QAAQ,CAAC;AAGvB,cAAc,gBAAgB,CAAC;AAG/B,cAAc,YAAY,CAAC;AAG3B,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,SAAS,CAAC;AAGxB,cAAc,UAAU,CAAC;AAGzB,cAAc,QAAQ,CAAC;AAGvB,cAAc,gBAAgB,CAAC;AAG/B,cAAc,YAAY,CAAC;AAG3B,cAAc,cAAc,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -9,5 +9,5 @@ export * from './auth';
|
|
|
9
9
|
export * from './auth-handler';
|
|
10
10
|
// Security utilities
|
|
11
11
|
export * from './security';
|
|
12
|
-
// Middleware
|
|
13
|
-
export
|
|
12
|
+
// Middleware
|
|
13
|
+
export * from './middleware';
|
package/dist/middleware.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAoCA,eAAO,MAAM,SAAS,mCA0FpB,CAAC"}
|
package/dist/middleware.js
CHANGED
|
@@ -1,47 +1,80 @@
|
|
|
1
1
|
// Global middleware for session validation
|
|
2
2
|
// Runs before all route handlers to enforce authentication
|
|
3
|
+
//
|
|
4
|
+
// ASTRO 6 MIGRATION:
|
|
5
|
+
// - Astro v6 removed context.locals.runtime.env. Env vars now import from 'cloudflare:workers'.
|
|
6
|
+
// - cloudflare:workers is marked external in astro.config.vite.ssr to avoid esbuild scan errors.
|
|
7
|
+
// - Dev mode bypass uses import.meta.env.DEV (build-time constant: true in dev, false in prod).
|
|
3
8
|
import { defineMiddleware } from 'astro:middleware';
|
|
9
|
+
import { env } from 'cloudflare:workers';
|
|
4
10
|
import { PUBLIC_ROUTES, PUBLIC_PREFIXES, GET_SECURITY_HEADERS, GET_SKIP_ASSETS } from './config';
|
|
5
11
|
import { sanitizePath, generateNonce } from './security';
|
|
6
12
|
import { validateSession, validateMemberIdInUrl } from './auth';
|
|
7
13
|
/** Check if a path is a public route (no auth required) */
|
|
8
14
|
function isPublicRoute(pathname) {
|
|
9
15
|
return PUBLIC_ROUTES.includes(pathname) ||
|
|
10
|
-
PUBLIC_PREFIXES.some(prefix => pathname.startsWith(prefix));
|
|
16
|
+
PUBLIC_PREFIXES.some((prefix) => pathname.startsWith(prefix));
|
|
11
17
|
}
|
|
12
|
-
/** Add security headers
|
|
18
|
+
/** Add security headers to a response */
|
|
19
|
+
// NOTE: In Cloudflare Workers, Response.headers is immutable.
|
|
20
|
+
// We must create a new Response with a fresh Headers object instead of mutating.
|
|
13
21
|
function addSecurityHeaders(response, nonce) {
|
|
22
|
+
const newHeaders = new Headers(response.headers);
|
|
14
23
|
Object.entries(GET_SECURITY_HEADERS(nonce)).forEach(([key, value]) => {
|
|
15
|
-
|
|
24
|
+
newHeaders.set(key, value);
|
|
25
|
+
});
|
|
26
|
+
return new Response(response.body, {
|
|
27
|
+
status: response.status,
|
|
28
|
+
statusText: response.statusText,
|
|
29
|
+
headers: newHeaders,
|
|
16
30
|
});
|
|
17
|
-
return response;
|
|
18
31
|
}
|
|
19
32
|
// Main middleware function
|
|
20
33
|
export const onRequest = defineMiddleware(async (context, next) => {
|
|
21
34
|
const { request, url, redirect, locals } = context;
|
|
22
35
|
const pathname = url.pathname;
|
|
23
|
-
//
|
|
24
|
-
|
|
36
|
+
// Redirect HTTP to HTTPS (skip in dev mode and localhost)
|
|
37
|
+
if (!import.meta.env.DEV && url.protocol === 'http:' && url.hostname !== 'localhost' && url.hostname !== '127.0.0.1') {
|
|
38
|
+
const httpsUrl = url.toString().replace('http://', 'https://');
|
|
39
|
+
return redirect(httpsUrl, 307);
|
|
40
|
+
}
|
|
25
41
|
// Generate a per-request nonce for CSP. Exposed as locals.cspNonce so
|
|
26
42
|
// layouts can add nonce={Astro.locals.cspNonce} to inline <script> tags.
|
|
27
43
|
const nonce = generateNonce();
|
|
28
|
-
|
|
44
|
+
locals.cspNonce = nonce;
|
|
29
45
|
// Skip middleware for static assets FIRST (before dev mode)
|
|
30
46
|
if (GET_SKIP_ASSETS().includes(pathname)) {
|
|
31
47
|
return next();
|
|
32
48
|
}
|
|
33
|
-
// DEV MODE: Skip auth
|
|
34
|
-
|
|
49
|
+
// DEV MODE: Skip auth
|
|
50
|
+
// import.meta.env.DEV is a build-time constant replaced by Vite:
|
|
51
|
+
// - true during local dev (never included in prod build)
|
|
52
|
+
// - false in production builds (tree-shaken out entirely)
|
|
53
|
+
// Localhost auth is skipped because Mindful Auth blocks localhost requests.
|
|
54
|
+
if (import.meta.env.DEV) {
|
|
55
|
+
// Check if public route first
|
|
35
56
|
if (isPublicRoute(pathname)) {
|
|
36
|
-
|
|
57
|
+
locals.recordId = null;
|
|
37
58
|
return next();
|
|
38
59
|
}
|
|
39
60
|
// For protected routes, extract or create mock recordId
|
|
40
61
|
// Match memberid with trailing slash
|
|
41
62
|
const match = pathname.match(/^\/([a-zA-Z0-9-]+)(?:\/|$)/);
|
|
42
|
-
|
|
63
|
+
locals.recordId = match ? match[1] : 'dev-user-123';
|
|
43
64
|
return next();
|
|
44
65
|
}
|
|
66
|
+
// PREVIEW MODE: Skip auth (for testing without Mindful Auth on localhost)
|
|
67
|
+
// npm run preview builds the project first, so import.meta.env.DEV is false.
|
|
68
|
+
// We need a runtime check for localhost to simulate auth in preview.
|
|
69
|
+
if (url.hostname === 'localhost' || url.hostname === '127.0.0.1') {
|
|
70
|
+
if (isPublicRoute(pathname)) {
|
|
71
|
+
locals.recordId = null;
|
|
72
|
+
return addSecurityHeaders(await next(), nonce);
|
|
73
|
+
}
|
|
74
|
+
const match = pathname.match(/^\/([a-zA-Z0-9-]+)(?:\/|$)/);
|
|
75
|
+
locals.recordId = match ? match[1] : 'preview-user-123';
|
|
76
|
+
return addSecurityHeaders(await next(), nonce);
|
|
77
|
+
}
|
|
45
78
|
// Sanitize path
|
|
46
79
|
const safePath = sanitizePath(pathname);
|
|
47
80
|
if (!safePath) {
|
|
@@ -49,11 +82,13 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
49
82
|
}
|
|
50
83
|
// Public routes - no auth needed
|
|
51
84
|
if (isPublicRoute(safePath)) {
|
|
52
|
-
|
|
85
|
+
locals.recordId = null;
|
|
53
86
|
return addSecurityHeaders(await next(), nonce);
|
|
54
87
|
}
|
|
55
88
|
// Protected route - validate session
|
|
56
|
-
|
|
89
|
+
// ASTRO 6 CHANGE: Environment variables are accessed directly from 'cloudflare:workers' env,
|
|
90
|
+
// not from context.locals.runtime.env (which was removed).
|
|
91
|
+
const internalApiKey = env.INTERNAL_API_KEY || import.meta.env.INTERNAL_API_KEY;
|
|
57
92
|
if (!internalApiKey) {
|
|
58
93
|
console.error('[middleware] CRITICAL: INTERNAL_API_KEY not configured');
|
|
59
94
|
return new Response('Internal Server Error', { status: 500 });
|
|
@@ -71,6 +106,6 @@ export const onRequest = defineMiddleware(async (context, next) => {
|
|
|
71
106
|
if (!validateMemberIdInUrl(safePath, session.recordId).valid) {
|
|
72
107
|
return new Response('Forbidden: Invalid user ID in URL', { status: 403 });
|
|
73
108
|
}
|
|
74
|
-
|
|
109
|
+
locals.recordId = session.recordId;
|
|
75
110
|
return addSecurityHeaders(await next(), nonce);
|
|
76
111
|
});
|
package/dist/types.d.ts
CHANGED
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAG/C,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE;QACR,GAAG,CAAC,EAAE;YACJ,gBAAgB,CAAC,EAAE,MAAM,CAAC;SAC3B,CAAC;KACH,CAAC;CACH;AAGD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,GAAG,CAAC;QACZ,UAAU,MAAO,SAAQ,iBAAiB;SAAG;KAC9C;CACF;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,qBAAqB,GAAG,iBAAiB,CAAC"}
|
package/dist/types.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindfulauth/core",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Mindful Auth core authentication library for Astro",
|
|
3
|
+
"version": "2.0.0-beta.3",
|
|
4
|
+
"description": "Mindful Auth core authentication library for Astro 6",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -42,10 +42,11 @@
|
|
|
42
42
|
"author": "Mindful Auth",
|
|
43
43
|
"license": "MIT",
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"astro": "^
|
|
45
|
+
"astro": "^6.0.0-beta.14"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"
|
|
48
|
+
"@cloudflare/workers-types": "^4.20260303.0",
|
|
49
|
+
"astro": "^6.0.0-beta.15",
|
|
49
50
|
"typescript": "^5.9.3"
|
|
50
51
|
}
|
|
51
|
-
}
|
|
52
|
+
}
|