@blaxel/core 0.2.52-preview.126 → 0.2.52

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.
@@ -7,7 +7,7 @@ function getPackageVersion() {
7
7
  if (typeof require !== "undefined") {
8
8
  // Try to require package.json (Node.js only, gracefully fails in browser)
9
9
  // eslint-disable-next-line @typescript-eslint/no-require-imports
10
- const packageJson = {"version":"0.2.52-preview.126","commit":"807fffa3fcd34b9d1e080282743f22122e024c84"};
10
+ const packageJson = {"version":"0.2.52","commit":"4acd7b5efa6c9e04c5131f55e7a87029c4889b1d"};
11
11
  return packageJson.version || "unknown";
12
12
  }
13
13
  else {
@@ -59,7 +59,7 @@ function getCommitHash() {
59
59
  if (typeof require !== "undefined") {
60
60
  // Try to require package.json and look for commit field (set during build)
61
61
  // eslint-disable-next-line @typescript-eslint/no-require-imports
62
- const packageJson = {"version":"0.2.52-preview.126","commit":"807fffa3fcd34b9d1e080282743f22122e024c84"};
62
+ const packageJson = {"version":"0.2.52","commit":"4acd7b5efa6c9e04c5131f55e7a87029c4889b1d"};
63
63
  // Check for commit in various possible locations
64
64
  const commit = packageJson.commit || packageJson.buildInfo?.commit;
65
65
  if (commit) {
@@ -0,0 +1,97 @@
1
+ import { createHmac, timingSafeEqual } from 'crypto';
2
+ /**
3
+ * Verify the HMAC-SHA256 signature of a webhook callback from async-sidecar
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * import { verifyWebhookSignature } from '@blaxel/core';
8
+ *
9
+ * // In your Express endpoint
10
+ * app.post('/webhook', express.text({ type: 'application/json' }), (req, res) => {
11
+ * const isValid = verifyWebhookSignature({
12
+ * body: req.body,
13
+ * signature: req.headers['x-blaxel-signature'] as string,
14
+ * secret: process.env.CALLBACK_SECRET!
15
+ * });
16
+ *
17
+ * if (!isValid) {
18
+ * return res.status(401).json({ error: 'Invalid signature' });
19
+ * }
20
+ *
21
+ * const data = JSON.parse(req.body);
22
+ * // Process callback...
23
+ * });
24
+ * ```
25
+ *
26
+ * @param options - Verification options
27
+ * @returns true if the signature is valid, false otherwise
28
+ */
29
+ export function verifyWebhookSignature(options) {
30
+ const { body, signature, secret, timestamp, maxAge = 300 } = options;
31
+ if (!body || !signature || !secret) {
32
+ return false;
33
+ }
34
+ try {
35
+ // Verify timestamp if provided (prevents replay attacks)
36
+ if (timestamp) {
37
+ const requestTime = parseInt(timestamp, 10);
38
+ const currentTime = Math.floor(Date.now() / 1000);
39
+ const age = Math.abs(currentTime - requestTime);
40
+ if (isNaN(requestTime) || age > maxAge) {
41
+ return false;
42
+ }
43
+ }
44
+ // Extract hex signature from "sha256=<hex>" format
45
+ const expectedSignature = signature.replace('sha256=', '');
46
+ // Compute HMAC-SHA256 signature
47
+ const hmac = createHmac('sha256', secret);
48
+ hmac.update(body);
49
+ const computedSignature = hmac.digest('hex');
50
+ // Timing-safe comparison to prevent timing attacks
51
+ return timingSafeEqual(Buffer.from(expectedSignature, 'hex'), Buffer.from(computedSignature, 'hex'));
52
+ }
53
+ catch {
54
+ // Invalid signature format or other error
55
+ return false;
56
+ }
57
+ }
58
+ /**
59
+ * Helper to verify webhook from Express request object
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * import { verifyWebhookFromRequest } from '@blaxel/core';
64
+ * import express from 'express';
65
+ *
66
+ * app.use(express.text({ type: 'application/json' }));
67
+ *
68
+ * app.post('/webhook', (req, res) => {
69
+ * if (!verifyWebhookFromRequest(req, process.env.CALLBACK_SECRET!)) {
70
+ * return res.status(401).json({ error: 'Invalid signature' });
71
+ * }
72
+ *
73
+ * const data = JSON.parse(req.body);
74
+ * console.log('Received callback:', data);
75
+ * res.json({ received: true });
76
+ * });
77
+ * ```
78
+ *
79
+ * @param request - Express request object (must use express.text() middleware)
80
+ * @param secret - The callback secret
81
+ * @param maxAge - Optional maximum age in seconds (default: 300)
82
+ * @returns true if the signature is valid, false otherwise
83
+ */
84
+ export function verifyWebhookFromRequest(request, secret, maxAge) {
85
+ const signature = request.headers['x-blaxel-signature'];
86
+ const timestamp = request.headers['x-blaxel-timestamp'];
87
+ if (typeof signature !== 'string') {
88
+ return false;
89
+ }
90
+ return verifyWebhookSignature({
91
+ body: request.body,
92
+ signature,
93
+ secret,
94
+ timestamp: typeof timestamp === 'string' ? timestamp : undefined,
95
+ maxAge
96
+ });
97
+ }
package/dist/esm/index.js CHANGED
@@ -8,6 +8,7 @@ export * from "./common/errors.js";
8
8
  export * from "./common/internal.js";
9
9
  export * from "./common/logger.js";
10
10
  export * from "./common/settings.js";
11
+ export * from "./common/webhook.js";
11
12
  export * from "./jobs/index.js";
12
13
  export * from "./mcp/index.js";
13
14
  export * from "./models/index.js";