hi-secure 1.0.0

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 (210) hide show
  1. package/dist/adapters/ArgonAdapter.d.ts +8 -0
  2. package/dist/adapters/ArgonAdapter.d.ts.map +1 -0
  3. package/dist/adapters/ArgonAdapter.js +45 -0
  4. package/dist/adapters/ArgonAdapter.js.map +1 -0
  5. package/dist/adapters/BcryptAdapter.d.ts +7 -0
  6. package/dist/adapters/BcryptAdapter.d.ts.map +1 -0
  7. package/dist/adapters/BcryptAdapter.js +48 -0
  8. package/dist/adapters/BcryptAdapter.js.map +1 -0
  9. package/dist/adapters/DomPurifyAdapter.d.ts +13 -0
  10. package/dist/adapters/DomPurifyAdapter.d.ts.map +1 -0
  11. package/dist/adapters/DomPurifyAdapter.js +61 -0
  12. package/dist/adapters/DomPurifyAdapter.js.map +1 -0
  13. package/dist/adapters/ExpressRLAdapter.d.ts +13 -0
  14. package/dist/adapters/ExpressRLAdapter.d.ts.map +1 -0
  15. package/dist/adapters/ExpressRLAdapter.js +68 -0
  16. package/dist/adapters/ExpressRLAdapter.js.map +1 -0
  17. package/dist/adapters/ExpressValidatorAdapter.d.ts +6 -0
  18. package/dist/adapters/ExpressValidatorAdapter.d.ts.map +1 -0
  19. package/dist/adapters/ExpressValidatorAdapter.js +78 -0
  20. package/dist/adapters/ExpressValidatorAdapter.js.map +1 -0
  21. package/dist/adapters/GoggleAdapter.d.ts +15 -0
  22. package/dist/adapters/GoggleAdapter.d.ts.map +1 -0
  23. package/dist/adapters/GoggleAdapter.js +91 -0
  24. package/dist/adapters/GoggleAdapter.js.map +1 -0
  25. package/dist/adapters/GoogleAdapter.d.ts +15 -0
  26. package/dist/adapters/GoogleAdapter.d.ts.map +1 -0
  27. package/dist/adapters/GoogleAdapter.js +159 -0
  28. package/dist/adapters/GoogleAdapter.js.map +1 -0
  29. package/dist/adapters/JWTAdapter.d.ts +28 -0
  30. package/dist/adapters/JWTAdapter.d.ts.map +1 -0
  31. package/dist/adapters/JWTAdapter.js +276 -0
  32. package/dist/adapters/JWTAdapter.js.map +1 -0
  33. package/dist/adapters/RLFlexibleAdapter.d.ts +11 -0
  34. package/dist/adapters/RLFlexibleAdapter.d.ts.map +1 -0
  35. package/dist/adapters/RLFlexibleAdapter.js +115 -0
  36. package/dist/adapters/RLFlexibleAdapter.js.map +1 -0
  37. package/dist/adapters/SanitizeHtmlAdapter.d.ts +12 -0
  38. package/dist/adapters/SanitizeHtmlAdapter.d.ts.map +1 -0
  39. package/dist/adapters/SanitizeHtmlAdapter.js +141 -0
  40. package/dist/adapters/SanitizeHtmlAdapter.js.map +1 -0
  41. package/dist/adapters/XSSAdapter.d.ts +33 -0
  42. package/dist/adapters/XSSAdapter.d.ts.map +1 -0
  43. package/dist/adapters/XSSAdapter.js +127 -0
  44. package/dist/adapters/XSSAdapter.js.map +1 -0
  45. package/dist/adapters/ZodAdapter.d.ts +7 -0
  46. package/dist/adapters/ZodAdapter.d.ts.map +1 -0
  47. package/dist/adapters/ZodAdapter.js +39 -0
  48. package/dist/adapters/ZodAdapter.js.map +1 -0
  49. package/dist/core/HiSecure.d.ts +62 -0
  50. package/dist/core/HiSecure.d.ts.map +1 -0
  51. package/dist/core/HiSecure.js +273 -0
  52. package/dist/core/HiSecure.js.map +1 -0
  53. package/dist/core/config.d.ts +3 -0
  54. package/dist/core/config.d.ts.map +1 -0
  55. package/dist/core/config.js +53 -0
  56. package/dist/core/config.js.map +1 -0
  57. package/dist/core/constants.d.ts +37 -0
  58. package/dist/core/constants.d.ts.map +1 -0
  59. package/dist/core/constants.js +67 -0
  60. package/dist/core/constants.js.map +1 -0
  61. package/dist/core/errors/AdapterError.d.ts +5 -0
  62. package/dist/core/errors/AdapterError.d.ts.map +1 -0
  63. package/dist/core/errors/AdapterError.js +15 -0
  64. package/dist/core/errors/AdapterError.js.map +1 -0
  65. package/dist/core/errors/HttpErrror.d.ts +17 -0
  66. package/dist/core/errors/HttpErrror.d.ts.map +1 -0
  67. package/dist/core/errors/HttpErrror.js +36 -0
  68. package/dist/core/errors/HttpErrror.js.map +1 -0
  69. package/dist/core/errors/SanitizerError.d.ts +5 -0
  70. package/dist/core/errors/SanitizerError.d.ts.map +1 -0
  71. package/dist/core/errors/SanitizerError.js +14 -0
  72. package/dist/core/errors/SanitizerError.js.map +1 -0
  73. package/dist/core/errors/SecurityError.d.ts +5 -0
  74. package/dist/core/errors/SecurityError.d.ts.map +1 -0
  75. package/dist/core/errors/SecurityError.js +14 -0
  76. package/dist/core/errors/SecurityError.js.map +1 -0
  77. package/dist/core/errors/ValidationError.d.ts +5 -0
  78. package/dist/core/errors/ValidationError.d.ts.map +1 -0
  79. package/dist/core/errors/ValidationError.js +14 -0
  80. package/dist/core/errors/ValidationError.js.map +1 -0
  81. package/dist/core/types/HiSecureConfig.d.ts +47 -0
  82. package/dist/core/types/HiSecureConfig.d.ts.map +1 -0
  83. package/dist/core/types/HiSecureConfig.js +3 -0
  84. package/dist/core/types/HiSecureConfig.js.map +1 -0
  85. package/dist/core/types/SecureOptions.d.ts +30 -0
  86. package/dist/core/types/SecureOptions.d.ts.map +1 -0
  87. package/dist/core/types/SecureOptions.js +4 -0
  88. package/dist/core/types/SecureOptions.js.map +1 -0
  89. package/dist/core/useSecure.d.ts +10 -0
  90. package/dist/core/useSecure.d.ts.map +1 -0
  91. package/dist/core/useSecure.js +85 -0
  92. package/dist/core/useSecure.js.map +1 -0
  93. package/dist/examples/e1.d.ts +1 -0
  94. package/dist/examples/e1.d.ts.map +1 -0
  95. package/dist/examples/e1.js +3 -0
  96. package/dist/examples/e1.js.map +1 -0
  97. package/dist/index.d.ts +9 -0
  98. package/dist/index.d.ts.map +1 -0
  99. package/dist/index.js +15 -0
  100. package/dist/index.js.map +1 -0
  101. package/dist/logging/index.d.ts +3 -0
  102. package/dist/logging/index.d.ts.map +1 -0
  103. package/dist/logging/index.js +19 -0
  104. package/dist/logging/index.js.map +1 -0
  105. package/dist/logging/morganSetup.d.ts +2 -0
  106. package/dist/logging/morganSetup.d.ts.map +1 -0
  107. package/dist/logging/morganSetup.js +9 -0
  108. package/dist/logging/morganSetup.js.map +1 -0
  109. package/dist/logging/winstonSetup.d.ts +6 -0
  110. package/dist/logging/winstonSetup.d.ts.map +1 -0
  111. package/dist/logging/winstonSetup.js +22 -0
  112. package/dist/logging/winstonSetup.js.map +1 -0
  113. package/dist/managers/AuthManager.d.ts +23 -0
  114. package/dist/managers/AuthManager.d.ts.map +1 -0
  115. package/dist/managers/AuthManager.js +190 -0
  116. package/dist/managers/AuthManager.js.map +1 -0
  117. package/dist/managers/CorsManager.d.ts +9 -0
  118. package/dist/managers/CorsManager.d.ts.map +1 -0
  119. package/dist/managers/CorsManager.js +55 -0
  120. package/dist/managers/CorsManager.js.map +1 -0
  121. package/dist/managers/HashManager.d.ts +22 -0
  122. package/dist/managers/HashManager.d.ts.map +1 -0
  123. package/dist/managers/HashManager.js +319 -0
  124. package/dist/managers/HashManager.js.map +1 -0
  125. package/dist/managers/JsonManager.d.ts +6 -0
  126. package/dist/managers/JsonManager.d.ts.map +1 -0
  127. package/dist/managers/JsonManager.js +142 -0
  128. package/dist/managers/JsonManager.js.map +1 -0
  129. package/dist/managers/RateLimitManager.d.ts +16 -0
  130. package/dist/managers/RateLimitManager.d.ts.map +1 -0
  131. package/dist/managers/RateLimitManager.js +108 -0
  132. package/dist/managers/RateLimitManager.js.map +1 -0
  133. package/dist/managers/SanitizerManager.d.ts +18 -0
  134. package/dist/managers/SanitizerManager.d.ts.map +1 -0
  135. package/dist/managers/SanitizerManager.js +296 -0
  136. package/dist/managers/SanitizerManager.js.map +1 -0
  137. package/dist/managers/ValidatorManager.d.ts +13 -0
  138. package/dist/managers/ValidatorManager.d.ts.map +1 -0
  139. package/dist/managers/ValidatorManager.js +218 -0
  140. package/dist/managers/ValidatorManager.js.map +1 -0
  141. package/dist/middlewares/errorHandler.d.ts +3 -0
  142. package/dist/middlewares/errorHandler.d.ts.map +1 -0
  143. package/dist/middlewares/errorHandler.js +94 -0
  144. package/dist/middlewares/errorHandler.js.map +1 -0
  145. package/dist/middlewares/index.d.ts +3 -0
  146. package/dist/middlewares/index.d.ts.map +1 -0
  147. package/dist/middlewares/index.js +19 -0
  148. package/dist/middlewares/index.js.map +1 -0
  149. package/dist/middlewares/requestLogger.d.ts +2 -0
  150. package/dist/middlewares/requestLogger.d.ts.map +1 -0
  151. package/dist/middlewares/requestLogger.js +8 -0
  152. package/dist/middlewares/requestLogger.js.map +1 -0
  153. package/dist/test/t1.d.ts +1 -0
  154. package/dist/test/t1.d.ts.map +1 -0
  155. package/dist/test/t1.js +3 -0
  156. package/dist/test/t1.js.map +1 -0
  157. package/dist/utils/deepFreeze.d.ts +2 -0
  158. package/dist/utils/deepFreeze.d.ts.map +1 -0
  159. package/dist/utils/deepFreeze.js +69 -0
  160. package/dist/utils/deepFreeze.js.map +1 -0
  161. package/dist/utils/deepMerge.d.ts +5 -0
  162. package/dist/utils/deepMerge.d.ts.map +1 -0
  163. package/dist/utils/deepMerge.js +68 -0
  164. package/dist/utils/deepMerge.js.map +1 -0
  165. package/dist/utils/normalizeOptions.d.ts +38 -0
  166. package/dist/utils/normalizeOptions.d.ts.map +1 -0
  167. package/dist/utils/normalizeOptions.js +119 -0
  168. package/dist/utils/normalizeOptions.js.map +1 -0
  169. package/package.json +50 -0
  170. package/src/adapters/ArgonAdapter.ts +41 -0
  171. package/src/adapters/BcryptAdapter.ts +49 -0
  172. package/src/adapters/ExpressRLAdapter.ts +84 -0
  173. package/src/adapters/ExpressValidatorAdapter.ts +99 -0
  174. package/src/adapters/GoogleAdapter.ts +206 -0
  175. package/src/adapters/JWTAdapter.ts +346 -0
  176. package/src/adapters/RLFlexibleAdapter.ts +139 -0
  177. package/src/adapters/SanitizeHtmlAdapter.ts +162 -0
  178. package/src/adapters/XSSAdapter.ts +153 -0
  179. package/src/adapters/ZodAdapter.ts +91 -0
  180. package/src/core/HiSecure.ts +955 -0
  181. package/src/core/config.ts +156 -0
  182. package/src/core/constants.ts +73 -0
  183. package/src/core/errors/AdapterError.ts +14 -0
  184. package/src/core/errors/HttpErrror.ts +46 -0
  185. package/src/core/errors/SanitizerError.ts +13 -0
  186. package/src/core/errors/SecurityError.ts +13 -0
  187. package/src/core/errors/ValidationError.ts +13 -0
  188. package/src/core/types/HiSecureConfig.ts +62 -0
  189. package/src/core/types/SecureOptions.ts +61 -0
  190. package/src/core/useSecure.ts +111 -0
  191. package/src/examples/e1.ts +1 -0
  192. package/src/index.ts +17 -0
  193. package/src/logging/index.ts +2 -0
  194. package/src/logging/morganSetup.ts +3 -0
  195. package/src/logging/winstonSetup.ts +17 -0
  196. package/src/managers/AuthManager.ts +237 -0
  197. package/src/managers/CorsManager.ts +58 -0
  198. package/src/managers/HashManager.ts +390 -0
  199. package/src/managers/JsonManager.ts +149 -0
  200. package/src/managers/RateLimitManager.ts +368 -0
  201. package/src/managers/SanitizerManager.ts +359 -0
  202. package/src/managers/ValidatorManager.ts +269 -0
  203. package/src/middlewares/errorHandler.ts +265 -0
  204. package/src/middlewares/index.ts +2 -0
  205. package/src/middlewares/requestLogger.ts +5 -0
  206. package/src/test/t1.ts +1 -0
  207. package/src/utils/deepFreeze.ts +76 -0
  208. package/src/utils/deepMerge.ts +87 -0
  209. package/src/utils/normalizeOptions.ts +265 -0
  210. package/tsconfig.json +30 -0
