feat: initial public release (MAESTRO)
This commit is contained in:
@@ -0,0 +1,49 @@
|
||||
#!/usr/bin/env tsx
|
||||
/**
|
||||
* Rotate the VAPID keypair used by Web Push notifications.
|
||||
*
|
||||
* Behavior:
|
||||
* 1. Read the current key from `data/secrets/vapid.json` (or wherever
|
||||
* `notifications.push.vapid_current_path` points, default
|
||||
* `data/secrets/vapid.json`).
|
||||
* 2. Move it to the history directory (default `data/secrets/vapid-history/`).
|
||||
* 3. Generate a fresh keypair and write it as the new current.
|
||||
* 4. Existing subscriptions in the DB are NOT modified — they retain the
|
||||
* old `vapid_key_id` and will still receive pushes (we read from history
|
||||
* based on that id). To force re-subscribe, delete the history file
|
||||
* manually after a grace period; users will see 401 on next push and
|
||||
* can re-subscribe from Settings.
|
||||
*
|
||||
* Usage:
|
||||
* npm run vapid-rotate
|
||||
*/
|
||||
import { join } from 'path';
|
||||
import { loadConfig } from '../src/config.js';
|
||||
import { VapidKeyStore } from '../src/vapid-store.js';
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const config = await loadConfig();
|
||||
const pushCfg = config.notifications?.push;
|
||||
const subject =
|
||||
pushCfg?.vapidSubject ?? 'https://maestro.example.com/';
|
||||
const currentPath = join(process.cwd(), 'data/secrets/vapid.json');
|
||||
const historyDir =
|
||||
pushCfg?.vapidHistoryDir ?? join(process.cwd(), 'data/secrets/vapid-history');
|
||||
|
||||
const store = new VapidKeyStore(currentPath, historyDir);
|
||||
const newKey = store.rotate(subject);
|
||||
|
||||
console.log('VAPID rotation complete.');
|
||||
console.log(` new keyId: ${newKey.keyId}`);
|
||||
console.log(` public key: ${newKey.publicKey}`);
|
||||
console.log(` history dir: ${historyDir}`);
|
||||
console.log('');
|
||||
console.log('Existing subscriptions remain valid via the history key.');
|
||||
console.log('To force re-subscribe, remove the history file after the grace period');
|
||||
console.log('and notify users via Settings → Notifications.');
|
||||
}
|
||||
|
||||
main().catch(err => {
|
||||
console.error('VAPID rotation failed:', err);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user