@tern-secure/nextjs 5.2.0-canary.v20251127235234 → 5.2.0-canary.v20251202162458

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.
Files changed (97) hide show
  1. package/dist/cjs/__tests__/gemini_fnTernSecureNextHandler.bench.js +2 -2
  2. package/dist/cjs/__tests__/gemini_fnTernSecureNextHandler.bench.js.map +1 -1
  3. package/dist/cjs/app-router/admin/actions.js.map +1 -1
  4. package/dist/cjs/app-router/admin/endpointRouter.js +4 -13
  5. package/dist/cjs/app-router/admin/endpointRouter.js.map +1 -1
  6. package/dist/cjs/app-router/admin/{sessionHandlers.js → handlers.js} +16 -115
  7. package/dist/cjs/app-router/admin/handlers.js.map +1 -0
  8. package/dist/cjs/app-router/admin/index.js.map +1 -1
  9. package/dist/cjs/app-router/admin/request.js +1 -8
  10. package/dist/cjs/app-router/admin/request.js.map +1 -1
  11. package/dist/cjs/app-router/admin/signInCreateHandler.js.map +1 -1
  12. package/dist/cjs/app-router/admin/ternsecureNextjsHandler.js +7 -17
  13. package/dist/cjs/app-router/admin/ternsecureNextjsHandler.js.map +1 -1
  14. package/dist/cjs/app-router/admin/types.js +9 -0
  15. package/dist/cjs/app-router/admin/types.js.map +1 -1
  16. package/dist/cjs/app-router/admin/validators.js +96 -171
  17. package/dist/cjs/app-router/admin/validators.js.map +1 -1
  18. package/dist/cjs/app-router/server/TernSecureProvider.js +18 -0
  19. package/dist/cjs/app-router/server/TernSecureProvider.js.map +1 -1
  20. package/dist/cjs/server/constant.js +6 -0
  21. package/dist/cjs/server/constant.js.map +1 -1
  22. package/dist/cjs/server/data/getAuthDataFromRequest.js +16 -9
  23. package/dist/cjs/server/data/getAuthDataFromRequest.js.map +1 -1
  24. package/dist/cjs/server/headers-utils.js +3 -3
  25. package/dist/cjs/server/headers-utils.js.map +1 -1
  26. package/dist/cjs/server/proxy-storage.js +33 -0
  27. package/dist/cjs/server/proxy-storage.js.map +1 -0
  28. package/dist/cjs/server/ternSecureProxy.js +2 -13
  29. package/dist/cjs/server/ternSecureProxy.js.map +1 -1
  30. package/dist/cjs/server/utils.js +16 -4
  31. package/dist/cjs/server/utils.js.map +1 -1
  32. package/dist/esm/__tests__/gemini_fnTernSecureNextHandler.bench.js +1 -1
  33. package/dist/esm/__tests__/gemini_fnTernSecureNextHandler.bench.js.map +1 -1
  34. package/dist/esm/app-router/admin/actions.js.map +1 -1
  35. package/dist/esm/app-router/admin/endpointRouter.js +3 -12
  36. package/dist/esm/app-router/admin/endpointRouter.js.map +1 -1
  37. package/dist/esm/app-router/admin/{sessionHandlers.js → handlers.js} +18 -110
  38. package/dist/esm/app-router/admin/handlers.js.map +1 -0
  39. package/dist/esm/app-router/admin/index.js.map +1 -1
  40. package/dist/esm/app-router/admin/request.js +2 -14
  41. package/dist/esm/app-router/admin/request.js.map +1 -1
  42. package/dist/esm/app-router/admin/signInCreateHandler.js.map +1 -1
  43. package/dist/esm/app-router/admin/ternsecureNextjsHandler.js +9 -19
  44. package/dist/esm/app-router/admin/ternsecureNextjsHandler.js.map +1 -1
  45. package/dist/esm/app-router/admin/types.js +8 -0
  46. package/dist/esm/app-router/admin/types.js.map +1 -1
  47. package/dist/esm/app-router/admin/validators.js +88 -166
  48. package/dist/esm/app-router/admin/validators.js.map +1 -1
  49. package/dist/esm/app-router/server/TernSecureProvider.js +19 -1
  50. package/dist/esm/app-router/server/TernSecureProvider.js.map +1 -1
  51. package/dist/esm/server/constant.js +4 -0
  52. package/dist/esm/server/constant.js.map +1 -1
  53. package/dist/esm/server/data/getAuthDataFromRequest.js +18 -11
  54. package/dist/esm/server/data/getAuthDataFromRequest.js.map +1 -1
  55. package/dist/esm/server/headers-utils.js +2 -2
  56. package/dist/esm/server/headers-utils.js.map +1 -1
  57. package/dist/esm/server/proxy-storage.js +8 -0
  58. package/dist/esm/server/proxy-storage.js.map +1 -0
  59. package/dist/esm/server/ternSecureProxy.js +7 -14
  60. package/dist/esm/server/ternSecureProxy.js.map +1 -1
  61. package/dist/esm/server/utils.js +16 -4
  62. package/dist/esm/server/utils.js.map +1 -1
  63. package/dist/types/app-router/admin/actions.d.ts +2 -2
  64. package/dist/types/app-router/admin/actions.d.ts.map +1 -1
  65. package/dist/types/app-router/admin/endpointRouter.d.ts +4 -4
  66. package/dist/types/app-router/admin/endpointRouter.d.ts.map +1 -1
  67. package/dist/types/app-router/admin/handlers.d.ts +5 -0
  68. package/dist/types/app-router/admin/handlers.d.ts.map +1 -0
  69. package/dist/types/app-router/admin/index.d.ts +1 -1
  70. package/dist/types/app-router/admin/index.d.ts.map +1 -1
  71. package/dist/types/app-router/admin/request.d.ts +2 -2
  72. package/dist/types/app-router/admin/request.d.ts.map +1 -1
  73. package/dist/types/app-router/admin/signInCreateHandler.d.ts +1 -1
  74. package/dist/types/app-router/admin/signInCreateHandler.d.ts.map +1 -1
  75. package/dist/types/app-router/admin/ternsecureNextjsHandler.d.ts +6 -2
  76. package/dist/types/app-router/admin/ternsecureNextjsHandler.d.ts.map +1 -1
  77. package/dist/types/app-router/admin/types.d.ts +24 -2
  78. package/dist/types/app-router/admin/types.d.ts.map +1 -1
  79. package/dist/types/app-router/admin/validators.d.ts +36 -33
  80. package/dist/types/app-router/admin/validators.d.ts.map +1 -1
  81. package/dist/types/app-router/server/TernSecureProvider.d.ts.map +1 -1
  82. package/dist/types/server/constant.d.ts +2 -0
  83. package/dist/types/server/constant.d.ts.map +1 -1
  84. package/dist/types/server/data/getAuthDataFromRequest.d.ts.map +1 -1
  85. package/dist/types/server/headers-utils.d.ts +1 -1
  86. package/dist/types/server/headers-utils.d.ts.map +1 -1
  87. package/dist/types/server/proxy-storage.d.ts +5 -0
  88. package/dist/types/server/proxy-storage.d.ts.map +1 -0
  89. package/dist/types/server/ternSecureProxy.d.ts +1 -3
  90. package/dist/types/server/ternSecureProxy.d.ts.map +1 -1
  91. package/dist/types/server/utils.d.ts +2 -2
  92. package/dist/types/server/utils.d.ts.map +1 -1
  93. package/package.json +5 -5
  94. package/dist/cjs/app-router/admin/sessionHandlers.js.map +0 -1
  95. package/dist/esm/app-router/admin/sessionHandlers.js.map +0 -1
  96. package/dist/types/app-router/admin/sessionHandlers.d.ts +0 -7
  97. package/dist/types/app-router/admin/sessionHandlers.d.ts.map +0 -1
@@ -18,199 +18,124 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var validators_exports = {};
20
20
  __export(validators_exports, {
21
- CorsValidator: () => CorsValidator,
22
- CsrfValidator: () => CsrfValidator,
23
- RequestValidator: () => RequestValidator,
24
- RouteValidator: () => RouteValidator,
25
- SecurityValidator: () => SecurityValidator
21
+ extractSessionRequestData: () => extractSessionRequestData,
22
+ validateCsrfToken: () => validateCsrfToken,
23
+ validateEmail: () => validateEmail,
24
+ validateIdToken: () => validateIdToken,
25
+ validateJsonBody: () => validateJsonBody,
26
+ validatePassword: () => validatePassword,
27
+ validateRequiredFields: () => validateRequiredFields,
28
+ validateSubEndpointPresent: () => validateSubEndpointPresent
26
29
  });
27
30
  module.exports = __toCommonJS(validators_exports);
31
+ var import_backend = require("@tern-secure/backend");
32
+ var import_headers = require("next/headers");
28
33
  var import_responses = require("./responses");