@@ -0,0 +1,41 @@
1
+ import argon2 from "argon2";
2
+ import { AdapterError } from "../core/errors/AdapterError";
3
+ import { logger } from "../logging";
4
+
5
+ export class ArgonAdapter {
6
+ private options: argon2.Options | undefined;
7
+
8
+ constructor(options?: argon2.Options) {
9
+ if (options) {
10
+ this.options = options;
11
+ }
12
+ }
13
+
14
+ async hash(value: string): Promise<string> {
15
+ try {
16
+ return this.options
17
+ ? await argon2.hash(value, this.options)
18
+ : await argon2.hash(value); // avoid passing undefined
19
+ } catch (err: any) {
20
+ logger.error("❌ Argon2 hashing failed", {
21
+ error: err?.message || err
22
+ });
23
+ throw new AdapterError("Argon2 hashing failed.");
24
+ }
25
+ }
26
+
27
+ async verify(value: string, hashed: string): Promise<boolean> {
28
+ try {
29
+ if (!hashed || typeof hashed !== "string") {
30
+ throw new AdapterError("Invalid hash provided for verification.");
31
+ }
32
+
33
+ return await argon2.verify(hashed, value);
34
+ } catch (err: any) {
35
+ logger.error("❌ Argon2 verify failed", {
36
+ error: err?.message || err
37
+ });
38
+ throw new AdapterError("Argon2 verify failed.");
39
+ }
40
+ }
41
+ }
@@ -0,0 +1,49 @@
1
+ import bcrypt from "bcryptjs";
2
+ import { AdapterError } from "../core/errors/AdapterError";
3
+ import { logger } from "../logging";
4
+
5
+ export class BcryptAdapter {
6
+ constructor(private saltRounds: number = 10) {}
7
+
8
+ async hash(value: string): Promise<string> {
9
+ try {
10
+ if (typeof value !== "string") {
11
+ throw new AdapterError("Value to hash must be a string.");
12
+ }
13
+
14
+ return await bcrypt.hash(value, this.saltRounds);
15
+ } catch (err: any) {
16
+ logger.error("❌ Bcrypt hashing failed", {
17
+ error: err?.message || err,
18
+ saltRounds: this.saltRounds
19
+ });
20
+
21
+ throw new AdapterError("Bcrypt hashing failed.");
22
+ }
23
+ }
24
+
25
+ async verify(value: string, hashed: string): Promise<boolean> {
26
+ try {
27
+ if (typeof value !== "string") {
28
+ throw new AdapterError("Value to verify must be a string.");
29
+ }
30
+
31
+ if (!hashed || typeof hashed !== "string") {
32
+ throw new AdapterError("Invalid hashed string provided.");
33
+ }
34
+
35
+ return await bcrypt.compare(value, hashed);
36
+ } catch (err: any) {
37
+ logger.error("❌ Bcrypt verify failed", {
38
+ error: err?.message || err
39
+ });
40
+
41
+ throw new AdapterError("Bcrypt verify failed.");
42
+ }
43
+ }
44
+ }
45
+
46
+
47
+
48
+
49
+
@@ -0,0 +1,84 @@
1
+ // import rateLimit from "express-rate-limit";
2
+ // import { logger } from "../logging";
3
+ // import { AdapterError } from "../core/errors/AdapterError";
4
+
5
+ // export class ExpressRLAdapter {
6
+
7
+ // /**
8
+ // * Create express rate-limit middleware dynamically
9
+ // */
10
+ // getMiddleware(options: {
11
+ // windowMs?: number;
12
+ // max?: number;
13
+ // message?: any;
14
+ // } = {}) {
15
+
16
+ // try {
17
+ // const limiter = rateLimit({
18
+ // windowMs: options.windowMs ?? 15 * 60 * 1000, // default
19
+ // max: options.max ?? 100,
20
+ // message: options.message ?? { error: "Too many requests" },
21
+ // standardHeaders: true,
22
+ // legacyHeaders: false,
23
+ // });
24
+
25
+ // return limiter;
26
+
27
+ // } catch (err: any) {
28
+ // logger.error("❌ ExpressRLAdapter: failed to create limiter", {
29
+ // error: err?.message || err
30
+ // });
31
+ // throw new AdapterError("Express rate limiter creation failed.");
32
+ // }
33
+ // }
34
+ // }
35
+
36
+
37
+
38
+
39
+ // src/adapters/ExpressRLAdapter.ts - IMPROVED
40
+ import rateLimit from "express-rate-limit";
41
+ import { logger } from "../logging/index.js";
42
+ import { AdapterError } from "../core/errors/AdapterError.js";
43
+
44
+ export interface RateLimitOptions {
45
+ windowMs?: number;
46
+ max?: number;
47
+ message?: any;
48
+ skipFailedRequests?: boolean;
49
+ standardHeaders?: boolean;
50
+ legacyHeaders?: boolean;
51
+ [key: string]: any;
52
+ }
53
+
54
+ export class ExpressRLAdapter {
55
+ getMiddleware(options: RateLimitOptions = {}) {
56
+ try {
57
+ const defaultOptions = {
58
+ windowMs: 15 * 60 * 1000, // 15 minutes
59
+ max: 100,
60
+ message: { error: "Too many requests" },
61
+ standardHeaders: true,
62
+ legacyHeaders: false,
63
+ skipFailedRequests: false
64
+ };
65
+
66
+ const finalOptions = { ...defaultOptions, ...options };
67
+
68
+ const limiter = rateLimit(finalOptions);
69
+
70
+ logger.debug("📌 Express rate limiter configured", {
71
+ windowMs: finalOptions.windowMs,
72
+ max: finalOptions.max
73
+ });
74
+
75
+ return limiter;
76
+
77
+ } catch (err: any) {
78
+ logger.error("❌ ExpressRLAdapter: failed to create limiter", {
79
+ error: err?.message || err
80
+ });
81
+ throw new AdapterError("Express rate limiter creation failed.");
82
+ }
83
+ }
84
+ }
@@ -0,0 +1,99 @@
1
+ // import { validationResult } from "express-validator";
2
+ // import { ValidationError } from "../core/errors/ValidationError";
3
+ // import { logger } from "../logging";
4
+
5
+ // export class ExpressValidatorAdapter {
6
+ // private globalSchema?: any[];
7
+
8
+ // constructor(globalSchema?: any[]) {
9
+ // this.globalSchema = globalSchema as any;;
10
+ // }
11
+
12
+ // /**
13
+ // * Dynamic schema override
14
+ // */
15
+ // validate(dynamicSchema?: any[]) {
16
+ // const schema = dynamicSchema || this.globalSchema;
17
+
18
+ // if (!schema || !Array.isArray(schema)) {
19
+ // return (req: any, res: any, next: any) => next();
20
+ // }
21
+
22
+ // return [
23
+ // ...schema,
24
+
25
+ // (req: any, res: any, next: any) => {
26
+ // const errors = validationResult(req);
27
+
28
+ // if (!errors.isEmpty()) {
29
+ // const formatted = errors.array().map(err => ({
30
+ // message: err.msg,
31
+ // }));
32
+
33
+ // logger.warn("⚠ express-validator failed", {
34
+ // path: req.path,
35
+ // method: req.method,
36
+ // errors: formatted,
37
+ // preview: JSON.stringify(req.body).slice(0, 200)
38
+ // });
39
+
40
+ // return next(new ValidationError("Validation failed."));
41
+ // }
42
+
43
+ // next();
44
+ // }
45
+ // ];
46
+ // }
47
+ // }
48
+
49
+
50
+
51
+
52
+
53
+ // src/adapters/ExpressValidatorAdapter.ts - FIXED
54
+ import { validationResult } from "express-validator";
55
+ import { ValidationError } from "../core/errors/ValidationError.js"; // ✅ Add .js
56
+ import { logger } from "../logging/index.js";
57
+
58
+ export class ExpressValidatorAdapter {
59
+ private globalSchema?: any[];
60
+
61
+ constructor(globalSchema?: any[]) {
62
+ this.globalSchema = globalSchema;
63
+ }
64
+
65
+ validate(dynamicSchema?: any[]) {
66
+ const schema = dynamicSchema || this.globalSchema;
67
+
68
+ if (!schema || !Array.isArray(schema)) {
69
+ return (req: any, res: any, next: any) => next();
70
+ }
71
+
72
+ return [
73
+ ...schema,
74
+
75
+ (req: any, res: any, next: any) => {
76
+ const errors = validationResult(req);
77
+
78
+ if (!errors.isEmpty()) {
79
+ const formatted = errors.array().map(err => ({
80
+ message: err.msg,
81
+ // param: err.param ,
82
+ // location: err.location
83
+ }));
84
+
85
+ logger.warn("⚠ express-validator failed", {
86
+ path: req.path,
87
+ method: req.method,
88
+ errors: formatted,
89
+ preview: JSON.stringify(req.body).slice(0, 200)
90
+ });
91
+
92
+ return next(new ValidationError("Validation failed.", formatted as any));
93
+ }
94
+
95
+ next();
96
+ }
97
+ ];
98
+ }
99
+ }
@@ -0,0 +1,206 @@
1
+ // // import { OAuth2Client, LoginTicket } from "google-auth-library";
2
+ // // import { AdapterError } from "../core/errors/AdapterError";
3
+ // // import { logWarn, logError } from "../logging";
4
+
5
+ // // export class GoogleAdapter {
6
+ // // private client: OAuth2Client;
7
+ // // private clientId?: string;
8
+
9
+ // // constructor(clientId?: string) {
10
+ // // this.client = new OAuth2Client(clientId);
11
+ // // this.clientId = clientId as any;
12
+ // // }
13
+
14
+ // // async verifyIdToken(idToken: string) {
15
+ // // try {
16
+ // // const options: {
17
+ // // idToken: string;
18
+ // // audience?: string | string[];
19
+ // // } = { idToken };
20
+
21
+ // // // ADD ONLY IF DEFINED → FIXES TS ERROR
22
+ // // if (this.clientId !== undefined) {
23
+ // // options.audience = this.clientId;
24
+ // // }
25
+
26
+ // // const ticket: LoginTicket = await this.client.verifyIdToken(options);
27
+
28
+ // // const payload = ticket.getPayload();
29
+ // // if (!payload) {
30
+ // // logWarn("GoogleAdapter: Empty payload");
31
+ // // throw new AdapterError("Invalid Google ID token payload.");
32
+ // // }
33
+
34
+ // // return {
35
+ // // sub: payload.sub,
36
+ // // email: payload.email,
37
+ // // email_verified: payload.email_verified,
38
+ // // name: payload.name,
39
+ // // picture: payload.picture,
40
+ // // };
41
+
42
+ // // } catch (err: any) {
43
+ // // logError("GoogleAdapter.verifyIdToken failed", { error: err?.message });
44
+ // // throw new AdapterError(err?.message || "Google token verification failed");
45
+ // // }
46
+ // // }
47
+ // // }
48
+
49
+
50
+
51
+
52
+ // // src/adapters/GoogleAdapter.ts - IMPROVED
53
+ // import { OAuth2Client, LoginTicket } from "google-auth-library";
54
+ // import { AdapterError } from "../core/errors/AdapterError.js";
55
+ // import { logWarn, logError } from "../logging/index.js";
56
+
57
+ // export interface GoogleTokenPayload {
58
+ // sub: string;
59
+ // email: string;
60
+ // email_verified: boolean;
61
+ // name?: string;
62
+ // picture?: string;
63
+ // [key: string]: any;
64
+ // }
65
+
66
+ // export class GoogleAdapter {
67
+ // private client: OAuth2Client;
68
+ // private clientId?: string;
69
+
70
+ // constructor(clientId?: string) {
71
+ // if (clientId && clientId.trim().length === 0) {
72
+ // throw new AdapterError("Google clientId cannot be empty string");
73
+ // }
74
+
75
+ // this.client = new OAuth2Client(clientId);
76
+ // this.clientId = clientId;
77
+ // }
78
+
79
+ // async verifyIdToken(idToken: string): Promise<GoogleTokenPayload> {
80
+ // try {
81
+ // if (!idToken || typeof idToken !== 'string') {
82
+ // throw new AdapterError("Invalid ID token provided");
83
+ // }
84
+
85
+ // const options: { idToken: string; audience?: string | string[] } = {
86
+ // idToken
87
+ // };
88
+
89
+ // // Add audience only if clientId is provided and not empty
90
+ // if (this.clientId && this.clientId.trim().length > 0) {
91
+ // options.audience = this.clientId;
92
+ // }
93
+
94
+ // const ticket: LoginTicket = await this.client.verifyIdToken(options);
95
+ // const payload = ticket.getPayload();
96
+
97
+ // if (!payload) {
98
+ // logWarn("GoogleAdapter: Empty payload");
99
+ // throw new AdapterError("Invalid Google ID token payload.");
100
+ // }
101
+
102
+ // return {
103
+ // sub: payload.sub,
104
+ // email: payload.email || '',
105
+ // email_verified: payload.email_verified || false,
106
+ // name: payload.name,
107
+ // picture: payload.picture,
108
+ // ...payload
109
+ // };
110
+
111
+ // } catch (err: any) {
112
+ // logError("GoogleAdapter.verifyIdToken failed", {
113
+ // error: err?.message,
114
+ // hasClientId: !!this.clientId
115
+ // });
116
+
117
+ // if (err.message?.includes('audience')) {
118
+ // throw new AdapterError("Invalid Google client ID configured.");
119
+ // }
120
+
121
+ // throw new AdapterError(err?.message || "Google token verification failed");
122
+ // }
123
+ // }
124
+ // }
125
+
126
+
127
+
128
+ // src/adapters/GoogleAdapter.ts - FIXED
129
+ import { OAuth2Client, LoginTicket } from "google-auth-library";
130
+ import { AdapterError } from "../core/errors/AdapterError.js";
131
+ import { logWarn, logError } from "../logging/index.js";
132
+
133
+ export interface GoogleTokenPayload {
134
+ sub: string;
135
+ email: string;
136
+ email_verified: boolean;
137
+ name?: string;
138
+ picture?: string;
139
+ [key: string]: any;
140
+ }
141
+
142
+ export class GoogleAdapter {
143
+ private client: OAuth2Client;
144
+ private clientId?: string;
145
+
146
+ constructor(clientId?: string) {
147
+ if (clientId && clientId.trim().length === 0) {
148
+ throw new AdapterError("Google clientId cannot be empty string");
149
+ }
150
+
151
+ this.client = new OAuth2Client(clientId);
152
+ this.clientId = clientId;
153
+ }
154
+
155
+ async verifyIdToken(idToken: string): Promise<GoogleTokenPayload> {
156
+ try {
157
+ if (!idToken || typeof idToken !== 'string') {
158
+ throw new AdapterError("Invalid ID token provided");
159
+ }
160
+
161
+ const options: { idToken: string; audience?: string | string[] } = {
162
+ idToken
163
+ };
164
+
165
+ // Add audience only if clientId is provided and not empty
166
+ if (this.clientId && this.clientId.trim().length > 0) {
167
+ options.audience = this.clientId;
168
+ }
169
+
170
+ const ticket: LoginTicket = await this.client.verifyIdToken(options);
171
+ const payload = ticket.getPayload();
172
+
173
+ if (!payload) {
174
+ logWarn("GoogleAdapter: Empty payload");
175
+ throw new AdapterError("Invalid Google ID token payload.");
176
+ }
177
+
178
+ // Create result object
179
+ const result: GoogleTokenPayload = {
180
+ sub: payload.sub,
181
+ email: payload.email || '',
182
+ email_verified: payload.email_verified || false,
183
+ name: payload.name,
184
+ picture: payload.picture
185
+ };
186
+
187
+ // Add remaining properties from payload (excluding duplicates)
188
+ const { sub, email, email_verified, name, picture, ...rest } = payload;
189
+ Object.assign(result, rest);
190
+
191
+ return result;
192
+
193
+ } catch (err: any) {
194
+ logError("GoogleAdapter.verifyIdToken failed", {
195
+ error: err?.message,
196
+ hasClientId: !!this.clientId
197
+ });
198
+
199
+ if (err.message?.includes('audience')) {
200
+ throw new AdapterError("Invalid Google client ID configured.");
201
+ }
202
+
203
+ throw new AdapterError(err?.message || "Google token verification failed");
204
+ }
205
+ }
206
+ }