image2ppt 0.5.3 → 0.6.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.
- package/README.md +175 -13
- package/dist/client.d.ts +80 -17
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +424 -54
- package/dist/client.js.map +1 -1
- package/dist/compress.d.ts +3 -3
- package/dist/compress.d.ts.map +1 -1
- package/dist/compress.js +7 -5
- package/dist/compress.js.map +1 -1
- package/dist/errors.d.ts +118 -8
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +150 -18
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/limits.d.ts +23 -5
- package/dist/limits.d.ts.map +1 -1
- package/dist/limits.js +51 -10
- package/dist/limits.js.map +1 -1
- package/dist/pages.d.ts +47 -0
- package/dist/pages.d.ts.map +1 -0
- package/dist/pages.js +90 -0
- package/dist/pages.js.map +1 -0
- package/dist/types.d.ts +122 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +87 -2
- package/dist/types.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/webhook.d.ts +75 -0
- package/dist/webhook.d.ts.map +1 -0
- package/dist/webhook.js +182 -0
- package/dist/webhook.js.map +1 -0
- package/package.json +1 -1
package/dist/types.js
CHANGED
|
@@ -19,7 +19,7 @@ import { MalformedResponseError } from "./errors.js";
|
|
|
19
19
|
*
|
|
20
20
|
* `what` names the envelope for the message ("job response").
|
|
21
21
|
*/
|
|
22
|
-
function isJsonObject(value) {
|
|
22
|
+
export function isJsonObject(value) {
|
|
23
23
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24
24
|
}
|
|
25
25
|
function requireFields(data, keys, what) {
|
|
@@ -83,7 +83,12 @@ export class PageError {
|
|
|
83
83
|
}
|
|
84
84
|
/** What happened to one page of the deck. */
|
|
85
85
|
export class PageResult {
|
|
86
|
-
/**
|
|
86
|
+
/**
|
|
87
|
+
* 1-based, and counts **pages of the delivered deck**. Without `pages` that is the
|
|
88
|
+
* order the files were submitted in (a PDF follows its own page order). With
|
|
89
|
+
* `pages` it is the k-th *selected* page, not the page number you selected:
|
|
90
|
+
* `pages: "3,7"` gives entries 1 and 2.
|
|
91
|
+
*/
|
|
87
92
|
pageNumber;
|
|
88
93
|
/** `converted` or `failed`; an unrecognised value is passed through as-is. */
|
|
89
94
|
status;
|
|
@@ -164,6 +169,49 @@ function parsePageResults(value) {
|
|
|
164
169
|
}
|
|
165
170
|
return value.map((entry) => new PageResult(entry));
|
|
166
171
|
}
|
|
172
|
+
/** A whole number: `3` and `3.0` count, `"3"`, `true` and `1.5` do not. */
|
|
173
|
+
export function wholeNumber(value) {
|
|
174
|
+
return Number.isInteger(value) ? value : null;
|
|
175
|
+
}
|
|
176
|
+
function stringOrNull(value) {
|
|
177
|
+
return typeof value === "string" ? value : null;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* How delivering the completion callback is going (only for jobs submitted with
|
|
181
|
+
* `callbackUrl`).
|
|
182
|
+
*
|
|
183
|
+
* `status` is `pending` (the job has not finished, or the next attempt is
|
|
184
|
+
* scheduled), `delivered`, or `failed` (all 6 attempts failed; no more retries).
|
|
185
|
+
* `lastResponseStatus` is `null` for a network error or timeout. Times are
|
|
186
|
+
* `YYYY-MM-DD HH:MM:SS` in UTC, or `null`.
|
|
187
|
+
*
|
|
188
|
+
* Read leniently, like `PageError`: this is a report on a side channel, and a
|
|
189
|
+
* surprise inside it should not cost you the job it is attached to. A field of the
|
|
190
|
+
* wrong type reads as `null`; the original is on `raw`.
|
|
191
|
+
*/
|
|
192
|
+
export class CallbackStatus {
|
|
193
|
+
url;
|
|
194
|
+
/** `pending` | `delivered` | `failed`. */
|
|
195
|
+
status;
|
|
196
|
+
attempts;
|
|
197
|
+
lastAttemptAt;
|
|
198
|
+
lastResponseStatus;
|
|
199
|
+
nextAttemptAt;
|
|
200
|
+
raw;
|
|
201
|
+
constructor(data) {
|
|
202
|
+
this.url = stringOrNull(data.url);
|
|
203
|
+
this.status = stringOrNull(data.status);
|
|
204
|
+
this.attempts = wholeNumber(data.attempts);
|
|
205
|
+
this.lastAttemptAt = stringOrNull(data.lastAttemptAt);
|
|
206
|
+
this.lastResponseStatus = wholeNumber(data.lastResponseStatus);
|
|
207
|
+
this.nextAttemptAt = stringOrNull(data.nextAttemptAt);
|
|
208
|
+
this.raw = data;
|
|
209
|
+
}
|
|
210
|
+
/** Build it from a `callback` value, or return null for anything but an object. */
|
|
211
|
+
static fromJson(value) {
|
|
212
|
+
return isJsonObject(value) ? new CallbackStatus(value) : null;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
167
215
|
/** A snapshot of a conversion job's state. */
|
|
168
216
|
export class Job {
|
|
169
217
|
jobId;
|
|
@@ -204,6 +252,15 @@ export class Job {
|
|
|
204
252
|
* which is the confusion `null` exists to prevent.
|
|
205
253
|
*/
|
|
206
254
|
pageResults;
|
|
255
|
+
/** Delivery of the completion callback; `null` unless submitted with `callbackUrl`. */
|
|
256
|
+
callback;
|
|
257
|
+
/**
|
|
258
|
+
* True when `submit` got this job back from an earlier request with the same
|
|
259
|
+
* `Idempotency-Key` (response header `Idempotent-Replayed: true`) instead of
|
|
260
|
+
* creating it now. Nothing was charged for the replay. Set by the client after
|
|
261
|
+
* construction, since it comes from a header rather than the body.
|
|
262
|
+
*/
|
|
263
|
+
replayed = false;
|
|
207
264
|
/** Raw response body, for forward-compatible access to new fields. */
|
|
208
265
|
raw;
|
|
209
266
|
constructor(data) {
|
|
@@ -235,6 +292,7 @@ export class Job {
|
|
|
235
292
|
// still on `raw`.
|
|
236
293
|
this.error = isJsonObject(d.error) ? d.error : null;
|
|
237
294
|
this.pageResults = parsePageResults(d.pageResults);
|
|
295
|
+
this.callback = CallbackStatus.fromJson(d.callback);
|
|
238
296
|
this.raw = data;
|
|
239
297
|
}
|
|
240
298
|
/** Whether the job finished successfully (deliverable downloadable). */
|
|
@@ -253,4 +311,31 @@ export class Job {
|
|
|
253
311
|
return new Job(data);
|
|
254
312
|
}
|
|
255
313
|
}
|
|
314
|
+
/**
|
|
315
|
+
* One page of `listJobs`: API-submitted jobs, newest first.
|
|
316
|
+
*
|
|
317
|
+
* Each job in `data` has the same shape as `getJob` returns, minus `pageResults`.
|
|
318
|
+
* `nextCursor` is `null` on the last page; otherwise pass it back as `cursor`
|
|
319
|
+
* unchanged. For reconciliation, add up each job's `creditsUsed` (charged) and
|
|
320
|
+
* `creditsRefunded`.
|
|
321
|
+
*/
|
|
322
|
+
export class JobList {
|
|
323
|
+
data;
|
|
324
|
+
nextCursor;
|
|
325
|
+
raw;
|
|
326
|
+
/**
|
|
327
|
+
* `nextCursor` that is missing or not a string reads as the last page: an
|
|
328
|
+
* unreadable cursor could not be passed back anyway, and stopping is the answer
|
|
329
|
+
* that cannot loop forever.
|
|
330
|
+
*/
|
|
331
|
+
constructor(data) {
|
|
332
|
+
const d = requireFields(data, ["data"], "job list response");
|
|
333
|
+
if (!Array.isArray(d.data)) {
|
|
334
|
+
throw new MalformedResponseError("malformed job list response, data must be an array");
|
|
335
|
+
}
|
|
336
|
+
this.data = d.data.map((item) => Job.fromJson(item));
|
|
337
|
+
this.nextCursor = typeof d.nextCursor === "string" && d.nextCursor !== "" ? d.nextCursor : null;
|
|
338
|
+
this.raw = d;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
256
341
|
//# sourceMappingURL=types.js.map
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAEtC,OAAO,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAgBrD;;;;;;;;;;;;;;;;;;GAkBG;AACH,
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verifying completion callbacks (the Standard Webhooks scheme,
|
|
3
|
+
* https://www.standardwebhooks.com).
|
|
4
|
+
*
|
|
5
|
+
* A job submitted with `callbackUrl` is announced by a `POST` to that URL when it
|
|
6
|
+
* ends. Anyone can send a POST, so check every delivery with `verifyWebhook` before
|
|
7
|
+
* acting on it:
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* // Express: the raw body, not express.json()
|
|
11
|
+
* app.post("/hook", express.raw({ type: "application/json" }), (req, res) => {
|
|
12
|
+
* let event;
|
|
13
|
+
* try {
|
|
14
|
+
* event = verifyWebhook(req.body, req.headers, process.env.IMAGE2PPT_WEBHOOK_SECRET!);
|
|
15
|
+
* } catch (err) {
|
|
16
|
+
* if (err instanceof WebhookVerificationError) return res.sendStatus(400);
|
|
17
|
+
* throw err;
|
|
18
|
+
* }
|
|
19
|
+
* if (event.type === "job.completed") { ... }
|
|
20
|
+
* res.sendStatus(204); // any 2xx within 10 seconds counts as delivered
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* Every rule here is pinned identically in the Python client.
|
|
25
|
+
*/
|
|
26
|
+
import { Job } from "./types.js";
|
|
27
|
+
/** How far `webhook-timestamp` may be from the receiver's clock, either way. */
|
|
28
|
+
export declare const DEFAULT_TOLERANCE_SECONDS = 300;
|
|
29
|
+
/** Anything a framework hands over as request headers. */
|
|
30
|
+
export type WebhookHeaders = Headers | Record<string, string | string[] | undefined | null>;
|
|
31
|
+
export interface VerifyWebhookOptions {
|
|
32
|
+
/** Largest allowed gap between `webhook-timestamp` and now, either way. Default 300. */
|
|
33
|
+
toleranceSeconds?: number;
|
|
34
|
+
/** Current Unix time in seconds, for tests; defaults to the clock. */
|
|
35
|
+
now?: number;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* A verified callback.
|
|
39
|
+
*
|
|
40
|
+
* `type` is `job.completed` or `job.failed` today; **ignore types you do not
|
|
41
|
+
* recognise** (still answer 2xx) — more may be added. `data` is the job, shaped like
|
|
42
|
+
* `getJob`'s response without `callback`; `job` parses it for you. `id` stays the
|
|
43
|
+
* same across retries of one delivery, so use it to drop duplicates.
|
|
44
|
+
*/
|
|
45
|
+
export declare class WebhookEvent {
|
|
46
|
+
readonly id: string;
|
|
47
|
+
readonly timestamp: number;
|
|
48
|
+
readonly type: string | null;
|
|
49
|
+
readonly data: Record<string, unknown>;
|
|
50
|
+
readonly raw: Record<string, unknown>;
|
|
51
|
+
constructor(id: string, timestamp: number, type: string | null, data: Record<string, unknown>, raw: Record<string, unknown>);
|
|
52
|
+
/** `data` as a `Job`. Throws `MalformedResponseError` if it is not one. */
|
|
53
|
+
get job(): Job;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Check a callback's signature and timestamp; return the event it carries.
|
|
57
|
+
*
|
|
58
|
+
* @param payload The request body **exactly as received** — a Buffer/Uint8Array, or
|
|
59
|
+
* the same text decoded as UTF-8. Parsing the JSON and re-serialising it changes the
|
|
60
|
+
* bytes and the signature will not match; with Express use `express.raw()`.
|
|
61
|
+
* @param headers The request headers: a fetch `Headers`, or a plain record such as
|
|
62
|
+
* Node's `req.headers`. Names are matched ignoring case.
|
|
63
|
+
* @param secret The callback signing secret from the Developer / API page
|
|
64
|
+
* (`whsec_...`). During a rotation the service signs with the old and the new one
|
|
65
|
+
* for 24 hours, so a receiver holding either passes.
|
|
66
|
+
* @throws WebhookVerificationError Missing header, timestamp outside the tolerance, no
|
|
67
|
+
* matching `v1` signature, or a verified body that is not a JSON object. Refuse the
|
|
68
|
+
* delivery.
|
|
69
|
+
* @throws TypeError `secret` is not a `whsec_` + base64 secret — a configuration
|
|
70
|
+
* mistake on the receiving side, not a bad delivery, so it is kept apart: answering
|
|
71
|
+
* every genuine callback with 4xx would hide it. Also thrown when `payload` is not
|
|
72
|
+
* bytes or text, typically a body a framework has already parsed.
|
|
73
|
+
*/
|
|
74
|
+
export declare function verifyWebhook(payload: Uint8Array | string, headers: WebhookHeaders, secret: string, options?: VerifyWebhookOptions): WebhookEvent;
|
|
75
|
+
//# sourceMappingURL=webhook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAKH,OAAO,EAAE,GAAG,EAAgB,MAAM,YAAY,CAAC;AAE/C,gFAAgF;AAChF,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAa7C,0DAA0D;AAC1D,MAAM,MAAM,cAAc,GACtB,OAAO,GACP,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,GAAG,IAAI,CAAC,CAAC;AAEzD,MAAM,WAAW,oBAAoB;IACnC,wFAAwF;IACxF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sEAAsE;IACtE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,qBAAa,YAAY;IAErB,QAAQ,CAAC,EAAE,EAAE,MAAM;IACnB,QAAQ,CAAC,SAAS,EAAE,MAAM;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACtC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;gBAJ5B,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,GAAG,IAAI,EACnB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAGvC,2EAA2E;IAC3E,IAAI,GAAG,IAAI,GAAG,CAEb;CACF;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,UAAU,GAAG,MAAM,EAC5B,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,MAAM,EACd,OAAO,GAAE,oBAAyB,GACjC,YAAY,CAyDd"}
|
package/dist/webhook.js
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verifying completion callbacks (the Standard Webhooks scheme,
|
|
3
|
+
* https://www.standardwebhooks.com).
|
|
4
|
+
*
|
|
5
|
+
* A job submitted with `callbackUrl` is announced by a `POST` to that URL when it
|
|
6
|
+
* ends. Anyone can send a POST, so check every delivery with `verifyWebhook` before
|
|
7
|
+
* acting on it:
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* // Express: the raw body, not express.json()
|
|
11
|
+
* app.post("/hook", express.raw({ type: "application/json" }), (req, res) => {
|
|
12
|
+
* let event;
|
|
13
|
+
* try {
|
|
14
|
+
* event = verifyWebhook(req.body, req.headers, process.env.IMAGE2PPT_WEBHOOK_SECRET!);
|
|
15
|
+
* } catch (err) {
|
|
16
|
+
* if (err instanceof WebhookVerificationError) return res.sendStatus(400);
|
|
17
|
+
* throw err;
|
|
18
|
+
* }
|
|
19
|
+
* if (event.type === "job.completed") { ... }
|
|
20
|
+
* res.sendStatus(204); // any 2xx within 10 seconds counts as delivered
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* Every rule here is pinned identically in the Python client.
|
|
25
|
+
*/
|
|
26
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
27
|
+
import { WebhookVerificationError } from "./errors.js";
|
|
28
|
+
import { Job, isJsonObject } from "./types.js";
|
|
29
|
+
/** How far `webhook-timestamp` may be from the receiver's clock, either way. */
|
|
30
|
+
export const DEFAULT_TOLERANCE_SECONDS = 300;
|
|
31
|
+
const SECRET_PREFIX = "whsec_";
|
|
32
|
+
/**
|
|
33
|
+
* Strict standard base64. `Buffer.from(x, "base64")` silently skips any character it
|
|
34
|
+
* does not know, while Python's decoder refuses it — so the secret is checked against
|
|
35
|
+
* the alphabet first and both clients agree on which secrets are malformed.
|
|
36
|
+
*/
|
|
37
|
+
const BASE64 = /^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/;
|
|
38
|
+
const TIMESTAMP = /^[0-9]+$/;
|
|
39
|
+
/** Unix seconds stay within 12 digits for tens of thousands of years; longer is refused. */
|
|
40
|
+
const MAX_TIMESTAMP_DIGITS = 12;
|
|
41
|
+
/**
|
|
42
|
+
* A verified callback.
|
|
43
|
+
*
|
|
44
|
+
* `type` is `job.completed` or `job.failed` today; **ignore types you do not
|
|
45
|
+
* recognise** (still answer 2xx) — more may be added. `data` is the job, shaped like
|
|
46
|
+
* `getJob`'s response without `callback`; `job` parses it for you. `id` stays the
|
|
47
|
+
* same across retries of one delivery, so use it to drop duplicates.
|
|
48
|
+
*/
|
|
49
|
+
export class WebhookEvent {
|
|
50
|
+
id;
|
|
51
|
+
timestamp;
|
|
52
|
+
type;
|
|
53
|
+
data;
|
|
54
|
+
raw;
|
|
55
|
+
constructor(id, timestamp, type, data, raw) {
|
|
56
|
+
this.id = id;
|
|
57
|
+
this.timestamp = timestamp;
|
|
58
|
+
this.type = type;
|
|
59
|
+
this.data = data;
|
|
60
|
+
this.raw = raw;
|
|
61
|
+
}
|
|
62
|
+
/** `data` as a `Job`. Throws `MalformedResponseError` if it is not one. */
|
|
63
|
+
get job() {
|
|
64
|
+
return Job.fromJson(this.data);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Check a callback's signature and timestamp; return the event it carries.
|
|
69
|
+
*
|
|
70
|
+
* @param payload The request body **exactly as received** — a Buffer/Uint8Array, or
|
|
71
|
+
* the same text decoded as UTF-8. Parsing the JSON and re-serialising it changes the
|
|
72
|
+
* bytes and the signature will not match; with Express use `express.raw()`.
|
|
73
|
+
* @param headers The request headers: a fetch `Headers`, or a plain record such as
|
|
74
|
+
* Node's `req.headers`. Names are matched ignoring case.
|
|
75
|
+
* @param secret The callback signing secret from the Developer / API page
|
|
76
|
+
* (`whsec_...`). During a rotation the service signs with the old and the new one
|
|
77
|
+
* for 24 hours, so a receiver holding either passes.
|
|
78
|
+
* @throws WebhookVerificationError Missing header, timestamp outside the tolerance, no
|
|
79
|
+
* matching `v1` signature, or a verified body that is not a JSON object. Refuse the
|
|
80
|
+
* delivery.
|
|
81
|
+
* @throws TypeError `secret` is not a `whsec_` + base64 secret — a configuration
|
|
82
|
+
* mistake on the receiving side, not a bad delivery, so it is kept apart: answering
|
|
83
|
+
* every genuine callback with 4xx would hide it. Also thrown when `payload` is not
|
|
84
|
+
* bytes or text, typically a body a framework has already parsed.
|
|
85
|
+
*/
|
|
86
|
+
export function verifyWebhook(payload, headers, secret, options = {}) {
|
|
87
|
+
const key = decodeSecret(secret);
|
|
88
|
+
const body = payloadBytes(payload);
|
|
89
|
+
const tolerance = options.toleranceSeconds ?? DEFAULT_TOLERANCE_SECONDS;
|
|
90
|
+
if (typeof tolerance !== "number" || !Number.isFinite(tolerance) || tolerance < 0) {
|
|
91
|
+
throw new TypeError("toleranceSeconds must be a finite, non-negative number");
|
|
92
|
+
}
|
|
93
|
+
if (options.now !== undefined && (typeof options.now !== "number" || !Number.isFinite(options.now))) {
|
|
94
|
+
throw new TypeError("now must be a finite number of Unix seconds");
|
|
95
|
+
}
|
|
96
|
+
const msgId = header(headers, "webhook-id");
|
|
97
|
+
const timestamp = header(headers, "webhook-timestamp");
|
|
98
|
+
const signatures = header(headers, "webhook-signature");
|
|
99
|
+
if (!msgId || !timestamp || !signatures) {
|
|
100
|
+
throw new WebhookVerificationError("missing webhook-id, webhook-timestamp or webhook-signature header");
|
|
101
|
+
}
|
|
102
|
+
if (!TIMESTAMP.test(timestamp)) {
|
|
103
|
+
throw new WebhookVerificationError(`webhook-timestamp ${JSON.stringify(timestamp)} is not Unix seconds`);
|
|
104
|
+
}
|
|
105
|
+
if (timestamp.length > MAX_TIMESTAMP_DIGITS) {
|
|
106
|
+
// Far outside any window, and too long to do arithmetic on safely.
|
|
107
|
+
throw new WebhookVerificationError("webhook-timestamp is outside the tolerance");
|
|
108
|
+
}
|
|
109
|
+
const sentAt = Number(timestamp);
|
|
110
|
+
const current = options.now ?? Date.now() / 1000;
|
|
111
|
+
if (Math.abs(current - sentAt) > tolerance) {
|
|
112
|
+
throw new WebhookVerificationError(`webhook-timestamp is ${Math.trunc(current - sentAt)}s from now, outside the ` +
|
|
113
|
+
`${tolerance}s tolerance`);
|
|
114
|
+
}
|
|
115
|
+
const expected = Buffer.from(createHmac("sha256", key)
|
|
116
|
+
.update(Buffer.from(`${msgId}.${timestamp}.`, "utf8"))
|
|
117
|
+
.update(body)
|
|
118
|
+
.digest("base64"), "utf8");
|
|
119
|
+
// Split on the ASCII space the scheme uses, nothing wider: a /\s+/ and Python's
|
|
120
|
+
// bare split() disagree about what whitespace is.
|
|
121
|
+
for (const entry of signatures.split(" ")) {
|
|
122
|
+
const comma = entry.indexOf(",");
|
|
123
|
+
if (comma === -1 || entry.slice(0, comma) !== "v1")
|
|
124
|
+
continue;
|
|
125
|
+
const signature = Buffer.from(entry.slice(comma + 1), "utf8");
|
|
126
|
+
// timingSafeEqual throws on a length mismatch, so compare lengths first; a
|
|
127
|
+
// length is no secret.
|
|
128
|
+
if (signature.length === expected.length && timingSafeEqual(signature, expected)) {
|
|
129
|
+
return toEvent(msgId, sentAt, body);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
throw new WebhookVerificationError("no webhook-signature matches this payload and secret");
|
|
133
|
+
}
|
|
134
|
+
/** The HMAC key: the base64 after `whsec_` (a bare base64 secret is accepted too). */
|
|
135
|
+
function decodeSecret(secret) {
|
|
136
|
+
if (typeof secret !== "string") {
|
|
137
|
+
throw new TypeError(`secret must be a string, not ${typeof secret}`);
|
|
138
|
+
}
|
|
139
|
+
const encoded = secret.startsWith(SECRET_PREFIX) ? secret.slice(SECRET_PREFIX.length) : secret;
|
|
140
|
+
if (!encoded || !BASE64.test(encoded)) {
|
|
141
|
+
throw new TypeError("secret is not a webhook signing secret (expected whsec_<base64>)");
|
|
142
|
+
}
|
|
143
|
+
return Buffer.from(encoded, "base64");
|
|
144
|
+
}
|
|
145
|
+
function payloadBytes(payload) {
|
|
146
|
+
if (typeof payload === "string")
|
|
147
|
+
return Buffer.from(payload, "utf8");
|
|
148
|
+
if (payload instanceof Uint8Array) {
|
|
149
|
+
return Buffer.from(payload.buffer, payload.byteOffset, payload.byteLength);
|
|
150
|
+
}
|
|
151
|
+
throw new TypeError("payload must be the raw request body (Buffer, Uint8Array or string), not " +
|
|
152
|
+
`${payload === null ? "null" : typeof payload} — with Express, use express.raw() ` +
|
|
153
|
+
"instead of express.json() for this route");
|
|
154
|
+
}
|
|
155
|
+
/** Case-insensitive lookup; a list of values is joined by spaces. */
|
|
156
|
+
function header(headers, name) {
|
|
157
|
+
if (typeof Headers !== "undefined" && headers instanceof Headers) {
|
|
158
|
+
return headers.get(name) ?? undefined;
|
|
159
|
+
}
|
|
160
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
161
|
+
if (key.toLowerCase() !== name)
|
|
162
|
+
continue;
|
|
163
|
+
if (Array.isArray(value))
|
|
164
|
+
return value.map(String).join(" ");
|
|
165
|
+
return value == null ? undefined : String(value);
|
|
166
|
+
}
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|
|
169
|
+
function toEvent(msgId, sentAt, body) {
|
|
170
|
+
let parsed;
|
|
171
|
+
try {
|
|
172
|
+
parsed = JSON.parse(body.toString("utf8"));
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
parsed = undefined;
|
|
176
|
+
}
|
|
177
|
+
if (!isJsonObject(parsed)) {
|
|
178
|
+
throw new WebhookVerificationError("signature matches, but the body is not a JSON object");
|
|
179
|
+
}
|
|
180
|
+
return new WebhookEvent(msgId, sentAt, typeof parsed.type === "string" ? parsed.type : null, isJsonObject(parsed.data) ? parsed.data : {}, parsed);
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=webhook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.js","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"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"}
|