@tern-secure/nextjs 4.2.2 → 4.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/dist/cjs/app-router/admin/sessionTernSecure.js +29 -25
  2. package/dist/cjs/app-router/admin/sessionTernSecure.js.map +1 -1
  3. package/dist/cjs/components/sign-in.js +3 -0
  4. package/dist/cjs/components/sign-in.js.map +1 -1
  5. package/dist/cjs/server/auth.js +59 -44
  6. package/dist/cjs/server/auth.js.map +1 -1
  7. package/dist/cjs/server/crypto.js +43 -0
  8. package/dist/cjs/server/crypto.js.map +1 -0
  9. package/dist/cjs/server/ctx-store.js +65 -0
  10. package/dist/cjs/server/ctx-store.js.map +1 -0
  11. package/dist/cjs/server/edge-session.js +23 -19
  12. package/dist/cjs/server/edge-session.js.map +1 -1
  13. package/dist/cjs/server/index.js +0 -2
  14. package/dist/cjs/server/index.js.map +1 -1
  15. package/dist/cjs/server/jwt-edge.js +0 -9
  16. package/dist/cjs/server/jwt-edge.js.map +1 -1
  17. package/dist/cjs/server/jwt.js +0 -10
  18. package/dist/cjs/server/jwt.js.map +1 -1
  19. package/dist/cjs/server/session-store.js +72 -0
  20. package/dist/cjs/server/session-store.js.map +1 -0
  21. package/dist/cjs/server/ternSecureMiddleware.js +25 -53
  22. package/dist/cjs/server/ternSecureMiddleware.js.map +1 -1
  23. package/dist/cjs/server/types.js.map +1 -1
  24. package/dist/cjs/server/utils.js +108 -0
  25. package/dist/cjs/server/utils.js.map +1 -0
  26. package/dist/esm/app-router/admin/sessionTernSecure.js +29 -25
  27. package/dist/esm/app-router/admin/sessionTernSecure.js.map +1 -1
  28. package/dist/esm/components/sign-in.js +3 -0
  29. package/dist/esm/components/sign-in.js.map +1 -1
  30. package/dist/esm/server/auth.js +57 -43
  31. package/dist/esm/server/auth.js.map +1 -1
  32. package/dist/esm/server/crypto.js +18 -0
  33. package/dist/esm/server/crypto.js.map +1 -0
  34. package/dist/esm/server/ctx-store.js +41 -0
  35. package/dist/esm/server/ctx-store.js.map +1 -0
  36. package/dist/esm/server/edge-session.js +23 -19
  37. package/dist/esm/server/edge-session.js.map +1 -1
  38. package/dist/esm/server/index.js +1 -2
  39. package/dist/esm/server/index.js.map +1 -1
  40. package/dist/esm/server/jwt-edge.js +0 -9
  41. package/dist/esm/server/jwt-edge.js.map +1 -1
  42. package/dist/esm/server/jwt.js +0 -10
  43. package/dist/esm/server/jwt.js.map +1 -1
  44. package/dist/esm/server/session-store.js +47 -0
  45. package/dist/esm/server/session-store.js.map +1 -0
  46. package/dist/esm/server/ternSecureMiddleware.js +25 -52
  47. package/dist/esm/server/ternSecureMiddleware.js.map +1 -1
  48. package/dist/esm/server/utils.js +84 -0
  49. package/dist/esm/server/utils.js.map +1 -0
  50. package/dist/types/app-router/admin/sessionTernSecure.d.ts +9 -10
  51. package/dist/types/app-router/admin/sessionTernSecure.d.ts.map +1 -1
  52. package/dist/types/components/sign-in.d.ts.map +1 -1
  53. package/dist/types/server/auth.d.ts +8 -4
  54. package/dist/types/server/auth.d.ts.map +1 -1
  55. package/dist/types/server/crypto.d.ts +3 -0
  56. package/dist/types/server/crypto.d.ts.map +1 -0
  57. package/dist/types/server/ctx-store.d.ts +24 -0
  58. package/dist/types/server/ctx-store.d.ts.map +1 -0
  59. package/dist/types/server/edge-session.d.ts.map +1 -1
  60. package/dist/types/server/index.d.ts +1 -2
  61. package/dist/types/server/index.d.ts.map +1 -1
  62. package/dist/types/server/jwt-edge.d.ts.map +1 -1
  63. package/dist/types/server/jwt.d.ts.map +1 -1
  64. package/dist/types/server/session-store.d.ts +30 -0
  65. package/dist/types/server/session-store.d.ts.map +1 -0
  66. package/dist/types/server/ternSecureMiddleware.d.ts +2 -3
  67. package/dist/types/server/ternSecureMiddleware.d.ts.map +1 -1
  68. package/dist/types/server/types.d.ts +2 -1
  69. package/dist/types/server/types.d.ts.map +1 -1
  70. package/dist/types/server/utils.d.ts +22 -0
  71. package/dist/types/server/utils.d.ts.map +1 -0
  72. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/server/edge-session.ts"],"sourcesContent":["import { verifyFirebaseToken } from \"./jwt-edge\"\nimport type { NextRequest } from \"next/server\"\nimport type { SessionResult } from \"./types\"\n\n\nexport async function verifySession(request: NextRequest): Promise<SessionResult> {\n try {\n //const cookieStore = await cookies()\n\n // First try session cookie\n const sessionCookie = request.cookies.get(\"_session_cookie\")?.value\n if (sessionCookie) {\n const result = await verifyFirebaseToken(sessionCookie, true)\n if (result.valid) {\n return {\n isAuthenticated: true,\n user: {\n uid: result.uid ?? '',\n email: result.email || null,\n emailVerified: result.emailVerified ?? false,\n disabled: false,\n },\n }\n }\n console.log(\"Session cookie verification failed:\", result.error)\n }\n\n // Then try ID token\n const idToken = request.cookies.get(\"_session_token\")?.value\n if (idToken) {\n const result = await verifyFirebaseToken(idToken, false)\n if (result.valid) {\n return {\n isAuthenticated: true,\n user: {\n uid: result.uid ?? '',\n email: result.email || null,\n emailVerified: result.emailVerified ?? false,\n disabled: false,\n },\n }\n }\n console.log(\"ID token verification failed:\", result.error)\n }\n\n return {\n isAuthenticated: false,\n user: null,\n error: \"No valid session found\",\n }\n } catch (error) {\n console.error(\"Session verification error:\", error)\n return {\n isAuthenticated: false,\n user: null,\n error: error instanceof Error ? error.message : \"Session verification failed\",\n }\n }\n}"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAoC;AAKpC,eAAsB,cAAc,SAA8C;AALlF;AAME,MAAI;AAIF,UAAM,iBAAgB,aAAQ,QAAQ,IAAI,iBAAiB,MAArC,mBAAwC;AAC9D,QAAI,eAAe;AACjB,YAAM,SAAS,UAAM,qCAAoB,eAAe,IAAI;AAC5D,UAAI,OAAO,OAAO;AAChB,eAAO;AAAA,UACL,iBAAiB;AAAA,UACjB,MAAM;AAAA,YACJ,MAAK,YAAO,QAAP,YAAc;AAAA,YACnB,OAAO,OAAO,SAAS;AAAA,YACvB,gBAAe,YAAO,kBAAP,YAAwB;AAAA,YACvC,UAAU;AAAA,UACZ;AAAA,QACF;AAAA,MACF;AACA,cAAQ,IAAI,uCAAuC,OAAO,KAAK;AAAA,IACjE;AAGA,UAAM,WAAU,aAAQ,QAAQ,IAAI,gBAAgB,MAApC,mBAAuC;AACvD,QAAI,SAAS;AACX,YAAM,SAAS,UAAM,qCAAoB,SAAS,KAAK;AACvD,UAAI,OAAO,OAAO;AAChB,eAAO;AAAA,UACL,iBAAiB;AAAA,UACjB,MAAM;AAAA,YACJ,MAAK,YAAO,QAAP,YAAc;AAAA,YACnB,OAAO,OAAO,SAAS;AAAA,YACvB,gBAAe,YAAO,kBAAP,YAAwB;AAAA,YACvC,UAAU;AAAA,UACZ;AAAA,QACF;AAAA,MACF;AACA,cAAQ,IAAI,iCAAiC,OAAO,KAAK;AAAA,IAC3D;AAEA,WAAO;AAAA,MACL,iBAAiB;AAAA,MACjB,MAAM;AAAA,MACN,OAAO;AAAA,IACT;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,+BAA+B,KAAK;AAClD,WAAO;AAAA,MACL,iBAAiB;AAAA,MACjB,MAAM;AAAA,MACN,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,IAClD;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/server/edge-session.ts"],"sourcesContent":["import { verifyFirebaseToken } from \"./jwt-edge\"\nimport type { NextRequest } from \"next/server\"\nimport type { SessionResult, UserInfo } from \"./types\"\n\n\n\nexport async function verifySession(request: NextRequest): Promise<SessionResult> {\n try {\n //const cookieStore = await cookies()\n\n // First try session cookie\n\n const sessionCookie = request.cookies.get(\"_session_cookie\")?.value\n const idToken = request.cookies.get(\"_session_token\")?.value\n\n //const sessionCookie = request.cookies.get(\"_session_cookie\")?.value\n if (sessionCookie) {\n const result = await verifyFirebaseToken(sessionCookie, true)\n if (result.valid) {\n const user: UserInfo = {\n uid: result.uid ?? '',\n email: result.email || null,\n emailVerified: result.emailVerified ?? false,\n authTime: result.authTime,\n }\n\n return {\n user,\n token: sessionCookie,\n sessionId: sessionCookie,\n }\n }\n }\n\n // Then try ID token\n //const idToken = request.cookies.get(\"_session_token\")?.value\n if (idToken) {\n const result = await verifyFirebaseToken(idToken, false)\n if (result.valid) {\n const user: UserInfo = {\n uid: result.uid ?? '',\n email: result.email || null,\n emailVerified: result.emailVerified ?? false,\n authTime: result.authTime,\n }\n\n\n return {\n user,\n token: idToken,\n sessionId: idToken,\n }\n }\n }\n\n return {\n user: null,\n token: null,\n sessionId: null,\n error: \"No valid session found\",\n }\n } catch (error) {\n console.error(\"Session verification error:\", error)\n return {\n user: null,\n token: null,\n sessionId: null,\n error: error instanceof Error ? error.message : \"Session verification failed\",\n }\n }\n}"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sBAAoC;AAMpC,eAAsB,cAAc,SAA8C;AANlF;AAOE,MAAI;AAKF,UAAM,iBAAgB,aAAQ,QAAQ,IAAI,iBAAiB,MAArC,mBAAwC;AAC9D,UAAM,WAAU,aAAQ,QAAQ,IAAI,gBAAgB,MAApC,mBAAuC;AAGvD,QAAI,eAAe;AACjB,YAAM,SAAS,UAAM,qCAAoB,eAAe,IAAI;AAC5D,UAAI,OAAO,OAAO;AACd,cAAM,OAAiB;AAAA,UACrB,MAAK,YAAO,QAAP,YAAc;AAAA,UACnB,OAAO,OAAO,SAAS;AAAA,UACvB,gBAAe,YAAO,kBAAP,YAAwB;AAAA,UACvC,UAAU,OAAO;AAAA,QACrB;AAEA,eAAO;AAAA,UACL;AAAA,UACA,OAAO;AAAA,UACP,WAAW;AAAA,QACb;AAAA,MACF;AAAA,IACF;AAIA,QAAI,SAAS;AACX,YAAM,SAAS,UAAM,qCAAoB,SAAS,KAAK;AACvD,UAAI,OAAO,OAAO;AAChB,cAAM,OAAkB;AAAA,UACpB,MAAK,YAAO,QAAP,YAAc;AAAA,UACnB,OAAO,OAAO,SAAS;AAAA,UACvB,gBAAe,YAAO,kBAAP,YAAwB;AAAA,UACvC,UAAU,OAAO;AAAA,QACrB;AAGA,eAAO;AAAA,UACL;AAAA,UACA,OAAO;AAAA,UACP,WAAW;AAAA,QACb;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,WAAW;AAAA,MACX,OAAO;AAAA,IACT;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,+BAA+B,KAAK;AAClD,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP,WAAW;AAAA,MACX,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,IAClD;AAAA,EACF;AACF;","names":[]}
