mailery 0.16.0 → 0.16.1

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/dist/testing.cjs CHANGED
@@ -314,8 +314,36 @@ var init_webhook_tolerance = __esm({
314
314
  // src/server/providers/sendgrid.ts
315
315
  var sendgrid_exports = {};
316
316
  __export(sendgrid_exports, {
317
- SendGridProvider: () => SendGridProvider
317
+ SendGridProvider: () => SendGridProvider,
318
+ normalizeWebhookVerificationKey: () => normalizeWebhookVerificationKey
318
319
  });
320
+ function normalizeWebhookVerificationKey(input) {
321
+ let key = String(input ?? "").trim().replace(/^["']|["']$/g, "");
322
+ if (key.includes("\\n")) key = key.replace(/\\n/g, "\n");
323
+ let pem;
324
+ if (key.includes(PEM_HEADER)) {
325
+ pem = key;
326
+ } else {
327
+ const b64 = key.replace(/\s+/g, "");
328
+ if (!b64 || !/^[A-Za-z0-9+/=]+$/.test(b64)) {
329
+ throw new Error(
330
+ "SendGridProvider: webhookVerificationKey is neither a PEM public key nor a base64 SPKI key. Copy the Verification Key from SendGrid \u2192 Settings \u2192 Mail Settings \u2192 Signed Event Webhook."
331
+ );
332
+ }
333
+ pem = `${PEM_HEADER}
334
+ ${b64.match(/.{1,64}/g).join("\n")}
335
+ ${PEM_FOOTER}
336
+ `;
337
+ }
338
+ try {
339
+ crypto2__default.default.createPublicKey(pem);
340
+ } catch (err) {
341
+ throw new Error(
342
+ `SendGridProvider: webhookVerificationKey did not parse as a public key (${String(err?.message ?? err)}). Copy the Verification Key from SendGrid \u2192 Settings \u2192 Mail Settings \u2192 Signed Event Webhook.`
343
+ );
344
+ }
345
+ return pem;
346
+ }
319
347
  function normalizeSendGridEvent(e) {
320
348
  const type = mapEventType(e.event);
321
349
  if (!type) return null;
@@ -354,24 +382,29 @@ function mapEventType(sgEvent) {
354
382
  return null;
355
383
  }
356
384
  }
357
- var SG_SIG_HEADER, SG_TS_HEADER, SendGridProvider;
385
+ var SG_SIG_HEADER, SG_TS_HEADER, PEM_HEADER, PEM_FOOTER, SendGridProvider;
358
386
  var init_sendgrid = __esm({
359
387
  "src/server/providers/sendgrid.ts"() {
360
388
  init_webhook_tolerance();
361
389
  SG_SIG_HEADER = "x-twilio-email-event-webhook-signature";
362
390
  SG_TS_HEADER = "x-twilio-email-event-webhook-timestamp";
391
+ PEM_HEADER = "-----BEGIN PUBLIC KEY-----";
392
+ PEM_FOOTER = "-----END PUBLIC KEY-----";
363
393
  SendGridProvider = class {
364
394
  constructor(opts) {
365
395
  this.opts = opts;
366
396
  sgMail__default.default.setApiKey(opts.apiKey);
367
397
  this.sendRatePerSecond = opts.sendRatePerSecond ?? 10;
368
398
  this.webhookToleranceSeconds = resolveWebhookToleranceSeconds(opts.webhookToleranceSeconds);
399
+ this.verificationKeyPem = opts.webhookVerificationKey ? normalizeWebhookVerificationKey(opts.webhookVerificationKey) : null;
369
400
  }
370
401
  opts;
371
402
  name = "sendgrid";
372
403
  sendRatePerSecond;
373
404
  /** Resolved replay window in seconds; `0` means the check is disabled. */
374
405
  webhookToleranceSeconds;
406
+ /** The verification key as PEM, whatever shape it was configured in. */
407
+ verificationKeyPem;
375
408
  async send(args) {
376
409
  const msg = {
377
410
  to: args.to,
@@ -403,7 +436,7 @@ var init_sendgrid = __esm({
403
436
  };
404
437
  }
405
438
  async verifyWebhook(rawBody, headers) {
406
- if (!this.opts.webhookVerificationKey) return false;
439
+ if (!this.verificationKeyPem) return false;
407
440
  const sig = headers[SG_SIG_HEADER];
408
441
  const ts = headers[SG_TS_HEADER];
409
442
  if (!sig || !ts) return false;
@@ -411,7 +444,7 @@ var init_sendgrid = __esm({
411
444
  try {
412
445
  const verifier = crypto2__default.default.createVerify("sha256");
413
446
  verifier.update(payload);
414
- if (!verifier.verify(this.opts.webhookVerificationKey, sig, "base64")) return false;
447
+ if (!verifier.verify(this.verificationKeyPem, sig, "base64")) return false;
415
448
  } catch {
416
449
  return false;
417
450
  }