29
- class CorsValidator {
30
- static async validate(request, corsOptions) {
31
- const origin = request.headers.get("origin");
32
- const host = request.headers.get("host");
33
- if (!origin || host && origin.includes(host)) {
34
- return null;
35
- }
36
- if (corsOptions.allowedOrigins !== "*") {
37
- const isAllowed = corsOptions.allowedOrigins.some((allowedOrigin) => {
38
- if (allowedOrigin.startsWith("*")) {
39
- const domain = allowedOrigin.slice(1);
40
- return origin?.endsWith(domain);
41
- }
42
- return origin === allowedOrigin;
43
- });
44
- if (!isAllowed) {
45
- return (0, import_responses.createApiErrorResponse)("CORS_ORIGIN_NOT_ALLOWED", "Origin not allowed", 403);
46
- }
47
- }
48
- return null;
34
+ async function validateJsonBody(request) {
35
+ try {
36
+ const body = await request.json();
37
+ return { body };
38
+ } catch (error) {
39
+ return {
40
+ body: null,
41
+ error: (0, import_responses.createApiErrorResponse)("INVALID_REQUEST_FORMAT", "Invalid JSON in request body", 400)
42
+ };
49
43
  }
50
- static createOptionsResponse(corsOptions) {
51
- const response = new Response(null, { status: 204 });
52
- if (corsOptions.allowedOrigins === "*") {
53
- response.headers.set("Access-Control-Allow-Origin", "*");
54
- } else {
55
- response.headers.set("Access-Control-Allow-Origin", corsOptions.allowedOrigins.join(","));
56
- }
57
- response.headers.set(
58
- "Access-Control-Allow-Methods",
59
- corsOptions.allowedMethods?.join(",") || "GET,POST"
44
+ }
45
+ function validateIdToken(idToken) {
46
+ if (!idToken) {
47
+ return (0, import_responses.createApiErrorResponse)(
48
+ "INVALID_TOKEN",
49
+ "ID token is required",
50
+ 400
60
51
  );
61
- response.headers.set(
62
- "Access-Control-Allow-Headers",
63
- corsOptions.allowedHeaders?.join(",") || "Content-Type,Authorization"
52
+ }
53
+ if (idToken.split(".").length !== 3) {
54
+ return (0, import_responses.createApiErrorResponse)(
55
+ "INVALID_TOKEN_FORMAT",
56
+ "ID token must be a valid JWT",
57
+ 400
64
58
  );
65
- if (corsOptions.allowCredentials) {
66
- response.headers.set("Access-Control-Allow-Credentials", "true");
67
- }
68
- if (corsOptions.maxAge) {
69
- response.headers.set("Access-Control-Max-Age", corsOptions.maxAge.toString());
70
- }
71
- return response;
72
59
  }
60
+ return null;
73
61
  }
74
- class SecurityValidator {
75
- static async validate(request, securityOptions) {
76
- const origin = request.headers.get("origin");
77
- const host = request.headers.get("host");
78
- const referer = request.headers.get("referer");
79
- const userAgent = request.headers.get("user-agent") || "";
80
- const csrfResult = this.validateCsrf(request, securityOptions, origin, host, referer);
81
- if (csrfResult) return csrfResult;
82
- const headersResult = this.validateRequiredHeaders(request, securityOptions);
83
- if (headersResult) return headersResult;
84
- const userAgentResult = this.validateUserAgent(userAgent, securityOptions);
85
- if (userAgentResult) return userAgentResult;
86
- return null;
87
- }
88
- static validateCsrf(request, securityOptions, origin, host, referer) {
89
- if (securityOptions.requireCSRF && origin && host && !origin.includes(host)) {
90
- const hasCSRFHeader = request.headers.get("x-requested-with") === "XMLHttpRequest";
91
- const hasValidReferer = referer && host && referer.includes(host);
92
- if (!hasCSRFHeader && !hasValidReferer) {
93
- const isAllowedReferer = securityOptions.allowedReferers?.some(
94
- (allowedRef) => referer?.includes(allowedRef)
95
- );
96
- if (!isAllowedReferer) {
97
- return (0, import_responses.createApiErrorResponse)("CSRF_PROTECTION", "Access denied", 403);
98
- }
99
- }
100
- }
101
- return null;
62
+ async function validateCsrfToken(csrfToken) {
63
+ if (!csrfToken) {
64
+ return (0, import_responses.createApiErrorResponse)("INVALID_CSRF_TOKEN", "CSRF token is required", 400);
102
65
  }
103
- static validateRequiredHeaders(request, securityOptions) {
104
- if (securityOptions.requiredHeaders) {
105
- for (const [headerName, expectedValue] of Object.entries(securityOptions.requiredHeaders)) {
106
- const actualValue = request.headers.get(headerName);
107
- if (actualValue !== expectedValue) {
108
- return (0, import_responses.createApiErrorResponse)(
109
- "INVALID_HEADERS",
110
- "Required header missing or invalid",
111
- 400
112
- );
113
- }
114
- }
115
- }
116
- return null;
66
+ const cookieStore = await (0, import_headers.cookies)();
67
+ const csrfCookieValue = cookieStore.get(import_backend.constants.Cookies.CsrfToken)?.value;
68
+ if (!csrfCookieValue) {
69
+ return (0, import_responses.createApiErrorResponse)("CSRF_MISSING", "CSRF token cookie not found", 403);
117
70
  }
118
- static validateUserAgent(userAgent, securityOptions) {
119
- if (securityOptions.userAgent?.block?.length) {
120
- const isBlocked = securityOptions.userAgent.block.some(
121
- (blocked) => userAgent.toLowerCase().includes(blocked.toLowerCase())
122
- );
123
- if (isBlocked) {
124
- return (0, import_responses.createApiErrorResponse)("USER_AGENT_BLOCKED", "Access denied", 403);
125
- }
126
- }
127
- if (securityOptions.userAgent?.allow?.length) {
128
- const isAllowed = securityOptions.userAgent.allow.some(
129
- (allowed) => userAgent.toLowerCase().includes(allowed.toLowerCase())
130
- );
131
- if (!isAllowed) {
132
- return (0, import_responses.createApiErrorResponse)("USER_AGENT_NOT_ALLOWED", "Access denied", 403);
133
- }
134
- }
135
- return null;
71
+ if (csrfToken !== csrfCookieValue) {
72
+ return (0, import_responses.createApiErrorResponse)("CSRF_TOKEN_MISMATCH", "CSRF token mismatch", 403);
136
73
  }
74
+ return null;
137
75
  }
138
- class CsrfValidator {
139
- static validate(csrfToken, csrfCookieValue) {
140
- if (!csrfToken) {
141
- return (0, import_responses.createApiErrorResponse)("INVALID_CSRF_TOKEN", "CSRF token is required", 400);
142
- }
143
- if (!csrfCookieValue) {
144
- return (0, import_responses.createApiErrorResponse)("CSRF_COOKIE_MISSING", "CSRF token cookie not found", 403);
145
- }
146
- if (csrfToken !== csrfCookieValue) {
147
- return (0, import_responses.createApiErrorResponse)("CSRF_TOKEN_MISMATCH", "CSRF token mismatch", 403);
148
- }
149
- return null;
76
+ function validateEmail(email) {
77
+ if (!email || typeof email !== "string") {
78
+ return (0, import_responses.createApiErrorResponse)("EMAIL_REQUIRED", "Email is required", 400);
150
79
  }
80
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
81
+ if (!emailRegex.test(email)) {
82
+ return (0, import_responses.createApiErrorResponse)("INVALID_EMAIL", "Invalid email format", 400);
83
+ }
84
+ return null;
151
85
  }
152
- class RouteValidator {
153
- static validatePathStructure(pathSegments) {
154
- if (pathSegments.length < 3) {
155
- return (0, import_responses.createApiErrorResponse)(
156
- "INVALID_ROUTE",
157
- "Invalid route structure. Expected: /api/auth/{endpoint}",
158
- 404
159
- );
160
- }
161
- return null;
86
+ function validatePassword(password) {
87
+ if (!password || typeof password !== "string") {
88
+ return (0, import_responses.createApiErrorResponse)("PASSWORD_REQUIRED", "Password is required", 400);
162
89
  }
163
- static validateEndpoint(_endpoint, endpointConfig, method) {
164
- if (!endpointConfig || !endpointConfig.enabled) {
165
- return (0, import_responses.createApiErrorResponse)("ENDPOINT_NOT_FOUND", "Endpoint not found", 404);
166
- }
167
- if (method !== "OPTIONS" && !endpointConfig.methods.includes(method)) {
168
- return (0, import_responses.createApiErrorResponse)("METHOD_NOT_ALLOWED", "Method not allowed", 405);
169
- }
170
- return null;
90
+ if (password.length < 6) {
91
+ return (0, import_responses.createApiErrorResponse)(
92
+ "PASSWORD_TOO_SHORT",
93
+ "Password must be at least 6 characters",
94
+ 400
95
+ );
171
96
  }
172
- static validateSubEndpoint(subEndpoint, subEndpointConfig, method) {
173
- if (!subEndpoint) {
174
- return (0, import_responses.createApiErrorResponse)("SUB_ENDPOINT_REQUIRED", "Session sub-endpoint required", 400);
175
- }
176
- if (!subEndpointConfig || !subEndpointConfig.enabled) {
177
- return (0, import_responses.createApiErrorResponse)("ENDPOINT_NOT_FOUND", "Endpoint not found", 404);
178
- }
179
- if (!subEndpointConfig.methods?.includes(method)) {
180
- return (0, import_responses.createApiErrorResponse)("METHOD_NOT_ALLOWED", "Method not allowed", 405);
181
- }
182
- return null;
97
+ return null;
98
+ }
99
+ function validateRequiredFields(body, fields) {
100
+ const missingFields = fields.filter((field) => !body[field]);
101
+ if (missingFields.length > 0) {
102
+ return (0, import_responses.createApiErrorResponse)(
103
+ "MISSING_REQUIRED_FIELDS",
104
+ `Missing required fields: ${missingFields.join(", ")}`,
105
+ 400
106
+ );
183
107
  }
108
+ return null;
184
109
  }
185
- class RequestValidator {
186
- static async validateSessionRequest(request) {
187
- try {
188
- const body = await request.json();
189
- return { body, idToken: body.idToken, csrfToken: body.csrfToken };
190
- } catch (error) {
191
- return {
192
- body: null,
193
- error: (0, import_responses.createApiErrorResponse)("INVALID_REQUEST_FORMAT", "Invalid request format", 400)
194
- };
195
- }
110
+ function validateSubEndpointPresent(context, endpointType) {
111
+ if (!context.subEndpoint) {
112
+ return (0, import_responses.createApiErrorResponse)(
113
+ "SUB_ENDPOINT_REQUIRED",
114
+ `${endpointType} sub-endpoint required`,
115
+ 400
116
+ );
196
117
  }
197
- static validateIdToken(idToken) {
198
- if (!idToken) {
199
- return (0, import_responses.createApiErrorResponse)(
200
- "INVALID_TOKEN",
201
- "ID token is required for creating session",
202
- 400
203
- );
204
- }
205
- return null;
118
+ return null;
119
+ }
120
+ async function extractSessionRequestData(request) {
121
+ const { body, error } = await validateJsonBody(request);
122
+ if (error) {
123
+ return { error };
206
124
  }
125
+ return {
126
+ idToken: body.idToken,
127
+ csrfToken: body.csrfToken
128
+ };
207
129
  }
208
130
  // Annotate the CommonJS export names for ESM import in node:
209
131
  0 && (module.exports = {
210
- CorsValidator,
211
- CsrfValidator,
212
- RequestValidator,
213
- RouteValidator,
214
- SecurityValidator
132
+ extractSessionRequestData,
133
+ validateCsrfToken,
134
+ validateEmail,
135
+ validateIdToken,
136
+ validateJsonBody,
137
+ validatePassword,
138
+ validateRequiredFields,
139
+ validateSubEndpointPresent
215
140
  });
216
141
  //# sourceMappingURL=validators.js.map
@@ -1 +1 @@
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
+ {"version":3,"sources":["../../../../src/app-router/admin/validators.ts"],"sourcesContent":["import type { RequestProcessorContext } from '@tern-secure/backend';\nimport { constants } from '@tern-secure/backend'\nimport { cookies } from 'next/headers';\n\nimport { createApiErrorResponse } from './responses';\n\n/**\n * Lightweight validators for API route handlers\n * Note: Middleware already handles CORS, security, and CSRF validation\n * These validators only handle endpoint-specific validation\n */\n\n/**\n * Validates that the request body is valid JSON\n */\nexport async function validateJsonBody(request: Request): Promise<{\n body: any;\n error?: Response;\n}> {\n try {\n const body = await request.json();\n return { body };\n } catch (error) {\n return {\n body: null,\n error: createApiErrorResponse('INVALID_REQUEST_FORMAT', 'Invalid JSON in request body', 400),\n };\n }\n}\n\n/**\n * Validates that an ID token is present and has correct JWT structure\n */\nexport function validateIdToken(idToken: string | undefined): Response | null {\n if (!idToken) {\n return createApiErrorResponse(\n 'INVALID_TOKEN',\n 'ID token is required',\n 400,\n );\n }\n \n if (idToken.split('.').length !== 3) {\n return createApiErrorResponse(\n 'INVALID_TOKEN_FORMAT',\n 'ID token must be a valid JWT',\n 400,\n );\n }\n \n return null;\n}\n\n/**\n * Validates CSRF token matches the cookie value\n * Note: This is only used for specific endpoints that need double-submit CSRF\n */\nexport async function validateCsrfToken(\n csrfToken: string | undefined,\n): Promise<Response | null> {\n if (!csrfToken) {\n return createApiErrorResponse('INVALID_CSRF_TOKEN', 'CSRF token is required', 400);\n }\n\n const cookieStore = await cookies();\n const csrfCookieValue = cookieStore.get(constants.Cookies.CsrfToken)?.value;\n\n if (!csrfCookieValue) {\n return createApiErrorResponse('CSRF_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 * Validates email format (basic validation)\n */\nexport function validateEmail(email: string | undefined): Response | null {\n if (!email || typeof email !== 'string') {\n return createApiErrorResponse('EMAIL_REQUIRED', 'Email is required', 400);\n }\n\n // Basic email validation\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(email)) {\n return createApiErrorResponse('INVALID_EMAIL', 'Invalid email format', 400);\n }\n\n return null;\n}\n\n/**\n * Validates password meets minimum requirements\n */\nexport function validatePassword(password: string | undefined): Response | null {\n if (!password || typeof password !== 'string') {\n return createApiErrorResponse('PASSWORD_REQUIRED', 'Password is required', 400);\n }\n\n if (password.length < 6) {\n return createApiErrorResponse(\n 'PASSWORD_TOO_SHORT',\n 'Password must be at least 6 characters',\n 400,\n );\n }\n\n return null;\n}\n\n/**\n * Validates required fields are present in request body\n */\nexport function validateRequiredFields(\n body: any,\n fields: string[],\n): Response | null {\n const missingFields = fields.filter(field => !body[field]);\n \n if (missingFields.length > 0) {\n return createApiErrorResponse(\n 'MISSING_REQUIRED_FIELDS',\n `Missing required fields: ${missingFields.join(', ')}`,\n 400,\n );\n }\n\n return null;\n}\n\n/**\n * Validates that a sub-endpoint exists in the URL\n */\nexport function validateSubEndpointPresent(\n context: RequestProcessorContext,\n endpointType: string,\n): Response | null {\n if (!context.subEndpoint) {\n return createApiErrorResponse(\n 'SUB_ENDPOINT_REQUIRED',\n `${endpointType} sub-endpoint required`,\n 400,\n );\n }\n \n return null;\n}\n\n/**\n * Helper to extract and validate session request data\n */\nexport async function extractSessionRequestData(request: Request): Promise<{\n idToken?: string;\n csrfToken?: string;\n error?: Response;\n}> {\n const { body, error } = await validateJsonBody(request);\n \n if (error) {\n return { error };\n }\n\n return {\n idToken: body.idToken,\n csrfToken: body.csrfToken,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,qBAA0B;AAC1B,qBAAwB;AAExB,uBAAuC;AAWvC,eAAsB,iBAAiB,SAGpC;AACD,MAAI;AACF,UAAM,OAAO,MAAM,QAAQ,KAAK;AAChC,WAAO,EAAE,KAAK;AAAA,EAChB,SAAS,OAAO;AACd,WAAO;AAAA,MACL,MAAM;AAAA,MACN,WAAO,yCAAuB,0BAA0B,gCAAgC,GAAG;AAAA,IAC7F;AAAA,EACF;AACF;AAKO,SAAS,gBAAgB,SAA8C;AAC5E,MAAI,CAAC,SAAS;AACZ,eAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,MAAI,QAAQ,MAAM,GAAG,EAAE,WAAW,GAAG;AACnC,eAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAMA,eAAsB,kBACpB,WAC0B;AAC1B,MAAI,CAAC,WAAW;AACd,eAAO,yCAAuB,sBAAsB,0BAA0B,GAAG;AAAA,EACnF;AAEA,QAAM,cAAc,UAAM,wBAAQ;AAClC,QAAM,kBAAkB,YAAY,IAAI,yBAAU,QAAQ,SAAS,GAAG;AAEtE,MAAI,CAAC,iBAAiB;AACpB,eAAO,yCAAuB,gBAAgB,+BAA+B,GAAG;AAAA,EAClF;AAEA,MAAI,cAAc,iBAAiB;AACjC,eAAO,yCAAuB,uBAAuB,uBAAuB,GAAG;AAAA,EACjF;AAEA,SAAO;AACT;AAKO,SAAS,cAAc,OAA4C;AACxE,MAAI,CAAC,SAAS,OAAO,UAAU,UAAU;AACvC,eAAO,yCAAuB,kBAAkB,qBAAqB,GAAG;AAAA,EAC1E;AAGA,QAAM,aAAa;AACnB,MAAI,CAAC,WAAW,KAAK,KAAK,GAAG;AAC3B,eAAO,yCAAuB,iBAAiB,wBAAwB,GAAG;AAAA,EAC5E;AAEA,SAAO;AACT;AAKO,SAAS,iBAAiB,UAA+C;AAC9E,MAAI,CAAC,YAAY,OAAO,aAAa,UAAU;AAC7C,eAAO,yCAAuB,qBAAqB,wBAAwB,GAAG;AAAA,EAChF;AAEA,MAAI,SAAS,SAAS,GAAG;AACvB,eAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,uBACd,MACA,QACiB;AACjB,QAAM,gBAAgB,OAAO,OAAO,WAAS,CAAC,KAAK,KAAK,CAAC;AAEzD,MAAI,cAAc,SAAS,GAAG;AAC5B,eAAO;AAAA,MACL;AAAA,MACA,4BAA4B,cAAc,KAAK,IAAI,CAAC;AAAA,MACpD;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,2BACd,SACA,cACiB;AACjB,MAAI,CAAC,QAAQ,aAAa;AACxB,eAAO;AAAA,MACL;AAAA,MACA,GAAG,YAAY;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,eAAsB,0BAA0B,SAI7C;AACD,QAAM,EAAE,MAAM,MAAM,IAAI,MAAM,iBAAiB,OAAO;AAEtD,MAAI,OAAO;AACT,WAAO,EAAE,MAAM;AAAA,EACjB;AAEA,SAAO;AAAA,IACL,SAAS,KAAK;AAAA,IACd,WAAW,KAAK;AAAA,EAClB;AACF;","names":[]}
@@ -32,6 +32,7 @@ __export(TernSecureProvider_exports, {
32
32
  });
33
33
  module.exports = __toCommonJS(TernSecureProvider_exports);
34
34
  var import_jsx_runtime = require("react/jsx-runtime");
35
+ var import_headers = require("next/headers");
35
36
  var import_react = __toESM(require("react"));
36
37
  var import_PromiseAuthProvider = require("../../boundary/PromiseAuthProvider");
37
38
  var import_getAuthDataFromRequest = require("../../server/data/getAuthDataFromRequest");
@@ -44,6 +45,11 @@ const getTernSecureState = import_react.default.cache(async function getTernSecu
44
45
  const data = (0, import_getAuthDataFromRequest.getTernSecureAuthData)(request);
45
46
  return data;
46
47
  });
48
+ const getNonceHeaders = import_react.default.cache(async function getNonceHeaders2() {
49
+ const headersList = await (0, import_headers.headers)();
50
+ const nonce = headersList.get("X-Nonce");
51
+ return nonce ? nonce : (0, import_utils.getScriptNonceFromHeader)(headersList.get("Content-Security-Policy") || "") || "";
52
+ });
47
53
  async function TernSecureProvider(props) {
48
54
  const { children, ...rest } = props;
49
55
  const { persistence } = rest;
@@ -57,6 +63,15 @@ async function TernSecureProvider(props) {
57
63
  }
58
64
  return getTernSecureState();
59
65
  }
66
+ async function generateNonce() {
67
+ if (!browserCookiePersistence) {
68
+ return Promise.resolve("");
69
+ }
70
+ if (import_sdk_versions.isNext13) {
71
+ return Promise.resolve(await getNonceHeaders());
72
+ }
73
+ return getNonceHeaders();
74
+ }
60
75
  const providerProps = (0, import_allNextProviderProps.allNextProviderPropsWithEnv)({ ...rest });
61
76
  let output;
62
77
  if (browserCookiePersistence) {
@@ -68,6 +83,7 @@ async function TernSecureProvider(props) {
68
83
  import_TernSecureProvider.ClientTernSecureProvider,
69
84
  {
70
85
  ...providerProps,
86
+ nonce: await generateNonce(),
71
87
  initialState: await generateStatePromise(),
72
88
  children
73
89
  }
@@ -79,6 +95,8 @@ async function TernSecureProvider(props) {
79
95
  import_TernSecureProvider.ClientTernSecureProvider,
80
96
  {
81
97
  ...providerProps,
98
+ nonce: await generateNonce(),
99
+ initialState: await getTernSecureState(),
82
100
  children
83
101
  }
84
102
  );
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/app-router/server/TernSecureProvider.tsx"],"sourcesContent":["import type { TernSecureInitialState } from '@tern-secure/types';\nimport type { ReactNode } from 'react';\nimport React from 'react';\n\nimport { PromiseAuthProvider } from '../../boundary/PromiseAuthProvider';\nimport { getTernSecureAuthData } from '../../server/data/getAuthDataFromRequest';\nimport { isNext13 } from '../../server/sdk-versions';\nimport type { TernSecureNextProps } from '../../types';\nimport { allNextProviderPropsWithEnv } from '../../utils/allNextProviderProps';\nimport { ClientTernSecureProvider } from '../client/TernSecureProvider';\nimport { buildRequestLike } from './utils';\n\nconst getTernSecureState = React.cache(async function getTernSecureState() {\n const request = await buildRequestLike();\n const data = getTernSecureAuthData(request);\n return data;\n});\n\nexport async function TernSecureProvider(props: TernSecureNextProps) {\n const { children, ...rest } = props;\n const { persistence } = rest;\n\n const browserCookiePersistence = persistence === 'browserCookie';\n\n async function generateStatePromise() {\n if (!browserCookiePersistence) {\n return Promise.resolve(undefined);\n }\n if (isNext13) {\n return Promise.resolve(await getTernSecureState());\n }\n return getTernSecureState();\n }\n\n const providerProps = allNextProviderPropsWithEnv({ ...rest });\n\n let output: ReactNode;\n\n if (browserCookiePersistence) {\n output = (\n <PromiseAuthProvider\n authPromise={generateStatePromise() as unknown as Promise<TernSecureInitialState>}\n >\n <ClientTernSecureProvider\n {...providerProps}\n initialState={await generateStatePromise()}\n >\n {children}\n </ClientTernSecureProvider>\n </PromiseAuthProvider>\n );\n } else {\n output = (\n <ClientTernSecureProvider\n {...providerProps}\n >\n {children}\n </ClientTernSecureProvider>\n );\n }\n\n return output;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA2CQ;AAzCR,mBAAkB;AAElB,iCAAoC;AACpC,oCAAsC;AACtC,0BAAyB;AAEzB,kCAA4C;AAC5C,gCAAyC;AACzC,mBAAiC;AAEjC,MAAM,qBAAqB,aAAAA,QAAM,MAAM,eAAeC,sBAAqB;AACzE,QAAM,UAAU,UAAM,+BAAiB;AACvC,QAAM,WAAO,qDAAsB,OAAO;AAC1C,SAAO;AACT,CAAC;AAED,eAAsB,mBAAmB,OAA4B;AACnE,QAAM,EAAE,UAAU,GAAG,KAAK,IAAI;AAC9B,QAAM,EAAE,YAAY,IAAI;AAExB,QAAM,2BAA2B,gBAAgB;AAEjD,iBAAe,uBAAuB;AACpC,QAAI,CAAC,0BAA0B;AAC7B,aAAO,QAAQ,QAAQ,MAAS;AAAA,IAClC;AACA,QAAI,8BAAU;AACZ,aAAO,QAAQ,QAAQ,MAAM,mBAAmB,CAAC;AAAA,IACnD;AACA,WAAO,mBAAmB;AAAA,EAC5B;AAEA,QAAM,oBAAgB,yDAA4B,EAAE,GAAG,KAAK,CAAC;AAE7D,MAAI;AAEJ,MAAI,0BAA0B;AAC5B,aACE;AAAA,MAAC;AAAA;AAAA,QACC,aAAa,qBAAqB;AAAA,QAElC;AAAA,UAAC;AAAA;AAAA,YACE,GAAG;AAAA,YACJ,cAAc,MAAM,qBAAqB;AAAA,YAExC;AAAA;AAAA,QACH;AAAA;AAAA,IACF;AAAA,EAEJ,OAAO;AACL,aACE;AAAA,MAAC;AAAA;AAAA,QACE,GAAG;AAAA,QAEH;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,SAAO;AACT;","names":["React","getTernSecureState"]}
1
+ {"version":3,"sources":["../../../../src/app-router/server/TernSecureProvider.tsx"],"sourcesContent":["import type { TernSecureInitialState } from '@tern-secure/types';\nimport { headers } from 'next/headers';\nimport type { ReactNode } from 'react';\nimport React from 'react';\n\nimport { PromiseAuthProvider } from '../../boundary/PromiseAuthProvider';\nimport { getTernSecureAuthData } from '../../server/data/getAuthDataFromRequest';\nimport { isNext13 } from '../../server/sdk-versions';\nimport type { TernSecureNextProps } from '../../types';\nimport { allNextProviderPropsWithEnv } from '../../utils/allNextProviderProps';\nimport { ClientTernSecureProvider } from '../client/TernSecureProvider';\nimport { buildRequestLike, getScriptNonceFromHeader } from './utils';\n\nconst getTernSecureState = React.cache(async function getTernSecureState() {\n const request = await buildRequestLike();\n const data = getTernSecureAuthData(request);\n\n return data;\n});\n\nconst getNonceHeaders = React.cache(async function getNonceHeaders() {\n const headersList = await headers();\n const nonce = headersList.get('X-Nonce');\n return nonce \n ? nonce\n : getScriptNonceFromHeader(headersList.get('Content-Security-Policy') || '') || '';\n});\n\nexport async function TernSecureProvider(props: TernSecureNextProps) {\n const { children, ...rest } = props;\n const { persistence } = rest;\n\n const browserCookiePersistence = persistence === 'browserCookie';\n\n async function generateStatePromise() {\n if (!browserCookiePersistence) {\n return Promise.resolve(undefined);\n }\n if (isNext13) {\n return Promise.resolve(await getTernSecureState());\n }\n return getTernSecureState();\n }\n\n async function generateNonce() {\n if (!browserCookiePersistence) {\n return Promise.resolve('');\n }\n if (isNext13) {\n return Promise.resolve(await getNonceHeaders());\n }\n return getNonceHeaders();\n }\n\n const providerProps = allNextProviderPropsWithEnv({ ...rest });\n\n let output: ReactNode;\n\n if (browserCookiePersistence) {\n output = (\n <PromiseAuthProvider\n authPromise={generateStatePromise() as unknown as Promise<TernSecureInitialState>}\n >\n <ClientTernSecureProvider\n {...providerProps}\n nonce={await generateNonce()}\n initialState={await generateStatePromise()}\n >\n {children}\n </ClientTernSecureProvider>\n </PromiseAuthProvider>\n );\n } else {\n output = (\n <ClientTernSecureProvider\n {...providerProps}\n nonce={await generateNonce()}\n initialState={await getTernSecureState()}\n >\n {children}\n </ClientTernSecureProvider>\n );\n }\n\n return output;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA+DQ;AA9DR,qBAAwB;AAExB,mBAAkB;AAElB,iCAAoC;AACpC,oCAAsC;AACtC,0BAAyB;AAEzB,kCAA4C;AAC5C,gCAAyC;AACzC,mBAA2D;AAE3D,MAAM,qBAAqB,aAAAA,QAAM,MAAM,eAAeC,sBAAqB;AACzE,QAAM,UAAU,UAAM,+BAAiB;AACvC,QAAM,WAAO,qDAAsB,OAAO;AAE1C,SAAO;AACT,CAAC;AAED,MAAM,kBAAkB,aAAAD,QAAM,MAAM,eAAeE,mBAAkB;AACnE,QAAM,cAAc,UAAM,wBAAQ;AAClC,QAAM,QAAQ,YAAY,IAAI,SAAS;AACvC,SAAO,QACH,YACA,uCAAyB,YAAY,IAAI,yBAAyB,KAAK,EAAE,KAAK;AACpF,CAAC;AAED,eAAsB,mBAAmB,OAA4B;AACnE,QAAM,EAAE,UAAU,GAAG,KAAK,IAAI;AAC9B,QAAM,EAAE,YAAY,IAAI;AAExB,QAAM,2BAA2B,gBAAgB;AAEjD,iBAAe,uBAAuB;AACpC,QAAI,CAAC,0BAA0B;AAC7B,aAAO,QAAQ,QAAQ,MAAS;AAAA,IAClC;AACA,QAAI,8BAAU;AACZ,aAAO,QAAQ,QAAQ,MAAM,mBAAmB,CAAC;AAAA,IACnD;AACA,WAAO,mBAAmB;AAAA,EAC5B;AAEA,iBAAe,gBAAgB;AAC7B,QAAI,CAAC,0BAA0B;AAC7B,aAAO,QAAQ,QAAQ,EAAE;AAAA,IAC3B;AACA,QAAI,8BAAU;AACZ,aAAO,QAAQ,QAAQ,MAAM,gBAAgB,CAAC;AAAA,IAChD;AACA,WAAO,gBAAgB;AAAA,EACzB;AAEA,QAAM,oBAAgB,yDAA4B,EAAE,GAAG,KAAK,CAAC;AAE7D,MAAI;AAEJ,MAAI,0BAA0B;AAC5B,aACE;AAAA,MAAC;AAAA;AAAA,QACC,aAAa,qBAAqB;AAAA,QAElC;AAAA,UAAC;AAAA;AAAA,YACE,GAAG;AAAA,YACJ,OAAO,MAAM,cAAc;AAAA,YAC3B,cAAc,MAAM,qBAAqB;AAAA,YAExC;AAAA;AAAA,QACH;AAAA;AAAA,IACF;AAAA,EAEJ,OAAO;AACL,aACE;AAAA,MAAC;AAAA;AAAA,QACE,GAAG;AAAA,QACJ,OAAO,MAAM,cAAc;AAAA,QAC3B,cAAc,MAAM,mBAAmB;AAAA,QAEtC;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,SAAO;AACT;","names":["React","getTernSecureState","getNonceHeaders"]}
@@ -24,8 +24,10 @@ __export(constant_exports, {
24
24
  FIREBASE_API_KEY: () => FIREBASE_API_KEY,
25
25
  FIREBASE_APP_ID: () => FIREBASE_APP_ID,
26
26
  FIREBASE_AUTH_DOMAIN: () => FIREBASE_AUTH_DOMAIN,
27
+ FIREBASE_CLIENT_EMAIL: () => FIREBASE_CLIENT_EMAIL,
27
28
  FIREBASE_MEASUREMENT_ID: () => FIREBASE_MEASUREMENT_ID,
28
29
  FIREBASE_MESSAGING_SENDER_ID: () => FIREBASE_MESSAGING_SENDER_ID,
30
+ FIREBASE_PRIVATE_KEY: () => FIREBASE_PRIVATE_KEY,
29
31
  FIREBASE_PROJECT_ID: () => FIREBASE_PROJECT_ID,
30
32
  FIREBASE_STORAGE_BUCKET: () => FIREBASE_STORAGE_BUCKET,
31
33
  SIGN_IN_URL: () => SIGN_IN_URL,
@@ -39,6 +41,8 @@ const FIREBASE_STORAGE_BUCKET = process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET
39
41
  const FIREBASE_MESSAGING_SENDER_ID = process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID || "";
40
42
  const FIREBASE_APP_ID = process.env.NEXT_PUBLIC_FIREBASE_APP_ID || "";
41
43
  const FIREBASE_MEASUREMENT_ID = process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID || "";
44
+ const FIREBASE_CLIENT_EMAIL = process.env.FIREBASE_CLIENT_EMAIL || "";
45
+ const FIREBASE_PRIVATE_KEY = process.env.FIREBASE_PRIVATE_KEY;
42
46
  const API_KEY = process.env.NEXT_PUBLIC_FIREBASE_API_KEY || "";
43
47
  const API_URL = process.env.TERNSECURE_API_URL || "";
44
48
  const API_VERSION = process.env.TERNSECURE_API_VERSION || "v1";
@@ -52,8 +56,10 @@ const SIGN_UP_URL = process.env.NEXT_PUBLIC_SIGN_UP_URL || "";
52
56
  FIREBASE_API_KEY,
53
57
  FIREBASE_APP_ID,
54
58
  FIREBASE_AUTH_DOMAIN,
59
+ FIREBASE_CLIENT_EMAIL,
55
60
  FIREBASE_MEASUREMENT_ID,
56
61
  FIREBASE_MESSAGING_SENDER_ID,
62
+ FIREBASE_PRIVATE_KEY,
57
63
  FIREBASE_PROJECT_ID,
58
64
  FIREBASE_STORAGE_BUCKET,
59
65
  SIGN_IN_URL,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/server/constant.ts"],"sourcesContent":["export const FIREBASE_API_KEY = process.env.NEXT_PUBLIC_FIREBASE_API_KEY || '';\nexport const FIREBASE_AUTH_DOMAIN = process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN || '';\nexport const FIREBASE_PROJECT_ID = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID || '';\nexport const FIREBASE_STORAGE_BUCKET = process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET || '';\nexport const FIREBASE_MESSAGING_SENDER_ID = process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID || '';\nexport const FIREBASE_APP_ID = process.env.NEXT_PUBLIC_FIREBASE_APP_ID || '';\nexport const FIREBASE_MEASUREMENT_ID = process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID || '';\n\nexport const API_KEY = process.env.NEXT_PUBLIC_FIREBASE_API_KEY || '';\nexport const API_URL = process.env.TERNSECURE_API_URL || '';\nexport const API_VERSION = process.env.TERNSECURE_API_VERSION || 'v1';\nexport const SIGN_IN_URL = process.env.NEXT_PUBLIC_SIGN_IN_URL || '';\nexport const SIGN_UP_URL = process.env.NEXT_PUBLIC_SIGN_UP_URL || '';"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,MAAM,mBAAmB,QAAQ,IAAI,gCAAgC;AACrE,MAAM,uBAAuB,QAAQ,IAAI,oCAAoC;AAC7E,MAAM,sBAAsB,QAAQ,IAAI,mCAAmC;AAC3E,MAAM,0BAA0B,QAAQ,IAAI,uCAAuC;AACnF,MAAM,+BAA+B,QAAQ,IAAI,4CAA4C;AAC7F,MAAM,kBAAkB,QAAQ,IAAI,+BAA+B;AACnE,MAAM,0BAA0B,QAAQ,IAAI,uCAAuC;AAEnF,MAAM,UAAU,QAAQ,IAAI,gCAAgC;AAC5D,MAAM,UAAU,QAAQ,IAAI,sBAAsB;AAClD,MAAM,cAAc,QAAQ,IAAI,0BAA0B;AAC1D,MAAM,cAAc,QAAQ,IAAI,2BAA2B;AAC3D,MAAM,cAAc,QAAQ,IAAI,2BAA2B;","names":[]}
1
+ {"version":3,"sources":["../../../src/server/constant.ts"],"sourcesContent":["export const FIREBASE_API_KEY = process.env.NEXT_PUBLIC_FIREBASE_API_KEY || '';\nexport const FIREBASE_AUTH_DOMAIN = process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN || '';\nexport const FIREBASE_PROJECT_ID = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID || '';\nexport const FIREBASE_STORAGE_BUCKET = process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET || '';\nexport const FIREBASE_MESSAGING_SENDER_ID = process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID || '';\nexport const FIREBASE_APP_ID = process.env.NEXT_PUBLIC_FIREBASE_APP_ID || '';\nexport const FIREBASE_MEASUREMENT_ID = process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID || '';\n\nexport const FIREBASE_CLIENT_EMAIL = process.env.FIREBASE_CLIENT_EMAIL || '';\nexport const FIREBASE_PRIVATE_KEY = process.env.FIREBASE_PRIVATE_KEY\n\nexport const API_KEY = process.env.NEXT_PUBLIC_FIREBASE_API_KEY || '';\nexport const API_URL = process.env.TERNSECURE_API_URL || '';\nexport const API_VERSION = process.env.TERNSECURE_API_VERSION || 'v1';\nexport const SIGN_IN_URL = process.env.NEXT_PUBLIC_SIGN_IN_URL || '';\nexport const SIGN_UP_URL = process.env.NEXT_PUBLIC_SIGN_UP_URL || '';"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,MAAM,mBAAmB,QAAQ,IAAI,gCAAgC;AACrE,MAAM,uBAAuB,QAAQ,IAAI,oCAAoC;AAC7E,MAAM,sBAAsB,QAAQ,IAAI,mCAAmC;AAC3E,MAAM,0BAA0B,QAAQ,IAAI,uCAAuC;AACnF,MAAM,+BAA+B,QAAQ,IAAI,4CAA4C;AAC7F,MAAM,kBAAkB,QAAQ,IAAI,+BAA+B;AACnE,MAAM,0BAA0B,QAAQ,IAAI,uCAAuC;AAEnF,MAAM,wBAAwB,QAAQ,IAAI,yBAAyB;AACnE,MAAM,uBAAuB,QAAQ,IAAI;AAEzC,MAAM,UAAU,QAAQ,IAAI,gCAAgC;AAC5D,MAAM,UAAU,QAAQ,IAAI,sBAAsB;AAClD,MAAM,cAAc,QAAQ,IAAI,0BAA0B;AAC1D,MAAM,cAAc,QAAQ,IAAI,2BAA2B;AAC3D,MAAM,cAAc,QAAQ,IAAI,2BAA2B;","names":[]}
@@ -27,6 +27,7 @@ __export(getAuthDataFromRequest_exports, {
27
27
  });
28
28
  module.exports = __toCommonJS(getAuthDataFromRequest_exports);
29
29
  var import_backend = require("@tern-secure/backend");
30
+ var import_app_check = require("@tern-secure/backend/app-check");
30
31
  var import_jwt = require("@tern-secure/backend/jwt");
31
32
  var import_app = require("firebase/app");
32
33
  var import_auth = require("firebase/auth");
@@ -43,8 +44,6 @@ function getTernSecureAuthDataJwt(req, initialState = {}) {
43
44
  function getAuthDataFromRequestJwt(req) {
44
45
  const authStatus = (0, import_headers_utils.getAuthKeyFromRequest)(req, "AuthStatus");
45
46
  const authToken = (0, import_headers_utils.getAuthKeyFromRequest)(req, "AuthToken");
46
- const authSignature = (0, import_headers_utils.getAuthKeyFromRequest)(req, "AuthSignature");
47
- const authReason = (0, import_headers_utils.getAuthKeyFromRequest)(req, "AuthReason");
48
47
  let authObject;
49
48
  if (!authStatus || authStatus !== import_backend.AuthStatus.SignedIn) {
50
49
  authObject = (0, import_backend.signedOutAuthObject)();
@@ -65,7 +64,6 @@ async function getTernSecureAuthData(req, initialState = {}) {
65
64
  async function getAuthDataFromRequest(req) {
66
65
  const authStatus = (0, import_headers_utils.getAuthKeyFromRequest)(req, "AuthStatus");
67
66
  const authToken = (0, import_headers_utils.getAuthKeyFromRequest)(req, "AuthToken");
68
- const appCheckToken = (0, import_headers_utils.getHeader)(req, "X-Firebase-AppCheck");
69
67
  if (!authStatus || authStatus !== import_backend.AuthStatus.SignedIn) {
70
68
  return {
71
69
  ...(0, import_backend.signedOutAuthObject)(),
@@ -75,8 +73,7 @@ async function getAuthDataFromRequest(req) {
75
73
  }
76
74
  const firebaseUser = await authenticateRequest(
77
75
  authToken,
78
- req,
79
- appCheckToken
76
+ req
80
77
  );
81
78
  if (!firebaseUser || !firebaseUser.claims) {
82
79
  return {
@@ -92,12 +89,22 @@ async function getAuthDataFromRequest(req) {
92
89
  user: user || null
93
90
  };
94
91
  }
95
- const authenticateRequest = async (token, request, appCheckToken) => {
92
+ const authenticateRequest = async (token, request) => {
96
93
  try {
97
- const origin = new URL(request.url).origin;
94
+ const reqDataHeader = request.headers.get(import_backend.constants.Headers.TernSecureRequestData);
95
+ let reqData;
96
+ try {
97
+ reqData = reqDataHeader ? JSON.parse(reqDataHeader) : null;
98
+ } catch (e) {
99
+ console.error("Failed to parse request data:", e);
100
+ reqData = null;
101
+ }
102
+ let appCheckToken;
103
+ if (reqData?.appCheck) {
104
+ const serverAppCheck = import_app_check.ServerAppCheckManager.getInstance(reqData.appCheck);
105
+ appCheckToken = await serverAppCheck.getOrGenerateToken(import_constant.FIREBASE_APP_ID) || void 0;
106
+ }
98
107
  const requestHeaders = new Headers(request.headers);
99
- requestHeaders.set("referer", origin);
100
- requestHeaders.set("Referer", origin);
101
108
  const mockRequest = {
102
109
  headers: requestHeaders
103
110
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/server/data/getAuthDataFromRequest.ts"],"sourcesContent":["import type { AuthObject } from '@tern-secure/backend';\nimport { AuthStatus, signedInAuthObject, signedOutAuthObject } from '@tern-secure/backend';\nimport { ternDecodeJwt } from '@tern-secure/backend/jwt';\nimport type { ParsedToken, TernSecureConfig, TernSecureUser } from '@tern-secure/types';\nimport type { FirebaseServerApp } from \"firebase/app\";\nimport { initializeServerApp } from \"firebase/app\";\nimport type { Auth } from \"firebase/auth\";\nimport { getAuth } from \"firebase/auth\";\n\nimport { getAuthKeyFromRequest, getHeader } from '../../server/headers-utils';\nimport type { RequestLike } from '../../server/types';\nimport {\n FIREBASE_API_KEY,\n FIREBASE_APP_ID,\n FIREBASE_AUTH_DOMAIN,\n FIREBASE_MEASUREMENT_ID,\n FIREBASE_MESSAGING_SENDER_ID,\n FIREBASE_PROJECT_ID,\n FIREBASE_STORAGE_BUCKET\n} from \"../constant\";\n\n\n/**\n * Auth objects moving through the server -> client boundary need to be serializable\n * as we need to ensure that they can be transferred via the network as pure strings.\n * Some frameworks like Remix or Next (/pages dir only) handle this serialization by simply\n * ignoring any non-serializable keys, however Nextjs /app directory is stricter and\n * throws an error if a non-serializable value is found.\n * @internal\n */\nexport const authObjectToSerializableJwt = <T extends Record<string, unknown>>(obj: T): T => {\n // remove any non-serializable props from the returned object\n\n const { require, ...rest } = obj as unknown as AuthObject;\n return rest as unknown as T;\n};\n\nexport function getTernSecureAuthDataJwt(req: RequestLike, initialState = {}) {\n const authObject = getAuthDataFromRequestJwt(req);\n return authObjectToSerializable({ ...initialState, ...authObject });\n}\n\nexport function getAuthDataFromRequestJwt(req: RequestLike): AuthObject {\n const authStatus = getAuthKeyFromRequest(req, 'AuthStatus');\n const authToken = getAuthKeyFromRequest(req, 'AuthToken');\n const authSignature = getAuthKeyFromRequest(req, 'AuthSignature');\n const authReason = getAuthKeyFromRequest(req, 'AuthReason');\n\n let authObject;\n if (!authStatus || authStatus !== AuthStatus.SignedIn) {\n authObject = signedOutAuthObject();\n } else {\n const jwt = ternDecodeJwt(authToken as string);\n\n authObject = signedInAuthObject(jwt.raw.text, jwt.payload);\n }\n return authObject;\n}\n\n\nexport type SerializableTernSecureUser = Omit<TernSecureUser, 'delete' | 'getIdToken' | 'getIdTokenResult' | 'reload' | 'toJSON'>;\n\nexport type Aobj = {\n user: SerializableTernSecureUser | null\n userId: string | null\n}\n\n\n// Serializable auth object type\n/**\n * Auth objects moving through the server -> client boundary need to be serializable\n * as we need to ensure that they can be transferred via the network as pure strings.\n * Some frameworks like Remix or Next (/pages dir only) handle this serialization by simply\n * ignoring any non-serializable keys, however Nextjs /app directory is stricter and\n * throws an error if a non-serializable value is found.\n * @internal\n */\nexport const authObjectToSerializable = <T extends Record<string, unknown>>(\n obj: T\n): T => {\n // remove any non-serializable props from the returned object\n\n const { require, ...rest } = obj as unknown as AuthObject;\n return rest as unknown as T;\n};\n\nexport async function getTernSecureAuthData(\n req: RequestLike,\n initialState = {}\n) {\n const authObject = await getAuthDataFromRequest(req);\n return authObjectToSerializable({ ...initialState, ...authObject });\n}\n\nexport async function getAuthDataFromRequest(req: RequestLike): Promise<AuthObject & Aobj> {\n const authStatus = getAuthKeyFromRequest(req, \"AuthStatus\");\n const authToken = getAuthKeyFromRequest(req, \"AuthToken\");\n const appCheckToken = getHeader(req, \"X-Firebase-AppCheck\");\n\n if (!authStatus || authStatus !== AuthStatus.SignedIn) {\n return {\n ...signedOutAuthObject(),\n user: null,\n userId: null\n }\n }\n\n const firebaseUser = await authenticateRequest(\n authToken as string, \n req as any, \n appCheckToken as string | undefined\n );\n if (!firebaseUser || !firebaseUser.claims) {\n return {\n ...signedOutAuthObject(),\n user: null,\n userId: null\n }\n }\n const { user, claims } = firebaseUser;\n const authObject = signedInAuthObject(authToken as string, claims as any);\n return {\n ...authObject,\n user: user || null,\n };\n}\n\nconst authenticateRequest = async (\n token: string,\n request: Request,\n appCheckToken?: string\n): Promise<{ user: SerializableTernSecureUser; claims: ParsedToken } | null> => {\n try {\n //console.log(\"[getAuthDataFromRequest] App Check Token:\", appCheckToken);\n const origin = new URL(request.url).origin;\n\n const requestHeaders = new Headers(request.headers);\n requestHeaders.set(\"referer\", origin);\n requestHeaders.set(\"Referer\", origin);\n\n const mockRequest = {\n headers: requestHeaders,\n };\n\n const config: TernSecureConfig = {\n apiKey: FIREBASE_API_KEY,\n authDomain: FIREBASE_AUTH_DOMAIN,\n projectId: FIREBASE_PROJECT_ID,\n storageBucket: FIREBASE_STORAGE_BUCKET,\n messagingSenderId: FIREBASE_MESSAGING_SENDER_ID,\n appId: FIREBASE_APP_ID,\n measurementId: FIREBASE_MEASUREMENT_ID,\n };\n\n const firebaseServerApp: FirebaseServerApp = initializeServerApp(\n config,\n {\n authIdToken: token,\n appCheckToken: appCheckToken,\n releaseOnDeref: mockRequest,\n }\n );\n\n const auth: Auth = getAuth(firebaseServerApp);\n await auth.authStateReady();\n\n if (auth.currentUser) {\n const idTokenResult = await auth.currentUser.getIdTokenResult();\n const claims = idTokenResult.claims;\n\n const userObj: SerializableTernSecureUser = {\n uid: auth.currentUser.uid,\n email: auth.currentUser.email,\n emailVerified: auth.currentUser.emailVerified,\n displayName: auth.currentUser.displayName,\n isAnonymous: auth.currentUser.isAnonymous,\n phoneNumber: auth.currentUser.phoneNumber,\n photoURL: auth.currentUser.photoURL,\n providerId: auth.currentUser.providerId,\n tenantId: auth.currentUser.tenantId,\n refreshToken: auth.currentUser.refreshToken,\n metadata: {\n creationTime: auth.currentUser.metadata.creationTime,\n lastSignInTime: auth.currentUser.metadata.lastSignInTime,\n },\n providerData: auth.currentUser.providerData.map((provider) => ({\n uid: provider.uid,\n displayName: provider.displayName,\n email: provider.email,\n phoneNumber: provider.phoneNumber,\n photoURL: provider.photoURL,\n providerId: provider.providerId,\n })),\n };\n\n return { user: userObj, claims };\n }\n\n return null;\n } catch (error) {\n return null;\n }\n};\n\nexport { TernSecureUser }\n"],"mappings":"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","names":["require"]}
1
+ {"version":3,"sources":["../../../../src/server/data/getAuthDataFromRequest.ts"],"sourcesContent":["import type { AuthObject } from '@tern-secure/backend';\nimport { AuthStatus, constants, signedInAuthObject, signedOutAuthObject } from '@tern-secure/backend';\nimport { ServerAppCheckManager } from '@tern-secure/backend/app-check';\nimport { ternDecodeJwt } from '@tern-secure/backend/jwt';\nimport type { ParsedToken, TernSecureConfig, TernSecureUser } from '@tern-secure/types';\nimport type { FirebaseServerApp } from \"firebase/app\";\nimport { initializeServerApp } from \"firebase/app\";\nimport type { Auth } from \"firebase/auth\";\nimport { getAuth } from \"firebase/auth\";\n\nimport { getAuthKeyFromRequest } from '../../server/headers-utils';\nimport type { RequestLike } from '../../server/types';\nimport {\n FIREBASE_API_KEY,\n FIREBASE_APP_ID,\n FIREBASE_AUTH_DOMAIN,\n FIREBASE_MEASUREMENT_ID,\n FIREBASE_MESSAGING_SENDER_ID,\n FIREBASE_PROJECT_ID,\n FIREBASE_STORAGE_BUCKET\n} from \"../constant\";\n\n\n/**\n * Auth objects moving through the server -> client boundary need to be serializable\n * as we need to ensure that they can be transferred via the network as pure strings.\n * Some frameworks like Remix or Next (/pages dir only) handle this serialization by simply\n * ignoring any non-serializable keys, however Nextjs /app directory is stricter and\n * throws an error if a non-serializable value is found.\n * @internal\n */\nexport const authObjectToSerializableJwt = <T extends Record<string, unknown>>(obj: T): T => {\n // remove any non-serializable props from the returned object\n\n const { require, ...rest } = obj as unknown as AuthObject;\n return rest as unknown as T;\n};\n\nexport function getTernSecureAuthDataJwt(req: RequestLike, initialState = {}) {\n const authObject = getAuthDataFromRequestJwt(req);\n return authObjectToSerializable({ ...initialState, ...authObject });\n}\n\nexport function getAuthDataFromRequestJwt(req: RequestLike): AuthObject {\n const authStatus = getAuthKeyFromRequest(req, 'AuthStatus');\n const authToken = getAuthKeyFromRequest(req, 'AuthToken');\n\n let authObject;\n if (!authStatus || authStatus !== AuthStatus.SignedIn) {\n authObject = signedOutAuthObject();\n } else {\n const jwt = ternDecodeJwt(authToken as string);\n\n authObject = signedInAuthObject(jwt.raw.text, jwt.payload);\n }\n return authObject;\n}\n\n\nexport type SerializableTernSecureUser = Omit<TernSecureUser, 'delete' | 'getIdToken' | 'getIdTokenResult' | 'reload' | 'toJSON'>;\n\nexport type Aobj = {\n user: SerializableTernSecureUser | null\n userId: string | null\n}\n\n\n// Serializable auth object type\n/**\n * Auth objects moving through the server -> client boundary need to be serializable\n * as we need to ensure that they can be transferred via the network as pure strings.\n * Some frameworks like Remix or Next (/pages dir only) handle this serialization by simply\n * ignoring any non-serializable keys, however Nextjs /app directory is stricter and\n * throws an error if a non-serializable value is found.\n * @internal\n */\nexport const authObjectToSerializable = <T extends Record<string, unknown>>(\n obj: T\n): T => {\n // remove any non-serializable props from the returned object\n\n const { require, ...rest } = obj as unknown as AuthObject;\n return rest as unknown as T;\n};\n\nexport async function getTernSecureAuthData(\n req: RequestLike,\n initialState = {}\n) {\n const authObject = await getAuthDataFromRequest(req);\n return authObjectToSerializable({ ...initialState, ...authObject });\n}\n\nexport async function getAuthDataFromRequest(req: RequestLike): Promise<AuthObject & Aobj> {\n const authStatus = getAuthKeyFromRequest(req, \"AuthStatus\");\n const authToken = getAuthKeyFromRequest(req, \"AuthToken\");\n\n if (!authStatus || authStatus !== AuthStatus.SignedIn) {\n return {\n ...signedOutAuthObject(),\n user: null,\n userId: null\n }\n }\n\n const firebaseUser = await authenticateRequest(\n authToken as string,\n req as any\n );\n if (!firebaseUser || !firebaseUser.claims) {\n return {\n ...signedOutAuthObject(),\n user: null,\n userId: null\n }\n }\n const { user, claims } = firebaseUser;\n const authObject = signedInAuthObject(authToken as string, claims as any);\n return {\n ...authObject,\n user: user || null,\n };\n}\n\nconst authenticateRequest = async (\n token: string,\n request: Request,\n): Promise<{ user: SerializableTernSecureUser; claims: ParsedToken } | null> => {\n try {\n const reqDataHeader = request.headers.get(constants.Headers.TernSecureRequestData);\n\n let reqData;\n try {\n reqData = reqDataHeader ? JSON.parse(reqDataHeader) : null;\n } catch (e) {\n console.error('Failed to parse request data:', e);\n reqData = null;\n }\n\n let appCheckToken;\n if (reqData?.appCheck) {\n const serverAppCheck = ServerAppCheckManager.getInstance(reqData.appCheck);\n appCheckToken = await serverAppCheck.getOrGenerateToken(FIREBASE_APP_ID) || undefined;\n }\n\n const requestHeaders = new Headers(request.headers);\n\n const mockRequest = {\n headers: requestHeaders,\n };\n\n const config: TernSecureConfig = {\n apiKey: FIREBASE_API_KEY,\n authDomain: FIREBASE_AUTH_DOMAIN,\n projectId: FIREBASE_PROJECT_ID,\n storageBucket: FIREBASE_STORAGE_BUCKET,\n messagingSenderId: FIREBASE_MESSAGING_SENDER_ID,\n appId: FIREBASE_APP_ID,\n measurementId: FIREBASE_MEASUREMENT_ID,\n };\n\n const firebaseServerApp: FirebaseServerApp = initializeServerApp(\n config,\n {\n authIdToken: token,\n appCheckToken: appCheckToken,\n releaseOnDeref: mockRequest,\n }\n );\n\n const auth: Auth = getAuth(firebaseServerApp);\n await auth.authStateReady();\n\n if (auth.currentUser) {\n const idTokenResult = await auth.currentUser.getIdTokenResult();\n const claims = idTokenResult.claims;\n\n const userObj: SerializableTernSecureUser = {\n uid: auth.currentUser.uid,\n email: auth.currentUser.email,\n emailVerified: auth.currentUser.emailVerified,\n displayName: auth.currentUser.displayName,\n isAnonymous: auth.currentUser.isAnonymous,\n phoneNumber: auth.currentUser.phoneNumber,\n photoURL: auth.currentUser.photoURL,\n providerId: auth.currentUser.providerId,\n tenantId: auth.currentUser.tenantId,\n refreshToken: auth.currentUser.refreshToken,\n metadata: {\n creationTime: auth.currentUser.metadata.creationTime,\n lastSignInTime: auth.currentUser.metadata.lastSignInTime,\n },\n providerData: auth.currentUser.providerData.map((provider) => ({\n uid: provider.uid,\n displayName: provider.displayName,\n email: provider.email,\n phoneNumber: provider.phoneNumber,\n photoURL: provider.photoURL,\n providerId: provider.providerId,\n })),\n };\n\n return { user: userObj, claims };\n }\n\n return null;\n } catch (error) {\n return null;\n }\n};\n\nexport { TernSecureUser }"],"mappings":"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","names":["require"]}
@@ -18,7 +18,7 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var headers_utils_exports = {};
20
20
  __export(headers_utils_exports, {
21
- detectClerkMiddleware: () => detectClerkMiddleware,
21
+ detectTernSecureMiddleware: () => detectTernSecureMiddleware,
22
22
  getAuthKeyFromRequest: () => getAuthKeyFromRequest,
23
23
  getCustomAttributeFromRequest: () => getCustomAttributeFromRequest,
24
24
  getHeader: () => getHeader,
@@ -39,7 +39,7 @@ function getHeader(req, name) {
39
39
  }
40
40
  return req.headers[name] || req.headers[name.toLowerCase()] || req.socket?._httpMessage?.getHeader(name);
41
41
  }
42
- function detectClerkMiddleware(req) {
42
+ function detectTernSecureMiddleware(req) {
43
43
  return Boolean(getAuthKeyFromRequest(req, "AuthStatus"));
44
44
  }
45
45
  function isNextRequest(val) {
@@ -60,7 +60,7 @@ function isRequestWebAPI(val) {
60
60
  }
61
61
  // Annotate the CommonJS export names for ESM import in node:
62
62
  0 && (module.exports = {
63
- detectClerkMiddleware,
63
+ detectTernSecureMiddleware,
64
64
  getAuthKeyFromRequest,
65
65
  getCustomAttributeFromRequest,
66
66
  getHeader,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/server/headers-utils.ts"],"sourcesContent":["import { constants } from '@tern-secure/backend';\nimport type { NextRequest } from 'next/server';\n\nimport type { RequestLike } from './types';\n\nexport function getCustomAttributeFromRequest(req: RequestLike, key: string): string | null | undefined {\n // @ts-expect-error - TS doesn't like indexing into RequestLike\n return key in req ? req[key] : undefined;\n}\n\nexport function getAuthKeyFromRequest(\n req: RequestLike,\n key: keyof typeof constants.Attributes,\n): string | null | undefined {\n return getCustomAttributeFromRequest(req, constants.Attributes[key]) || getHeader(req, constants.Headers[key]);\n}\n\nexport function getHeader(req: RequestLike, name: string): string | null | undefined {\n if (isNextRequest(req) || isRequestWebAPI(req)) {\n return req.headers.get(name);\n }\n\n // If no header has been determined for IncomingMessage case, check if available within private `socket` headers\n // When deployed to vercel, req.headers for API routes is a `IncomingHttpHeaders` key-val object which does not follow\n // the Headers spec so the name is no longer case-insensitive.\n return req.headers[name] || req.headers[name.toLowerCase()] || (req.socket as any)?._httpMessage?.getHeader(name);\n}\n\nexport function detectClerkMiddleware(req: RequestLike): boolean {\n return Boolean(getAuthKeyFromRequest(req, 'AuthStatus'));\n}\n\nexport function isNextRequest(val: unknown): val is NextRequest {\n try {\n const { headers, nextUrl, cookies } = (val || {}) as NextRequest;\n return (\n typeof headers?.get === 'function' &&\n typeof nextUrl?.searchParams.get === 'function' &&\n typeof cookies?.get === 'function'\n );\n } catch {\n return false;\n }\n}\n\nexport function isRequestWebAPI(val: unknown): val is Request {\n try {\n const { headers } = (val || {}) as Request;\n return typeof headers?.get === 'function';\n } catch {\n return false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA0B;AAKnB,SAAS,8BAA8B,KAAkB,KAAwC;AAEtG,SAAO,OAAO,MAAM,IAAI,GAAG,IAAI;AACjC;AAEO,SAAS,sBACd,KACA,KAC2B;AAC3B,SAAO,8BAA8B,KAAK,yBAAU,WAAW,GAAG,CAAC,KAAK,UAAU,KAAK,yBAAU,QAAQ,GAAG,CAAC;AAC/G;AAEO,SAAS,UAAU,KAAkB,MAAyC;AACnF,MAAI,cAAc,GAAG,KAAK,gBAAgB,GAAG,GAAG;AAC9C,WAAO,IAAI,QAAQ,IAAI,IAAI;AAAA,EAC7B;AAKA,SAAO,IAAI,QAAQ,IAAI,KAAK,IAAI,QAAQ,KAAK,YAAY,CAAC,KAAM,IAAI,QAAgB,cAAc,UAAU,IAAI;AAClH;AAEO,SAAS,sBAAsB,KAA2B;AAC/D,SAAO,QAAQ,sBAAsB,KAAK,YAAY,CAAC;AACzD;AAEO,SAAS,cAAc,KAAkC;AAC9D,MAAI;AACF,UAAM,EAAE,SAAS,SAAS,QAAQ,IAAK,OAAO,CAAC;AAC/C,WACE,OAAO,SAAS,QAAQ,cACxB,OAAO,SAAS,aAAa,QAAQ,cACrC,OAAO,SAAS,QAAQ;AAAA,EAE5B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,gBAAgB,KAA8B;AAC5D,MAAI;AACF,UAAM,EAAE,QAAQ,IAAK,OAAO,CAAC;AAC7B,WAAO,OAAO,SAAS,QAAQ;AAAA,EACjC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/server/headers-utils.ts"],"sourcesContent":["import { constants } from '@tern-secure/backend';\nimport type { NextRequest } from 'next/server';\n\nimport type { RequestLike } from './types';\n\nexport function getCustomAttributeFromRequest(req: RequestLike, key: string): string | null | undefined {\n // @ts-expect-error - TS doesn't like indexing into RequestLike\n return key in req ? req[key] : undefined;\n}\n\nexport function getAuthKeyFromRequest(\n req: RequestLike,\n key: keyof typeof constants.Attributes,\n): string | null | undefined {\n return getCustomAttributeFromRequest(req, constants.Attributes[key]) || getHeader(req, constants.Headers[key]);\n}\n\nexport function getHeader(req: RequestLike, name: string): string | null | undefined {\n if (isNextRequest(req) || isRequestWebAPI(req)) {\n return req.headers.get(name);\n }\n\n // If no header has been determined for IncomingMessage case, check if available within private `socket` headers\n // When deployed to vercel, req.headers for API routes is a `IncomingHttpHeaders` key-val object which does not follow\n // the Headers spec so the name is no longer case-insensitive.\n return req.headers[name] || req.headers[name.toLowerCase()] || (req.socket as any)?._httpMessage?.getHeader(name);\n}\n\nexport function detectTernSecureMiddleware(req: RequestLike): boolean {\n return Boolean(getAuthKeyFromRequest(req, 'AuthStatus'));\n}\n\nexport function isNextRequest(val: unknown): val is NextRequest {\n try {\n const { headers, nextUrl, cookies } = (val || {}) as NextRequest;\n return (\n typeof headers?.get === 'function' &&\n typeof nextUrl?.searchParams.get === 'function' &&\n typeof cookies?.get === 'function'\n );\n } catch {\n return false;\n }\n}\n\nexport function isRequestWebAPI(val: unknown): val is Request {\n try {\n const { headers } = (val || {}) as Request;\n return typeof headers?.get === 'function';\n } catch {\n return false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAA0B;AAKnB,SAAS,8BAA8B,KAAkB,KAAwC;AAEtG,SAAO,OAAO,MAAM,IAAI,GAAG,IAAI;AACjC;AAEO,SAAS,sBACd,KACA,KAC2B;AAC3B,SAAO,8BAA8B,KAAK,yBAAU,WAAW,GAAG,CAAC,KAAK,UAAU,KAAK,yBAAU,QAAQ,GAAG,CAAC;AAC/G;AAEO,SAAS,UAAU,KAAkB,MAAyC;AACnF,MAAI,cAAc,GAAG,KAAK,gBAAgB,GAAG,GAAG;AAC9C,WAAO,IAAI,QAAQ,IAAI,IAAI;AAAA,EAC7B;AAKA,SAAO,IAAI,QAAQ,IAAI,KAAK,IAAI,QAAQ,KAAK,YAAY,CAAC,KAAM,IAAI,QAAgB,cAAc,UAAU,IAAI;AAClH;AAEO,SAAS,2BAA2B,KAA2B;AACpE,SAAO,QAAQ,sBAAsB,KAAK,YAAY,CAAC;AACzD;AAEO,SAAS,cAAc,KAAkC;AAC9D,MAAI;AACF,UAAM,EAAE,SAAS,SAAS,QAAQ,IAAK,OAAO,CAAC;AAC/C,WACE,OAAO,SAAS,QAAQ,cACxB,OAAO,SAAS,aAAa,QAAQ,cACrC,OAAO,SAAS,QAAQ;AAAA,EAE5B,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,gBAAgB,KAA8B;AAC5D,MAAI;AACF,UAAM,EAAE,QAAQ,IAAK,OAAO,CAAC;AAC7B,WAAO,OAAO,SAAS,QAAQ;AAAA,EACjC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":[]}