@@ -20,7 +20,6 @@ var server_exports = {};
20
20
  __export(server_exports, {
21
21
  auth: () => import_auth.auth,
22
22
  createRouteMatcher: () => import_ternSecureMiddleware.createRouteMatcher,
23
- getUserInfo: () => import_auth.getUserInfo,
24
23
  ternSecureMiddleware: () => import_ternSecureMiddleware.ternSecureMiddleware
25
24
  });
26
25
  module.exports = __toCommonJS(server_exports);
@@ -30,7 +29,6 @@ var import_auth = require("./auth");
30
29
  0 && (module.exports = {
31
30
  auth,
32
31
  createRouteMatcher,
33
- getUserInfo,
34
32
  ternSecureMiddleware
35
33
  });
36
34
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/server/index.ts"],"sourcesContent":["\n\nexport { ternSecureMiddleware, createRouteMatcher } from './ternSecureMiddleware'\nexport { auth, getUserInfo } from './auth'\nexport type { AuthResult } from './auth'\nexport type { UserInfo, SessionResult } from './types'"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,kCAAyD;AACzD,kBAAkC;","names":[]}
1
+ {"version":3,"sources":["../../../src/server/index.ts"],"sourcesContent":["export { ternSecureMiddleware, createRouteMatcher } from './ternSecureMiddleware'\nexport { auth, type AuthResult } from './auth'\nexport type { UserInfo, SessionResult } from './types'"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kCAAyD;AACzD,kBAAsC;","names":[]}
@@ -78,18 +78,9 @@ async function verifyFirebaseToken(token, isSessionCookie = false) {
78
78
  });
79
79
  const firebasePayload = payload;
80
80
  const now = Math.floor(Date.now() / 1e3);
81
- if (firebasePayload.exp <= now) {
82
- throw new Error("Token has expired");
83
- }
84
- if (firebasePayload.iat > now) {
85
- throw new Error("Token issued time is in the future");
86
- }
87
81
  if (!firebasePayload.sub) {
88
82
  throw new Error("Token subject is empty");
89
83
  }
90
- if (firebasePayload.auth_time > now) {
91
- throw new Error("Token auth time is in the future");
92
- }
93
84
  return {
94
85
  valid: true,
95
86
  uid: firebasePayload.sub,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/server/jwt-edge.ts"],"sourcesContent":["import { jwtVerify, createRemoteJWKSet } from \"jose\"\nimport { cache } from \"react\"\n\ninterface FirebaseIdTokenPayload {\n iss: string\n aud: string\n auth_time: number\n user_id: string\n sub: string\n iat: number\n exp: number\n email?: string\n email_verified?: boolean\n firebase: {\n identities: {\n [key: string]: any\n }\n sign_in_provider: string\n }\n}\n\n// Firebase public key endpoints\nconst FIREBASE_ID_TOKEN_URL = \"https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com\"\nconst FIREBASE_SESSION_CERT_URL = \"https://identitytoolkit.googleapis.com/v1/sessionCookiePublicKeys\"\n\n// Cache the JWKS using React cache\nconst getIdTokenJWKS = cache(() => {\n return createRemoteJWKSet(new URL(FIREBASE_ID_TOKEN_URL), {\n cacheMaxAge: 3600000, // 1 hour\n timeoutDuration: 5000, // 5 seconds\n cooldownDuration: 30000, // 30 seconds between retries\n })\n})\n\nconst getSessionJWKS = cache(() => {\n return createRemoteJWKSet(new URL(FIREBASE_SESSION_CERT_URL), {\n cacheMaxAge: 3600000, // 1 hour\n timeoutDuration: 5000, // 5 seconds\n cooldownDuration: 30000, // 30 seconds between retries\n })\n})\n\n// Helper to decode JWT without verification\nfunction decodeJwt(token: string) {\n try {\n const [headerB64, payloadB64] = token.split(\".\")\n const header = JSON.parse(Buffer.from(headerB64, \"base64\").toString())\n const payload = JSON.parse(Buffer.from(payloadB64, \"base64\").toString())\n return { header, payload }\n } catch (error) {\n console.error(\"Error decoding JWT:\", error)\n return null\n }\n}\n\nexport async function verifyFirebaseToken(token: string, isSessionCookie = false) {\n try {\n const projectId = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID\n if (!projectId) {\n throw new Error(\"Firebase Project ID is not configured\")\n }\n\n // Decode token for debugging and type checking\n const decoded = decodeJwt(token)\n if (!decoded) {\n throw new Error(\"Invalid token format\")\n }\n\n console.log(\"Token details:\", {\n header: decoded.header,\n type: isSessionCookie ? \"session_cookie\" : \"id_token\",\n })\n\n\n // Use different JWKS based on token type\n const JWKS = isSessionCookie ? await getSessionJWKS() : await getIdTokenJWKS()\n\n const { payload } = await jwtVerify(token, JWKS, {\n issuer: isSessionCookie\n ? \"https://session.firebase.google.com/\" + projectId\n : \"https://securetoken.google.com/\" + projectId,\n audience: projectId,\n algorithms: [\"RS256\"],\n })\n\n const firebasePayload = payload as unknown as FirebaseIdTokenPayload\n const now = Math.floor(Date.now() / 1000)\n\n // Verify token claims\n if (firebasePayload.exp <= now) {\n throw new Error(\"Token has expired\")\n }\n\n if (firebasePayload.iat > now) {\n throw new Error(\"Token issued time is in the future\")\n }\n\n if (!firebasePayload.sub) {\n throw new Error(\"Token subject is empty\")\n }\n\n if (firebasePayload.auth_time > now) {\n throw new Error(\"Token auth time is in the future\")\n }\n\n return {\n valid: true,\n uid: firebasePayload.sub,\n email: firebasePayload.email,\n emailVerified: firebasePayload.email_verified,\n authTime: firebasePayload.auth_time,\n issuedAt: firebasePayload.iat,\n expiresAt: firebasePayload.exp,\n }\n } catch (error) {\n console.error(\"Token verification details:\", {\n error:\n error instanceof Error\n ? {\n name: error.name,\n message: error.message,\n stack: error.stack,\n }\n : error,\n decoded: decodeJwt(token),\n //projectId,\n isSessionCookie,\n })\n \n return {\n valid: false,\n error: error instanceof Error ? error.message : \"Invalid token\",\n }\n }\n }"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../src/server/jwt-edge.ts"],"sourcesContent":["import { jwtVerify, createRemoteJWKSet } from \"jose\"\nimport { cache } from \"react\"\n\ninterface FirebaseIdTokenPayload {\n iss: string\n aud: string\n auth_time: number\n user_id: string\n sub: string\n iat: number\n exp: number\n email?: string\n email_verified?: boolean\n firebase: {\n identities: {\n [key: string]: any\n }\n sign_in_provider: string\n }\n}\n\n// Firebase public key endpoints\nconst FIREBASE_ID_TOKEN_URL = \"https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com\"\nconst FIREBASE_SESSION_CERT_URL = \"https://identitytoolkit.googleapis.com/v1/sessionCookiePublicKeys\"\n\n// Cache the JWKS using React cache\nconst getIdTokenJWKS = cache(() => {\n return createRemoteJWKSet(new URL(FIREBASE_ID_TOKEN_URL), {\n cacheMaxAge: 3600000, // 1 hour\n timeoutDuration: 5000, // 5 seconds\n cooldownDuration: 30000, // 30 seconds between retries\n })\n})\n\nconst getSessionJWKS = cache(() => {\n return createRemoteJWKSet(new URL(FIREBASE_SESSION_CERT_URL), {\n cacheMaxAge: 3600000, // 1 hour\n timeoutDuration: 5000, // 5 seconds\n cooldownDuration: 30000, // 30 seconds between retries\n })\n})\n\n// Helper to decode JWT without verification\nfunction decodeJwt(token: string) {\n try {\n const [headerB64, payloadB64] = token.split(\".\")\n const header = JSON.parse(Buffer.from(headerB64, \"base64\").toString())\n const payload = JSON.parse(Buffer.from(payloadB64, \"base64\").toString())\n return { header, payload }\n } catch (error) {\n console.error(\"Error decoding JWT:\", error)\n return null\n }\n}\n\nexport async function verifyFirebaseToken(token: string, isSessionCookie = false) {\n try {\n const projectId = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID\n if (!projectId) {\n throw new Error(\"Firebase Project ID is not configured\")\n }\n\n // Decode token for debugging and type checking\n const decoded = decodeJwt(token)\n if (!decoded) {\n throw new Error(\"Invalid token format\")\n }\n\n console.log(\"Token details:\", {\n header: decoded.header,\n type: isSessionCookie ? \"session_cookie\" : \"id_token\",\n })\n\n\n // Use different JWKS based on token type\n const JWKS = isSessionCookie ? await getSessionJWKS() : await getIdTokenJWKS()\n\n const { payload } = await jwtVerify(token, JWKS, {\n issuer: isSessionCookie\n ? \"https://session.firebase.google.com/\" + projectId\n : \"https://securetoken.google.com/\" + projectId,\n audience: projectId,\n algorithms: [\"RS256\"],\n })\n\n const firebasePayload = payload as unknown as FirebaseIdTokenPayload\n const now = Math.floor(Date.now() / 1000)\n\n\n if (!firebasePayload.sub) {\n throw new Error(\"Token subject is empty\")\n }\n\n return {\n valid: true,\n uid: firebasePayload.sub,\n email: firebasePayload.email,\n emailVerified: firebasePayload.email_verified,\n authTime: firebasePayload.auth_time,\n issuedAt: firebasePayload.iat,\n expiresAt: firebasePayload.exp,\n }\n } catch (error) {\n console.error(\"Token verification details:\", {\n error:\n error instanceof Error\n ? {\n name: error.name,\n message: error.message,\n stack: error.stack,\n }\n : error,\n decoded: decodeJwt(token),\n //projectId,\n isSessionCookie,\n })\n \n return {\n valid: false,\n error: error instanceof Error ? error.message : \"Invalid token\",\n }\n }\n }"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAA8C;AAC9C,mBAAsB;AAqBtB,MAAM,wBAAwB;AAC9B,MAAM,4BAA4B;AAGlC,MAAM,qBAAiB,oBAAM,MAAM;AACjC,aAAO,gCAAmB,IAAI,IAAI,qBAAqB,GAAG;AAAA,IACxD,aAAa;AAAA;AAAA,IACb,iBAAiB;AAAA;AAAA,IACjB,kBAAkB;AAAA;AAAA,EACpB,CAAC;AACH,CAAC;AAED,MAAM,qBAAiB,oBAAM,MAAM;AACjC,aAAO,gCAAmB,IAAI,IAAI,yBAAyB,GAAG;AAAA,IAC5D,aAAa;AAAA;AAAA,IACb,iBAAiB;AAAA;AAAA,IACjB,kBAAkB;AAAA;AAAA,EACpB,CAAC;AACH,CAAC;AAGD,SAAS,UAAU,OAAe;AAChC,MAAI;AACF,UAAM,CAAC,WAAW,UAAU,IAAI,MAAM,MAAM,GAAG;AAC/C,UAAM,SAAS,KAAK,MAAM,OAAO,KAAK,WAAW,QAAQ,EAAE,SAAS,CAAC;AACrE,UAAM,UAAU,KAAK,MAAM,OAAO,KAAK,YAAY,QAAQ,EAAE,SAAS,CAAC;AACvE,WAAO,EAAE,QAAQ,QAAQ;AAAA,EAC3B,SAAS,OAAO;AACd,YAAQ,MAAM,uBAAuB,KAAK;AAC1C,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,oBAAoB,OAAe,kBAAkB,OAAO;AAChF,MAAI;AACF,UAAM,YAAY,QAAQ,IAAI;AAC9B,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,MAAM,uCAAuC;AAAA,IACzD;AAGA,UAAM,UAAU,UAAU,KAAK;AAC/B,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,sBAAsB;AAAA,IACxC;AAEA,YAAQ,IAAI,kBAAkB;AAAA,MAC5B,QAAQ,QAAQ;AAAA,MAChB,MAAM,kBAAkB,mBAAmB;AAAA,IAC7C,CAAC;AAID,UAAM,OAAO,kBAAkB,MAAM,eAAe,IAAI,MAAM,eAAe;AAE7E,UAAM,EAAE,QAAQ,IAAI,UAAM,uBAAU,OAAO,MAAM;AAAA,MAC3C,QAAQ,kBACJ,yCAAyC,YACzC,oCAAoC;AAAA,MACxC,UAAU;AAAA,MACV,YAAY,CAAC,OAAO;AAAA,IAC1B,CAAC;AAED,UAAM,kBAAkB;AACxB,UAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAGxC,QAAI,CAAC,gBAAgB,KAAK;AACpB,YAAM,IAAI,MAAM,wBAAwB;AAAA,IAC9C;AAEA,WAAO;AAAA,MACD,OAAO;AAAA,MACP,KAAK,gBAAgB;AAAA,MACrB,OAAO,gBAAgB;AAAA,MACvB,eAAe,gBAAgB;AAAA,MAC/B,UAAU,gBAAgB;AAAA,MAC1B,UAAU,gBAAgB;AAAA,MAC1B,WAAW,gBAAgB;AAAA,IAC7B;AAAA,EACJ,SAAS,OAAO;AACZ,YAAQ,MAAM,+BAA+B;AAAA,MAC3C,OACE,iBAAiB,QACb;AAAA,QACE,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM;AAAA,QACf,OAAO,MAAM;AAAA,MACf,IACA;AAAA,MACN,SAAS,UAAU,KAAK;AAAA;AAAA,MAExB;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,IAClD;AAAA,EACF;AACF;","names":[]}
@@ -81,19 +81,9 @@ async function verifyFirebaseToken(token, isSessionCookie = false) {
81
81
  algorithms: ["RS256"]
82
82
  });
83
83
  const firebasePayload = payload;
84
- const now = Math.floor(Date.now() / 1e3);
85
- if (firebasePayload.exp <= now) {
86
- throw new Error("Token has expired");
87
- }
88
- if (firebasePayload.iat > now) {
89
- throw new Error("Token issued time is in the future");
90
- }
91
84
  if (!firebasePayload.sub) {
92
85
  throw new Error("Token subject is empty");
93
86
  }
94
- if (firebasePayload.auth_time > now) {
95
- throw new Error("Token auth time is in the future");
96
- }
97
87
  return {
98
88
  valid: true,
99
89
  uid: firebasePayload.sub,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/server/jwt.ts"],"sourcesContent":["import { jwtVerify, createRemoteJWKSet } from \"jose\"\nimport { cache } from \"react\"\n\ninterface FirebaseIdTokenPayload {\n iss: string\n aud: string\n auth_time: number\n user_id: string\n sub: string\n iat: number\n exp: number\n email?: string\n email_verified?: boolean\n firebase: {\n identities: {\n [key: string]: any\n }\n sign_in_provider: string\n }\n}\n\n// Firebase public key endpoints\nconst FIREBASE_ID_TOKEN_URL = \"https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com\"\nconst FIREBASE_SESSION_CERT_URL = \"https://identitytoolkit.googleapis.com/v1/sessionCookiePublicKeys\"\n\n// Cache the JWKS using React cache\nconst getIdTokenJWKS = cache(() => {\n return createRemoteJWKSet(new URL(FIREBASE_ID_TOKEN_URL), {\n cacheMaxAge: 3600000, // 1 hour\n timeoutDuration: 5000, // 5 seconds\n cooldownDuration: 30000, // 30 seconds between retries\n })\n})\n\nconst getSessionJWKS = cache(() => {\n return createRemoteJWKSet(new URL(FIREBASE_SESSION_CERT_URL), {\n cacheMaxAge: 3600000, // 1 hour\n timeoutDuration: 5000, // 5 seconds\n cooldownDuration: 30000, // 30 seconds between retries\n })\n})\n\n// Helper to decode JWT without verification\nfunction decodeJwt(token: string) {\n try {\n const [headerB64, payloadB64] = token.split(\".\")\n const header = JSON.parse(Buffer.from(headerB64, \"base64\").toString())\n const payload = JSON.parse(Buffer.from(payloadB64, \"base64\").toString())\n return { header, payload }\n } catch (error) {\n console.error(\"Error decoding JWT:\", error)\n return null\n }\n}\n\nexport async function verifyFirebaseToken(token: string, isSessionCookie = false) {\n try {\n const projectId = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID\n if (!projectId) {\n throw new Error(\"Firebase Project ID is not configured\")\n }\n\n // Decode token for debugging and type checking\n const decoded = decodeJwt(token)\n if (!decoded) {\n throw new Error(\"Invalid token format\")\n }\n\n console.log(\"Token details:\", {\n header: decoded.header,\n type: isSessionCookie ? \"session_cookie\" : \"id_token\",\n })\n\n let retries = 3\n let lastError: Error | null = null\n\n while (retries > 0) {\n try {\n // Use different JWKS based on token type\n const JWKS = isSessionCookie ? await getSessionJWKS() : await getIdTokenJWKS()\n\n const { payload } = await jwtVerify(token, JWKS, {\n issuer: isSessionCookie\n ? \"https://session.firebase.google.com/\" + projectId\n : \"https://securetoken.google.com/\" + projectId,\n audience: projectId,\n algorithms: [\"RS256\"],\n })\n\n const firebasePayload = payload as unknown as FirebaseIdTokenPayload\n const now = Math.floor(Date.now() / 1000)\n\n // Verify token claims\n if (firebasePayload.exp <= now) {\n throw new Error(\"Token has expired\")\n }\n\n if (firebasePayload.iat > now) {\n throw new Error(\"Token issued time is in the future\")\n }\n\n if (!firebasePayload.sub) {\n throw new Error(\"Token subject is empty\")\n }\n\n if (firebasePayload.auth_time > now) {\n throw new Error(\"Token auth time is in the future\")\n }\n\n return {\n valid: true,\n uid: firebasePayload.sub,\n email: firebasePayload.email,\n emailVerified: firebasePayload.email_verified,\n authTime: firebasePayload.auth_time,\n issuedAt: firebasePayload.iat,\n expiresAt: firebasePayload.exp,\n }\n } catch (error) {\n lastError = error as Error\n if (error instanceof Error && error.name === \"JWKSNoMatchingKey\") {\n console.warn(`JWKS retry attempt ${4 - retries}:`, error.message)\n retries--\n if (retries > 0) {\n await new Promise((resolve) => setTimeout(resolve, 1000))\n continue\n }\n }\n throw error\n }\n }\n\n throw lastError || new Error(\"Failed to verify token after retries\")\n } catch (error) {\n console.error(\"Token verification details:\", {\n error:\n error instanceof Error\n ? {\n name: error.name,\n message: error.message,\n stack: error.stack,\n }\n : error,\n decoded: decodeJwt(token),\n //projectId,\n isSessionCookie,\n })\n\n return {\n valid: false,\n error: error instanceof Error ? error.message : \"Invalid token\",\n }\n }\n}"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,kBAA8C;AAC9C,mBAAsB;AAqBtB,MAAM,wBAAwB;AAC9B,MAAM,4BAA4B;AAGlC,MAAM,qBAAiB,oBAAM,MAAM;AACjC,aAAO,gCAAmB,IAAI,IAAI,qBAAqB,GAAG;AAAA,IACxD,aAAa;AAAA;AAAA,IACb,iBAAiB;AAAA;AAAA,IACjB,kBAAkB;AAAA;AAAA,EACpB,CAAC;AACH,CAAC;AAED,MAAM,qBAAiB,oBAAM,MAAM;AACjC,aAAO,gCAAmB,IAAI,IAAI,yBAAyB,GAAG;AAAA,IAC5D,aAAa;AAAA;AAAA,IACb,iBAAiB;AAAA;AAAA,IACjB,kBAAkB;AAAA;AAAA,EACpB,CAAC;AACH,CAAC;AAGD,SAAS,UAAU,OAAe;AAChC,MAAI;AACF,UAAM,CAAC,WAAW,UAAU,IAAI,MAAM,MAAM,GAAG;AAC/C,UAAM,SAAS,KAAK,MAAM,OAAO,KAAK,WAAW,QAAQ,EAAE,SAAS,CAAC;AACrE,UAAM,UAAU,KAAK,MAAM,OAAO,KAAK,YAAY,QAAQ,EAAE,SAAS,CAAC;AACvE,WAAO,EAAE,QAAQ,QAAQ;AAAA,EAC3B,SAAS,OAAO;AACd,YAAQ,MAAM,uBAAuB,KAAK;AAC1C,WAAO;AAAA,EACT;AACF;AAEA,eAAsB,oBAAoB,OAAe,kBAAkB,OAAO;AAChF,MAAI;AACF,UAAM,YAAY,QAAQ,IAAI;AAC9B,QAAI,CAAC,WAAW;AACd,YAAM,IAAI,MAAM,uCAAuC;AAAA,IACzD;AAGA,UAAM,UAAU,UAAU,KAAK;AAC/B,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,sBAAsB;AAAA,IACxC;AAEA,YAAQ,IAAI,kBAAkB;AAAA,MAC5B,QAAQ,QAAQ;AAAA,MAChB,MAAM,kBAAkB,mBAAmB;AAAA,IAC7C,CAAC;AAED,QAAI,UAAU;AACd,QAAI,YAA0B;AAE9B,WAAO,UAAU,GAAG;AAClB,UAAI;AAEF,cAAM,OAAO,kBAAkB,MAAM,eAAe,IAAI,MAAM,eAAe;AAE7E,cAAM,EAAE,QAAQ,IAAI,UAAM,uBAAU,OAAO,MAAM;AAAA,UAC/C,QAAQ,kBACJ,yCAAyC,YACzC,oCAAoC;AAAA,UACxC,UAAU;AAAA,UACV,YAAY,CAAC,OAAO;AAAA,QACtB,CAAC;AAED,cAAM,kBAAkB;AACxB,cAAM,MAAM,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAGxC,YAAI,gBAAgB,OAAO,KAAK;AAC9B,gBAAM,IAAI,MAAM,mBAAmB;AAAA,QACrC;AAEA,YAAI,gBAAgB,MAAM,KAAK;AAC7B,gBAAM,IAAI,MAAM,oCAAoC;AAAA,QACtD;AAEA,YAAI,CAAC,gBAAgB,KAAK;AACxB,gBAAM,IAAI,MAAM,wBAAwB;AAAA,QAC1C;AAEA,YAAI,gBAAgB,YAAY,KAAK;AACnC,gBAAM,IAAI,MAAM,kCAAkC;AAAA,QACpD;AAEA,eAAO;AAAA,UACL,OAAO;AAAA,UACP,KAAK,gBAAgB;AAAA,UACrB,OAAO,gBAAgB;AAAA,UACvB,eAAe,gBAAgB;AAAA,UAC/B,UAAU,gBAAgB;AAAA,UAC1B,UAAU,gBAAgB;AAAA,UAC1B,WAAW,gBAAgB;AAAA,QAC7B;AAAA,MACF,SAAS,OAAO;AACd,oBAAY;AACZ,YAAI,iBAAiB,SAAS,MAAM,SAAS,qBAAqB;AAChE,kBAAQ,KAAK,sBAAsB,IAAI,OAAO,KAAK,MAAM,OAAO;AAChE;AACA,cAAI,UAAU,GAAG;AACf,kBAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAI,CAAC;AACxD;AAAA,UACF;AAAA,QACF;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAEA,UAAM,aAAa,IAAI,MAAM,sCAAsC;AAAA,EACrE,SAAS,OAAO;AACd,YAAQ,MAAM,+BAA+B;AAAA,MAC3C,OACE,iBAAiB,QACb;AAAA,QACE,MAAM,MAAM;AAAA,QACZ,SAAS,MAAM;AAAA,QACf,OAAO,MAAM;AAAA,MACf,IACA;AAAA,MACN,SAAS,UAAU,KAAK;AAAA;AAAA,MAExB;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL,OAAO;AAAA,MACP,OAAO,iBAAiB,QAAQ,MAAM,UAAU;AAAA,IAClD;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/server/jwt.ts"],"sourcesContent":["import { jwtVerify, createRemoteJWKSet } from \"jose\"\nimport { cache } from \"react\"\n\ninterface FirebaseIdTokenPayload {\n iss: string\n aud: string\n auth_time: number\n user_id: string\n sub: string\n iat: number\n exp: number\n email?: string\n email_verified?: boolean\n firebase: {\n identities: {\n [key: string]: any\n }\n sign_in_provider: string\n }\n}\n\n// Firebase public key endpoints\nconst FIREBASE_ID_TOKEN_URL = \"https://www.googleapis.com/robot/v1/metadata/x509/securetoken@system.gserviceaccount.com\"\nconst FIREBASE_SESSION_CERT_URL = \"https://identitytoolkit.googleapis.com/v1/sessionCookiePublicKeys\"\n\n// Cache the JWKS using React cache\nconst getIdTokenJWKS = cache(() => {\n return createRemoteJWKSet(new URL(FIREBASE_ID_TOKEN_URL), {\n cacheMaxAge: 3600000, // 1 hour\n timeoutDuration: 5000, // 5 seconds\n cooldownDuration: 30000, // 30 seconds between retries\n })\n})\n\nconst getSessionJWKS = cache(() => {\n return createRemoteJWKSet(new URL(FIREBASE_SESSION_CERT_URL), {\n cacheMaxAge: 3600000, // 1 hour\n timeoutDuration: 5000, // 5 seconds\n cooldownDuration: 30000, // 30 seconds between retries\n })\n})\n\n// Helper to decode JWT without verification\nfunction decodeJwt(token: string) {\n try {\n const [headerB64, payloadB64] = token.split(\".\")\n const header = JSON.parse(Buffer.from(headerB64, \"base64\").toString())\n const payload = JSON.parse(Buffer.from(payloadB64, \"base64\").toString())\n return { header, payload }\n } catch (error) {\n console.error(\"Error decoding JWT:\", error)\n return null\n }\n}\n\nexport async function verifyFirebaseToken(token: string, isSessionCookie = false) {\n try {\n const projectId = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID\n if (!projectId) {\n throw new Error(\"Firebase Project ID is not configured\")\n }\n\n // Decode token for debugging and type checking\n const decoded = decodeJwt(token)\n if (!decoded) {\n throw new Error(\"Invalid token format\")\n }\n\n console.log(\"Token details:\", {\n header: decoded.header,\n type: isSessionCookie ? \"session_cookie\" : \"id_token\",\n })\n\n let retries = 3\n let lastError: Error | null = null\n\n while (retries > 0) {\n try {\n // Use different JWKS based on token type\n const JWKS = isSessionCookie ? await getSessionJWKS() : await getIdTokenJWKS()\n\n const { payload } = await jwtVerify(token, JWKS, {\n issuer: isSessionCookie\n ? \"https://session.firebase.google.com/\" + projectId\n : \"https://securetoken.google.com/\" + projectId,\n audience: projectId,\n algorithms: [\"RS256\"],\n })\n\n const firebasePayload = payload as unknown as FirebaseIdTokenPayload\n\n if (!firebasePayload.sub) {\n throw new Error(\"Token subject is empty\")\n }\n\n return {\n valid: true,\n uid: firebasePayload.sub,\n email: firebasePayload.email,\n emailVerified: firebasePayload.email_verified,\n authTime: firebasePayload.auth_time,\n issuedAt: firebasePayload.iat,\n expiresAt: firebasePayload.exp,\n }\n } catch (error) {\n lastError = error as Error\n if (error instanceof Error && error.name === \"JWKSNoMatchingKey\") {\n console.warn(`JWKS retry attempt ${4 - retries}:`, error.message)\n retries--\n if (retries > 0) {\n await new Promise((resolve) => setTimeout(resolve, 1000))\n continue\n }\n }\n throw error\n }\n }\n\n throw lastError || new Error(\"Failed to verify token after retries\")\n } catch (error) {\n console.error(\"Token verification details:\", {\n error:\n error instanceof Error\n ? {\n name: error.name,\n message: error.message,\n stack: error.stack,\n }\n : error,\n decoded: decodeJwt(token),\n //projectId,\n isSessionCookie,\n })\n\n return {\n valid: false,\n error: error instanceof Error ? error.message : \"Invalid token\",\n }\n }\n}"],"mappings":"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","names":[]}
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var session_store_exports = {};
20
+ __export(session_store_exports, {
21
+ getVerifiedUser: () => getVerifiedUser,
22
+ sessionStore: () => sessionStore
23
+ });
24
+ module.exports = __toCommonJS(session_store_exports);
25
+ var import_react = require("react");
26
+ class SessionStore {
27
+ constructor() {
28
+ this.currentSessionId = null;
29
+ this.sessions = /* @__PURE__ */ new Map();
30
+ }
31
+ static getInstance() {
32
+ if (!SessionStore.instance) {
33
+ SessionStore.instance = new SessionStore();
34
+ }
35
+ return SessionStore.instance;
36
+ }
37
+ setUser(sessionId, user) {
38
+ console.log("SessionStore: Setting user:", { sessionId, user });
39
+ this.sessions.set(sessionId, user);
40
+ this.currentSessionId = sessionId;
41
+ }
42
+ getUser(sessionId) {
43
+ return this.sessions.get(sessionId) || null;
44
+ }
45
+ getCurrentUser() {
46
+ if (!this.currentSessionId) return null;
47
+ return this.sessions.get(this.currentSessionId) || null;
48
+ }
49
+ removeUser(sessionId) {
50
+ this.sessions.delete(sessionId);
51
+ }
52
+ clear() {
53
+ this.sessions.clear();
54
+ }
55
+ debug() {
56
+ return {
57
+ sessionsCount: this.sessions.size,
58
+ currentSessionId: this.currentSessionId,
59
+ sessions: Array.from(this.sessions.entries())
60
+ };
61
+ }
62
+ }
63
+ const sessionStore = SessionStore.getInstance();
64
+ const getVerifiedUser = (0, import_react.cache)((sessionId) => {
65
+ return sessionStore.getUser(sessionId);
66
+ });
67
+ // Annotate the CommonJS export names for ESM import in node:
68
+ 0 && (module.exports = {
69
+ getVerifiedUser,
70
+ sessionStore
71
+ });
72
+ //# sourceMappingURL=session-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/server/session-store.ts"],"sourcesContent":["import { cache } from \"react\"\nimport type { UserInfo } from \"./types\"\n\n/**\n * Simple in-memory session store\n * In a real app, this would be backed by Redis/etc\n */\nclass SessionStore {\n private static instance: SessionStore\n private sessions: Map<string, UserInfo>\n private currentSessionId: string | null = null\n\n private constructor() {\n this.sessions = new Map()\n }\n\n static getInstance(): SessionStore {\n if (!SessionStore.instance) {\n SessionStore.instance = new SessionStore()\n }\n return SessionStore.instance\n }\n\n setUser(sessionId: string, user: UserInfo) {\n console.log(\"SessionStore: Setting user:\", { sessionId, user })\n this.sessions.set(sessionId, user)\n this.currentSessionId = sessionId\n }\n\n getUser(sessionId: string): UserInfo | null {\n return this.sessions.get(sessionId) || null\n }\n\n getCurrentUser(): UserInfo | null {\n if (!this.currentSessionId) return null\n return this.sessions.get(this.currentSessionId) || null\n }\n\n removeUser(sessionId: string) {\n this.sessions.delete(sessionId)\n }\n\n clear() {\n this.sessions.clear()\n }\n\n debug() {\n return {\n sessionsCount: this.sessions.size,\n currentSessionId: this.currentSessionId,\n sessions: Array.from(this.sessions.entries())\n }\n}\n}\n\n// Export singleton instance\nexport const sessionStore = SessionStore.getInstance()\n\n/**\n * Cached function to get user from session store\n * Uses React cache for SSR optimization\n */\nexport const getVerifiedUser = cache((sessionId: string): UserInfo | null => {\n return sessionStore.getUser(sessionId)\n})\n\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mBAAsB;AAOtB,MAAM,aAAa;AAAA,EAKT,cAAc;AAFtB,SAAQ,mBAAkC;AAGxC,SAAK,WAAW,oBAAI,IAAI;AAAA,EAC1B;AAAA,EAEA,OAAO,cAA4B;AACjC,QAAI,CAAC,aAAa,UAAU;AAC1B,mBAAa,WAAW,IAAI,aAAa;AAAA,IAC3C;AACA,WAAO,aAAa;AAAA,EACtB;AAAA,EAEA,QAAQ,WAAmB,MAAgB;AACzC,YAAQ,IAAI,+BAA+B,EAAE,WAAW,KAAK,CAAC;AAC9D,SAAK,SAAS,IAAI,WAAW,IAAI;AACjC,SAAK,mBAAmB;AAAA,EAC1B;AAAA,EAEA,QAAQ,WAAoC;AAC1C,WAAO,KAAK,SAAS,IAAI,SAAS,KAAK;AAAA,EACzC;AAAA,EAEA,iBAAkC;AAChC,QAAI,CAAC,KAAK,iBAAkB,QAAO;AACnC,WAAO,KAAK,SAAS,IAAI,KAAK,gBAAgB,KAAK;AAAA,EACrD;AAAA,EAEA,WAAW,WAAmB;AAC5B,SAAK,SAAS,OAAO,SAAS;AAAA,EAChC;AAAA,EAEA,QAAQ;AACN,SAAK,SAAS,MAAM;AAAA,EACtB;AAAA,EAEA,QAAQ;AACN,WAAO;AAAA,MACL,eAAe,KAAK,SAAS;AAAA,MAC7B,kBAAkB,KAAK;AAAA,MACvB,UAAU,MAAM,KAAK,KAAK,SAAS,QAAQ,CAAC;AAAA,IAC9C;AAAA,EACJ;AACA;AAGO,MAAM,eAAe,aAAa,YAAY;AAM9C,MAAM,sBAAkB,oBAAM,CAAC,cAAuC;AAC3E,SAAO,aAAa,QAAQ,SAAS;AACvC,CAAC;","names":[]}
@@ -19,13 +19,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  var ternSecureMiddleware_exports = {};
20
20
  __export(ternSecureMiddleware_exports, {
21
21
  createRouteMatcher: () => createRouteMatcher,
22
- runtime: () => runtime,
23
22
  ternSecureMiddleware: () => ternSecureMiddleware
24
23
  });
