@mindfulauth/core 2.0.0-beta.5 → 2.0.0-beta.7
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/astro/ForgotPasswordScript.astro +64 -0
- package/dist/astro/LoginScript.astro +209 -0
- package/dist/astro/MagicLoginScript.astro +62 -0
- package/dist/astro/MagicRegisterScript.astro +73 -0
- package/dist/astro/MainScript.astro +236 -0
- package/dist/astro/RegisterPasswordScript.astro +118 -0
- package/dist/astro/ResendVerificationScript.astro +51 -0
- package/dist/astro/ResetPasswordScript.astro +155 -0
- package/dist/astro/SecurityScript.astro +490 -0
- package/dist/astro/TurnstileInit.astro +112 -0
- package/dist/astro/VerifyEmailScript.astro +72 -0
- package/dist/astro/VerifyMagicLinkScript.astro +195 -0
- package/dist/core/csp.d.ts +19 -0
- package/dist/core/csp.d.ts.map +1 -0
- package/dist/core/csp.js +36 -0
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +2 -0
- package/package.json +23 -13
- package/dist/auth-handler.d.ts +0 -5
- package/dist/auth-handler.d.ts.map +0 -1
- package/dist/auth-handler.js +0 -154
- package/dist/auth.d.ts +0 -9
- package/dist/auth.d.ts.map +0 -1
- package/dist/auth.js +0 -56
- package/dist/config.d.ts +0 -49
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -95
- package/dist/index.d.ts +0 -7
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -13
- package/dist/middleware.d.ts +0 -2
- package/dist/middleware.d.ts.map +0 -1
- package/dist/middleware.js +0 -108
- package/dist/security.d.ts +0 -5
- package/dist/security.d.ts.map +0 -1
- package/dist/security.js +0 -31
- package/dist/types.d.ts +0 -22
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -2
package/dist/config.js
DELETED
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
// ============================================================================
|
|
2
|
-
// Configuration for the Astro Portal
|
|
3
|
-
// ============================================================================
|
|
4
|
-
// API Endpoints
|
|
5
|
-
export const CENTRAL_AUTH_ORIGIN = 'https://api.mindfulauth.com';
|
|
6
|
-
export const CDN_ORIGIN = 'https://cdn.mindfulauth.com';
|
|
7
|
-
// Request & Timeout Configuration
|
|
8
|
-
export const ALLOWED_AUTH_METHODS = ['GET', 'POST'];
|
|
9
|
-
export const MAX_BODY_SIZE_BYTES = 1048576; // 1MB limit
|
|
10
|
-
export const AUTH_PROXY_TIMEOUT_MS = 15000;
|
|
11
|
-
export const SESSION_VALIDATION_TIMEOUT_MS = 10000;
|
|
12
|
-
// ============================================================================
|
|
13
|
-
// Static Assets & Route Configuration
|
|
14
|
-
// ============================================================================
|
|
15
|
-
// Static assets to skip session validation (favicon, robots.txt, etc.)
|
|
16
|
-
// SECURITY CRITICAL: Only add actual static file requests here.
|
|
17
|
-
// Examples of safe entries: /favicon.ico, /robots.txt, /sitemap.xml
|
|
18
|
-
// NEVER add application routes like [memberid]/dashboard, [memberid]/profile, [memberid]/secure/* - this COMPLETELY bypasses authentication. If you add a route here, unauthenticated users can access it without logging in.
|
|
19
|
-
const DEFAULT_SKIP_ASSETS = ['/favicon.ico', '/robots.txt', '/.well-known/security.txt'];
|
|
20
|
-
/**
|
|
21
|
-
* Returns the combined list of assets to skip session validation for.
|
|
22
|
-
* Merges defaults with any custom assets configured via mauthSecurityConfig() in astro.config.mjs.
|
|
23
|
-
*/
|
|
24
|
-
export function GET_SKIP_ASSETS() {
|
|
25
|
-
return [...DEFAULT_SKIP_ASSETS, ...__MAUTH_SKIP_ASSETS__];
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Configure Mindful Auth security settings including custom skip assets.
|
|
29
|
-
* Call in astro.config.mjs and pass the result to getMauthViteDefines().
|
|
30
|
-
*
|
|
31
|
-
* @example
|
|
32
|
-
* // astro.config.mjs
|
|
33
|
-
* const mauthCfg = mauthSecurityConfig({
|
|
34
|
-
* skipAssets: ['/sitemap.xml', '/manifest.webmanifest']
|
|
35
|
-
* });
|
|
36
|
-
*
|
|
37
|
-
* export default defineConfig({
|
|
38
|
-
* vite: { define: getMauthViteDefines(mauthCfg) }
|
|
39
|
-
* });
|
|
40
|
-
*/
|
|
41
|
-
export function mauthSecurityConfig(options) {
|
|
42
|
-
return options;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Converts the result of mauthSecurityConfig() into Vite define entries.
|
|
46
|
-
* Pass the output to vite.define in astro.config.mjs so custom values are
|
|
47
|
-
* baked into the SSR bundle at build time.
|
|
48
|
-
*/
|
|
49
|
-
export function getMauthViteDefines(options) {
|
|
50
|
-
return {
|
|
51
|
-
__MAUTH_SKIP_ASSETS__: JSON.stringify(options?.skipAssets ?? []),
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
// Public routes that do not require authentication
|
|
55
|
-
// ⚠️ DO NOT EDIT - These are critical for the authentication system to work correctly
|
|
56
|
-
export const PUBLIC_ROUTES = [
|
|
57
|
-
'/',
|
|
58
|
-
'/login',
|
|
59
|
-
'/register',
|
|
60
|
-
'/magic-login',
|
|
61
|
-
'/magic-register',
|
|
62
|
-
'/forgot-password',
|
|
63
|
-
'/resend-verification',
|
|
64
|
-
];
|
|
65
|
-
// Dynamic public routes (prefix matching)
|
|
66
|
-
// ⚠️ DO NOT EDIT - These are critical for the authentication system to work correctly
|
|
67
|
-
export const PUBLIC_PREFIXES = [
|
|
68
|
-
'/auth/',
|
|
69
|
-
'/email-verified/',
|
|
70
|
-
'/reset-password/',
|
|
71
|
-
'/verify-email/',
|
|
72
|
-
'/verify-magic-link/',
|
|
73
|
-
'/api/public/',
|
|
74
|
-
];
|
|
75
|
-
// ============================================================================
|
|
76
|
-
// Security Headers
|
|
77
|
-
// ============================================================================
|
|
78
|
-
/**
|
|
79
|
-
* Returns security headers to be added to every SSR response.
|
|
80
|
-
* CSP (Content-Security-Policy) for script-src and style-src is handled by
|
|
81
|
-
* Astro 6's native security.csp in astro.config.mjs using hashes.
|
|
82
|
-
* The remaining headers here cover transport security, framing, and permissions.
|
|
83
|
-
*
|
|
84
|
-
* Note: X-Frame-Options: SAMEORIGIN covers clickjacking protection
|
|
85
|
-
* (equivalent to CSP frame-ancestors 'self', which cannot be set via meta tag).
|
|
86
|
-
*/
|
|
87
|
-
export function GET_SECURITY_HEADERS() {
|
|
88
|
-
return {
|
|
89
|
-
'X-Content-Type-Options': 'nosniff',
|
|
90
|
-
'X-Frame-Options': 'SAMEORIGIN',
|
|
91
|
-
'Referrer-Policy': 'strict-origin-when-cross-origin',
|
|
92
|
-
'Strict-Transport-Security': 'max-age=31536000; includeSubDomains',
|
|
93
|
-
'Permissions-Policy': 'geolocation=(), microphone=(), camera=()',
|
|
94
|
-
};
|
|
95
|
-
}
|
package/dist/index.d.ts
DELETED
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
// Mindful Auth Core - Main exports
|
|
2
|
-
// Types
|
|
3
|
-
export * from './types';
|
|
4
|
-
// Configuration
|
|
5
|
-
export * from './config';
|
|
6
|
-
// Authentication
|
|
7
|
-
export * from './auth';
|
|
8
|
-
// Auth handler for API routes
|
|
9
|
-
export * from './auth-handler';
|
|
10
|
-
// Security utilities
|
|
11
|
-
export * from './security';
|
|
12
|
-
// Middleware
|
|
13
|
-
export * from './middleware';
|
package/dist/middleware.d.ts
DELETED
package/dist/middleware.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AAqCA,eAAO,MAAM,SAAS,mCAqFpB,CAAC"}
|
package/dist/middleware.js
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
// Global middleware for session validation
|
|
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).
|
|
8
|
-
import { defineMiddleware } from 'astro:middleware';
|
|
9
|
-
import { env } from 'cloudflare:workers';
|
|
10
|
-
import { PUBLIC_ROUTES, PUBLIC_PREFIXES, GET_SECURITY_HEADERS, GET_SKIP_ASSETS } from './config';
|
|
11
|
-
import { sanitizePath } from './security';
|
|
12
|
-
import { validateSession, validateMemberIdInUrl } from './auth';
|
|
13
|
-
/** Check if a path is a public route (no auth required) */
|
|
14
|
-
function isPublicRoute(pathname) {
|
|
15
|
-
return PUBLIC_ROUTES.includes(pathname) ||
|
|
16
|
-
PUBLIC_PREFIXES.some((prefix) => pathname.startsWith(prefix));
|
|
17
|
-
}
|
|
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.
|
|
21
|
-
// CSP for script-src/style-src is handled by Astro 6's native security.csp (via <meta> tag).
|
|
22
|
-
function addSecurityHeaders(response) {
|
|
23
|
-
const newHeaders = new Headers(response.headers);
|
|
24
|
-
Object.entries(GET_SECURITY_HEADERS()).forEach(([key, value]) => {
|
|
25
|
-
newHeaders.set(key, value);
|
|
26
|
-
});
|
|
27
|
-
return new Response(response.body, {
|
|
28
|
-
status: response.status,
|
|
29
|
-
statusText: response.statusText,
|
|
30
|
-
headers: newHeaders,
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
// Main middleware function
|
|
34
|
-
export const onRequest = defineMiddleware(async (context, next) => {
|
|
35
|
-
const { request, url, redirect, locals } = context;
|
|
36
|
-
const pathname = url.pathname;
|
|
37
|
-
// Redirect HTTP to HTTPS (skip in dev mode and localhost)
|
|
38
|
-
if (!import.meta.env.DEV && url.protocol === 'http:' && url.hostname !== 'localhost' && url.hostname !== '127.0.0.1') {
|
|
39
|
-
const httpsUrl = url.toString().replace('http://', 'https://');
|
|
40
|
-
return redirect(httpsUrl, 307);
|
|
41
|
-
}
|
|
42
|
-
// Skip middleware for static assets FIRST (before dev mode)
|
|
43
|
-
if (GET_SKIP_ASSETS().includes(pathname)) {
|
|
44
|
-
return next();
|
|
45
|
-
}
|
|
46
|
-
// DEV MODE: Skip auth
|
|
47
|
-
// import.meta.env.DEV is a build-time constant replaced by Vite:
|
|
48
|
-
// - true during local dev (never included in prod build)
|
|
49
|
-
// - false in production builds (tree-shaken out entirely)
|
|
50
|
-
// Localhost auth is skipped because Mindful Auth blocks localhost requests.
|
|
51
|
-
if (import.meta.env.DEV) {
|
|
52
|
-
// Check if public route first
|
|
53
|
-
if (isPublicRoute(pathname)) {
|
|
54
|
-
locals.recordId = null;
|
|
55
|
-
return next();
|
|
56
|
-
}
|
|
57
|
-
// For protected routes, extract or create mock recordId
|
|
58
|
-
// Match memberid with trailing slash
|
|
59
|
-
const match = pathname.match(/^\/([a-zA-Z0-9-]+)(?:\/|$)/);
|
|
60
|
-
locals.recordId = match ? match[1] : 'dev-user-123';
|
|
61
|
-
return next();
|
|
62
|
-
}
|
|
63
|
-
// PREVIEW MODE: Skip auth (for testing without Mindful Auth on localhost)
|
|
64
|
-
// npm run preview builds the project first, so import.meta.env.DEV is false.
|
|
65
|
-
// We need a runtime check for localhost to simulate auth in preview.
|
|
66
|
-
if (url.hostname === 'localhost' || url.hostname === '127.0.0.1') {
|
|
67
|
-
if (isPublicRoute(pathname)) {
|
|
68
|
-
locals.recordId = null;
|
|
69
|
-
return addSecurityHeaders(await next());
|
|
70
|
-
}
|
|
71
|
-
const match = pathname.match(/^\/([a-zA-Z0-9-]+)(?:\/|$)/);
|
|
72
|
-
locals.recordId = match ? match[1] : 'preview-user-123';
|
|
73
|
-
return addSecurityHeaders(await next());
|
|
74
|
-
}
|
|
75
|
-
// Sanitize path
|
|
76
|
-
const safePath = sanitizePath(pathname);
|
|
77
|
-
if (!safePath) {
|
|
78
|
-
return new Response('Bad Request', { status: 400 });
|
|
79
|
-
}
|
|
80
|
-
// Public routes - no auth needed
|
|
81
|
-
if (isPublicRoute(safePath)) {
|
|
82
|
-
locals.recordId = null;
|
|
83
|
-
return addSecurityHeaders(await next());
|
|
84
|
-
}
|
|
85
|
-
// Protected route - validate session
|
|
86
|
-
// ASTRO 6 CHANGE: Environment variables are accessed directly from 'cloudflare:workers' env,
|
|
87
|
-
// not from context.locals.runtime.env (which was removed).
|
|
88
|
-
const internalApiKey = env.INTERNAL_API_KEY || import.meta.env.INTERNAL_API_KEY;
|
|
89
|
-
if (!internalApiKey) {
|
|
90
|
-
console.error('[middleware] CRITICAL: INTERNAL_API_KEY not configured');
|
|
91
|
-
return new Response('Internal Server Error', { status: 500 });
|
|
92
|
-
}
|
|
93
|
-
// URL must have memberid
|
|
94
|
-
if (!validateMemberIdInUrl(safePath, null).valid) {
|
|
95
|
-
return new Response('Forbidden: URL must include memberid', { status: 403 });
|
|
96
|
-
}
|
|
97
|
-
// Validate session
|
|
98
|
-
const session = await validateSession(request, url.hostname, safePath, internalApiKey);
|
|
99
|
-
if (!session.valid) {
|
|
100
|
-
return redirect('/login');
|
|
101
|
-
}
|
|
102
|
-
// Validate memberid matches session
|
|
103
|
-
if (!validateMemberIdInUrl(safePath, session.recordId).valid) {
|
|
104
|
-
return new Response('Forbidden: Invalid user ID in URL', { status: 403 });
|
|
105
|
-
}
|
|
106
|
-
locals.recordId = session.recordId;
|
|
107
|
-
return addSecurityHeaders(await next());
|
|
108
|
-
});
|
package/dist/security.d.ts
DELETED
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
/** Sanitize endpoint path (prevents ../ traversal and encoded variants) */
|
|
2
|
-
export declare function sanitizeEndpoint(endpoint: string): string | null;
|
|
3
|
-
/** Sanitize URL path (prevents ../ traversal and encoded variants) */
|
|
4
|
-
export declare function sanitizePath(pathname: string): string | null;
|
|
5
|
-
//# sourceMappingURL=security.d.ts.map
|
package/dist/security.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
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"}
|
package/dist/security.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
// Security utilities - path traversal prevention
|
|
2
|
-
const MAX_PATH_LENGTH = 2048;
|
|
3
|
-
/** Decode and check for traversal attacks */
|
|
4
|
-
function decodeAndValidate(str) {
|
|
5
|
-
if (!str || typeof str !== 'string' || str.length > MAX_PATH_LENGTH)
|
|
6
|
-
return null;
|
|
7
|
-
try {
|
|
8
|
-
let decoded = decodeURIComponent(str);
|
|
9
|
-
// Catch double-encoded traversal attempts
|
|
10
|
-
if (decoded.includes('%'))
|
|
11
|
-
decoded = decodeURIComponent(decoded);
|
|
12
|
-
return decoded;
|
|
13
|
-
}
|
|
14
|
-
catch {
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
/** Sanitize endpoint path (prevents ../ traversal and encoded variants) */
|
|
19
|
-
export function sanitizeEndpoint(endpoint) {
|
|
20
|
-
const decoded = decodeAndValidate(endpoint);
|
|
21
|
-
if (!decoded || decoded.includes('..') || decoded.includes('\\'))
|
|
22
|
-
return null;
|
|
23
|
-
return decoded;
|
|
24
|
-
}
|
|
25
|
-
/** Sanitize URL path (prevents ../ traversal and encoded variants) */
|
|
26
|
-
export function sanitizePath(pathname) {
|
|
27
|
-
const decoded = decodeAndValidate(pathname);
|
|
28
|
-
if (!decoded || decoded.includes('..') || decoded.includes('\\'))
|
|
29
|
-
return null;
|
|
30
|
-
return decoded;
|
|
31
|
-
}
|
package/dist/types.d.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import type { MiddlewareHandler } from 'astro';
|
|
2
|
-
export interface MindfulAuthLocals {
|
|
3
|
-
recordId: string | null;
|
|
4
|
-
runtime?: {
|
|
5
|
-
env?: {
|
|
6
|
-
INTERNAL_API_KEY?: string;
|
|
7
|
-
};
|
|
8
|
-
};
|
|
9
|
-
}
|
|
10
|
-
declare global {
|
|
11
|
-
namespace App {
|
|
12
|
-
interface Locals extends MindfulAuthLocals {
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
}
|
|
16
|
-
export interface SessionValidationResult {
|
|
17
|
-
valid: boolean;
|
|
18
|
-
reason?: string;
|
|
19
|
-
recordId?: string;
|
|
20
|
-
}
|
|
21
|
-
export type MindfulAuthMiddleware = MiddlewareHandler;
|
|
22
|
-
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,OAAO,CAAC;AAG/C,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,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
DELETED