image2ppt 0.5.3 → 0.7.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 +246 -13
- package/dist/client.d.ts +80 -17
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +433 -55
- 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 +121 -8
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +154 -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 +163 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +125 -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.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,sCAAsC;AAItC,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AACpC,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AAClD,MAAM,MAAM,SAAS,GAAG,SAAS,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE1E;;;;;;;GAOG;AACH,MAAM,MAAM,UAAU,GAAG,WAAW,GAAG,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
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,9 +169,74 @@ 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
|
+
/**
|
|
177
|
+
* Parse `pageProgress` leniently: it only feeds a progress display. Unlike
|
|
178
|
+
* `pageResults`, nothing is decided from it, so a malformed value reads as absent
|
|
179
|
+
* (or a malformed entry is skipped) rather than failing the poll.
|
|
180
|
+
*/
|
|
181
|
+
function parsePageProgress(value) {
|
|
182
|
+
if (!Array.isArray(value))
|
|
183
|
+
return null;
|
|
184
|
+
const entries = [];
|
|
185
|
+
for (const item of value) {
|
|
186
|
+
if (!isJsonObject(item))
|
|
187
|
+
continue;
|
|
188
|
+
const pageNumber = wholeNumber(item.pageNumber);
|
|
189
|
+
const progress = wholeNumber(item.progress);
|
|
190
|
+
if (pageNumber != null && progress != null) {
|
|
191
|
+
entries.push({ pageNumber, progress, stepLabel: stringOrNull(item.stepLabel) });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return entries;
|
|
195
|
+
}
|
|
196
|
+
function stringOrNull(value) {
|
|
197
|
+
return typeof value === "string" ? value : null;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* How delivering the completion callback is going (only for jobs submitted with
|
|
201
|
+
* `callbackUrl`).
|
|
202
|
+
*
|
|
203
|
+
* `status` is `pending` (the job has not finished, or the next attempt is
|
|
204
|
+
* scheduled), `delivered`, or `failed` (all 6 attempts failed; no more retries).
|
|
205
|
+
* `lastResponseStatus` is `null` for a network error or timeout. Times are
|
|
206
|
+
* `YYYY-MM-DD HH:MM:SS` in UTC, or `null`.
|
|
207
|
+
*
|
|
208
|
+
* Read leniently, like `PageError`: this is a report on a side channel, and a
|
|
209
|
+
* surprise inside it should not cost you the job it is attached to. A field of the
|
|
210
|
+
* wrong type reads as `null`; the original is on `raw`.
|
|
211
|
+
*/
|
|
212
|
+
export class CallbackStatus {
|
|
213
|
+
url;
|
|
214
|
+
/** `pending` | `delivered` | `failed`. */
|
|
215
|
+
status;
|
|
216
|
+
attempts;
|
|
217
|
+
lastAttemptAt;
|
|
218
|
+
lastResponseStatus;
|
|
219
|
+
nextAttemptAt;
|
|
220
|
+
raw;
|
|
221
|
+
constructor(data) {
|
|
222
|
+
this.url = stringOrNull(data.url);
|
|
223
|
+
this.status = stringOrNull(data.status);
|
|
224
|
+
this.attempts = wholeNumber(data.attempts);
|
|
225
|
+
this.lastAttemptAt = stringOrNull(data.lastAttemptAt);
|
|
226
|
+
this.lastResponseStatus = wholeNumber(data.lastResponseStatus);
|
|
227
|
+
this.nextAttemptAt = stringOrNull(data.nextAttemptAt);
|
|
228
|
+
this.raw = data;
|
|
229
|
+
}
|
|
230
|
+
/** Build it from a `callback` value, or return null for anything but an object. */
|
|
231
|
+
static fromJson(value) {
|
|
232
|
+
return isJsonObject(value) ? new CallbackStatus(value) : null;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
167
235
|
/** A snapshot of a conversion job's state. */
|
|
168
236
|
export class Job {
|
|
169
237
|
jobId;
|
|
238
|
+
/** Current resolved task name, or null when an older server does not send it. */
|
|
239
|
+
name;
|
|
170
240
|
status;
|
|
171
241
|
slideCount;
|
|
172
242
|
progress;
|
|
@@ -204,6 +274,27 @@ export class Job {
|
|
|
204
274
|
* which is the confusion `null` exists to prevent.
|
|
205
275
|
*/
|
|
206
276
|
pageResults;
|
|
277
|
+
/** Delivery of the completion callback; `null` unless submitted with `callbackUrl`. */
|
|
278
|
+
callback;
|
|
279
|
+
/**
|
|
280
|
+
* True when `submit` got this job back from an earlier request with the same
|
|
281
|
+
* `Idempotency-Key` (response header `Idempotent-Replayed: true`) instead of
|
|
282
|
+
* creating it now. Nothing was charged for the replay. Set by the client after
|
|
283
|
+
* construction, since it comes from a header rather than the body.
|
|
284
|
+
*/
|
|
285
|
+
replayed = false;
|
|
286
|
+
/**
|
|
287
|
+
* While the job runs: seconds the service expects it still needs. `null` while
|
|
288
|
+
* no estimate is available yet, and once the job has ended.
|
|
289
|
+
*/
|
|
290
|
+
estimatedRemainingSeconds;
|
|
291
|
+
/** Jobs ahead of this one while it waits to start; `null` once it is running. */
|
|
292
|
+
queueAhead;
|
|
293
|
+
/**
|
|
294
|
+
* Per-page progress while the job is `pending` / `processing`, one entry per
|
|
295
|
+
* page; `null` otherwise. `progress` is the whole job's figure.
|
|
296
|
+
*/
|
|
297
|
+
pageProgress;
|
|
207
298
|
/** Raw response body, for forward-compatible access to new fields. */
|
|
208
299
|
raw;
|
|
209
300
|
constructor(data) {
|
|
@@ -214,6 +305,7 @@ export class Job {
|
|
|
214
305
|
// is why all three envelopes now go through one check.
|
|
215
306
|
const d = requireFields(data, ["jobId", "status"], "job response");
|
|
216
307
|
this.jobId = d.jobId;
|
|
308
|
+
this.name = stringOrNull(d.name);
|
|
217
309
|
this.status = d.status;
|
|
218
310
|
this.slideCount = d.slideCount ?? null;
|
|
219
311
|
this.progress = d.progress ?? null;
|
|
@@ -235,6 +327,10 @@ export class Job {
|
|
|
235
327
|
// still on `raw`.
|
|
236
328
|
this.error = isJsonObject(d.error) ? d.error : null;
|
|
237
329
|
this.pageResults = parsePageResults(d.pageResults);
|
|
330
|
+
this.callback = CallbackStatus.fromJson(d.callback);
|
|
331
|
+
this.estimatedRemainingSeconds = wholeNumber(d.estimatedRemainingSeconds);
|
|
332
|
+
this.queueAhead = wholeNumber(d.queueAhead);
|
|
333
|
+
this.pageProgress = parsePageProgress(d.pageProgress);
|
|
238
334
|
this.raw = data;
|
|
239
335
|
}
|
|
240
336
|
/** Whether the job finished successfully (deliverable downloadable). */
|
|
@@ -253,4 +349,31 @@ export class Job {
|
|
|
253
349
|
return new Job(data);
|
|
254
350
|
}
|
|
255
351
|
}
|
|
352
|
+
/**
|
|
353
|
+
* One page of `listJobs`: API-submitted jobs, newest first.
|
|
354
|
+
*
|
|
355
|
+
* Each job in `data` has the same shape as `getJob` returns, minus `pageResults`.
|
|
356
|
+
* `nextCursor` is `null` on the last page; otherwise pass it back as `cursor`
|
|
357
|
+
* unchanged. For reconciliation, add up each job's `creditsUsed` (charged) and
|
|
358
|
+
* `creditsRefunded`.
|
|
359
|
+
*/
|
|
360
|
+
export class JobList {
|
|
361
|
+
data;
|
|
362
|
+
nextCursor;
|
|
363
|
+
raw;
|
|
364
|
+
/**
|
|
365
|
+
* `nextCursor` that is missing or not a string reads as the last page: an
|
|
366
|
+
* unreadable cursor could not be passed back anyway, and stopping is the answer
|
|
367
|
+
* that cannot loop forever.
|
|
368
|
+
*/
|
|
369
|
+
constructor(data) {
|
|
370
|
+
const d = requireFields(data, ["data"], "job list response");
|
|
371
|
+
if (!Array.isArray(d.data)) {
|
|
372
|
+
throw new MalformedResponseError("malformed job list response, data must be an array");
|
|
373
|
+
}
|
|
374
|
+
this.data = d.data.map((item) => Job.fromJson(item));
|
|
375
|
+
this.nextCursor = typeof d.nextCursor === "string" && d.nextCursor !== "" ? d.nextCursor : null;
|
|
376
|
+
this.raw = d;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
256
379
|
//# 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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"}
|