@hookflo/tern 1.0.0 → 1.0.2

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.
@@ -1,13 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HMACSHA512Verifier = exports.HMACSHA1Verifier = exports.HMACSHA256Verifier = exports.AlgorithmBasedVerifier = void 0;
3
+ exports.HMACSHA512Verifier = exports.HMACSHA1Verifier = exports.HMACSHA256Verifier = exports.GenericHMACVerifier = exports.AlgorithmBasedVerifier = void 0;
4
4
  exports.createAlgorithmVerifier = createAlgorithmVerifier;
5
5
  const crypto_1 = require("crypto");
6
6
  const base_1 = require("./base");
7
7
  class AlgorithmBasedVerifier extends base_1.WebhookVerifier {
8
- constructor(secret, config, toleranceInSeconds = 300) {
8
+ constructor(secret, config, platform, toleranceInSeconds = 300) {
9
9
  super(secret, toleranceInSeconds);
10
10
  this.config = config;
11
+ this.platform = platform;
11
12
  }
12
13
  extractSignature(request) {
13
14
  const headerValue = request.headers.get(this.config.headerName);
@@ -15,9 +16,8 @@ class AlgorithmBasedVerifier extends base_1.WebhookVerifier {
15
16
  return null;
16
17
  switch (this.config.headerFormat) {
17
18
  case "prefixed":
18
- return headerValue.startsWith(this.config.prefix || "")
19
- ? headerValue.substring((this.config.prefix || "").length)
20
- : null;
19
+ // For GitHub, return the full signature including prefix for comparison
20
+ return headerValue;
21
21
  case "comma-separated":
22
22
  // Handle comma-separated format like Stripe: "t=1234567890,v1=abc123"
23
23
  const parts = headerValue.split(",");
@@ -31,6 +31,17 @@ class AlgorithmBasedVerifier extends base_1.WebhookVerifier {
31
31
  return sigMap.v1 || sigMap.signature || null;
32
32
  case "raw":
33
33
  default:
34
+ // For Clerk, handle space-separated signatures
35
+ if (this.platform === "clerk") {
36
+ const signatures = headerValue.split(" ");
37
+ for (const sig of signatures) {
38
+ const [version, signature] = sig.split(",");
39
+ if (version === "v1") {
40
+ return signature;
41
+ }
42
+ }
43
+ return null;
44
+ }
34
45
  return headerValue;
35
46
  }
36
47
  }
@@ -52,18 +63,62 @@ class AlgorithmBasedVerifier extends base_1.WebhookVerifier {
52
63
  return parseInt(timestampHeader, 10);
53
64
  }
54
65
  }
55
- formatPayload(rawBody, timestamp) {
66
+ extractTimestampFromSignature(request) {
67
+ // For platforms like Stripe where timestamp is embedded in signature
68
+ if (this.config.headerFormat === "comma-separated") {
69
+ const headerValue = request.headers.get(this.config.headerName);
70
+ if (!headerValue)
71
+ return null;
72
+ const parts = headerValue.split(",");
73
+ const sigMap = {};
74
+ for (const part of parts) {
75
+ const [key, value] = part.split("=");
76
+ if (key && value) {
77
+ sigMap[key] = value;
78
+ }
79
+ }
80
+ return sigMap.t ? parseInt(sigMap.t, 10) : null;
81
+ }
82
+ return null;
83
+ }
84
+ formatPayload(rawBody, request) {
56
85
  switch (this.config.payloadFormat) {
57
86
  case "timestamped":
87
+ // For Stripe, timestamp is embedded in signature
88
+ const timestamp = this.extractTimestampFromSignature(request) ||
89
+ this.extractTimestamp(request);
58
90
  return timestamp ? `${timestamp}.${rawBody}` : rawBody;
59
91
  case "custom":
60
- // Custom payload formatting logic can be added here
61
- return rawBody;
92
+ return this.formatCustomPayload(rawBody, request);
62
93
  case "raw":
63
94
  default:
64
95
  return rawBody;
65
96
  }
66
97
  }
98
+ formatCustomPayload(rawBody, request) {
99
+ if (!this.config.customConfig?.payloadFormat) {
100
+ return rawBody;
101
+ }
102
+ const customFormat = this.config.customConfig.payloadFormat;
103
+ // Handle Clerk-style format: {id}.{timestamp}.{body}
104
+ if (customFormat.includes("{id}") && customFormat.includes("{timestamp}")) {
105
+ const id = request.headers.get(this.config.customConfig.idHeader || "x-webhook-id");
106
+ const timestamp = request.headers.get(this.config.timestampHeader || "x-webhook-timestamp");
107
+ return customFormat
108
+ .replace("{id}", id || "")
109
+ .replace("{timestamp}", timestamp || "")
110
+ .replace("{body}", rawBody);
111
+ }
112
+ // Handle Stripe-style format: {timestamp}.{body}
113
+ if (customFormat.includes("{timestamp}") &&
114
+ customFormat.includes("{body}")) {
115
+ const timestamp = this.extractTimestamp(request);
116
+ return customFormat
117
+ .replace("{timestamp}", timestamp?.toString() || "")
118
+ .replace("{body}", rawBody);
119
+ }
120
+ return rawBody;
121
+ }
67
122
  verifyHMAC(payload, signature, algorithm = "sha256") {
68
123
  const hmac = (0, crypto_1.createHmac)(algorithm, this.secret);
69
124
  hmac.update(payload);
@@ -76,9 +131,54 @@ class AlgorithmBasedVerifier extends base_1.WebhookVerifier {
76
131
  const expectedSignature = `${this.config.prefix || ""}${hmac.digest("hex")}`;
77
132
  return this.safeCompare(signature, expectedSignature);
78
133
  }
134
+ verifyHMACWithBase64(payload, signature, algorithm = "sha256") {
135
+ // For platforms like Clerk that use base64 encoding
136
+ const secretBytes = new Uint8Array(Buffer.from(this.secret.split("_")[1], "base64"));
137
+ const hmac = (0, crypto_1.createHmac)(algorithm, secretBytes);
138
+ hmac.update(payload);
139
+ const expectedSignature = hmac.digest("base64");
140
+ return this.safeCompare(signature, expectedSignature);
141
+ }
142
+ extractMetadata(request) {
143
+ const metadata = {
144
+ algorithm: this.config.algorithm,
145
+ };
146
+ // Add timestamp if available
147
+ const timestamp = this.extractTimestamp(request);
148
+ if (timestamp) {
149
+ metadata.timestamp = timestamp.toString();
150
+ }
151
+ // Add platform-specific metadata
152
+ switch (this.platform) {
153
+ case "github":
154
+ metadata.event = request.headers.get("x-github-event");
155
+ metadata.delivery = request.headers.get("x-github-delivery");
156
+ break;
157
+ case "stripe":
158
+ // Extract Stripe-specific metadata from signature
159
+ const headerValue = request.headers.get(this.config.headerName);
160
+ if (headerValue && this.config.headerFormat === "comma-separated") {
161
+ const parts = headerValue.split(",");
162
+ const sigMap = {};
163
+ for (const part of parts) {
164
+ const [key, value] = part.split("=");
165
+ if (key && value) {
166
+ sigMap[key] = value;
167
+ }
168
+ }
169
+ metadata.id = sigMap.id;
170
+ }
171
+ break;
172
+ case "clerk":
173
+ metadata.id = request.headers.get("svix-id");
174
+ break;
175
+ }
176
+ return metadata;
177
+ }
79
178
  }
80
179
  exports.AlgorithmBasedVerifier = AlgorithmBasedVerifier;
81
- class HMACSHA256Verifier extends AlgorithmBasedVerifier {
180
+ // Generic HMAC Verifier that handles all HMAC-based algorithms
181
+ class GenericHMACVerifier extends AlgorithmBasedVerifier {
82
182
  async verify(request) {
83
183
  try {
84
184
  const signature = this.extractSignature(request);
@@ -86,88 +186,53 @@ class HMACSHA256Verifier extends AlgorithmBasedVerifier {
86
186
  return {
87
187
  isValid: false,
88
188
  error: `Missing signature header: ${this.config.headerName}`,
89
- platform: "unknown",
189
+ platform: this.platform,
90
190
  };
91
191
  }
92
192
  const rawBody = await request.text();
93
- const timestamp = this.extractTimestamp(request);
193
+ // Extract timestamp based on platform configuration
194
+ let timestamp = null;
195
+ if (this.config.headerFormat === "comma-separated") {
196
+ // For platforms like Stripe where timestamp is embedded in signature
197
+ timestamp = this.extractTimestampFromSignature(request);
198
+ }
199
+ else {
200
+ // For platforms with separate timestamp header
201
+ timestamp = this.extractTimestamp(request);
202
+ }
203
+ // Validate timestamp if required
94
204
  if (timestamp && !this.isTimestampValid(timestamp)) {
95
205
  return {
96
206
  isValid: false,
97
207
  error: "Webhook timestamp expired",
98
- platform: "unknown",
208
+ platform: this.platform,
99
209
  };
100
210
  }
101
- const payload = this.formatPayload(rawBody, timestamp);
102
- const isValid = this.config.prefix
103
- ? this.verifyHMACWithPrefix(payload, signature, "sha256")
104
- : this.verifyHMAC(payload, signature, "sha256");
105
- if (!isValid) {
106
- return {
107
- isValid: false,
108
- error: "Invalid signature",
109
- platform: "unknown",
110
- };
211
+ // Format payload according to platform requirements
212
+ const payload = this.formatPayload(rawBody, request);
213
+ // Verify signature based on platform configuration
214
+ let isValid = false;
215
+ const algorithm = this.config.algorithm.replace("hmac-", "");
216
+ if (this.config.customConfig?.encoding === "base64") {
217
+ // For platforms like Clerk that use base64 encoding
218
+ isValid = this.verifyHMACWithBase64(payload, signature, algorithm);
111
219
  }
112
- let parsedPayload;
113
- try {
114
- parsedPayload = JSON.parse(rawBody);
220
+ else if (this.config.headerFormat === "prefixed") {
221
+ // For platforms like GitHub that use prefixed signatures
222
+ isValid = this.verifyHMACWithPrefix(payload, signature, algorithm);
115
223
  }
116
- catch (e) {
117
- // Return valid even if JSON parsing fails
118
- parsedPayload = rawBody;
224
+ else {
225
+ // Standard HMAC verification
226
+ isValid = this.verifyHMAC(payload, signature, algorithm);
119
227
  }
120
- return {
121
- isValid: true,
122
- platform: "unknown",
123
- payload: parsedPayload,
124
- metadata: {
125
- timestamp: timestamp?.toString(),
126
- algorithm: "hmac-sha256",
127
- },
128
- };
129
- }
130
- catch (error) {
131
- return {
132
- isValid: false,
133
- error: `HMAC-SHA256 verification error: ${error.message}`,
134
- platform: "unknown",
135
- };
136
- }
137
- }
138
- }
139
- exports.HMACSHA256Verifier = HMACSHA256Verifier;
140
- class HMACSHA1Verifier extends AlgorithmBasedVerifier {
141
- async verify(request) {
142
- try {
143
- const signature = this.extractSignature(request);
144
- if (!signature) {
145
- return {
146
- isValid: false,
147
- error: `Missing signature header: ${this.config.headerName}`,
148
- platform: "unknown",
149
- };
150
- }
151
- const rawBody = await request.text();
152
- const timestamp = this.extractTimestamp(request);
153
- if (timestamp && !this.isTimestampValid(timestamp)) {
154
- return {
155
- isValid: false,
156
- error: "Webhook timestamp expired",
157
- platform: "unknown",
158
- };
159
- }
160
- const payload = this.formatPayload(rawBody, timestamp);
161
- const isValid = this.config.prefix
162
- ? this.verifyHMACWithPrefix(payload, signature, "sha1")
163
- : this.verifyHMAC(payload, signature, "sha1");
164
228
  if (!isValid) {
165
229
  return {
166
230
  isValid: false,
167
231
  error: "Invalid signature",
168
- platform: "unknown",
232
+ platform: this.platform,
169
233
  };
170
234
  }
235
+ // Parse payload
171
236
  let parsedPayload;
172
237
  try {
173
238
  parsedPayload = JSON.parse(rawBody);
@@ -175,93 +240,51 @@ class HMACSHA1Verifier extends AlgorithmBasedVerifier {
175
240
  catch (e) {
176
241
  parsedPayload = rawBody;
177
242
  }
243
+ // Extract platform-specific metadata
244
+ const metadata = this.extractMetadata(request);
178
245
  return {
179
246
  isValid: true,
180
- platform: "unknown",
247
+ platform: this.platform,
181
248
  payload: parsedPayload,
182
- metadata: {
183
- timestamp: timestamp?.toString(),
184
- algorithm: "hmac-sha1",
185
- },
249
+ metadata,
186
250
  };
187
251
  }
188
252
  catch (error) {
189
253
  return {
190
254
  isValid: false,
191
- error: `HMAC-SHA1 verification error: ${error.message}`,
192
- platform: "unknown",
255
+ error: `${this.platform} verification error: ${error.message}`,
256
+ platform: this.platform,
193
257
  };
194
258
  }
195
259
  }
196
260
  }
261
+ exports.GenericHMACVerifier = GenericHMACVerifier;
262
+ // Legacy verifiers for backward compatibility
263
+ class HMACSHA256Verifier extends GenericHMACVerifier {
264
+ constructor(secret, config, platform = "unknown", toleranceInSeconds = 300) {
265
+ super(secret, config, platform, toleranceInSeconds);
266
+ }
267
+ }
268
+ exports.HMACSHA256Verifier = HMACSHA256Verifier;
269
+ class HMACSHA1Verifier extends GenericHMACVerifier {
270
+ constructor(secret, config, platform = "unknown", toleranceInSeconds = 300) {
271
+ super(secret, config, platform, toleranceInSeconds);
272
+ }
273
+ }
197
274
  exports.HMACSHA1Verifier = HMACSHA1Verifier;
198
- class HMACSHA512Verifier extends AlgorithmBasedVerifier {
199
- async verify(request) {
200
- try {
201
- const signature = this.extractSignature(request);
202
- if (!signature) {
203
- return {
204
- isValid: false,
205
- error: `Missing signature header: ${this.config.headerName}`,
206
- platform: "unknown",
207
- };
208
- }
209
- const rawBody = await request.text();
210
- const timestamp = this.extractTimestamp(request);
211
- if (timestamp && !this.isTimestampValid(timestamp)) {
212
- return {
213
- isValid: false,
214
- error: "Webhook timestamp expired",
215
- platform: "unknown",
216
- };
217
- }
218
- const payload = this.formatPayload(rawBody, timestamp);
219
- const isValid = this.config.prefix
220
- ? this.verifyHMACWithPrefix(payload, signature, "sha512")
221
- : this.verifyHMAC(payload, signature, "sha512");
222
- if (!isValid) {
223
- return {
224
- isValid: false,
225
- error: "Invalid signature",
226
- platform: "unknown",
227
- };
228
- }
229
- let parsedPayload;
230
- try {
231
- parsedPayload = JSON.parse(rawBody);
232
- }
233
- catch (e) {
234
- parsedPayload = rawBody;
235
- }
236
- return {
237
- isValid: true,
238
- platform: "unknown",
239
- payload: parsedPayload,
240
- metadata: {
241
- timestamp: timestamp?.toString(),
242
- algorithm: "hmac-sha512",
243
- },
244
- };
245
- }
246
- catch (error) {
247
- return {
248
- isValid: false,
249
- error: `HMAC-SHA512 verification error: ${error.message}`,
250
- platform: "unknown",
251
- };
252
- }
275
+ class HMACSHA512Verifier extends GenericHMACVerifier {
276
+ constructor(secret, config, platform = "unknown", toleranceInSeconds = 300) {
277
+ super(secret, config, platform, toleranceInSeconds);
253
278
  }
254
279
  }
255
280
  exports.HMACSHA512Verifier = HMACSHA512Verifier;
256
281
  // Factory function to create verifiers based on algorithm
257
- function createAlgorithmVerifier(secret, config, toleranceInSeconds = 300) {
282
+ function createAlgorithmVerifier(secret, config, platform = "unknown", toleranceInSeconds = 300) {
258
283
  switch (config.algorithm) {
259
284
  case "hmac-sha256":
260
- return new HMACSHA256Verifier(secret, config, toleranceInSeconds);
261
285
  case "hmac-sha1":
262
- return new HMACSHA1Verifier(secret, config, toleranceInSeconds);
263
286
  case "hmac-sha512":
264
- return new HMACSHA512Verifier(secret, config, toleranceInSeconds);
287
+ return new GenericHMACVerifier(secret, config, platform, toleranceInSeconds);
265
288
  case "rsa-sha256":
266
289
  case "ed25519":
267
290
  case "custom":
@@ -5,14 +5,4 @@ export declare class TokenBasedVerifier extends WebhookVerifier {
5
5
  constructor(secret: string, config: SignatureConfig, toleranceInSeconds?: number);
6
6
  verify(request: Request): Promise<WebhookVerificationResult>;
7
7
  }
8
- export declare class ClerkCustomVerifier extends WebhookVerifier {
9
- private config;
10
- constructor(secret: string, config: SignatureConfig, toleranceInSeconds?: number);
11
- verify(request: Request): Promise<WebhookVerificationResult>;
12
- }
13
- export declare class StripeCustomVerifier extends WebhookVerifier {
14
- private config;
15
- constructor(secret: string, config: SignatureConfig, toleranceInSeconds?: number);
16
- verify(request: Request): Promise<WebhookVerificationResult>;
17
- }
18
8
  export declare function createCustomVerifier(secret: string, config: SignatureConfig, toleranceInSeconds?: number): WebhookVerifier;
@@ -1,42 +1,9 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
2
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.StripeCustomVerifier = exports.ClerkCustomVerifier = exports.TokenBasedVerifier = void 0;
3
+ exports.TokenBasedVerifier = void 0;
37
4
  exports.createCustomVerifier = createCustomVerifier;
38
5
  const base_1 = require("./base");
39
- // Custom verifier for token-based authentication (like Supabase)
6
+ // Token-based verifier for platforms like Supabase
40
7
  class TokenBasedVerifier extends base_1.WebhookVerifier {
41
8
  constructor(secret, config, toleranceInSeconds = 300) {
42
9
  super(secret, toleranceInSeconds);
@@ -50,7 +17,7 @@ class TokenBasedVerifier extends base_1.WebhookVerifier {
50
17
  return {
51
18
  isValid: false,
52
19
  error: `Missing token header: ${this.config.headerName}`,
53
- platform: "unknown",
20
+ platform: "custom",
54
21
  };
55
22
  }
56
23
  // Simple token comparison
@@ -59,7 +26,7 @@ class TokenBasedVerifier extends base_1.WebhookVerifier {
59
26
  return {
60
27
  isValid: false,
61
28
  error: "Invalid token",
62
- platform: "unknown",
29
+ platform: "custom",
63
30
  };
64
31
  }
65
32
  const rawBody = await request.text();
@@ -72,7 +39,7 @@ class TokenBasedVerifier extends base_1.WebhookVerifier {
72
39
  }
73
40
  return {
74
41
  isValid: true,
75
- platform: "unknown",
42
+ platform: "custom",
76
43
  payload,
77
44
  metadata: {
78
45
  id,
@@ -84,194 +51,18 @@ class TokenBasedVerifier extends base_1.WebhookVerifier {
84
51
  return {
85
52
  isValid: false,
86
53
  error: `Token-based verification error: ${error.message}`,
87
- platform: "unknown",
54
+ platform: "custom",
88
55
  };
89
56
  }
90
57
  }
91
58
  }
92
59
  exports.TokenBasedVerifier = TokenBasedVerifier;
93
- // Custom verifier for Clerk's specific format
94
- class ClerkCustomVerifier extends base_1.WebhookVerifier {
95
- constructor(secret, config, toleranceInSeconds = 300) {
96
- super(secret, toleranceInSeconds);
97
- this.config = config;
98
- }
99
- async verify(request) {
100
- try {
101
- const body = await request.text();
102
- const svixId = request.headers.get("svix-id");
103
- const svixTimestamp = request.headers.get("svix-timestamp");
104
- const svixSignature = request.headers.get("svix-signature");
105
- if (!svixId || !svixTimestamp || !svixSignature) {
106
- return {
107
- isValid: false,
108
- error: "Missing required Clerk webhook headers",
109
- platform: "clerk",
110
- };
111
- }
112
- const timestamp = parseInt(svixTimestamp, 10);
113
- if (!this.isTimestampValid(timestamp)) {
114
- return {
115
- isValid: false,
116
- error: "Webhook timestamp is too old",
117
- platform: "clerk",
118
- };
119
- }
120
- const signedContent = `${svixId}.${svixTimestamp}.${body}`;
121
- const secretBytes = new Uint8Array(Buffer.from(this.secret.split("_")[1], "base64"));
122
- const { createHmac } = await Promise.resolve().then(() => __importStar(require("crypto")));
123
- const expectedSignature = createHmac("sha256", secretBytes)
124
- .update(signedContent)
125
- .digest("base64");
126
- const signatures = svixSignature.split(" ");
127
- let isValid = false;
128
- for (const sig of signatures) {
129
- const [version, signature] = sig.split(",");
130
- if (version === "v1" &&
131
- this.safeCompare(signature, expectedSignature)) {
132
- isValid = true;
133
- break;
134
- }
135
- }
136
- if (!isValid) {
137
- return {
138
- isValid: false,
139
- error: "Invalid signature",
140
- platform: "clerk",
141
- };
142
- }
143
- return {
144
- isValid: true,
145
- platform: "clerk",
146
- payload: JSON.parse(body),
147
- metadata: {
148
- id: svixId,
149
- timestamp: svixTimestamp,
150
- algorithm: "clerk-custom",
151
- },
152
- };
153
- }
154
- catch (error) {
155
- return {
156
- isValid: false,
157
- error: error instanceof Error ? error.message : "Unknown error",
158
- platform: "clerk",
159
- };
160
- }
161
- }
162
- }
163
- exports.ClerkCustomVerifier = ClerkCustomVerifier;
164
- // Custom verifier for Stripe's specific format
165
- class StripeCustomVerifier extends base_1.WebhookVerifier {
166
- constructor(secret, config, toleranceInSeconds = 300) {
167
- super(secret, toleranceInSeconds);
168
- this.config = config;
169
- }
170
- async verify(request) {
171
- try {
172
- const signature = request.headers.get("Stripe-Signature") ||
173
- request.headers.get("stripe-signature") ||
174
- request.headers.get("x-stripe-signature");
175
- if (!signature) {
176
- return {
177
- isValid: false,
178
- error: "Missing Stripe signature header",
179
- platform: "stripe",
180
- };
181
- }
182
- const rawBody = await request.text();
183
- const sigParts = signature.split(",");
184
- const sigMap = {};
185
- for (const part of sigParts) {
186
- const [key, value] = part.split("=");
187
- if (key && value) {
188
- sigMap[key] = value;
189
- }
190
- }
191
- const timestamp = sigMap.t;
192
- const sig = sigMap.v1;
193
- if (!timestamp || !sig) {
194
- return {
195
- isValid: false,
196
- error: "Invalid Stripe signature format",
197
- platform: "stripe",
198
- };
199
- }
200
- const timestampNum = parseInt(timestamp, 10);
201
- if (!this.isTimestampValid(timestampNum)) {
202
- return {
203
- isValid: false,
204
- error: "Stripe webhook timestamp expired",
205
- platform: "stripe",
206
- };
207
- }
208
- const signedPayload = `${timestamp}.${rawBody}`;
209
- const { createHmac } = await Promise.resolve().then(() => __importStar(require("crypto")));
210
- const hmac = createHmac("sha256", this.secret);
211
- hmac.update(signedPayload);
212
- const expectedSignature = hmac.digest("hex");
213
- const isValid = this.safeCompare(sig, expectedSignature);
214
- if (!isValid) {
215
- console.error("Stripe signature verification failed:", {
216
- received: sig,
217
- expected: expectedSignature,
218
- timestamp,
219
- bodyLength: rawBody.length,
220
- signedPayload: `${signedPayload.substring(0, 50)}...`,
221
- });
222
- return {
223
- isValid: false,
224
- error: "Invalid Stripe signature",
225
- platform: "stripe",
226
- };
227
- }
228
- let payload;
229
- try {
230
- payload = JSON.parse(rawBody);
231
- }
232
- catch (e) {
233
- return {
234
- isValid: true,
235
- platform: "stripe",
236
- metadata: {
237
- timestamp,
238
- id: sigMap.id,
239
- algorithm: "stripe-custom",
240
- },
241
- };
242
- }
243
- return {
244
- isValid: true,
245
- platform: "stripe",
246
- payload,
247
- metadata: {
248
- timestamp,
249
- id: sigMap.id,
250
- algorithm: "stripe-custom",
251
- },
252
- };
253
- }
254
- catch (error) {
255
- console.error("Stripe verification error:", error);
256
- return {
257
- isValid: false,
258
- error: `Stripe verification error: ${error.message}`,
259
- platform: "stripe",
260
- };
261
- }
262
- }
263
- }
264
- exports.StripeCustomVerifier = StripeCustomVerifier;
265
- // Factory function for custom verifiers
60
+ // Factory function to create custom verifiers
266
61
  function createCustomVerifier(secret, config, toleranceInSeconds = 300) {
267
62
  const customType = config.customConfig?.type;
268
63
  switch (customType) {
269
64
  case "token-based":
270
65
  return new TokenBasedVerifier(secret, config, toleranceInSeconds);
271
- case "clerk-custom":
272
- return new ClerkCustomVerifier(secret, config, toleranceInSeconds);
273
- case "stripe-custom":
274
- return new StripeCustomVerifier(secret, config, toleranceInSeconds);
275
66
  default:
276
67
  // Fallback to token-based for unknown custom types
277
68
  return new TokenBasedVerifier(secret, config, toleranceInSeconds);