@tern-secure/nextjs 5.1.12 → 5.2.0-canary.v20250918173007
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/cjs/app-router/admin/api/endpoints/abstract.js +39 -0
- package/dist/cjs/app-router/admin/api/endpoints/abstract.js.map +1 -0
- package/dist/cjs/app-router/admin/api/endpoints/sessions.js +2 -0
- package/dist/cjs/app-router/admin/api/endpoints/sessions.js.map +1 -0
- package/dist/cjs/app-router/admin/api/endpoints/users.js +4 -0
- package/dist/cjs/app-router/admin/api/endpoints/users.js.map +1 -0
- package/dist/cjs/app-router/admin/claude-authenticateRequestProcessor.js +79 -0
- package/dist/cjs/app-router/admin/claude-authenticateRequestProcessor.js.map +1 -0
- package/dist/cjs/app-router/admin/endpointRouter.js +72 -0
- package/dist/cjs/app-router/admin/endpointRouter.js.map +1 -0
- package/dist/cjs/app-router/admin/fnValidators.js +4 -3
- package/dist/cjs/app-router/admin/fnValidators.js.map +1 -1
- package/dist/cjs/app-router/admin/handlerUtils.js +63 -0
- package/dist/cjs/app-router/admin/handlerUtils.js.map +1 -0
- package/dist/cjs/app-router/admin/index.js +8 -0
- package/dist/cjs/app-router/admin/index.js.map +1 -1
- package/dist/cjs/app-router/admin/sessionHandlers.js +15 -13
- package/dist/cjs/app-router/admin/sessionHandlers.js.map +1 -1
- package/dist/cjs/app-router/admin/ternsecureNextjsHandler.js +31 -36
- package/dist/cjs/app-router/admin/ternsecureNextjsHandler.js.map +1 -1
- package/dist/cjs/app-router/admin/types.js +0 -1
- package/dist/cjs/app-router/admin/types.js.map +1 -1
- package/dist/cjs/app-router/admin/validators.js +1 -2
- package/dist/cjs/app-router/admin/validators.js.map +1 -1
- package/dist/cjs/utils/NextCookieAdapter.js.map +1 -1
- package/dist/esm/app-router/admin/api/endpoints/abstract.js +15 -0
- package/dist/esm/app-router/admin/api/endpoints/abstract.js.map +1 -0
- package/dist/esm/app-router/admin/api/endpoints/sessions.js +1 -0
- package/dist/esm/app-router/admin/api/endpoints/sessions.js.map +1 -0
- package/dist/esm/app-router/admin/api/endpoints/users.js +3 -0
- package/dist/esm/app-router/admin/api/endpoints/users.js.map +1 -0
- package/dist/esm/app-router/admin/claude-authenticateRequestProcessor.js +55 -0
- package/dist/esm/app-router/admin/claude-authenticateRequestProcessor.js.map +1 -0
- package/dist/esm/app-router/admin/endpointRouter.js +48 -0
- package/dist/esm/app-router/admin/endpointRouter.js.map +1 -0
- package/dist/esm/app-router/admin/fnValidators.js +4 -3
- package/dist/esm/app-router/admin/fnValidators.js.map +1 -1
- package/dist/esm/app-router/admin/handlerUtils.js +38 -0
- package/dist/esm/app-router/admin/handlerUtils.js.map +1 -0
- package/dist/esm/app-router/admin/index.js +5 -0
- package/dist/esm/app-router/admin/index.js.map +1 -1
- package/dist/esm/app-router/admin/sessionHandlers.js +15 -13
- package/dist/esm/app-router/admin/sessionHandlers.js.map +1 -1
- package/dist/esm/app-router/admin/ternsecureNextjsHandler.js +34 -41
- package/dist/esm/app-router/admin/ternsecureNextjsHandler.js.map +1 -1
- package/dist/esm/app-router/admin/types.js +0 -1
- package/dist/esm/app-router/admin/types.js.map +1 -1
- package/dist/esm/app-router/admin/validators.js +1 -2
- package/dist/esm/app-router/admin/validators.js.map +1 -1
- package/dist/esm/utils/NextCookieAdapter.js.map +1 -1
- package/dist/types/app-router/admin/api/endpoints/abstract.d.ts +19 -0
- package/dist/types/app-router/admin/api/endpoints/abstract.d.ts.map +1 -0
- package/dist/types/app-router/admin/api/endpoints/sessions.d.ts +2 -0
- package/dist/types/app-router/admin/api/endpoints/sessions.d.ts.map +1 -0
- package/dist/types/app-router/admin/api/endpoints/users.d.ts +2 -0
- package/dist/types/app-router/admin/api/endpoints/users.d.ts.map +1 -0
- package/dist/types/app-router/admin/claude-authenticateRequestProcessor.d.ts +37 -0
- package/dist/types/app-router/admin/claude-authenticateRequestProcessor.d.ts.map +1 -0
- package/dist/types/app-router/admin/endpointRouter.d.ts +10 -0
- package/dist/types/app-router/admin/endpointRouter.d.ts.map +1 -0
- package/dist/types/app-router/admin/fnValidators.d.ts +11 -12
- package/dist/types/app-router/admin/fnValidators.d.ts.map +1 -1
- package/dist/types/app-router/admin/handlerUtils.d.ts +19 -0
- package/dist/types/app-router/admin/handlerUtils.d.ts.map +1 -0
- package/dist/types/app-router/admin/index.d.ts +4 -1
- package/dist/types/app-router/admin/index.d.ts.map +1 -1
- package/dist/types/app-router/admin/sessionHandlers.d.ts +3 -4
- package/dist/types/app-router/admin/sessionHandlers.d.ts.map +1 -1
- package/dist/types/app-router/admin/ternsecureNextjsHandler.d.ts +3 -4
- package/dist/types/app-router/admin/ternsecureNextjsHandler.d.ts.map +1 -1
- package/dist/types/app-router/admin/types.d.ts +2 -3
- package/dist/types/app-router/admin/types.d.ts.map +1 -1
- package/dist/types/app-router/admin/validators.d.ts +10 -12
- package/dist/types/app-router/admin/validators.d.ts.map +1 -1
- package/dist/types/utils/NextCookieAdapter.d.ts.map +1 -1
- package/package.json +8 -8
|
@@ -22,56 +22,51 @@ __export(ternsecureNextjsHandler_exports, {
|
|
|
22
22
|
});
|
|
23
23
|
module.exports = __toCommonJS(ternsecureNextjsHandler_exports);
|
|
24
24
|
var import_constants = require("./constants");
|
|
25
|
+
var import_endpointRouter = require("./endpointRouter");
|
|
25
26
|
var import_fnValidators = require("./fnValidators");
|
|
27
|
+
var import_handlerUtils = require("./handlerUtils");
|
|
26
28
|
var import_responses = require("./responses");
|
|
27
|
-
var import_sessionHandlers = require("./sessionHandlers");
|
|
28
29
|
var import_types = require("./types");
|
|
29
30
|
var import_utils = require("./utils");
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
class HandlerConfigFactory {
|
|
32
|
+
static create(options) {
|
|
33
|
+
const baseConfig = import_utils.ConfigUtils.mergeWithDefaults(
|
|
34
|
+
import_types.DEFAULT_HANDLER_OPTIONS,
|
|
35
|
+
options
|
|
36
|
+
);
|
|
37
|
+
return {
|
|
38
|
+
...baseConfig,
|
|
39
|
+
tenantId: import_constants.TENANT_ID
|
|
40
|
+
};
|
|
36
41
|
}
|
|
37
|
-
const securityError = await validateSecurity(config.security);
|
|
38
|
-
if (securityError) return securityError;
|
|
39
|
-
return null;
|
|
40
42
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
default:
|
|
46
|
-
return (0, import_responses.createApiErrorResponse)("ENDPOINT_NOT_FOUND", "Endpoint not found", 404);
|
|
43
|
+
class TernSecureRequestHandler {
|
|
44
|
+
config;
|
|
45
|
+
constructor(config) {
|
|
46
|
+
this.config = config;
|
|
47
47
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
import_types.DEFAULT_HANDLER_OPTIONS,
|
|
52
|
-
options
|
|
53
|
-
);
|
|
54
|
-
const internalConfig = {
|
|
55
|
-
...baseConfig,
|
|
56
|
-
tenantId: import_constants.TENANT_ID
|
|
57
|
-
};
|
|
58
|
-
const handler = async (request) => {
|
|
59
|
-
const context = (0, import_fnValidators.createRequestContext)(request);
|
|
60
|
-
const { pathSegments } = context;
|
|
61
|
-
const endpoint = pathSegments[2];
|
|
62
|
-
const subEndpoint = pathSegments[3];
|
|
63
|
-
import_utils.LoggingUtils.logRequest(request, "Handler");
|
|
48
|
+
async handle(request) {
|
|
49
|
+
const handlerContext = import_handlerUtils.RequestContextBuilder.create(request);
|
|
50
|
+
const validationContext = (0, import_fnValidators.createRequestContext)(request);
|
|
64
51
|
try {
|
|
65
|
-
const validationResult = await
|
|
52
|
+
const validationResult = await this.executeValidation(validationContext);
|
|
66
53
|
if (validationResult) {
|
|
67
54
|
return validationResult;
|
|
68
55
|
}
|
|
69
|
-
return await
|
|
56
|
+
return await import_endpointRouter.EndpointRouter.route(handlerContext, this.config);
|
|
70
57
|
} catch (error) {
|
|
71
|
-
import_utils.LoggingUtils.logError(error, "Handler");
|
|
72
58
|
return (0, import_responses.createApiErrorResponse)("INTERNAL_SERVER_ERROR", "Internal server error", 500);
|
|
73
59
|
}
|
|
74
|
-
}
|
|
60
|
+
}
|
|
61
|
+
async executeValidation(validationContext) {
|
|
62
|
+
const validationPipeline = new import_handlerUtils.ValidationPipeline(this.config, validationContext);
|
|
63
|
+
return validationPipeline.execute();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function createTernSecureNextJsHandler(options) {
|
|
67
|
+
const config = HandlerConfigFactory.create(options);
|
|
68
|
+
const requestHandler = new TernSecureRequestHandler(config);
|
|
69
|
+
const handler = async (request) => await requestHandler.handle(request);
|
|
75
70
|
return {
|
|
76
71
|
GET: handler,
|
|
77
72
|
POST: handler
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/app-router/admin/ternsecureNextjsHandler.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../../../src/app-router/admin/ternsecureNextjsHandler.ts"],"sourcesContent":["\nimport { TENANT_ID } from './constants';\nimport { EndpointRouter } from './endpointRouter';\nimport { createRequestContext } from './fnValidators';\nimport { RequestContextBuilder, ValidationPipeline } from './handlerUtils';\nimport { createApiErrorResponse } from './responses';\nimport type { TernSecureHandlerOptions, TernSecureInternalHandlerConfig } from './types';\nimport { DEFAULT_HANDLER_OPTIONS } from './types';\nimport { ConfigUtils } from './utils';\n\nclass HandlerConfigFactory {\n static create(options?: TernSecureHandlerOptions): TernSecureInternalHandlerConfig {\n const baseConfig: Required<TernSecureHandlerOptions> = ConfigUtils.mergeWithDefaults(\n DEFAULT_HANDLER_OPTIONS,\n options,\n );\n\n return {\n ...baseConfig,\n tenantId: TENANT_ID,\n };\n }\n}\n\nclass TernSecureRequestHandler {\n private readonly config: TernSecureInternalHandlerConfig;\n\n constructor(config: TernSecureInternalHandlerConfig) {\n this.config = config;\n }\n\n async handle(request: Request): Promise<Response> {\n const handlerContext = RequestContextBuilder.create(request);\n const validationContext = createRequestContext(request);\n\n try {\n const validationResult = await this.executeValidation(validationContext);\n if (validationResult) {\n return validationResult;\n }\n\n return await EndpointRouter.route(handlerContext, this.config);\n } catch (error) {\n return createApiErrorResponse('INTERNAL_SERVER_ERROR', 'Internal server error', 500);\n }\n }\n\n private async executeValidation(validationContext: any): Promise<Response | null> {\n const validationPipeline = new ValidationPipeline(this.config, validationContext);\n return validationPipeline.execute();\n }\n}\n\nexport function createTernSecureNextJsHandler(options: TernSecureHandlerOptions) {\n const config = HandlerConfigFactory.create(options);\n const requestHandler = new TernSecureRequestHandler(config);\n\n const handler = async (request: Request) => await requestHandler.handle(request);\n\n //const handler = async (request: Request): Promise<Response> => {\n // const context = await createRequestProcessor(createTernSecureRequest(request), options);\n // const { validateCors, validateSecurity } = createValidators(context);\n // await validateCors(options.cors || '');\n // await validateSecurity(options.security || {});\n //};\n\n return {\n GET: handler,\n POST: handler,\n } as const;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,uBAA0B;AAC1B,4BAA+B;AAC/B,0BAAqC;AACrC,0BAA0D;AAC1D,uBAAuC;AAEvC,mBAAwC;AACxC,mBAA4B;AAE5B,MAAM,qBAAqB;AAAA,EACzB,OAAO,OAAO,SAAqE;AACjF,UAAM,aAAiD,yBAAY;AAAA,MACjE;AAAA,MACA;AAAA,IACF;AAEA,WAAO;AAAA,MACL,GAAG;AAAA,MACH,UAAU;AAAA,IACZ;AAAA,EACF;AACF;AAEA,MAAM,yBAAyB;AAAA,EACZ;AAAA,EAEjB,YAAY,QAAyC;AACnD,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,MAAM,OAAO,SAAqC;AAChD,UAAM,iBAAiB,0CAAsB,OAAO,OAAO;AAC3D,UAAM,wBAAoB,0CAAqB,OAAO;AAEtD,QAAI;AACF,YAAM,mBAAmB,MAAM,KAAK,kBAAkB,iBAAiB;AACvE,UAAI,kBAAkB;AACpB,eAAO;AAAA,MACT;AAEA,aAAO,MAAM,qCAAe,MAAM,gBAAgB,KAAK,MAAM;AAAA,IAC/D,SAAS,OAAO;AACd,iBAAO,yCAAuB,yBAAyB,yBAAyB,GAAG;AAAA,IACrF;AAAA,EACF;AAAA,EAEA,MAAc,kBAAkB,mBAAkD;AAChF,UAAM,qBAAqB,IAAI,uCAAmB,KAAK,QAAQ,iBAAiB;AAChF,WAAO,mBAAmB,QAAQ;AAAA,EACpC;AACF;AAEO,SAAS,8BAA8B,SAAmC;AAC/E,QAAM,SAAS,qBAAqB,OAAO,OAAO;AAClD,QAAM,iBAAiB,IAAI,yBAAyB,MAAM;AAE1D,QAAM,UAAU,OAAO,YAAqB,MAAM,eAAe,OAAO,OAAO;AAS/E,SAAO;AAAA,IACL,KAAK;AAAA,IACL,MAAM;AAAA,EACR;AACF;","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/app-router/admin/types.ts"],"sourcesContent":["import { type NextResponse } from 'next/server';\n\nexport interface CorsOptions {\n allowedOrigins: string[] | '*';\n allowedMethods?: string[];\n allowedHeaders?: string[];\n allowCredentials?: boolean;\n maxAge?: number;\n skipSameOrigin?: boolean;\n}\n\nexport interface CookieOptions {\n name?: string;\n domain?: string;\n path?: string;\n
|
|
1
|
+
{"version":3,"sources":["../../../../src/app-router/admin/types.ts"],"sourcesContent":["import { type NextResponse } from 'next/server';\n\nexport interface CorsOptions {\n allowedOrigins: string[] | '*';\n allowedMethods?: string[];\n allowedHeaders?: string[];\n allowCredentials?: boolean;\n maxAge?: number;\n skipSameOrigin?: boolean;\n}\n\nexport interface CookieOptions {\n name?: string;\n domain?: string;\n path?: string;\n httpOnly?: boolean;\n sameSite?: 'strict' | 'lax' | 'none';\n maxAge?: number;\n}\n\nexport interface RateLimitOptions {\n windowMs?: number;\n maxRequests?: number;\n skipSuccessful?: boolean;\n skipFailedRequests?: boolean;\n}\n\nexport interface SecurityOptions {\n requireCSRF?: boolean;\n allowedReferers?: string[];\n requiredHeaders?: Record<string, string>;\n ipWhitelist?: string[];\n userAgent?: {\n block?: string[];\n allow?: string[];\n };\n}\n\nexport interface EndpointConfig {\n enabled: boolean;\n methods: ('GET' | 'POST' | 'PUT' | 'DELETE')[];\n requireAuth?: boolean;\n rateLimit?: RateLimitOptions;\n security?: SecurityOptions;\n cors?: Partial<CorsOptions>;\n}\n\nexport interface SessionEndpointConfig extends EndpointConfig {\n subEndpoints?: {\n [K in SessionSubEndpoint]?: Partial<EndpointConfig>;\n };\n}\n\nexport interface TernSecureHandlerOptions {\n cors?: CorsOptions;\n cookies?: CookieOptions;\n rateLimit?: RateLimitOptions;\n security?: SecurityOptions;\n endpoints?: {\n sessions?: SessionEndpointConfig;\n };\n\n debug?: boolean;\n environment?: 'development' | 'production' | 'test';\n basePath?: string;\n}\n\n/**\n * Define an internal config type that extends the public options\n * with server-side only values like tenantId.\n */\nexport type TernSecureInternalHandlerConfig = Required<TernSecureHandlerOptions> & {\n tenantId?: string;\n};\n\nexport type AuthEndpoint = 'sessions' | 'users';\nexport type SessionSubEndpoint = 'verify' | 'createsession' | 'refresh' | 'revoke';\n\nexport const DEFAULT_CORS_OPTIONS: CorsOptions = {\n allowedOrigins: [],\n allowedMethods: ['GET', 'POST'],\n allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With'],\n allowCredentials: true,\n maxAge: 86400, // 24 hours\n};\n\nexport const DEFAULT_COOKIE_OPTIONS: CookieOptions = {\n name: '__session',\n path: '/',\n httpOnly: true,\n sameSite: 'lax',\n maxAge: 3600 * 24 * 7, // 7 days\n};\n\nexport const DEFAULT_SECURITY_OPTIONS: SecurityOptions = {\n requireCSRF: true,\n allowedReferers: [],\n requiredHeaders: {},\n ipWhitelist: [],\n userAgent: {\n block: [],\n allow: [],\n },\n};\n\nexport const DEFAULT_ENDPOINT_CONFIG: EndpointConfig = {\n enabled: true,\n methods: ['GET', 'POST'],\n requireAuth: false,\n security: DEFAULT_SECURITY_OPTIONS,\n};\n\nexport const DEFAULT_SESSIONS_CONFIG: SessionEndpointConfig = {\n ...DEFAULT_ENDPOINT_CONFIG,\n subEndpoints: {\n verify: {\n enabled: true,\n methods: ['GET'],\n requireAuth: false,\n security: {\n requireCSRF: true,\n allowedReferers: [],\n },\n },\n createsession: {\n enabled: true,\n methods: ['POST'],\n requireAuth: false,\n security: {\n requireCSRF: true,\n },\n },\n refresh: {\n enabled: true,\n methods: ['POST'],\n requireAuth: true,\n security: {\n requireCSRF: true,\n },\n },\n revoke: {\n enabled: true,\n methods: ['POST'],\n requireAuth: true,\n security: {\n requireCSRF: true,\n },\n },\n },\n};\n\nexport const DEFAULT_HANDLER_OPTIONS: Required<TernSecureHandlerOptions> & {\n endpoints: Required<NonNullable<TernSecureHandlerOptions['endpoints']>>;\n} = {\n cors: DEFAULT_CORS_OPTIONS,\n cookies: DEFAULT_COOKIE_OPTIONS,\n rateLimit: {\n windowMs: 15 * 60 * 1000, // 15 minutes\n maxRequests: 100,\n skipSuccessful: false,\n skipFailedRequests: false,\n },\n security: DEFAULT_SECURITY_OPTIONS,\n endpoints: {\n sessions: DEFAULT_SESSIONS_CONFIG,\n },\n debug: false,\n environment: 'production',\n basePath: '/api/auth',\n};\n\n\nexport interface ValidationResult {\n error?: NextResponse;\n data?: any;\n}\n\nexport interface ValidationConfig {\n cors?: CorsOptions;\n security?: SecurityOptions;\n endpoint?: {\n name: AuthEndpoint;\n config: EndpointConfig;\n };\n subEndpoint?: {\n name: SessionSubEndpoint;\n config: EndpointConfig;\n };\n requireIdToken?: boolean;\n requireCsrfToken?: boolean;\n}\n\nexport interface ComprehensiveValidationResult {\n isValid: boolean;\n error?: Response;\n corsResponse?: Response;\n sessionData?: {\n body: any;\n idToken?: string;\n csrfToken?: string;\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8EO,MAAM,uBAAoC;AAAA,EAC/C,gBAAgB,CAAC;AAAA,EACjB,gBAAgB,CAAC,OAAO,MAAM;AAAA,EAC9B,gBAAgB,CAAC,gBAAgB,iBAAiB,kBAAkB;AAAA,EACpE,kBAAkB;AAAA,EAClB,QAAQ;AAAA;AACV;AAEO,MAAM,yBAAwC;AAAA,EACnD,MAAM;AAAA,EACN,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU;AAAA,EACV,QAAQ,OAAO,KAAK;AAAA;AACtB;AAEO,MAAM,2BAA4C;AAAA,EACvD,aAAa;AAAA,EACb,iBAAiB,CAAC;AAAA,EAClB,iBAAiB,CAAC;AAAA,EAClB,aAAa,CAAC;AAAA,EACd,WAAW;AAAA,IACT,OAAO,CAAC;AAAA,IACR,OAAO,CAAC;AAAA,EACV;AACF;AAEO,MAAM,0BAA0C;AAAA,EACrD,SAAS;AAAA,EACT,SAAS,CAAC,OAAO,MAAM;AAAA,EACvB,aAAa;AAAA,EACb,UAAU;AACZ;AAEO,MAAM,0BAAiD;AAAA,EAC5D,GAAG;AAAA,EACH,cAAc;AAAA,IACZ,QAAQ;AAAA,MACN,SAAS;AAAA,MACT,SAAS,CAAC,KAAK;AAAA,MACf,aAAa;AAAA,MACb,UAAU;AAAA,QACR,aAAa;AAAA,QACb,iBAAiB,CAAC;AAAA,MACpB;AAAA,IACF;AAAA,IACA,eAAe;AAAA,MACb,SAAS;AAAA,MACT,SAAS,CAAC,MAAM;AAAA,MAChB,aAAa;AAAA,MACb,UAAU;AAAA,QACR,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA,SAAS;AAAA,MACP,SAAS;AAAA,MACT,SAAS,CAAC,MAAM;AAAA,MAChB,aAAa;AAAA,MACb,UAAU;AAAA,QACR,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA,QAAQ;AAAA,MACN,SAAS;AAAA,MACT,SAAS,CAAC,MAAM;AAAA,MAChB,aAAa;AAAA,MACb,UAAU;AAAA,QACR,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF;AACF;AAEO,MAAM,0BAET;AAAA,EACF,MAAM;AAAA,EACN,SAAS;AAAA,EACT,WAAW;AAAA,IACT,UAAU,KAAK,KAAK;AAAA;AAAA,IACpB,aAAa;AAAA,IACb,gBAAgB;AAAA,IAChB,oBAAoB;AAAA,EACtB;AAAA,EACA,UAAU;AAAA,EACV,WAAW;AAAA,IACT,UAAU;AAAA,EACZ;AAAA,EACA,OAAO;AAAA,EACP,aAAa;AAAA,EACb,UAAU;AACZ;","names":[]}
|
|
@@ -25,7 +25,6 @@ __export(validators_exports, {
|
|
|
25
25
|
SecurityValidator: () => SecurityValidator
|
|
26
26
|
});
|
|
27
27
|
module.exports = __toCommonJS(validators_exports);
|
|
28
|
-
var import_server = require("next/server");
|
|
29
28
|
var import_responses = require("./responses");
|
|
30
29
|
class CorsValidator {
|
|
31
30
|
static async validate(request, corsOptions) {
|
|
@@ -49,7 +48,7 @@ class CorsValidator {
|
|
|
49
48
|
return null;
|
|
50
49
|
}
|
|
51
50
|
static createOptionsResponse(corsOptions) {
|
|
52
|
-
const response = new
|
|
51
|
+
const response = new Response(null, { status: 204 });
|
|
53
52
|
if (corsOptions.allowedOrigins === "*") {
|
|
54
53
|
response.headers.set("Access-Control-Allow-Origin", "*");
|
|
55
54
|
} else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/app-router/admin/validators.ts"],"sourcesContent":["import type { NextRequest} from 'next/server';\nimport { NextResponse } from 'next/server';\n\nimport { createApiErrorResponse } from './responses';\nimport type { AuthEndpoint, CorsOptions, SecurityOptions, SessionSubEndpoint } from './types';\n\n/**\n * CORS validation utilities\n */\nexport class CorsValidator {\n static async validate(\n request: NextRequest,\n corsOptions: CorsOptions,\n ): Promise<NextResponse | null> {\n const origin = request.headers.get('origin');\n const host = request.headers.get('host');\n\n // Skip CORS for same-origin requests\n if (!origin || (host && origin.includes(host))) {\n return null;\n }\n\n if (corsOptions.allowedOrigins !== '*') {\n const isAllowed = corsOptions.allowedOrigins.some(allowedOrigin => {\n if (allowedOrigin.startsWith('*')) {\n const domain = allowedOrigin.slice(1);\n return origin?.endsWith(domain);\n }\n return origin === allowedOrigin;\n });\n\n if (!isAllowed) {\n return createApiErrorResponse('CORS_ORIGIN_NOT_ALLOWED', 'Origin not allowed', 403);\n }\n }\n\n return null;\n }\n\n static createOptionsResponse(corsOptions: CorsOptions): NextResponse {\n const response = new NextResponse(null, { status: 204 });\n\n if (corsOptions.allowedOrigins === '*') {\n response.headers.set('Access-Control-Allow-Origin', '*');\n } else {\n response.headers.set('Access-Control-Allow-Origin', corsOptions.allowedOrigins.join(','));\n }\n\n response.headers.set(\n 'Access-Control-Allow-Methods',\n corsOptions.allowedMethods?.join(',') || 'GET,POST',\n );\n response.headers.set(\n 'Access-Control-Allow-Headers',\n corsOptions.allowedHeaders?.join(',') || 'Content-Type,Authorization',\n );\n\n if (corsOptions.allowCredentials) {\n response.headers.set('Access-Control-Allow-Credentials', 'true');\n }\n\n if (corsOptions.maxAge) {\n response.headers.set('Access-Control-Max-Age', corsOptions.maxAge.toString());\n }\n\n return response;\n }\n}\n\n/**\n * Security validation utilities\n */\nexport class SecurityValidator {\n static async validate(\n request: NextRequest,\n securityOptions: SecurityOptions,\n ): Promise<NextResponse | null> {\n const origin = request.headers.get('origin');\n const host = request.headers.get('host');\n const referer = request.headers.get('referer');\n const userAgent = request.headers.get('user-agent') || '';\n\n // CSRF Protection for cross-origin requests\n const csrfResult = this.validateCsrf(request, securityOptions, origin, host, referer);\n if (csrfResult) return csrfResult;\n\n // Required headers validation\n const headersResult = this.validateRequiredHeaders(request, securityOptions);\n if (headersResult) return headersResult;\n\n // User Agent filtering\n const userAgentResult = this.validateUserAgent(userAgent, securityOptions);\n if (userAgentResult) return userAgentResult;\n\n return null;\n }\n\n private static validateCsrf(\n request: NextRequest,\n securityOptions: SecurityOptions,\n origin: string | null,\n host: string | null,\n referer: string | null,\n ): NextResponse | null {\n if (securityOptions.requireCSRF && origin && host && !origin.includes(host)) {\n const hasCSRFHeader = request.headers.get('x-requested-with') === 'XMLHttpRequest';\n const hasValidReferer = referer && host && referer.includes(host);\n\n if (!hasCSRFHeader && !hasValidReferer) {\n const isAllowedReferer = securityOptions.allowedReferers?.some((allowedRef: string) =>\n referer?.includes(allowedRef),\n );\n\n if (!isAllowedReferer) {\n return createApiErrorResponse('CSRF_PROTECTION', 'Access denied', 403);\n }\n }\n }\n return null;\n }\n\n private static validateRequiredHeaders(\n request: NextRequest,\n securityOptions: SecurityOptions,\n ): NextResponse | null {\n if (securityOptions.requiredHeaders) {\n for (const [headerName, expectedValue] of Object.entries(securityOptions.requiredHeaders)) {\n const actualValue = request.headers.get(headerName);\n if (actualValue !== expectedValue) {\n return createApiErrorResponse(\n 'INVALID_HEADERS',\n 'Required header missing or invalid',\n 400,\n );\n }\n }\n }\n return null;\n }\n\n private static validateUserAgent(\n userAgent: string,\n securityOptions: SecurityOptions,\n ): NextResponse | null {\n // User Agent blocking\n if (securityOptions.userAgent?.block?.length) {\n const isBlocked = securityOptions.userAgent.block.some((blocked: string) =>\n userAgent.toLowerCase().includes(blocked.toLowerCase()),\n );\n\n if (isBlocked) {\n return createApiErrorResponse('USER_AGENT_BLOCKED', 'Access denied', 403);\n }\n }\n\n // User Agent allowlist\n if (securityOptions.userAgent?.allow?.length) {\n const isAllowed = securityOptions.userAgent.allow.some((allowed: string) =>\n userAgent.toLowerCase().includes(allowed.toLowerCase()),\n );\n\n if (!isAllowed) {\n return createApiErrorResponse('USER_AGENT_NOT_ALLOWED', 'Access denied', 403);\n }\n }\n\n return null;\n }\n}\n\n/**\n * CSRF token validation utilities\n */\nexport class CsrfValidator {\n static validate(csrfToken: string, csrfCookieValue: string | undefined): NextResponse | null {\n if (!csrfToken) {\n return createApiErrorResponse('INVALID_CSRF_TOKEN', 'CSRF token is required', 400);\n }\n\n if (!csrfCookieValue) {\n return createApiErrorResponse('CSRF_COOKIE_MISSING', 'CSRF token cookie not found', 403);\n }\n\n if (csrfToken !== csrfCookieValue) {\n return createApiErrorResponse('CSRF_TOKEN_MISMATCH', 'CSRF token mismatch', 403);\n }\n\n return null;\n }\n}\n\n/**\n * Route validation utilities\n */\nexport class RouteValidator {\n static validatePathStructure(pathSegments: string[]): NextResponse | null {\n if (pathSegments.length < 3) {\n return createApiErrorResponse(\n 'INVALID_ROUTE',\n 'Invalid route structure. Expected: /api/auth/{endpoint}',\n 404,\n );\n }\n return null;\n }\n\n static validateEndpoint(\n _endpoint: AuthEndpoint,\n endpointConfig: any,\n method: string,\n ): NextResponse | null {\n if (!endpointConfig || !endpointConfig.enabled) {\n return createApiErrorResponse('ENDPOINT_NOT_FOUND', 'Endpoint not found', 404);\n }\n\n if (method !== 'OPTIONS' && !endpointConfig.methods.includes(method as any)) {\n return createApiErrorResponse('METHOD_NOT_ALLOWED', 'Method not allowed', 405);\n }\n\n return null;\n }\n\n static validateSubEndpoint(\n subEndpoint: SessionSubEndpoint | undefined,\n subEndpointConfig: any,\n method: string,\n ): NextResponse | null {\n if (!subEndpoint) {\n return createApiErrorResponse('SUB_ENDPOINT_REQUIRED', 'Session sub-endpoint required', 400);\n }\n\n if (!subEndpointConfig || !subEndpointConfig.enabled) {\n return createApiErrorResponse('ENDPOINT_NOT_FOUND', 'Endpoint not found', 404);\n }\n\n if (!subEndpointConfig.methods?.includes(method as any)) {\n return createApiErrorResponse('METHOD_NOT_ALLOWED', 'Method not allowed', 405);\n }\n\n return null;\n }\n}\n\n/**\n * Request body validation utilities\n */\nexport class RequestValidator {\n static async validateSessionRequest(request: NextRequest): Promise<{\n body: any;\n idToken?: string;\n csrfToken?: string;\n error?: NextResponse;\n }> {\n try {\n const body = await request.json();\n return { body, idToken: body.idToken, csrfToken: body.csrfToken };\n } catch (error) {\n return {\n body: null,\n error: createApiErrorResponse('INVALID_REQUEST_FORMAT', 'Invalid request format', 400),\n };\n }\n }\n\n static validateIdToken(idToken: string | undefined): NextResponse | null {\n if (!idToken) {\n return createApiErrorResponse(\n 'INVALID_TOKEN',\n 'ID token is required for creating session',\n 400,\n );\n }\n return null;\n }\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/app-router/admin/validators.ts"],"sourcesContent":["import { createApiErrorResponse } from './responses';\nimport type { AuthEndpoint, CorsOptions, SecurityOptions, SessionSubEndpoint } from './types';\n\n/**\n * CORS validation utilities\n */\nexport class CorsValidator {\n static async validate(\n request: Request,\n corsOptions: CorsOptions,\n ): Promise<Response | null> {\n const origin = request.headers.get('origin');\n const host = request.headers.get('host');\n\n // Skip CORS for same-origin requests\n if (!origin || (host && origin.includes(host))) {\n return null;\n }\n\n if (corsOptions.allowedOrigins !== '*') {\n const isAllowed = corsOptions.allowedOrigins.some(allowedOrigin => {\n if (allowedOrigin.startsWith('*')) {\n const domain = allowedOrigin.slice(1);\n return origin?.endsWith(domain);\n }\n return origin === allowedOrigin;\n });\n\n if (!isAllowed) {\n return createApiErrorResponse('CORS_ORIGIN_NOT_ALLOWED', 'Origin not allowed', 403);\n }\n }\n\n return null;\n }\n\n static createOptionsResponse(corsOptions: CorsOptions): Response {\n const response = new Response(null, { status: 204 });\n\n if (corsOptions.allowedOrigins === '*') {\n response.headers.set('Access-Control-Allow-Origin', '*');\n } else {\n response.headers.set('Access-Control-Allow-Origin', corsOptions.allowedOrigins.join(','));\n }\n\n response.headers.set(\n 'Access-Control-Allow-Methods',\n corsOptions.allowedMethods?.join(',') || 'GET,POST',\n );\n response.headers.set(\n 'Access-Control-Allow-Headers',\n corsOptions.allowedHeaders?.join(',') || 'Content-Type,Authorization',\n );\n\n if (corsOptions.allowCredentials) {\n response.headers.set('Access-Control-Allow-Credentials', 'true');\n }\n\n if (corsOptions.maxAge) {\n response.headers.set('Access-Control-Max-Age', corsOptions.maxAge.toString());\n }\n\n return response;\n }\n}\n\n/**\n * Security validation utilities\n */\nexport class SecurityValidator {\n static async validate(\n request: Request,\n securityOptions: SecurityOptions,\n ): Promise<Response | null> {\n const origin = request.headers.get('origin');\n const host = request.headers.get('host');\n const referer = request.headers.get('referer');\n const userAgent = request.headers.get('user-agent') || '';\n\n // CSRF Protection for cross-origin requests\n const csrfResult = this.validateCsrf(request, securityOptions, origin, host, referer);\n if (csrfResult) return csrfResult;\n\n // Required headers validation\n const headersResult = this.validateRequiredHeaders(request, securityOptions);\n if (headersResult) return headersResult;\n\n // User Agent filtering\n const userAgentResult = this.validateUserAgent(userAgent, securityOptions);\n if (userAgentResult) return userAgentResult;\n\n return null;\n }\n\n private static validateCsrf(\n request: Request,\n securityOptions: SecurityOptions,\n origin: string | null,\n host: string | null,\n referer: string | null,\n ): Response | null {\n if (securityOptions.requireCSRF && origin && host && !origin.includes(host)) {\n const hasCSRFHeader = request.headers.get('x-requested-with') === 'XMLHttpRequest';\n const hasValidReferer = referer && host && referer.includes(host);\n\n if (!hasCSRFHeader && !hasValidReferer) {\n const isAllowedReferer = securityOptions.allowedReferers?.some((allowedRef: string) =>\n referer?.includes(allowedRef),\n );\n\n if (!isAllowedReferer) {\n return createApiErrorResponse('CSRF_PROTECTION', 'Access denied', 403);\n }\n }\n }\n return null;\n }\n\n private static validateRequiredHeaders(\n request: Request,\n securityOptions: SecurityOptions,\n ): Response | null {\n if (securityOptions.requiredHeaders) {\n for (const [headerName, expectedValue] of Object.entries(securityOptions.requiredHeaders)) {\n const actualValue = request.headers.get(headerName);\n if (actualValue !== expectedValue) {\n return createApiErrorResponse(\n 'INVALID_HEADERS',\n 'Required header missing or invalid',\n 400,\n );\n }\n }\n }\n return null;\n }\n\n private static validateUserAgent(\n userAgent: string,\n securityOptions: SecurityOptions,\n ): Response | null {\n // User Agent blocking\n if (securityOptions.userAgent?.block?.length) {\n const isBlocked = securityOptions.userAgent.block.some((blocked: string) =>\n userAgent.toLowerCase().includes(blocked.toLowerCase()),\n );\n\n if (isBlocked) {\n return createApiErrorResponse('USER_AGENT_BLOCKED', 'Access denied', 403);\n }\n }\n\n // User Agent allowlist\n if (securityOptions.userAgent?.allow?.length) {\n const isAllowed = securityOptions.userAgent.allow.some((allowed: string) =>\n userAgent.toLowerCase().includes(allowed.toLowerCase()),\n );\n\n if (!isAllowed) {\n return createApiErrorResponse('USER_AGENT_NOT_ALLOWED', 'Access denied', 403);\n }\n }\n\n return null;\n }\n}\n\n/**\n * CSRF token validation utilities\n */\nexport class CsrfValidator {\n static validate(csrfToken: string, csrfCookieValue: string | undefined): Response | null {\n if (!csrfToken) {\n return createApiErrorResponse('INVALID_CSRF_TOKEN', 'CSRF token is required', 400);\n }\n\n if (!csrfCookieValue) {\n return createApiErrorResponse('CSRF_COOKIE_MISSING', 'CSRF token cookie not found', 403);\n }\n\n if (csrfToken !== csrfCookieValue) {\n return createApiErrorResponse('CSRF_TOKEN_MISMATCH', 'CSRF token mismatch', 403);\n }\n\n return null;\n }\n}\n\n/**\n * Route validation utilities\n */\nexport class RouteValidator {\n static validatePathStructure(pathSegments: string[]): Response | null {\n if (pathSegments.length < 3) {\n return createApiErrorResponse(\n 'INVALID_ROUTE',\n 'Invalid route structure. Expected: /api/auth/{endpoint}',\n 404,\n );\n }\n return null;\n }\n\n static validateEndpoint(\n _endpoint: AuthEndpoint,\n endpointConfig: any,\n method: string,\n ): Response | null {\n if (!endpointConfig || !endpointConfig.enabled) {\n return createApiErrorResponse('ENDPOINT_NOT_FOUND', 'Endpoint not found', 404);\n }\n\n if (method !== 'OPTIONS' && !endpointConfig.methods.includes(method as any)) {\n return createApiErrorResponse('METHOD_NOT_ALLOWED', 'Method not allowed', 405);\n }\n\n return null;\n }\n\n static validateSubEndpoint(\n subEndpoint: SessionSubEndpoint | undefined,\n subEndpointConfig: any,\n method: string,\n ): Response | null {\n if (!subEndpoint) {\n return createApiErrorResponse('SUB_ENDPOINT_REQUIRED', 'Session sub-endpoint required', 400);\n }\n\n if (!subEndpointConfig || !subEndpointConfig.enabled) {\n return createApiErrorResponse('ENDPOINT_NOT_FOUND', 'Endpoint not found', 404);\n }\n\n if (!subEndpointConfig.methods?.includes(method as any)) {\n return createApiErrorResponse('METHOD_NOT_ALLOWED', 'Method not allowed', 405);\n }\n\n return null;\n }\n}\n\n/**\n * Request body validation utilities\n */\nexport class RequestValidator {\n static async validateSessionRequest(request: Request): Promise<{\n body: any;\n idToken?: string;\n csrfToken?: string;\n error?: Response;\n }> {\n try {\n const body = await request.json();\n return { body, idToken: body.idToken, csrfToken: body.csrfToken };\n } catch (error) {\n return {\n body: null,\n error: createApiErrorResponse('INVALID_REQUEST_FORMAT', 'Invalid request format', 400),\n };\n }\n }\n\n static validateIdToken(idToken: string | undefined): Response | null {\n if (!idToken) {\n return createApiErrorResponse(\n 'INVALID_TOKEN',\n 'ID token is required for creating session',\n 400,\n );\n }\n return null;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/utils/NextCookieAdapter.ts"],"sourcesContent":["import type { CookieOptions,CookieStore } from '@tern-secure/types';\nimport { cookies } from 'next/headers';\n\nexport class NextCookieStore implements CookieStore {\n async get(name: string): Promise<{ value: string | undefined }> {\n const cookieStore = await cookies();\n const cookie = cookieStore.get(name);\n return { value: cookie?.value };\n }\n\n async set(name: string, value: string, options: CookieOptions): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(name, value, options);\n }\n\n async delete(name: string): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.delete(name);\n }\n}"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,qBAAwB;AAEjB,MAAM,gBAAuC;AAAA,EAClD,MAAM,IAAI,MAAsD;AAC9D,UAAM,cAAc,UAAM,wBAAQ;AAClC,UAAM,SAAS,YAAY,IAAI,IAAI;AACnC,WAAO,EAAE,OAAO,QAAQ,MAAM;AAAA,EAChC;AAAA,EAEA,MAAM,IAAI,MAAc,OAAe,SAAuC;AAC5E,UAAM,cAAc,UAAM,wBAAQ;AAClC,gBAAY,IAAI,MAAM,OAAO,OAAO;AAAA,EACtC;AAAA,EAEA,MAAM,OAAO,MAA6B;AACxC,UAAM,cAAc,UAAM,wBAAQ;AAClC,gBAAY,OAAO,IAAI;AAAA,EACzB;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/utils/NextCookieAdapter.ts"],"sourcesContent":["import type { CookieOptions, CookieStore } from '@tern-secure/types';\nimport { cookies } from 'next/headers';\n\nexport class NextCookieStore implements CookieStore {\n async get(name: string): Promise<{ value: string | undefined }> {\n const cookieStore = await cookies();\n const cookie = cookieStore.get(name);\n return { value: cookie?.value };\n }\n\n async set(name: string, value: string, options: CookieOptions): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(name, value, options);\n }\n\n async delete(name: string): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.delete(name);\n }\n}"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,qBAAwB;AAEjB,MAAM,gBAAuC;AAAA,EAClD,MAAM,IAAI,MAAsD;AAC9D,UAAM,cAAc,UAAM,wBAAQ;AAClC,UAAM,SAAS,YAAY,IAAI,IAAI;AACnC,WAAO,EAAE,OAAO,QAAQ,MAAM;AAAA,EAChC;AAAA,EAEA,MAAM,IAAI,MAAc,OAAe,SAAuC;AAC5E,UAAM,cAAc,UAAM,wBAAQ;AAClC,gBAAY,IAAI,MAAM,OAAO,OAAO;AAAA,EACtC;AAAA,EAEA,MAAM,OAAO,MAA6B;AACxC,UAAM,cAAc,UAAM,wBAAQ;AAClC,gBAAY,OAAO,IAAI;AAAA,EACzB;AACF;","names":[]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class BaseEndpointHandler {
|
|
2
|
+
validateMethod(allowedMethods, method) {
|
|
3
|
+
return allowedMethods.includes(method);
|
|
4
|
+
}
|
|
5
|
+
validateSubEndpoint(subEndpoint, requiredSubEndpoint) {
|
|
6
|
+
if (requiredSubEndpoint) {
|
|
7
|
+
return subEndpoint !== void 0;
|
|
8
|
+
}
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
BaseEndpointHandler
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=abstract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/app-router/admin/api/endpoints/abstract.ts"],"sourcesContent":["import type {\n AuthEndpoint,\n SessionSubEndpoint,\n TernSecureInternalHandlerConfig,\n} from '../../types';\n\nexport interface HandlerContext {\n request: Request;\n pathSegments: string[];\n endpoint: AuthEndpoint;\n subEndpoint: SessionSubEndpoint | undefined;\n method: string;\n}\n\nexport interface EndpointHandler {\n canHandle(endpoint: AuthEndpoint): boolean;\n handle(\n handlerContext: HandlerContext,\n config: TernSecureInternalHandlerConfig,\n ): Promise<Response>;\n}\n\nexport abstract class BaseEndpointHandler implements EndpointHandler {\n abstract canHandle(endpoint: AuthEndpoint): boolean;\n abstract handle(\n handlerContext: HandlerContext,\n config: TernSecureInternalHandlerConfig,\n ): Promise<Response>;\n\n protected validateMethod(allowedMethods: string[], method: string): boolean {\n return allowedMethods.includes(method);\n }\n\n protected validateSubEndpoint(\n subEndpoint: SessionSubEndpoint | undefined,\n requiredSubEndpoint?: boolean,\n ): boolean {\n if (requiredSubEndpoint) {\n return subEndpoint !== undefined;\n }\n return true;\n }\n}"],"mappings":"AAsBO,MAAe,oBAA+C;AAAA,EAOzD,eAAe,gBAA0B,QAAyB;AAC1E,WAAO,eAAe,SAAS,MAAM;AAAA,EACvC;AAAA,EAEU,oBACR,aACA,qBACS;AACT,QAAI,qBAAqB;AACvB,aAAO,gBAAgB;AAAA,IACzB;AACA,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=sessions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../src/app-router/admin/api/endpoints/users.ts"],"sourcesContent":["{/*import type { NextResponse } from 'next/server';\n\nimport type { AuthEndpoint, TernSecureInternalHandlerConfig } from '../../types';\nimport type { EndpointHandler, HandlerContext } from './abstract';\nimport { createApiErrorResponse } from './responses';\nimport { SessionEndpointHandler } from './sessionHandlers';\n\nclass UsersHandler implements EndpointHandler {\n canHandle(endpoint: AuthEndpoint): boolean {\n return endpoint === 'users';\n }\n\n handle(\n _handlerContext: HandlerContext,\n _config: TernSecureInternalHandlerConfig,\n ): Promise<NextResponse> {\n return Promise.resolve(\n createApiErrorResponse('ENDPOINT_NOT_IMPLEMENTED', 'Users endpoint not implemented', 501),\n );\n }\n}*/}"],"mappings":"AAAA;AAoBG;","names":[]}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { constants } from "@tern-secure/backend";
|
|
2
|
+
class RequestProcessorContext {
|
|
3
|
+
constructor(ternSecureRequest, options) {
|
|
4
|
+
this.ternSecureRequest = ternSecureRequest;
|
|
5
|
+
this.options = options;
|
|
6
|
+
this.initHeaderValues();
|
|
7
|
+
this.initCookieValues();
|
|
8
|
+
this.ternUrl = this.ternSecureRequest.ternUrl;
|
|
9
|
+
}
|
|
10
|
+
initHeaderValues() {
|
|
11
|
+
this.sessionTokenInHeader = this.parseAuthorizationHeader(
|
|
12
|
+
this.getHeader(constants.Headers.Authorization)
|
|
13
|
+
);
|
|
14
|
+
this.origin = this.getHeader(constants.Headers.Origin);
|
|
15
|
+
this.host = this.getHeader(constants.Headers.Host);
|
|
16
|
+
this.forwardedHost = this.getHeader(constants.Headers.ForwardedHost);
|
|
17
|
+
this.forwardedProto = this.getHeader(constants.Headers.CloudFrontForwardedProto) || this.getHeader(constants.Headers.ForwardedProto);
|
|
18
|
+
this.referrer = this.getHeader(constants.Headers.Referrer);
|
|
19
|
+
this.userAgent = this.getHeader(constants.Headers.UserAgent);
|
|
20
|
+
this.secFetchDest = this.getHeader(constants.Headers.SecFetchDest);
|
|
21
|
+
this.accept = this.getHeader(constants.Headers.Accept);
|
|
22
|
+
}
|
|
23
|
+
initCookieValues() {
|
|
24
|
+
this.csrfTokenInCookie = this.getCookie(constants.Cookies.CsrfToken);
|
|
25
|
+
}
|
|
26
|
+
getQueryParam(name) {
|
|
27
|
+
return this.ternSecureRequest.ternUrl.searchParams.get(name);
|
|
28
|
+
}
|
|
29
|
+
getHeader(name) {
|
|
30
|
+
return this.ternSecureRequest.headers.get(name) || void 0;
|
|
31
|
+
}
|
|
32
|
+
getCookie(name) {
|
|
33
|
+
return this.ternSecureRequest.cookies.get(name) || void 0;
|
|
34
|
+
}
|
|
35
|
+
parseAuthorizationHeader(authorizationHeader) {
|
|
36
|
+
if (!authorizationHeader) {
|
|
37
|
+
return void 0;
|
|
38
|
+
}
|
|
39
|
+
const [scheme, token] = authorizationHeader.split(" ", 2);
|
|
40
|
+
if (!token) {
|
|
41
|
+
return scheme;
|
|
42
|
+
}
|
|
43
|
+
if (scheme === "Bearer") {
|
|
44
|
+
return token;
|
|
45
|
+
}
|
|
46
|
+
return void 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const createRequestProcessor = async (ternSecureRequest, options) => {
|
|
50
|
+
return new RequestProcessorContext(ternSecureRequest, options);
|
|
51
|
+
};
|
|
52
|
+
export {
|
|
53
|
+
createRequestProcessor
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=claude-authenticateRequestProcessor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/app-router/admin/claude-authenticateRequestProcessor.ts"],"sourcesContent":["import type { TernSecureRequest } from '@tern-secure/backend';\nimport { constants } from '@tern-secure/backend';\n\nimport type { TernSecureHandlerOptions} from './types';\n\n/**\n * Request context for better type safety and clarity\n */\ninterface RequestProcessorContext extends TernSecureHandlerOptions {\n // header-based values\n sessionTokenInHeader: string | undefined;\n origin: string | undefined;\n host: string | undefined;\n forwardedHost: string | undefined;\n forwardedProto: string | undefined;\n referrer: string | undefined;\n userAgent: string | undefined;\n secFetchDest: string | undefined;\n accept: string | undefined;\n\n // cookie-based values\n sessionTokenInCookie: string | undefined;\n refreshTokenInCookie: string | undefined;\n csrfTokenInCookie: string | undefined;\n\n ternUrl: URL;\n}\n\n/**\n * Request processor utility class for common operations\n */\nclass RequestProcessorContext implements RequestProcessorContext {\n public constructor(\n private ternSecureRequest: TernSecureRequest,\n private options: TernSecureHandlerOptions,\n ) {\n this.initHeaderValues();\n this.initCookieValues();\n this.ternUrl = this.ternSecureRequest.ternUrl;\n }\n\n private initHeaderValues() {\n this.sessionTokenInHeader = this.parseAuthorizationHeader(\n this.getHeader(constants.Headers.Authorization),\n );\n this.origin = this.getHeader(constants.Headers.Origin);\n this.host = this.getHeader(constants.Headers.Host);\n this.forwardedHost = this.getHeader(constants.Headers.ForwardedHost);\n this.forwardedProto =\n this.getHeader(constants.Headers.CloudFrontForwardedProto) ||\n this.getHeader(constants.Headers.ForwardedProto);\n this.referrer = this.getHeader(constants.Headers.Referrer);\n this.userAgent = this.getHeader(constants.Headers.UserAgent);\n this.secFetchDest = this.getHeader(constants.Headers.SecFetchDest);\n this.accept = this.getHeader(constants.Headers.Accept);\n }\n\n private initCookieValues() {\n //this.sessionTokenInCookie = this.getCookie(this.options.cookies.name);\n this.csrfTokenInCookie = this.getCookie(constants.Cookies.CsrfToken);\n }\n\n private getQueryParam(name: string) {\n return this.ternSecureRequest.ternUrl.searchParams.get(name);\n }\n\n private getHeader(name: string) {\n return this.ternSecureRequest.headers.get(name) || undefined;\n }\n\n private getCookie(name: string) {\n return this.ternSecureRequest.cookies.get(name) || undefined;\n }\n\n private parseAuthorizationHeader(\n authorizationHeader: string | undefined | null,\n ): string | undefined {\n if (!authorizationHeader) {\n return undefined;\n }\n\n const [scheme, token] = authorizationHeader.split(' ', 2);\n\n if (!token) {\n // No scheme specified, treat the entire value as the token\n return scheme;\n }\n\n if (scheme === 'Bearer') {\n return token;\n }\n\n // Skip all other schemes\n return undefined;\n }\n}\n\nexport type { RequestProcessorContext };\n\nexport const createRequestProcessor = async (\n ternSecureRequest: TernSecureRequest,\n options: TernSecureHandlerOptions,\n): Promise<RequestProcessorContext> => {\n return new RequestProcessorContext(ternSecureRequest, options);\n};\n"],"mappings":"AACA,SAAS,iBAAiB;AA8B1B,MAAM,wBAA2D;AAAA,EACxD,YACG,mBACA,SACR;AAFQ;AACA;AAER,SAAK,iBAAiB;AACtB,SAAK,iBAAiB;AACtB,SAAK,UAAU,KAAK,kBAAkB;AAAA,EACxC;AAAA,EAEQ,mBAAmB;AACzB,SAAK,uBAAuB,KAAK;AAAA,MAC/B,KAAK,UAAU,UAAU,QAAQ,aAAa;AAAA,IAChD;AACA,SAAK,SAAS,KAAK,UAAU,UAAU,QAAQ,MAAM;AACrD,SAAK,OAAO,KAAK,UAAU,UAAU,QAAQ,IAAI;AACjD,SAAK,gBAAgB,KAAK,UAAU,UAAU,QAAQ,aAAa;AACnE,SAAK,iBACH,KAAK,UAAU,UAAU,QAAQ,wBAAwB,KACzD,KAAK,UAAU,UAAU,QAAQ,cAAc;AACjD,SAAK,WAAW,KAAK,UAAU,UAAU,QAAQ,QAAQ;AACzD,SAAK,YAAY,KAAK,UAAU,UAAU,QAAQ,SAAS;AAC3D,SAAK,eAAe,KAAK,UAAU,UAAU,QAAQ,YAAY;AACjE,SAAK,SAAS,KAAK,UAAU,UAAU,QAAQ,MAAM;AAAA,EACvD;AAAA,EAEQ,mBAAmB;AAEzB,SAAK,oBAAoB,KAAK,UAAU,UAAU,QAAQ,SAAS;AAAA,EACrE;AAAA,EAEQ,cAAc,MAAc;AAClC,WAAO,KAAK,kBAAkB,QAAQ,aAAa,IAAI,IAAI;AAAA,EAC7D;AAAA,EAEQ,UAAU,MAAc;AAC9B,WAAO,KAAK,kBAAkB,QAAQ,IAAI,IAAI,KAAK;AAAA,EACrD;AAAA,EAEQ,UAAU,MAAc;AAC9B,WAAO,KAAK,kBAAkB,QAAQ,IAAI,IAAI,KAAK;AAAA,EACrD;AAAA,EAEQ,yBACN,qBACoB;AACpB,QAAI,CAAC,qBAAqB;AACxB,aAAO;AAAA,IACT;AAEA,UAAM,CAAC,QAAQ,KAAK,IAAI,oBAAoB,MAAM,KAAK,CAAC;AAExD,QAAI,CAAC,OAAO;AAEV,aAAO;AAAA,IACT;AAEA,QAAI,WAAW,UAAU;AACvB,aAAO;AAAA,IACT;AAGA,WAAO;AAAA,EACT;AACF;AAIO,MAAM,yBAAyB,OACpC,mBACA,YACqC;AACrC,SAAO,IAAI,wBAAwB,mBAAmB,OAAO;AAC/D;","names":[]}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { createApiErrorResponse } from "./responses";
|
|
2
|
+
import { SessionEndpointHandler } from "./sessionHandlers";
|
|
3
|
+
class SessionsHandler {
|
|
4
|
+
canHandle(endpoint) {
|
|
5
|
+
return endpoint === "sessions";
|
|
6
|
+
}
|
|
7
|
+
async handle(handlerContext, config) {
|
|
8
|
+
const { request, subEndpoint, method } = handlerContext;
|
|
9
|
+
return await SessionEndpointHandler.handle(request, method, subEndpoint, config);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
class UsersHandler {
|
|
13
|
+
canHandle(endpoint) {
|
|
14
|
+
return endpoint === "users";
|
|
15
|
+
}
|
|
16
|
+
handle(_handlerContext, _config) {
|
|
17
|
+
return Promise.resolve(
|
|
18
|
+
createApiErrorResponse("ENDPOINT_NOT_IMPLEMENTED", "Users endpoint not implemented", 501)
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
class EndpointRouter {
|
|
23
|
+
static handlers = [
|
|
24
|
+
new SessionsHandler(),
|
|
25
|
+
new UsersHandler()
|
|
26
|
+
];
|
|
27
|
+
static async route(handlerContext, config) {
|
|
28
|
+
const { endpoint } = handlerContext;
|
|
29
|
+
const handler = this.handlers.find((h) => h.canHandle(endpoint));
|
|
30
|
+
if (!handler) {
|
|
31
|
+
return createApiErrorResponse("ENDPOINT_NOT_FOUND", "Endpoint not found", 404);
|
|
32
|
+
}
|
|
33
|
+
return handler.handle(handlerContext, config);
|
|
34
|
+
}
|
|
35
|
+
static addHandler(handler) {
|
|
36
|
+
this.handlers.push(handler);
|
|
37
|
+
}
|
|
38
|
+
static removeHandler(predicate) {
|
|
39
|
+
const index = this.handlers.findIndex(predicate);
|
|
40
|
+
if (index > -1) {
|
|
41
|
+
this.handlers.splice(index, 1);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
EndpointRouter
|
|
47
|
+
};
|
|
48
|
+
//# sourceMappingURL=endpointRouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/app-router/admin/endpointRouter.ts"],"sourcesContent":["import type { EndpointHandler} from './api/endpoints/abstract';\nimport type { HandlerContext } from './handlerUtils';\nimport { createApiErrorResponse } from './responses';\nimport { SessionEndpointHandler } from './sessionHandlers';\nimport type { AuthEndpoint, TernSecureInternalHandlerConfig } from './types';\n\nclass SessionsHandler implements EndpointHandler {\n canHandle(endpoint: AuthEndpoint): boolean {\n return endpoint === 'sessions';\n }\n\n async handle(\n handlerContext: HandlerContext,\n config: TernSecureInternalHandlerConfig,\n ): Promise<Response> {\n const { request, subEndpoint, method } = handlerContext;\n return await SessionEndpointHandler.handle(request, method, subEndpoint, config);\n }\n}\n\nclass UsersHandler implements EndpointHandler {\n canHandle(endpoint: AuthEndpoint): boolean {\n return endpoint === 'users';\n }\n\n handle(\n _handlerContext: HandlerContext,\n _config: TernSecureInternalHandlerConfig,\n ): Promise<Response> {\n return Promise.resolve(\n createApiErrorResponse('ENDPOINT_NOT_IMPLEMENTED', 'Users endpoint not implemented', 501),\n );\n }\n}\n\nexport class EndpointRouter {\n private static readonly handlers: EndpointHandler[] = [\n new SessionsHandler(),\n new UsersHandler(),\n ];\n\n static async route(\n handlerContext: HandlerContext,\n config: TernSecureInternalHandlerConfig,\n ): Promise<Response> {\n const { endpoint } = handlerContext;\n\n const handler = this.handlers.find(h => h.canHandle(endpoint));\n\n if (!handler) {\n return createApiErrorResponse('ENDPOINT_NOT_FOUND', 'Endpoint not found', 404);\n }\n\n return handler.handle(handlerContext, config);\n }\n\n static addHandler(handler: EndpointHandler): void {\n this.handlers.push(handler);\n }\n\n static removeHandler(predicate: (handler: EndpointHandler) => boolean): void {\n const index = this.handlers.findIndex(predicate);\n if (index > -1) {\n this.handlers.splice(index, 1);\n }\n }\n}"],"mappings":"AAEA,SAAS,8BAA8B;AACvC,SAAS,8BAA8B;AAGvC,MAAM,gBAA2C;AAAA,EAC/C,UAAU,UAAiC;AACzC,WAAO,aAAa;AAAA,EACtB;AAAA,EAEA,MAAM,OACJ,gBACA,QACmB;AACnB,UAAM,EAAE,SAAS,aAAa,OAAO,IAAI;AACzC,WAAO,MAAM,uBAAuB,OAAO,SAAS,QAAQ,aAAa,MAAM;AAAA,EACjF;AACF;AAEA,MAAM,aAAwC;AAAA,EAC5C,UAAU,UAAiC;AACzC,WAAO,aAAa;AAAA,EACtB;AAAA,EAEA,OACE,iBACA,SACmB;AACnB,WAAO,QAAQ;AAAA,MACb,uBAAuB,4BAA4B,kCAAkC,GAAG;AAAA,IAC1F;AAAA,EACF;AACF;AAEO,MAAM,eAAe;AAAA,EAC1B,OAAwB,WAA8B;AAAA,IACpD,IAAI,gBAAgB;AAAA,IACpB,IAAI,aAAa;AAAA,EACnB;AAAA,EAEA,aAAa,MACX,gBACA,QACmB;AACnB,UAAM,EAAE,SAAS,IAAI;AAErB,UAAM,UAAU,KAAK,SAAS,KAAK,OAAK,EAAE,UAAU,QAAQ,CAAC;AAE7D,QAAI,CAAC,SAAS;AACZ,aAAO,uBAAuB,sBAAsB,sBAAsB,GAAG;AAAA,IAC/E;AAEA,WAAO,QAAQ,OAAO,gBAAgB,MAAM;AAAA,EAC9C;AAAA,EAEA,OAAO,WAAW,SAAgC;AAChD,SAAK,SAAS,KAAK,OAAO;AAAA,EAC5B;AAAA,EAEA,OAAO,cAAc,WAAwD;AAC3E,UAAM,QAAQ,KAAK,SAAS,UAAU,SAAS;AAC/C,QAAI,QAAQ,IAAI;AACd,WAAK,SAAS,OAAO,OAAO,CAAC;AAAA,IAC/B;AAAA,EACF;AACF;","names":[]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cookies } from "next/headers";
|
|
2
2
|
import { createApiErrorResponse } from "./responses";
|
|
3
3
|
function createRequestContext(request) {
|
|
4
4
|
const url = new URL(request.url);
|
|
@@ -36,7 +36,7 @@ function createValidators(context) {
|
|
|
36
36
|
return null;
|
|
37
37
|
}
|
|
38
38
|
function createCorsOptionsResponse(corsOptions) {
|
|
39
|
-
const response = new
|
|
39
|
+
const response = new Response(null, { status: 204 });
|
|
40
40
|
if (corsOptions.allowedOrigins === "*") {
|
|
41
41
|
response.headers.set("Access-Control-Allow-Origin", "*");
|
|
42
42
|
} else {
|
|
@@ -232,7 +232,8 @@ function createValidators(context) {
|
|
|
232
232
|
}
|
|
233
233
|
}
|
|
234
234
|
if (config.requireCsrfToken && sessionData.csrfToken) {
|
|
235
|
-
const
|
|
235
|
+
const cookieStore = await cookies();
|
|
236
|
+
const csrfCookieValue = cookieStore.get("csrfToken")?.value;
|
|
236
237
|
const csrfError = validateCsrfToken(sessionData.csrfToken, csrfCookieValue);
|
|
237
238
|
if (csrfError) {
|
|
238
239
|
return { isValid: false, error: csrfError };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/app-router/admin/fnValidators.ts"],"sourcesContent":["import { type NextRequest, NextResponse } from 'next/server';\n\nimport { createApiErrorResponse } from './responses';\nimport type {\n AuthEndpoint,\n ComprehensiveValidationResult,\n CorsOptions,\n EndpointConfig,\n SecurityOptions,\n SessionSubEndpoint,\n ValidationConfig,\n} from './types';\n\nexport interface RequestContext {\n request: NextRequest;\n origin: string | null;\n host: string | null;\n referer: string | null;\n userAgent: string;\n method: string;\n pathSegments: string[];\n}\n\nexport function createRequestContext(request: NextRequest): RequestContext {\n const url = new URL(request.url);\n const pathSegments = url.pathname.split('/').filter(Boolean);\n\n return {\n request,\n origin: request.headers.get('origin'),\n host: request.headers.get('host'),\n referer: request.headers.get('referer'),\n userAgent: request.headers.get('user-agent') || '',\n method: request.method,\n pathSegments,\n };\n}\n\n/**\n * Main validators factory function\n * Returns an object containing all validator functions and utilities\n */\nexport function createValidators(context: RequestContext) {\n const { request, origin, host, referer, userAgent, method, pathSegments } = context;\n\n async function validateCors(corsOptions: CorsOptions): Promise<NextResponse | null> {\n if (corsOptions.skipSameOrigin) {\n if (!origin || (host && origin.includes(host))) {\n return null;\n }\n }\n\n if (corsOptions.allowedOrigins !== '*') {\n const isAllowed = corsOptions.allowedOrigins.some(allowedOrigin => {\n if (allowedOrigin.startsWith('*')) {\n const domain = allowedOrigin.slice(1);\n return origin?.endsWith(domain);\n }\n return origin === allowedOrigin;\n });\n\n if (!isAllowed) {\n return createApiErrorResponse('CORS_ORIGIN_NOT_ALLOWED', 'Origin not allowed', 403);\n }\n }\n\n return null;\n }\n\n function createCorsOptionsResponse(corsOptions: CorsOptions): NextResponse {\n const response = new NextResponse(null, { status: 204 });\n\n if (corsOptions.allowedOrigins === '*') {\n response.headers.set('Access-Control-Allow-Origin', '*');\n } else {\n response.headers.set('Access-Control-Allow-Origin', corsOptions.allowedOrigins.join(','));\n }\n\n response.headers.set(\n 'Access-Control-Allow-Methods',\n corsOptions.allowedMethods?.join(',') || 'GET,POST',\n );\n response.headers.set(\n 'Access-Control-Allow-Headers',\n corsOptions.allowedHeaders?.join(',') || 'Content-Type,Authorization',\n );\n\n if (corsOptions.allowCredentials) {\n response.headers.set('Access-Control-Allow-Credentials', 'true');\n }\n\n if (corsOptions.maxAge) {\n response.headers.set('Access-Control-Max-Age', corsOptions.maxAge.toString());\n }\n\n return response;\n }\n\n async function validateSecurity(securityOptions: SecurityOptions): Promise<NextResponse | null> {\n const csrfResult = validateCsrf(securityOptions);\n if (csrfResult) return csrfResult;\n\n const headersResult = validateRequiredHeaders(securityOptions);\n if (headersResult) return headersResult;\n\n const userAgentResult = validateUserAgent(securityOptions);\n if (userAgentResult) return userAgentResult;\n\n return null;\n }\n\n function validateCsrf(securityOptions: SecurityOptions): NextResponse | null {\n if (securityOptions.requireCSRF && origin && host && !origin.includes(host)) {\n const hasCSRFHeader = request.headers.get('x-requested-with') === 'XMLHttpRequest';\n const hasValidReferer = referer && host && referer.includes(host);\n\n if (!hasCSRFHeader && !hasValidReferer) {\n const isAllowedReferer = securityOptions.allowedReferers?.some((allowedRef: string) =>\n referer?.includes(allowedRef),\n );\n\n if (!isAllowedReferer) {\n return createApiErrorResponse('CSRF_PROTECTION', 'Access denied', 403);\n }\n }\n }\n return null;\n }\n\n function validateRequiredHeaders(securityOptions: SecurityOptions): NextResponse | null {\n if (securityOptions.requiredHeaders) {\n for (const [headerName, expectedValue] of Object.entries(securityOptions.requiredHeaders)) {\n const actualValue = request.headers.get(headerName);\n if (actualValue !== expectedValue) {\n return createApiErrorResponse(\n 'INVALID_HEADERS',\n 'Required header missing or invalid',\n 400,\n );\n }\n }\n }\n return null;\n }\n\n function validateUserAgent(securityOptions: SecurityOptions): NextResponse | null {\n if (securityOptions.userAgent?.block?.length) {\n const isBlocked = securityOptions.userAgent.block.some((blocked: string) =>\n userAgent.toLowerCase().includes(blocked.toLowerCase()),\n );\n\n if (isBlocked) {\n return createApiErrorResponse('USER_AGENT_BLOCKED', 'Access denied', 403);\n }\n }\n\n if (securityOptions.userAgent?.allow?.length) {\n const isAllowed = securityOptions.userAgent.allow.some((allowed: string) =>\n userAgent.toLowerCase().includes(allowed.toLowerCase()),\n );\n\n if (!isAllowed) {\n return createApiErrorResponse('USER_AGENT_NOT_ALLOWED', 'Access denied', 403);\n }\n }\n\n return null;\n }\n\n function validateCsrfToken(\n csrfToken: string,\n csrfCookieValue: string | undefined,\n ): NextResponse | null {\n if (!csrfToken) {\n return createApiErrorResponse('INVALID_CSRF_TOKEN', 'CSRF token is required', 400);\n }\n\n if (!csrfCookieValue) {\n return createApiErrorResponse('CSRF_COOKIE_MISSING', 'CSRF token cookie not found', 403);\n }\n\n if (csrfToken !== csrfCookieValue) {\n return createApiErrorResponse('CSRF_TOKEN_MISMATCH', 'CSRF token mismatch', 403);\n }\n\n return null;\n }\n\n function validatePathStructure(): NextResponse | null {\n if (pathSegments.length < 3) {\n return createApiErrorResponse(\n 'INVALID_ROUTE',\n 'Invalid route structure. Expected: /api/auth/{endpoint}',\n 404,\n );\n }\n return null;\n }\n\n function validateEndpoint(\n _endpoint: AuthEndpoint,\n endpointConfig: EndpointConfig,\n ): NextResponse | null {\n if (!endpointConfig || !endpointConfig.enabled) {\n return createApiErrorResponse('ENDPOINT_NOT_FOUND', 'Endpoint not found', 404);\n }\n\n if (method !== 'OPTIONS' && !endpointConfig.methods.includes(method as any)) {\n return createApiErrorResponse('METHOD_NOT_ALLOWED', 'Method not allowed', 405);\n }\n\n return null;\n }\n\n function validateSubEndpoint(\n subEndpoint: SessionSubEndpoint | undefined,\n subEndpointConfig: any,\n ): NextResponse | null {\n if (!subEndpoint) {\n return createApiErrorResponse('SUB_ENDPOINT_REQUIRED', 'Session sub-endpoint required', 400);\n }\n\n if (!subEndpointConfig || !subEndpointConfig.enabled) {\n return createApiErrorResponse('ENDPOINT_NOT_FOUND', 'Endpoint not found', 404);\n }\n\n if (!subEndpointConfig.methods?.includes(method as any)) {\n return createApiErrorResponse('METHOD_NOT_ALLOWED', 'Method not allowed', 405);\n }\n\n return null;\n }\n\n async function validateSessionRequest(): Promise<{\n body: any;\n idToken?: string;\n csrfToken?: string;\n error?: NextResponse;\n }> {\n try {\n const body = await request.json();\n return { body, idToken: body.idToken, csrfToken: body.csrfToken };\n } catch (error) {\n return {\n body: null,\n error: createApiErrorResponse('INVALID_REQUEST_FORMAT', 'Invalid request format', 400),\n };\n }\n }\n\n function validateIdToken(idToken: string | undefined): NextResponse | null {\n if (!idToken) {\n return createApiErrorResponse(\n 'INVALID_TOKEN',\n 'ID token is required for creating session',\n 400,\n );\n }\n return null;\n }\n\n /**\n * Main validation orchestrator function\n * Runs all configured validations in the correct order\n */\n async function validateRequest(config: ValidationConfig): Promise<ComprehensiveValidationResult> {\n if (method === 'OPTIONS' && config.cors) {\n return {\n isValid: true,\n corsResponse: createCorsOptionsResponse(config.cors),\n };\n }\n const pathError = validatePathStructure();\n if (pathError) {\n return { isValid: false, error: pathError };\n }\n\n if (config.cors) {\n const corsError = await validateCors(config.cors);\n if (corsError) {\n return { isValid: false, error: corsError };\n }\n }\n\n if (config.security) {\n const securityError = await validateSecurity(config.security);\n if (securityError) {\n return { isValid: false, error: securityError };\n }\n }\n\n if (config.endpoint) {\n const endpointError = validateEndpoint(config.endpoint.name, config.endpoint.config);\n if (endpointError) {\n return { isValid: false, error: endpointError };\n }\n }\n\n if (config.subEndpoint) {\n const subEndpointError = validateSubEndpoint(\n config.subEndpoint.name,\n config.subEndpoint.config,\n );\n if (subEndpointError) {\n return { isValid: false, error: subEndpointError };\n }\n }\n\n let sessionData;\n if (method === 'POST' && (config.requireIdToken || config.requireCsrfToken)) {\n const sessionResult = await validateSessionRequest();\n if (sessionResult.error) {\n return { isValid: false, error: sessionResult.error };\n }\n\n sessionData = sessionResult;\n\n if (config.requireIdToken) {\n const idTokenError = validateIdToken(sessionData.idToken);\n if (idTokenError) {\n return { isValid: false, error: idTokenError };\n }\n }\n\n if (config.requireCsrfToken && sessionData.csrfToken) {\n const csrfCookieValue = request.cookies.get('csrfToken')?.value;\n const csrfError = validateCsrfToken(sessionData.csrfToken, csrfCookieValue);\n if (csrfError) {\n return { isValid: false, error: csrfError };\n }\n }\n }\n\n return {\n isValid: true,\n sessionData,\n };\n }\n\n /**\n * Convenience function for quick validation setup\n */\n function createValidationConfig(overrides: Partial<ValidationConfig> = {}): ValidationConfig {\n return {\n ...overrides,\n };\n }\n\n return {\n createValidationConfig,\n\n validateRequest,\n\n validateCors,\n validateSecurity,\n validatePathStructure,\n validateEndpoint,\n validateSubEndpoint,\n validateSessionRequest,\n validateIdToken,\n validateCsrfToken,\n\n createCorsOptionsResponse,\n };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../../src/app-router/admin/fnValidators.ts"],"sourcesContent":["import { cookies } from 'next/headers';\n\nimport { createApiErrorResponse } from './responses';\nimport type {\n AuthEndpoint,\n ComprehensiveValidationResult,\n CorsOptions,\n EndpointConfig,\n SecurityOptions,\n SessionSubEndpoint,\n ValidationConfig,\n} from './types';\n//import type { RequestProcessorContext } from './claude-authenticateRequestProcessor';\n\nexport interface RequestContext {\n request: Request;\n origin: string | null;\n host: string | null;\n referer: string | null;\n userAgent: string;\n method: string;\n pathSegments: string[];\n}\n\nexport function createRequestContext(request: Request): RequestContext {\n const url = new URL(request.url);\n const pathSegments = url.pathname.split('/').filter(Boolean);\n\n return {\n request,\n origin: request.headers.get('origin'),\n host: request.headers.get('host'),\n referer: request.headers.get('referer'),\n userAgent: request.headers.get('user-agent') || '',\n method: request.method,\n pathSegments,\n };\n}\n\n/**\n * Main validators factory function\n * Returns an object containing all validator functions and utilities\n */\nexport function createValidators(context: RequestContext) {\n const { request, origin, host, referer, userAgent, method, pathSegments } = context;\n\n async function validateCors(corsOptions: CorsOptions): Promise<Response | null> {\n if (corsOptions.skipSameOrigin) {\n if (!origin || (host && origin.includes(host))) {\n return null;\n }\n }\n\n if (corsOptions.allowedOrigins !== '*') {\n const isAllowed = corsOptions.allowedOrigins.some(allowedOrigin => {\n if (allowedOrigin.startsWith('*')) {\n const domain = allowedOrigin.slice(1);\n return origin?.endsWith(domain);\n }\n return origin === allowedOrigin;\n });\n\n if (!isAllowed) {\n return createApiErrorResponse('CORS_ORIGIN_NOT_ALLOWED', 'Origin not allowed', 403);\n }\n }\n\n return null;\n }\n\n function createCorsOptionsResponse(corsOptions: CorsOptions): Response {\n const response = new Response(null, { status: 204 });\n\n if (corsOptions.allowedOrigins === '*') {\n response.headers.set('Access-Control-Allow-Origin', '*');\n } else {\n response.headers.set('Access-Control-Allow-Origin', corsOptions.allowedOrigins.join(','));\n }\n\n response.headers.set(\n 'Access-Control-Allow-Methods',\n corsOptions.allowedMethods?.join(',') || 'GET,POST',\n );\n response.headers.set(\n 'Access-Control-Allow-Headers',\n corsOptions.allowedHeaders?.join(',') || 'Content-Type,Authorization',\n );\n\n if (corsOptions.allowCredentials) {\n response.headers.set('Access-Control-Allow-Credentials', 'true');\n }\n\n if (corsOptions.maxAge) {\n response.headers.set('Access-Control-Max-Age', corsOptions.maxAge.toString());\n }\n\n return response;\n }\n\n async function validateSecurity(securityOptions: SecurityOptions): Promise<Response | null> {\n const csrfResult = validateCsrf(securityOptions);\n if (csrfResult) return csrfResult;\n\n const headersResult = validateRequiredHeaders(securityOptions);\n if (headersResult) return headersResult;\n\n const userAgentResult = validateUserAgent(securityOptions);\n if (userAgentResult) return userAgentResult;\n\n return null;\n }\n\n function validateCsrf(securityOptions: SecurityOptions): Response | null {\n if (securityOptions.requireCSRF && origin && host && !origin.includes(host)) {\n const hasCSRFHeader = request.headers.get('x-requested-with') === 'XMLHttpRequest';\n const hasValidReferer = referer && host && referer.includes(host);\n\n if (!hasCSRFHeader && !hasValidReferer) {\n const isAllowedReferer = securityOptions.allowedReferers?.some((allowedRef: string) =>\n referer?.includes(allowedRef),\n );\n\n if (!isAllowedReferer) {\n return createApiErrorResponse('CSRF_PROTECTION', 'Access denied', 403);\n }\n }\n }\n return null;\n }\n\n function validateRequiredHeaders(securityOptions: SecurityOptions): Response | null {\n if (securityOptions.requiredHeaders) {\n for (const [headerName, expectedValue] of Object.entries(securityOptions.requiredHeaders)) {\n const actualValue = request.headers.get(headerName);\n if (actualValue !== expectedValue) {\n return createApiErrorResponse(\n 'INVALID_HEADERS',\n 'Required header missing or invalid',\n 400,\n );\n }\n }\n }\n return null;\n }\n\n function validateUserAgent(securityOptions: SecurityOptions): Response | null {\n if (securityOptions.userAgent?.block?.length) {\n const isBlocked = securityOptions.userAgent.block.some((blocked: string) =>\n userAgent.toLowerCase().includes(blocked.toLowerCase()),\n );\n\n if (isBlocked) {\n return createApiErrorResponse('USER_AGENT_BLOCKED', 'Access denied', 403);\n }\n }\n\n if (securityOptions.userAgent?.allow?.length) {\n const isAllowed = securityOptions.userAgent.allow.some((allowed: string) =>\n userAgent.toLowerCase().includes(allowed.toLowerCase()),\n );\n\n if (!isAllowed) {\n return createApiErrorResponse('USER_AGENT_NOT_ALLOWED', 'Access denied', 403);\n }\n }\n\n return null;\n }\n\n function validateCsrfToken(\n csrfToken: string,\n csrfCookieValue: string | undefined,\n ): Response | null {\n if (!csrfToken) {\n return createApiErrorResponse('INVALID_CSRF_TOKEN', 'CSRF token is required', 400);\n }\n\n if (!csrfCookieValue) {\n return createApiErrorResponse('CSRF_COOKIE_MISSING', 'CSRF token cookie not found', 403);\n }\n\n if (csrfToken !== csrfCookieValue) {\n return createApiErrorResponse('CSRF_TOKEN_MISMATCH', 'CSRF token mismatch', 403);\n }\n\n return null;\n }\n\n function validatePathStructure(): Response | null {\n if (pathSegments.length < 3) {\n return createApiErrorResponse(\n 'INVALID_ROUTE',\n 'Invalid route structure. Expected: /api/auth/{endpoint}',\n 404,\n );\n }\n return null;\n }\n\n function validateEndpoint(\n _endpoint: AuthEndpoint,\n endpointConfig: EndpointConfig,\n ): Response | null {\n if (!endpointConfig || !endpointConfig.enabled) {\n return createApiErrorResponse('ENDPOINT_NOT_FOUND', 'Endpoint not found', 404);\n }\n\n if (method !== 'OPTIONS' && !endpointConfig.methods.includes(method as any)) {\n return createApiErrorResponse('METHOD_NOT_ALLOWED', 'Method not allowed', 405);\n }\n\n return null;\n }\n\n function validateSubEndpoint(\n subEndpoint: SessionSubEndpoint | undefined,\n subEndpointConfig: any,\n ): Response | null {\n if (!subEndpoint) {\n return createApiErrorResponse('SUB_ENDPOINT_REQUIRED', 'Session sub-endpoint required', 400);\n }\n\n if (!subEndpointConfig || !subEndpointConfig.enabled) {\n return createApiErrorResponse('ENDPOINT_NOT_FOUND', 'Endpoint not found', 404);\n }\n\n if (!subEndpointConfig.methods?.includes(method as any)) {\n return createApiErrorResponse('METHOD_NOT_ALLOWED', 'Method not allowed', 405);\n }\n\n return null;\n }\n\n async function validateSessionRequest(): Promise<{\n body: any;\n idToken?: string;\n csrfToken?: string;\n error?: Response;\n }> {\n try {\n const body = await request.json();\n return { body, idToken: body.idToken, csrfToken: body.csrfToken };\n } catch (error) {\n return {\n body: null,\n error: createApiErrorResponse('INVALID_REQUEST_FORMAT', 'Invalid request format', 400),\n };\n }\n }\n\n function validateIdToken(idToken: string | undefined): Response | null {\n if (!idToken) {\n return createApiErrorResponse(\n 'INVALID_TOKEN',\n 'ID token is required for creating session',\n 400,\n );\n }\n return null;\n }\n\n /**\n * Main validation orchestrator function\n * Runs all configured validations in the correct order\n */\n async function validateRequest(config: ValidationConfig): Promise<ComprehensiveValidationResult> {\n if (method === 'OPTIONS' && config.cors) {\n return {\n isValid: true,\n corsResponse: createCorsOptionsResponse(config.cors),\n };\n }\n const pathError = validatePathStructure();\n if (pathError) {\n return { isValid: false, error: pathError };\n }\n\n if (config.cors) {\n const corsError = await validateCors(config.cors);\n if (corsError) {\n return { isValid: false, error: corsError };\n }\n }\n\n if (config.security) {\n const securityError = await validateSecurity(config.security);\n if (securityError) {\n return { isValid: false, error: securityError };\n }\n }\n\n if (config.endpoint) {\n const endpointError = validateEndpoint(config.endpoint.name, config.endpoint.config);\n if (endpointError) {\n return { isValid: false, error: endpointError };\n }\n }\n\n if (config.subEndpoint) {\n const subEndpointError = validateSubEndpoint(\n config.subEndpoint.name,\n config.subEndpoint.config,\n );\n if (subEndpointError) {\n return { isValid: false, error: subEndpointError };\n }\n }\n\n let sessionData;\n if (method === 'POST' && (config.requireIdToken || config.requireCsrfToken)) {\n const sessionResult = await validateSessionRequest();\n if (sessionResult.error) {\n return { isValid: false, error: sessionResult.error };\n }\n\n sessionData = sessionResult;\n\n if (config.requireIdToken) {\n const idTokenError = validateIdToken(sessionData.idToken);\n if (idTokenError) {\n return { isValid: false, error: idTokenError };\n }\n }\n\n if (config.requireCsrfToken && sessionData.csrfToken) {\n const cookieStore = await cookies();\n const csrfCookieValue = cookieStore.get('csrfToken')?.value;\n const csrfError = validateCsrfToken(sessionData.csrfToken, csrfCookieValue);\n if (csrfError) {\n return { isValid: false, error: csrfError };\n }\n }\n }\n\n return {\n isValid: true,\n sessionData,\n };\n }\n\n /**\n * Convenience function for quick validation setup\n */\n function createValidationConfig(overrides: Partial<ValidationConfig> = {}): ValidationConfig {\n return {\n ...overrides,\n };\n }\n\n return {\n createValidationConfig,\n\n validateRequest,\n\n validateCors,\n validateSecurity,\n validatePathStructure,\n validateEndpoint,\n validateSubEndpoint,\n validateSessionRequest,\n validateIdToken,\n validateCsrfToken,\n\n createCorsOptionsResponse,\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createRequestContext, createValidators } from "./fnValidators";
|
|
2
|
+
class RequestContextBuilder {
|
|
3
|
+
static create(request) {
|
|
4
|
+
const context = createRequestContext(request);
|
|
5
|
+
const { pathSegments } = context;
|
|
6
|
+
return {
|
|
7
|
+
request,
|
|
8
|
+
pathSegments,
|
|
9
|
+
endpoint: pathSegments[2],
|
|
10
|
+
subEndpoint: pathSegments[3],
|
|
11
|
+
method: request.method
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
class ValidationPipeline {
|
|
16
|
+
config;
|
|
17
|
+
context;
|
|
18
|
+
constructor(config, context) {
|
|
19
|
+
this.config = config;
|
|
20
|
+
this.context = context;
|
|
21
|
+
}
|
|
22
|
+
async execute() {
|
|
23
|
+
const validators = createValidators(this.context);
|
|
24
|
+
const corsError = await validators.validateCors(this.config.cors);
|
|
25
|
+
if (corsError) return corsError;
|
|
26
|
+
if (this.context.method === "OPTIONS") {
|
|
27
|
+
return validators.createCorsOptionsResponse(this.config.cors);
|
|
28
|
+
}
|
|
29
|
+
const securityError = await validators.validateSecurity(this.config.security);
|
|
30
|
+
if (securityError) return securityError;
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export {
|
|
35
|
+
RequestContextBuilder,
|
|
36
|
+
ValidationPipeline
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=handlerUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/app-router/admin/handlerUtils.ts"],"sourcesContent":["import type { RequestContext } from './fnValidators';\nimport { createRequestContext, createValidators } from './fnValidators';\nimport type {\n AuthEndpoint,\n SessionSubEndpoint,\n TernSecureHandlerOptions,\n} from './types';\n\nexport interface HandlerContext {\n request: Request;\n pathSegments: string[];\n endpoint: AuthEndpoint;\n subEndpoint: SessionSubEndpoint | undefined;\n method: string;\n}\n\nexport class RequestContextBuilder {\n static create(request: Request): HandlerContext {\n const context = createRequestContext(request);\n const { pathSegments } = context;\n\n return {\n request,\n pathSegments,\n endpoint: pathSegments[2] as AuthEndpoint,\n subEndpoint: pathSegments[3] as SessionSubEndpoint | undefined,\n method: request.method,\n };\n }\n}\n\nexport class ValidationPipeline {\n private readonly config: Required<TernSecureHandlerOptions>;\n private readonly context: RequestContext;\n\n constructor(\n config: Required<TernSecureHandlerOptions>,\n context: RequestContext,\n ) {\n this.config = config;\n this.context = context;\n }\n\n async execute(): Promise<Response | null> {\n const validators = createValidators(this.context);\n\n const corsError = await validators.validateCors(this.config.cors);\n if (corsError) return corsError;\n\n if (this.context.method === 'OPTIONS') {\n return validators.createCorsOptionsResponse(this.config.cors);\n }\n\n const securityError = await validators.validateSecurity(this.config.security);\n if (securityError) return securityError;\n\n return null;\n }\n}\n\n"],"mappings":"AACA,SAAS,sBAAsB,wBAAwB;AAehD,MAAM,sBAAsB;AAAA,EACjC,OAAO,OAAO,SAAkC;AAC9C,UAAM,UAAU,qBAAqB,OAAO;AAC5C,UAAM,EAAE,aAAa,IAAI;AAEzB,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,UAAU,aAAa,CAAC;AAAA,MACxB,aAAa,aAAa,CAAC;AAAA,MAC3B,QAAQ,QAAQ;AAAA,IAClB;AAAA,EACF;AACF;AAEO,MAAM,mBAAmB;AAAA,EACb;AAAA,EACA;AAAA,EAEjB,YACE,QACA,SACA;AACA,SAAK,SAAS;AACd,SAAK,UAAU;AAAA,EACjB;AAAA,EAEA,MAAM,UAAoC;AACxC,UAAM,aAAa,iBAAiB,KAAK,OAAO;AAEhD,UAAM,YAAY,MAAM,WAAW,aAAa,KAAK,OAAO,IAAI;AAChE,QAAI,UAAW,QAAO;AAEtB,QAAI,KAAK,QAAQ,WAAW,WAAW;AACrC,aAAO,WAAW,0BAA0B,KAAK,OAAO,IAAI;AAAA,IAC9D;AAEA,UAAM,gBAAgB,MAAM,WAAW,iBAAiB,KAAK,OAAO,QAAQ;AAC5E,QAAI,cAAe,QAAO;AAE1B,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
@@ -7,7 +7,12 @@ import {
|
|
|
7
7
|
setNextServerSession,
|
|
8
8
|
setNextServerToken
|
|
9
9
|
} from "./actions";
|
|
10
|
+
import { EndpointRouter } from "./endpointRouter";
|
|
11
|
+
import { RequestContextBuilder, ValidationPipeline } from "./handlerUtils";
|
|
10
12
|
export {
|
|
13
|
+
EndpointRouter,
|
|
14
|
+
RequestContextBuilder,
|
|
15
|
+
ValidationPipeline,
|
|
11
16
|
clearNextSessionCookie,
|
|
12
17
|
clearSessionCookieServer,
|
|
13
18
|
createNextSessionCookie,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/app-router/admin/index.ts"],"sourcesContent":["export { createTernSecureNextJsHandler } from './ternsecureNextjsHandler'\n\nexport {
|
|
1
|
+
{"version":3,"sources":["../../../../src/app-router/admin/index.ts"],"sourcesContent":["export { createTernSecureNextJsHandler } from './ternsecureNextjsHandler'\n\nexport {\n clearSessionCookieServer,\n clearNextSessionCookie,\n createSessionCookieServer,\n createNextSessionCookie,\n setNextServerSession,\n setNextServerToken\n} from './actions'\n\nexport { EndpointRouter } from './endpointRouter'\nexport { RequestContextBuilder, ValidationPipeline } from './handlerUtils'\nexport type { HandlerContext } from './handlerUtils'\n\nexport type { TernSecureHandlerOptions, TernSecureInternalHandlerConfig } from './types'"],"mappings":"AAAA,SAAS,qCAAqC;AAE9C;AAAA,EACI;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACG;AAEP,SAAS,sBAAsB;AAC/B,SAAS,uBAAuB,0BAA0B;","names":[]}
|