25
24
  module.exports = __toCommonJS(ternSecureMiddleware_exports);
26
25
  var import_server = require("next/server");
27
- var import_edge_session = require("./edge-session");
28
- const runtime = "edge";
26
+ var import_errors = require("../errors");
29
27
  function createRouteMatcher(patterns) {
30
28
  return (request) => {
31
29
  const { pathname } = request.nextUrl;
@@ -37,60 +35,36 @@ function createRouteMatcher(patterns) {
37
35
  });
38
36
  };
39
37
  }
40
- async function edgeAuth(request) {
41
- var _a, _b;
42
- async function protect() {
43
- throw new Error("Unauthorized access");
44
- }
45
- try {
46
- const sessionResult = await (0, import_edge_session.verifySession)(request);
47
- if (sessionResult.isAuthenticated && sessionResult.user) {
48
- return {
49
- user: sessionResult.user,
50
- token: ((_a = request.cookies.get("_session_cookie")) == null ? void 0 : _a.value) || ((_b = request.cookies.get("_session_token")) == null ? void 0 : _b.value) || null,
51
- protect: async () => {
52
- }
53
- };
54
- }
55
- return {
56
- user: null,
57
- token: null,
58
- protect
59
- };
60
- } catch (error) {
61
- console.error("Auth check error:", error);
62
- return {
63
- user: null,
64
- token: null,
65
- protect
66
- };
67
- }
68
- }
69
38
  function ternSecureMiddleware(callback) {
70
39
  return async function middleware(request) {
71
40
  try {
72
- const auth = await edgeAuth(request);
73
- try {
74
- await callback(auth, request);
75
- const response = import_server.NextResponse.next();
76
- if (auth.user) {
77
- response.headers.set("x-user-id", auth.user.uid);
78
- if (auth.user.email) {
79
- response.headers.set("x-user-email", auth.user.email);
80
- }
81
- if (auth.user.emailVerified !== void 0) {
82
- response.headers.set("x-email-verified", auth.user.emailVerified.toString());
83
- }
84
- if (auth.user.authTime) {
85
- response.headers.set("x-auth-time", auth.user.authTime.toString());
41
+ const hasCookies = request.cookies.has("_session_cookie") || request.cookies.has("_session_token");
42
+ const auth = {
43
+ user: null,
44
+ sessionId: null,
45
+ protect: async () => {
46
+ if (!hasCookies) {
47
+ const currentPath = request.nextUrl.pathname;
48
+ if (currentPath !== "/sign-in") {
49
+ const redirectUrl = new URL("/sign-in", request.url);
50
+ redirectUrl.searchParams.set("redirect", currentPath);
51
+ throw new import_errors.TernSecureError("UNAUTHENTICATED", redirectUrl.toString());
52
+ } else {
53
+ throw new Error("UNAUTHENTICATED");
54
+ }
86
55
  }
87
56
  }
88
- return response;
57
+ };
58
+ if (!callback) {
59
+ return import_server.NextResponse.next();
60
+ }
61
+ try {
62
+ await callback(auth, request);
63
+ return import_server.NextResponse.next();
89
64
  } catch (error) {
90
65
  if (error instanceof Error && error.message === "Unauthorized access") {
91
- const redirectUrl = new URL("/sign-in", request.url);
92
- redirectUrl.searchParams.set("redirect", request.nextUrl.pathname);
93
- return import_server.NextResponse.redirect(redirectUrl);
66
+ console.log("middleware: Unauthorized access, redirecting to sign-in");
67
+ return import_server.NextResponse.redirect(error.message);
94
68
  }
95
69
  throw error;
96
70
  }
@@ -103,15 +77,13 @@ function ternSecureMiddleware(callback) {
103
77
  } : error,
104
78
  path: request.nextUrl.pathname
105
79
  });
106
- const redirectUrl = new URL("/sign-in", request.url);
107
- return import_server.NextResponse.redirect(redirectUrl);
80
+ return import_server.NextResponse.redirect(new URL("/sign-in", request.url));
108
81
  }
109
82
  };
110
83
  }
111
84
  // Annotate the CommonJS export names for ESM import in node:
112
85
  0 && (module.exports = {
113
86
  createRouteMatcher,
114
- runtime,
115
87
  ternSecureMiddleware
116
88
  });
117
89
  //# sourceMappingURL=ternSecureMiddleware.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/server/ternSecureMiddleware.ts"],"sourcesContent":["import { NextRequest, NextResponse } from 'next/server';\nimport { verifySession } from './edge-session'\nimport type { UserInfo } from './types'\n\n\nexport const runtime = \"edge\"\n\n\ninterface Auth {\n user: UserInfo | null\n token: string | null\n protect: () => Promise<void>\n}\n\ntype MiddlewareCallback = (\n auth: Auth,\n request: NextRequest\n) => Promise<void>\n\n\n/**\n * Create a route matcher function for public paths\n */\nexport function createRouteMatcher(patterns: string[]) {\n return (request: NextRequest): boolean => {\n const { pathname } = request.nextUrl\n return patterns.some(pattern => {\n // Convert route pattern to regex\n const regexPattern = new RegExp(\n `^${pattern.replace(/\\*/g, '.*').replace(/\\((.*)\\)/, '(?:$1)?')}$`\n )\n return regexPattern.test(pathname)\n })\n }\n}\n\n\n/**\n * Edge-compatible auth check\n */\nasync function edgeAuth(request: NextRequest): Promise<Auth> {\n async function protect() {\n throw new Error(\"Unauthorized access\")\n }\n\n try {\n const sessionResult = await verifySession(request)\n\n if (sessionResult.isAuthenticated && sessionResult.user) {\n return {\n user: sessionResult.user,\n token: request.cookies.get(\"_session_cookie\")?.value || request.cookies.get(\"_session_token\")?.value || null,\n protect: async () => {},\n }\n }\n\n return {\n user: null,\n token: null,\n protect,\n }\n } catch (error) {\n console.error(\"Auth check error:\", error)\n return {\n user: null,\n token: null,\n protect,\n }\n }\n}\n\n\n\n/**\n * Middleware factory that handles authentication and custom logic\n * @param customHandler Optional function for additional custom logic\n */\n\nexport function ternSecureMiddleware(callback: MiddlewareCallback) {\n return async function middleware(request: NextRequest) {\n try {\n const auth = await edgeAuth(request)\n\n try {\n \n await callback(auth, request)\n\n const response = NextResponse.next()\n\n if (auth.user) {\n // Set auth headers\n response.headers.set(\"x-user-id\", auth.user.uid)\n if (auth.user.email) {\n response.headers.set(\"x-user-email\", auth.user.email)\n }\n if (auth.user.emailVerified !== undefined) {\n response.headers.set(\"x-email-verified\", auth.user.emailVerified.toString())\n }\n if (auth.user.authTime) {\n response.headers.set(\"x-auth-time\", auth.user.authTime.toString())\n }\n }\n\n return response\n } catch (error) {\n // Handle unauthorized access\n if (error instanceof Error && error.message === 'Unauthorized access') {\n const redirectUrl = new URL('/sign-in', request.url)\n redirectUrl.searchParams.set('redirect', request.nextUrl.pathname)\n return NextResponse.redirect(redirectUrl)\n }\n throw error\n }\n\n } catch (error) {\n console.error(\"Middleware error:\", {\n error:\n error instanceof Error\n ? {\n name: error.name,\n message: error.message,\n stack: error.stack,\n }\n : error,\n path: request.nextUrl.pathname,\n })\n\n const redirectUrl = new URL(\"/sign-in\", request.url)\n return NextResponse.redirect(redirectUrl)\n }\n }\n}"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA0C;AAC1C,0BAA8B;AAIvB,MAAM,UAAU;AAkBhB,SAAS,mBAAmB,UAAoB;AACrD,SAAO,CAAC,YAAkC;AACxC,UAAM,EAAE,SAAS,IAAI,QAAQ;AAC7B,WAAO,SAAS,KAAK,aAAW;AAE9B,YAAM,eAAe,IAAI;AAAA,QACvB,IAAI,QAAQ,QAAQ,OAAO,IAAI,EAAE,QAAQ,YAAY,SAAS,CAAC;AAAA,MACjE;AACA,aAAO,aAAa,KAAK,QAAQ;AAAA,IACnC,CAAC;AAAA,EACH;AACF;AAMA,eAAe,SAAS,SAAqC;AAxC7D;AAyCE,iBAAe,UAAU;AACvB,UAAM,IAAI,MAAM,qBAAqB;AAAA,EACvC;AAEA,MAAI;AACF,UAAM,gBAAgB,UAAM,mCAAc,OAAO;AAEjD,QAAI,cAAc,mBAAmB,cAAc,MAAM;AACvD,aAAO;AAAA,QACL,MAAM,cAAc;AAAA,QACpB,SAAO,aAAQ,QAAQ,IAAI,iBAAiB,MAArC,mBAAwC,YAAS,aAAQ,QAAQ,IAAI,gBAAgB,MAApC,mBAAuC,UAAS;AAAA,QACxG,SAAS,YAAY;AAAA,QAAC;AAAA,MACxB;AAAA,IACF;AAEA,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,qBAAqB,KAAK;AACxC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO;AAAA,MACP;AAAA,IACF;AAAA,EACF;AACF;AASO,SAAS,qBAAqB,UAA8B;AACjE,SAAO,eAAe,WAAW,SAAsB;AACrD,QAAI;AACF,YAAM,OAAO,MAAM,SAAS,OAAO;AAEnC,UAAI;AAEF,cAAM,SAAS,MAAM,OAAO;AAE5B,cAAM,WAAW,2BAAa,KAAK;AAEnC,YAAI,KAAK,MAAM;AAEb,mBAAS,QAAQ,IAAI,aAAa,KAAK,KAAK,GAAG;AAC/C,cAAI,KAAK,KAAK,OAAO;AACnB,qBAAS,QAAQ,IAAI,gBAAgB,KAAK,KAAK,KAAK;AAAA,UACtD;AACA,cAAI,KAAK,KAAK,kBAAkB,QAAW;AACzC,qBAAS,QAAQ,IAAI,oBAAoB,KAAK,KAAK,cAAc,SAAS,CAAC;AAAA,UAC7E;AACA,cAAI,KAAK,KAAK,UAAU;AACtB,qBAAS,QAAQ,IAAI,eAAe,KAAK,KAAK,SAAS,SAAS,CAAC;AAAA,UACnE;AAAA,QACF;AAEA,eAAO;AAAA,MACT,SAAS,OAAO;AAEd,YAAI,iBAAiB,SAAS,MAAM,YAAY,uBAAuB;AACrE,gBAAM,cAAc,IAAI,IAAI,YAAY,QAAQ,GAAG;AACnD,sBAAY,aAAa,IAAI,YAAY,QAAQ,QAAQ,QAAQ;AACjE,iBAAO,2BAAa,SAAS,WAAW;AAAA,QAC1C;AACA,cAAM;AAAA,MACR;AAAA,IAEF,SAAS,OAAO;AACd,cAAQ,MAAM,qBAAqB;AAAA,QACjC,OACE,iBAAiB,QACb;AAAA,UACE,MAAM,MAAM;AAAA,UACZ,SAAS,MAAM;AAAA,UACf,OAAO,MAAM;AAAA,QACf,IACA;AAAA,QACN,MAAM,QAAQ,QAAQ;AAAA,MACxB,CAAC;AAED,YAAM,cAAc,IAAI,IAAI,YAAY,QAAQ,GAAG;AACnD,aAAO,2BAAa,SAAS,WAAW;AAAA,IAC1C;AAAA,EACF;AACF;","names":[]}
1
+ {"version":3,"sources":["../../../src/server/ternSecureMiddleware.ts"],"sourcesContent":["import { type NextRequest, NextResponse } from 'next/server';\nimport type { UserInfo } from './types'\nimport { TernSecureError } from '../errors';\n\n\n\ninterface Auth {\n user: UserInfo | null\n sessionId : string | null\n protect: () => Promise<void>\n}\n\ntype MiddlewareCallback = (\n auth: Auth,\n request: NextRequest\n) => Promise<void>\n\n\n/**\n * Create a route matcher function for public paths\n */\nexport function createRouteMatcher(patterns: string[]) {\n return (request: NextRequest): boolean => {\n const { pathname } = request.nextUrl\n return patterns.some(pattern => {\n // Convert route pattern to regex\n const regexPattern = new RegExp(\n `^${pattern.replace(/\\*/g, '.*').replace(/\\((.*)\\)/, '(?:$1)?')}$`\n )\n return regexPattern.test(pathname)\n })\n }\n}\n\n\n/**\n * Middleware factory that handles authentication and custom logic\n * @param customHandler Optional function for additional custom logic\n */\n\nexport function ternSecureMiddleware(callback: MiddlewareCallback) {\n return async function middleware(request: NextRequest) {\n try {\n\n const hasCookies = request.cookies.has('_session_cookie') || request.cookies.has('_session_token')\n\n const auth: Auth = {\n user: null,\n sessionId: null,\n protect: async () => {\n if (!hasCookies) {\n const currentPath = request.nextUrl.pathname\n if (currentPath !== '/sign-in') {\n const redirectUrl = new URL('/sign-in', request.url)\n redirectUrl.searchParams.set('redirect', currentPath)\n throw new TernSecureError('UNAUTHENTICATED', redirectUrl.toString())\n } else {\n throw new Error('UNAUTHENTICATED')\n }\n }\n }\n }\n\n if (!callback) {\n return NextResponse.next()\n }\n\n\n\n try {\n await callback(auth, request)\n return NextResponse.next()\n } catch (error) {\n if (error instanceof Error && error.message === 'Unauthorized access') {\n console.log('middleware: Unauthorized access, redirecting to sign-in')\n return NextResponse.redirect(error.message)\n }\n throw error\n }\n\n } catch (error) {\n console.error(\"Middleware error:\", {\n error:\n error instanceof Error\n ? {\n name: error.name,\n message: error.message,\n stack: error.stack,\n }\n : error,\n path: request.nextUrl.pathname,\n })\n\n return NextResponse.redirect(new URL('/sign-in', request.url))\n }\n }\n}"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA+C;AAE/C,oBAAgC;AAmBzB,SAAS,mBAAmB,UAAoB;AACrD,SAAO,CAAC,YAAkC;AACxC,UAAM,EAAE,SAAS,IAAI,QAAQ;AAC7B,WAAO,SAAS,KAAK,aAAW;AAE9B,YAAM,eAAe,IAAI;AAAA,QACvB,IAAI,QAAQ,QAAQ,OAAO,IAAI,EAAE,QAAQ,YAAY,SAAS,CAAC;AAAA,MACjE;AACA,aAAO,aAAa,KAAK,QAAQ;AAAA,IACnC,CAAC;AAAA,EACH;AACF;AAQO,SAAS,qBAAqB,UAA8B;AACjE,SAAO,eAAe,WAAW,SAAsB;AACrD,QAAI;AAEF,YAAM,aAAa,QAAQ,QAAQ,IAAI,iBAAiB,KAAK,QAAQ,QAAQ,IAAI,gBAAgB;AAEjG,YAAM,OAAa;AAAA,QACjB,MAAM;AAAA,QACN,WAAW;AAAA,QACX,SAAS,YAAY;AACnB,cAAI,CAAC,YAAY;AACf,kBAAM,cAAc,QAAQ,QAAQ;AACpC,gBAAI,gBAAgB,YAAY;AAC9B,oBAAM,cAAc,IAAI,IAAI,YAAY,QAAQ,GAAG;AACnD,0BAAY,aAAa,IAAI,YAAY,WAAW;AACpD,oBAAM,IAAI,8BAAgB,mBAAmB,YAAY,SAAS,CAAC;AAAA,YACrE,OAAO;AACL,oBAAM,IAAI,MAAM,iBAAiB;AAAA,YACnC;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAEA,UAAI,CAAC,UAAU;AACb,eAAO,2BAAa,KAAK;AAAA,MAC3B;AAIA,UAAI;AACF,cAAM,SAAS,MAAM,OAAO;AAC5B,eAAO,2BAAa,KAAK;AAAA,MAC3B,SAAS,OAAO;AACd,YAAI,iBAAiB,SAAS,MAAM,YAAY,uBAAuB;AACrE,kBAAQ,IAAI,yDAAyD;AACrE,iBAAO,2BAAa,SAAS,MAAM,OAAO;AAAA,QAC5C;AACA,cAAM;AAAA,MACR;AAAA,IAEF,SAAS,OAAO;AACd,cAAQ,MAAM,qBAAqB;AAAA,QACjC,OACE,iBAAiB,QACb;AAAA,UACE,MAAM,MAAM;AAAA,UACZ,SAAS,MAAM;AAAA,UACf,OAAO,MAAM;AAAA,QACf,IACA;AAAA,QACN,MAAM,QAAQ,QAAQ;AAAA,MACxB,CAAC;AAED,aAAO,2BAAa,SAAS,IAAI,IAAI,YAAY,QAAQ,GAAG,CAAC;AAAA,IAC/D;AAAA,EACF;AACF;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/server/types.ts"],"sourcesContent":["export interface UserInfo {\n uid: string\n email: string | null\n emailVerified?: boolean\n authTime?: number\n disabled?: boolean\n }\n \n \n export interface SessionResult {\n isAuthenticated: boolean\n user: UserInfo | null\n error?: string\n }"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../../../src/server/types.ts"],"sourcesContent":["export interface UserInfo {\n uid: string\n email: string | null\n emailVerified?: boolean\n authTime?: number\n disabled?: boolean\n }\n \n \n export interface SessionResult {\n user: UserInfo | null\n token: string | null\n sessionId: string | null\n error?: string\n }"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var utils_exports = {};
20
+ __export(utils_exports, {
21
+ Store: () => Store
22
+ });
23
+ module.exports = __toCommonJS(utils_exports);
24
+ const getGlobalObject = () => {
25
+ if (typeof process !== "undefined") {
26
+ return process;
27
+ }
28
+ return globalThis;
29
+ };
30
+ const STORE_KEY = "__TERN_AUTH_STORE__";
31
+ class Store {
32
+ static getStore() {
33
+ const global = getGlobalObject();
34
+ if (!global[STORE_KEY]) {
35
+ global[STORE_KEY] = {
36
+ contexts: /* @__PURE__ */ new Map(),
37
+ sessions: /* @__PURE__ */ new Map(),
38
+ currentSession: null
39
+ };
40
+ }
41
+ return global[STORE_KEY];
42
+ }
43
+ static setContext(context) {
44
+ const store = this.getStore();
45
+ const { user, sessionId } = context;
46
+ console.log("Store: Setting context:", { sessionId, user });
47
+ store.contexts.set(sessionId, context);
48
+ store.sessions.set(sessionId, user);
49
+ store.currentSession = context;
50
+ console.log("Store: Updated state:", {
51
+ contextsSize: store.contexts.size,
52
+ sessionsSize: store.sessions.size,
53
+ currentSession: store.currentSession
54
+ });
55
+ }
56
+ static getContext() {
57
+ const store = this.getStore();
58
+ if (store.currentSession) {
59
+ const session = this.getSession(store.currentSession.sessionId);
60
+ if (session && session.uid === store.currentSession.user.uid) {
61
+ return store.currentSession;
62
+ }
63
+ }
64
+ for (const [sessionId, user] of store.sessions.entries()) {
65
+ const context = store.contexts.get(sessionId);
66
+ if (context && context.user.uid === user.uid) {
67
+ store.currentSession = context;
68
+ return context;
69
+ }
70
+ }
71
+ return null;
72
+ }
73
+ static setSession(sessionId, user) {
74
+ const store = this.getStore();
75
+ store.sessions.set(sessionId, user);
76
+ }
77
+ static getSession(sessionId) {
78
+ const store = this.getStore();
79
+ return store.sessions.get(sessionId) || null;
80
+ }
81
+ static debug() {
82
+ const store = this.getStore();
83
+ return {
84
+ contextsSize: store.contexts.size,
85
+ sessionsSize: store.sessions.size,
86
+ currentSession: store.currentSession,
87
+ contexts: Array.from(store.contexts.entries()),
88
+ sessions: Array.from(store.sessions.entries())
89
+ };
90
+ }
91
+ static cleanup() {
92
+ const store = this.getStore();
93
+ const MAX_ENTRIES = 1e3;
94
+ if (store.contexts.size > MAX_ENTRIES) {
95
+ const keys = Array.from(store.contexts.keys());
96
+ const toDelete = keys.slice(0, keys.length - MAX_ENTRIES);
97
+ toDelete.forEach((key) => {
98
+ store.contexts.delete(key);
99
+ store.sessions.delete(key);
100
+ });
101
+ }
102
+ }
103
+ }
104
+ // Annotate the CommonJS export names for ESM import in node:
105
+ 0 && (module.exports = {
106
+ Store
107
+ });
108
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/server/utils.ts"],"sourcesContent":["import type { UserInfo } from \"./types\"\n\ninterface RequestContext {\n user: UserInfo\n sessionId: string\n}\n\n// Use process.env in Node.js and globalThis in Edge\nconst getGlobalObject = () => {\n if (typeof process !== 'undefined') {\n return process\n }\n return globalThis\n}\n\nconst STORE_KEY = '__TERN_AUTH_STORE__'\n\nexport class Store {\n private static getStore() {\n const global = getGlobalObject() as any\n \n if (!global[STORE_KEY]) {\n global[STORE_KEY] = {\n contexts: new Map<string, RequestContext>(),\n sessions: new Map<string, UserInfo>(),\n currentSession: null as RequestContext | null\n }\n }\n \n return global[STORE_KEY]\n }\n\n static setContext(context: RequestContext) {\n const store = this.getStore()\n const { user, sessionId } = context\n \n console.log(\"Store: Setting context:\", { sessionId, user })\n \n // Store in both maps\n store.contexts.set(sessionId, context)\n store.sessions.set(sessionId, user)\n \n // Set as current session\n store.currentSession = context\n \n console.log(\"Store: Updated state:\", {\n contextsSize: store.contexts.size,\n sessionsSize: store.sessions.size,\n currentSession: store.currentSession\n })\n }\n\n static getContext(): RequestContext | null {\n const store = this.getStore()\n \n // First try current session\n if (store.currentSession) {\n const session = this.getSession(store.currentSession.sessionId)\n if (session && session.uid === store.currentSession.user.uid) {\n return store.currentSession\n }\n }\n \n // Then try to find any valid context\n for (const [sessionId, user] of store.sessions.entries()) {\n const context = store.contexts.get(sessionId)\n if (context && context.user.uid === user.uid) {\n // Update current session\n store.currentSession = context\n return context\n }\n }\n \n return null\n }\n\n static setSession(sessionId: string, user: UserInfo) {\n const store = this.getStore()\n store.sessions.set(sessionId, user)\n }\n\n static getSession(sessionId: string): UserInfo | null {\n const store = this.getStore()\n return store.sessions.get(sessionId) || null\n }\n\n static debug() {\n const store = this.getStore()\n return {\n contextsSize: store.contexts.size,\n sessionsSize: store.sessions.size,\n currentSession: store.currentSession,\n contexts: Array.from(store.contexts.entries()),\n sessions: Array.from(store.sessions.entries())\n }\n }\n\n static cleanup() {\n const store = this.getStore()\n const MAX_ENTRIES = 1000\n \n if (store.contexts.size > MAX_ENTRIES) {\n const keys = Array.from(store.contexts.keys())\n const toDelete = keys.slice(0, keys.length - MAX_ENTRIES)\n \n toDelete.forEach(key => {\n store.contexts.delete(key)\n store.sessions.delete(key)\n })\n }\n }\n}"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAQA,MAAM,kBAAkB,MAAM;AAC5B,MAAI,OAAO,YAAY,aAAa;AAClC,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,MAAM,YAAY;AAEX,MAAM,MAAM;AAAA,EACjB,OAAe,WAAW;AACxB,UAAM,SAAS,gBAAgB;AAE/B,QAAI,CAAC,OAAO,SAAS,GAAG;AACtB,aAAO,SAAS,IAAI;AAAA,QAClB,UAAU,oBAAI,IAA4B;AAAA,QAC1C,UAAU,oBAAI,IAAsB;AAAA,QACpC,gBAAgB;AAAA,MAClB;AAAA,IACF;AAEA,WAAO,OAAO,SAAS;AAAA,EACzB;AAAA,EAEA,OAAO,WAAW,SAAyB;AACzC,UAAM,QAAQ,KAAK,SAAS;AAC5B,UAAM,EAAE,MAAM,UAAU,IAAI;AAE5B,YAAQ,IAAI,2BAA2B,EAAE,WAAW,KAAK,CAAC;AAG1D,UAAM,SAAS,IAAI,WAAW,OAAO;AACrC,UAAM,SAAS,IAAI,WAAW,IAAI;AAGlC,UAAM,iBAAiB;AAEvB,YAAQ,IAAI,yBAAyB;AAAA,MACnC,cAAc,MAAM,SAAS;AAAA,MAC7B,cAAc,MAAM,SAAS;AAAA,MAC7B,gBAAgB,MAAM;AAAA,IACxB,CAAC;AAAA,EACH;AAAA,EAEA,OAAO,aAAoC;AACzC,UAAM,QAAQ,KAAK,SAAS;AAG5B,QAAI,MAAM,gBAAgB;AACxB,YAAM,UAAU,KAAK,WAAW,MAAM,eAAe,SAAS;AAC9D,UAAI,WAAW,QAAQ,QAAQ,MAAM,eAAe,KAAK,KAAK;AAC5D,eAAO,MAAM;AAAA,MACf;AAAA,IACF;AAGA,eAAW,CAAC,WAAW,IAAI,KAAK,MAAM,SAAS,QAAQ,GAAG;AACxD,YAAM,UAAU,MAAM,SAAS,IAAI,SAAS;AAC5C,UAAI,WAAW,QAAQ,KAAK,QAAQ,KAAK,KAAK;AAE5C,cAAM,iBAAiB;AACvB,eAAO;AAAA,MACT;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,WAAW,WAAmB,MAAgB;AACnD,UAAM,QAAQ,KAAK,SAAS;AAC5B,UAAM,SAAS,IAAI,WAAW,IAAI;AAAA,EACpC;AAAA,EAEA,OAAO,WAAW,WAAoC;AACpD,UAAM,QAAQ,KAAK,SAAS;AAC5B,WAAO,MAAM,SAAS,IAAI,SAAS,KAAK;AAAA,EAC1C;AAAA,EAEA,OAAO,QAAQ;AACb,UAAM,QAAQ,KAAK,SAAS;AAC5B,WAAO;AAAA,MACL,cAAc,MAAM,SAAS;AAAA,MAC7B,cAAc,MAAM,SAAS;AAAA,MAC7B,gBAAgB,MAAM;AAAA,MACtB,UAAU,MAAM,KAAK,MAAM,SAAS,QAAQ,CAAC;AAAA,MAC7C,UAAU,MAAM,KAAK,MAAM,SAAS,QAAQ,CAAC;AAAA,IAC/C;AAAA,EACF;AAAA,EAEA,OAAO,UAAU;AACf,UAAM,QAAQ,KAAK,SAAS;AAC5B,UAAM,cAAc;AAEpB,QAAI,MAAM,SAAS,OAAO,aAAa;AACrC,YAAM,OAAO,MAAM,KAAK,MAAM,SAAS,KAAK,CAAC;AAC7C,YAAM,WAAW,KAAK,MAAM,GAAG,KAAK,SAAS,WAAW;AAExD,eAAS,QAAQ,SAAO;AACtB,cAAM,SAAS,OAAO,GAAG;AACzB,cAAM,SAAS,OAAO,GAAG;AAAA,MAC3B,CAAC;AAAA,IACH;AAAA,EACF;AACF;","names":[]}
@@ -1,6 +1,7 @@
1
1
  "use server";
2
2
  import { cookies } from "next/headers";
3
3
  import { adminTernSecureAuth as adminAuth } from "../../utils/admin-init";
4
+ import { handleFirebaseAuthError } from "../../errors";
4
5
  async function createSessionCookie(idToken) {
5
6
  try {
6
7
  const expiresIn = 60 * 60 * 24 * 5 * 1e3;
@@ -71,37 +72,40 @@ async function setServerSession(token) {
71
72
  }
72
73
  async function verifyTernIdToken(token) {
73
74
  try {
74
- const decodedToken = await adminAuth.verifyIdToken(token, true);
75
- return { valid: true, uid: decodedToken.uid };
75
+ const decodedToken = await adminAuth.verifyIdToken(token);
76
+ return {
77
+ valid: true,
78
+ uid: decodedToken.uid,
79
+ email: decodedToken.email || null,
80
+ authTime: decodedToken.auth_time
81
+ };
76
82
  } catch (error) {
77
- if (error instanceof Error) {
78
- const firebaseError = error;
79
- if (error.name === "FirebaseAuthError") {
80
- switch (firebaseError.code) {
81
- case "auth/id-token-expired":
82
- return { valid: false, error: "Token has expired" };
83
- case "auth/id-token-revoked":
84
- return { valid: false, error: "Token has been revoked" };
85
- case "auth/user-disabled":
86
- return { valid: false, error: "User account has been disabled" };
87
- default:
88
- return { valid: false, error: "Invalid token" };
89
- }
90
- }
91
- }
92
- return { valid: false, error: "Error verifying token" };
83
+ const errorResponse = handleFirebaseAuthError(error);
84
+ return {
85
+ valid: false,
86
+ uid: null,
87
+ email: null,
88
+ error: errorResponse
89
+ };
93
90
  }
94
91
  }
95
92
  async function verifyTernSessionCookie(session) {
96
93
  try {
97
- const res = await adminAuth.verifySessionCookie(session, true);
98
- if (res) {
99
- return { valid: true, uid: res.uid };
100
- } else {
101
- return { valid: false, error: "Invalid session" };
102
- }
94
+ const res = await adminAuth.verifySessionCookie(session);
95
+ return {
96
+ valid: true,
97
+ uid: res.uid,
98
+ email: res.email || null,
99
+ authTime: res.auth_time
100
+ };
103
101
  } catch (error) {
104
- return { error, valid: false };
102
+ const errorResponse = handleFirebaseAuthError(error);
103
+ return {
104
+ valid: false,
105
+ uid: null,
106
+ email: null,
107
+ error: errorResponse
108
+ };
105
109
  }
106
110
  }
107
111
  async function clearSessionCookie() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/app-router/admin/sessionTernSecure.ts"],"sourcesContent":["'use server'\n\nimport { cookies } from 'next/headers';\nimport { adminTernSecureAuth as adminAuth } from '../../utils/admin-init';\n\ninterface FirebaseAuthError extends Error {\n code?: string;\n}\n\nexport interface User {\n uid: string | null;\n email: string | null;\n }\n\nexport interface Session {\n user: User | null;\n token: string | null;\n error: Error | null;\n}\n\nexport async function createSessionCookie(idToken: string) {\n try {\n const expiresIn = 60 * 60 * 24 * 5 * 1000;\n const sessionCookie = await adminAuth.createSessionCookie(idToken, { expiresIn });\n\n const cookieStore = await cookies();\n cookieStore.set('_session_cookie', sessionCookie, {\n maxAge: expiresIn,\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n path: '/',\n });\n return { success: true, message: 'Session created' };\n } catch (error) {\n return { success: false, message: 'Failed to create session' };\n }\n}\n\n\n\nexport async function getServerSessionCookie() {\n const cookieStore = await cookies();\n const sessionCookie = cookieStore.get('_session_cookie')?.value;\n\n if (!sessionCookie) {\n throw new Error('No session cookie found')\n }\n \n try {\n const decondeClaims = await adminAuth.verifySessionCookie(sessionCookie, true)\n return {\n token: sessionCookie,\n userId: decondeClaims.uid\n }\n } catch (error) {\n console.error('Error verifying session:', error)\n throw new Error('Invalid Session')\n }\n}\n\n\nexport async function getIdToken() {\n const cookieStore = await cookies();\n const token = cookieStore.get('_session_token')?.value;\n\n if (!token) {\n throw new Error('No session cookie found')\n }\n \n try {\n const decodedClaims = await adminAuth.verifyIdToken(token)\n return {\n token: token,\n userId: decodedClaims.uid\n }\n } catch (error) {\n console.error('Error verifying session:', error)\n throw new Error('Invalid Session')\n }\n}\n\nexport async function setServerSession(token: string) {\n try {\n const cookieStore = await cookies();\n cookieStore.set('_session_token', token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'strict',\n maxAge: 60 * 60, // 1 hour\n path: '/',\n });\n return { success: true, message: 'Session created' };\n } catch {\n return { success: false, message: 'Failed to create session' };\n }\n}\n\n export async function verifyTernIdToken(token: string): Promise<{ valid: boolean; uid?: string; error?: string }> {\n try {\n const decodedToken = await adminAuth.verifyIdToken(token, true);\n return { valid: true, uid: decodedToken.uid };\n } catch (error) {\n if (error instanceof Error) {\n const firebaseError = error as FirebaseAuthError;\n if (error.name === 'FirebaseAuthError') {\n // Handle specific Firebase Auth errors\n switch (firebaseError.code) {\n case 'auth/id-token-expired':\n return { valid: false, error: 'Token has expired' };\n case 'auth/id-token-revoked':\n return { valid: false, error: 'Token has been revoked' };\n case 'auth/user-disabled':\n return { valid: false, error: 'User account has been disabled' };\n default:\n return { valid: false, error: 'Invalid token' };\n }\n }\n }\n return { valid: false, error: 'Error verifying token' };\n }\n }\n \n\n export async function verifyTernSessionCookie(session: string): Promise<{ valid: boolean; uid?: any; error?: any }>{\n try {\n const res = await adminAuth.verifySessionCookie(session, true);\n if (res) {\n return { valid: true, uid: res.uid };\n } else {\n return { valid: false, error: 'Invalid session'};\n }\n } catch (error) {\n return {error: error, valid: false}\n }\n }\n\n\n export async function clearSessionCookie() {\n const cookieStore = await cookies()\n \n cookieStore.delete('_session_cookie')\n cookieStore.delete('_session_token')\n cookieStore.delete('_session')\n \n try {\n // Verify if there's an active session before revoking\n const sessionCookie = cookieStore.get('_session_cookie')?.value\n if (sessionCookie) {\n // Get the decoded claims to get the user's ID\n const decodedClaims = await adminAuth.verifySessionCookie(sessionCookie)\n \n // Revoke all sessions for the user\n await adminAuth.revokeRefreshTokens(decodedClaims.uid)\n }\n \n return { success: true, message: 'Session cleared successfully' }\n } catch (error) {\n console.error('Error clearing session:', error)\n // Still return success even if revoking fails, as cookies are cleared\n return { success: true, message: 'Session cookies cleared' }\n }\n }\n\n\n\n/*\n export async function GET(request: NextRequest) {\n const cookieStore = await cookies();\n const sessionCookie = cookieStore.get('session')?.value\n \n if (!sessionCookie) {\n return NextResponse.json({ isAuthenticated: false }, { status: 401 })\n }\n \n try {\n const decodedClaims = await adminAuth.verifySessionCookie(sessionCookie, true)\n return NextResponse.json({ isAuthenticated: true, user: decodedClaims }, { status: 200 })\n } catch (error) {\n console.error('Error verifying session cookie:', error)\n return NextResponse.json({ isAuthenticated: false }, { status: 401 })\n }\n }\n\n*/"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../src/app-router/admin/sessionTernSecure.ts"],"sourcesContent":["'use server'\n\nimport { cookies } from 'next/headers';\nimport { adminTernSecureAuth as adminAuth } from '../../utils/admin-init';\nimport { handleFirebaseAuthError, type AuthErrorResponse } from '../../errors';\n\ninterface FirebaseAuthError extends Error {\n code?: string;\n}\n\nexport interface User {\n uid: string | null;\n email: string | null;\n }\n\nexport interface Session {\n user: User | null;\n token: string | null;\n error: Error | null;\n}\n\ninterface TernVerificationResult extends User {\n valid: boolean\n authTime?: number\n error?: AuthErrorResponse\n}\n\nexport async function createSessionCookie(idToken: string) {\n try {\n const expiresIn = 60 * 60 * 24 * 5 * 1000;\n const sessionCookie = await adminAuth.createSessionCookie(idToken, { expiresIn });\n\n const cookieStore = await cookies();\n cookieStore.set('_session_cookie', sessionCookie, {\n maxAge: expiresIn,\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n path: '/',\n });\n return { success: true, message: 'Session created' };\n } catch (error) {\n return { success: false, message: 'Failed to create session' };\n }\n}\n\n\n\nexport async function getServerSessionCookie() {\n const cookieStore = await cookies();\n const sessionCookie = cookieStore.get('_session_cookie')?.value;\n\n if (!sessionCookie) {\n throw new Error('No session cookie found')\n }\n \n try {\n const decondeClaims = await adminAuth.verifySessionCookie(sessionCookie, true)\n return {\n token: sessionCookie,\n userId: decondeClaims.uid\n }\n } catch (error) {\n console.error('Error verifying session:', error)\n throw new Error('Invalid Session')\n }\n}\n\n\nexport async function getIdToken() {\n const cookieStore = await cookies();\n const token = cookieStore.get('_session_token')?.value;\n\n if (!token) {\n throw new Error('No session cookie found')\n }\n \n try {\n const decodedClaims = await adminAuth.verifyIdToken(token)\n return {\n token: token,\n userId: decodedClaims.uid\n }\n } catch (error) {\n console.error('Error verifying session:', error)\n throw new Error('Invalid Session')\n }\n}\n\nexport async function setServerSession(token: string) {\n try {\n const cookieStore = await cookies();\n cookieStore.set('_session_token', token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === 'production',\n sameSite: 'strict',\n maxAge: 60 * 60, // 1 hour\n path: '/',\n });\n return { success: true, message: 'Session created' };\n } catch {\n return { success: false, message: 'Failed to create session' };\n }\n}\n\n export async function verifyTernIdToken(token: string): Promise<TernVerificationResult> {\n try {\n const decodedToken = await adminAuth.verifyIdToken(token);\n return {\n valid: true,\n uid: decodedToken.uid,\n email: decodedToken.email || null,\n authTime: decodedToken.auth_time\n };\n } catch (error) {\n const errorResponse = handleFirebaseAuthError(error)\n return {\n valid: false,\n uid: null,\n email: null,\n error: errorResponse\n };\n }\n }\n \n\n export async function verifyTernSessionCookie(session: string): Promise<TernVerificationResult>{\n try {\n const res = await adminAuth.verifySessionCookie(session);\n return { \n valid: true, \n uid: res.uid,\n email: res.email || null,\n authTime: res.auth_time\n };\n } catch (error) {\n const errorResponse = handleFirebaseAuthError(error)\n return {\n valid: false, \n uid: null,\n email: null,\n error: errorResponse\n };\n }\n }\n\n\n export async function clearSessionCookie() {\n const cookieStore = await cookies()\n \n cookieStore.delete('_session_cookie')\n cookieStore.delete('_session_token')\n cookieStore.delete('_session')\n \n try {\n // Verify if there's an active session before revoking\n const sessionCookie = cookieStore.get('_session_cookie')?.value\n if (sessionCookie) {\n // Get the decoded claims to get the user's ID\n const decodedClaims = await adminAuth.verifySessionCookie(sessionCookie)\n \n // Revoke all sessions for the user\n await adminAuth.revokeRefreshTokens(decodedClaims.uid)\n }\n \n return { success: true, message: 'Session cleared successfully' }\n } catch (error) {\n console.error('Error clearing session:', error)\n // Still return success even if revoking fails, as cookies are cleared\n return { success: true, message: 'Session cookies cleared' }\n }\n }\n\n\n\n/*\n export async function GET(request: NextRequest) {\n const cookieStore = await cookies();\n const sessionCookie = cookieStore.get('session')?.value\n \n if (!sessionCookie) {\n return NextResponse.json({ isAuthenticated: false }, { status: 401 })\n }\n \n try {\n const decodedClaims = await adminAuth.verifySessionCookie(sessionCookie, true)\n return NextResponse.json({ isAuthenticated: true, user: decodedClaims }, { status: 200 })\n } catch (error) {\n console.error('Error verifying session cookie:', error)\n return NextResponse.json({ isAuthenticated: false }, { status: 401 })\n }\n }\n\n*/"],"mappings":"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","names":[]}