import ecKeyUtils from "eckey-utils"; import { VapidKeys } from './VapidKeys.js'; import jwt from 'jsonwebtoken'; import crypto from 'crypto'; import DBService from './db.js'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); export interface VapidKeyData { publicKey: string; privateKey: string; } class VapidService { private static instance: VapidService; private dbService: DBService = DBService.getInstance(); private constructor() { } public static getInstance(): VapidService { if (!VapidService.instance) { VapidService.instance = new VapidService(); } return VapidService.instance; } public async createVAPIDKeys(): Promise { let result = new VapidKeys(); if ( this.dbService.isReady ) { const keys = this.generateVAPIDKeys(); await this.dbService.saveVapidKeys(keys['publicKey'], keys['privateKey']); } else { console.log(__filename, "Database is not ready."); } return result; } private generateVAPIDKeys(): VapidKeyData { const ecdh = crypto.createECDH('prime256v1'); ecdh.generateKeys(); const result = { publicKey: ecdh.getPublicKey().toString('base64'), privateKey: ecdh.getPrivateKey().toString('base64') }; return result; } async getVapidKeys(): Promise { let result = await this.dbService.getVapidKeys(); return result; } async createVapidAuthHeader(endpoint: string, expiration: number, subject: string, appKeys: VapidKeys): Promise<{ 'Authorization': string, 'Crypto-Key': string }> { const { publicKey, privateKey } = appKeys; const jwtInfo = { aud: new URL(endpoint).origin, exp: Math.floor((Date.now() / 1000) + expiration), sub: subject }; const curveName = 'prime256v1'; const ecdh = crypto.createECDH(curveName); const privateKeyBuffer = Buffer.from(privateKey, 'base64'); ecdh.setPrivateKey(privateKeyBuffer); const pems = ecKeyUtils.generatePem({curveName, privateKey: ecdh.getPrivateKey(), publicKey: ecdh.getPublicKey() }); const jwtToken = jwt.sign(jwtInfo, pems.privateKey, { algorithm: 'ES256' }); return { 'Authorization': `vapid t=${jwtToken}, k=${publicKey}`, 'Crypto-Key': publicKey }; } } (async ()=> { })(); export default VapidService;