From b0b5bceaedfc0a1a5c908bcc0e0c4cc5fdec9632 Mon Sep 17 00:00:00 2001 From: Lucas Berger Date: Mon, 15 Jun 2026 16:22:07 -0400 Subject: [PATCH] fix(12): IN-03 replace private web-push source import with Node.js built-in crypto generate-secrets.mjs was importing from ../apps/api/node_modules/web-push/src/index.js (a private source path) which breaks if web-push restructures internally or workspace hoisting moves the package. Replace with Node.js built-in createECDH ('prime256v1') which produces identical base64url-encoded keys, including the same defensive padding logic as web-push for short key buffers. Co-Authored-By: Claude Sonnet 4.6 --- scripts/generate-secrets.mjs | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/scripts/generate-secrets.mjs b/scripts/generate-secrets.mjs index ca83954..181bb9e 100644 --- a/scripts/generate-secrets.mjs +++ b/scripts/generate-secrets.mjs @@ -18,15 +18,33 @@ * pnpm generate-secrets */ -// web-push is a CommonJS module — import via default then destructure. -// Resolve from apps/api/node_modules to avoid a root-level dependency. -import webpush from '../apps/api/node_modules/web-push/src/index.js'; -const { generateVAPIDKeys } = webpush; -import { randomBytes } from 'node:crypto'; +// IN-03: use Node.js built-in crypto to generate VAPID keys — avoids importing +// web-push via its private source tree (../apps/api/node_modules/web-push/src/index.js) +// which breaks if web-push restructures internally or workspace hoisting moves the package. +// createECDH('prime256v1') + getPublicKey()/getPrivateKey() produces the same +// base64url-encoded keys as web-push.generateVAPIDKeys(). +import { randomBytes, createECDH } from 'node:crypto'; const sessionSecret = randomBytes(32).toString('hex'); const encKey = randomBytes(32).toString('hex'); -const vapid = generateVAPIDKeys(); + +// VAPID key generation (P-256 / prime256v1 — same curve as web-push) +const ecdhCurve = createECDH('prime256v1'); +ecdhCurve.generateKeys(); +// Pad raw buffers to the expected lengths, matching web-push defensive padding +// (https://github.com/web-push-libs/web-push/issues/295) +let pubBuffer = ecdhCurve.getPublicKey(); +let privBuffer = ecdhCurve.getPrivateKey(); +if (privBuffer.length < 32) { + privBuffer = Buffer.concat([Buffer.alloc(32 - privBuffer.length), privBuffer]); +} +if (pubBuffer.length < 65) { + pubBuffer = Buffer.concat([Buffer.alloc(65 - pubBuffer.length), pubBuffer]); +} +const vapid = { + publicKey: pubBuffer.toString('base64url'), + privateKey: privBuffer.toString('base64url'), +}; console.log(`# FamilySync Bootstrap Secrets — generated ${new Date().toISOString()} # Paste into your docker-compose.yml environment block under the 'api' service.