Checkpoint: Problem with worker metdata for VapidKeys
This commit is contained in:
14
src/VapidKeys.ts
Normal file
14
src/VapidKeys.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
// Subscription.ts
|
||||
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';
|
||||
|
||||
@Entity()
|
||||
export class VapidKeys {
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column()
|
||||
publicKey: string;
|
||||
|
||||
@Column()
|
||||
privateKey: string;
|
||||
}
|
||||
24
src/db.ts
24
src/db.ts
@@ -1,10 +1,13 @@
|
||||
|
||||
import { DataSource, Repository } from "typeorm";
|
||||
import {Subscription} from './Subscription.js'
|
||||
import { VapidKeys } from './VapidKeys.js';
|
||||
|
||||
export class DBService {
|
||||
private dataSource: DataSource;
|
||||
private vapidSource: DataSource;
|
||||
private subscriptionRepository: Repository<Subscription>;
|
||||
private vapidRepository: Repository<VapidKeys>;
|
||||
|
||||
constructor() {
|
||||
this.dataSource = new DataSource({
|
||||
@@ -12,7 +15,15 @@ export class DBService {
|
||||
database: "subscriptions",
|
||||
entities: [Subscription],
|
||||
});
|
||||
this.dataSource.getRepository(Subscription)
|
||||
this.subscriptionRepository = this.dataSource.getRepository(Subscription)
|
||||
|
||||
this.vapidSource = new DataSource({
|
||||
type: "sqlite",
|
||||
database: "vapidKeys",
|
||||
entities: [VapidKeys],
|
||||
});
|
||||
|
||||
this.vapidRepository = this.vapidSource.getRepository(VapidKeys);
|
||||
}
|
||||
|
||||
async saveSubscription(endpoint: string, keys_p256dh: string, keys_auth: string) {
|
||||
@@ -26,4 +37,15 @@ export class DBService {
|
||||
async getSubscriptions(): Promise<Subscription[]> {
|
||||
return this.subscriptionRepository.find();
|
||||
}
|
||||
|
||||
async getVapidKeys(): Promise<VapidKeys[]> {
|
||||
return this.vapidRepository.find();
|
||||
}
|
||||
|
||||
async saveVapidKeys(publicKey: string, privateKey: string) {
|
||||
const vapidkeys = new VapidKeys();
|
||||
vapidkeys.privateKey = privateKey;
|
||||
vapidkeys.publicKey = publicKey;
|
||||
return this.vapidRepository.save(vapidkeys);
|
||||
}
|
||||
}
|
||||
|
||||
10
src/main.ts
10
src/main.ts
@@ -1,4 +1,4 @@
|
||||
import { Subscription, SubscriptionService } from './subscriptionService.js';
|
||||
import { SubscriptionService } from './subscriptionService.js';
|
||||
import express, { Express, Request, Response } from 'express';
|
||||
import { Worker } from 'worker_threads';
|
||||
import { fileURLToPath } from 'url';
|
||||
@@ -7,6 +7,14 @@ import { dirname, join } from 'path';
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = dirname(__filename);
|
||||
|
||||
export interface Subscription {
|
||||
endpoint: string;
|
||||
keys: {
|
||||
p256dh: string;
|
||||
auth: string;
|
||||
};
|
||||
}
|
||||
|
||||
class Server {
|
||||
private app: Express;
|
||||
private port: number;
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { SubscriptionService, Subscription } from './subscriptionService.js';
|
||||
import { VapidService, VapidKeys } from './vapidService.js';
|
||||
import { SubscriptionService } from './subscriptionService.js';
|
||||
import { VapidService } from './vapidService.js';
|
||||
import { VapidKeys } from './VapidKeys.js';
|
||||
import * as https from 'https';
|
||||
import * as http_ece from 'http_ece';
|
||||
import crypto from 'crypto';
|
||||
import { Subscription } from "./Subscription.js"
|
||||
|
||||
export interface Message {
|
||||
title: string;
|
||||
@@ -14,7 +16,6 @@ export class NotificationService {
|
||||
|
||||
private subscriptionService: SubscriptionService;
|
||||
private vapidService: VapidService;
|
||||
private vapidKeys: VapidKeys;
|
||||
|
||||
constructor() {
|
||||
this.subscriptionService = new SubscriptionService();
|
||||
@@ -27,7 +28,6 @@ export class NotificationService {
|
||||
|
||||
async broadcast(message: Message): Promise<void> {
|
||||
const subscriptions = await this.subscriptionService.fetchSubscriptions();
|
||||
this.vapidKeys = await this.vapidService.getVapidKeys();
|
||||
|
||||
for (const subscription of subscriptions) {
|
||||
await this.pushToEndpoint(subscription, message);
|
||||
@@ -35,14 +35,13 @@ export class NotificationService {
|
||||
}
|
||||
|
||||
async sendNotification(subscription: Subscription, message: Message) {
|
||||
this.vapidKeys = await this.vapidService.getVapidKeys();
|
||||
await this.pushToEndpoint(subscription, message);
|
||||
}
|
||||
|
||||
private async pushToEndpoint(subscription: Subscription, message: Message): Promise<void> {
|
||||
const payload = JSON.stringify(message);
|
||||
|
||||
const encrypted = this.encrypt(subscription.keys.p256dh, subscription.keys.auth, payload);
|
||||
const encrypted = this.encrypt(subscription.keys_p256dh, subscription.keys_auth, payload);
|
||||
const endpoint = subscription.endpoint;
|
||||
|
||||
const vapidHeaders = await this.vapidService.createVapidAuthHeader(endpoint, 12 * 60 * 60, 'mailto:example@example.com');
|
||||
@@ -86,12 +85,12 @@ export class NotificationService {
|
||||
'auth': auth
|
||||
};
|
||||
|
||||
const vapidKeys: VapidKeys = this.vapidService.getVapidKeys()[0];
|
||||
return http_ece.encrypt(payload, {
|
||||
'salt': this.generateSalt(),
|
||||
'dh': this.vapidKeys.publicKey,
|
||||
'dh': vapidKeys.publicKey,
|
||||
'keyid': 'p256dh',
|
||||
'contentEncoding': 'aes128gcm'
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { DBService } from './db.js';
|
||||
import { Subscription } from './Subscription.js';
|
||||
|
||||
export interface Subscription {
|
||||
export interface SubscriptionData {
|
||||
endpoint: string;
|
||||
keys: {
|
||||
p256dh: string;
|
||||
@@ -15,7 +16,7 @@ export class SubscriptionService {
|
||||
this.dbService = new DBService();
|
||||
}
|
||||
|
||||
async addSubscription(subscription: Subscription): Promise<void> {
|
||||
async addSubscription(subscription: SubscriptionData): Promise<void> {
|
||||
await this.dbService.saveSubscription(
|
||||
subscription.endpoint,
|
||||
subscription.keys.p256dh,
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
import { Database } from 'sqlite3';
|
||||
|
||||
import jwt from 'jsonwebtoken';
|
||||
import crypto from 'crypto';
|
||||
import { DBService } from './db.js';
|
||||
import { VapidKeys } from './VapidKeys.js';
|
||||
|
||||
export interface VapidKeys {
|
||||
export interface VapidKeyData {
|
||||
publicKey: string;
|
||||
privateKey: string;
|
||||
}
|
||||
|
||||
export class VapidService {
|
||||
private db: Database;
|
||||
private dbService: DBService;
|
||||
|
||||
constructor() {
|
||||
this.db = new Database('vapidKeys.db');
|
||||
this.initializeDatabase();
|
||||
this.dbService = new DBService();
|
||||
const keys = this.generateVAPIDKeys();
|
||||
this.addVapidKeys(keys);
|
||||
}
|
||||
|
||||
private initializeDatabase(): void {
|
||||
this.db.run(`CREATE TABLE IF NOT EXISTS vapid (id INTEGER PRIMARY KEY, publicKey TEXT, privateKey TEXT)`);
|
||||
}
|
||||
|
||||
private generateVAPIDKeys(): VapidKeys {
|
||||
private generateVAPIDKeys(): VapidKeyData {
|
||||
const ecdh = crypto.createECDH('prime256v1');
|
||||
ecdh.generateKeys();
|
||||
|
||||
@@ -29,26 +28,19 @@ export class VapidService {
|
||||
};
|
||||
}
|
||||
|
||||
async getVapidKeys(): Promise<VapidKeys> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.db.get('SELECT publicKey, privateKey FROM vapid WHERE id = ?', [1], (err, row: VapidKeys) => {
|
||||
if (err) reject(err);
|
||||
async addVapidKeys(vapidkeys: VapidKeyData) {
|
||||
const keys = await this.getVapidKeys();
|
||||
if (keys.length == 0) {
|
||||
this.dbService.saveVapidKeys(vapidkeys.publicKey, vapidkeys.privateKey);
|
||||
}
|
||||
}
|
||||
|
||||
if (row) {
|
||||
resolve({ publicKey: row.publicKey, privateKey: row.privateKey });
|
||||
} else {
|
||||
const keys = this.generateVAPIDKeys();
|
||||
this.db.run('INSERT INTO vapid (publicKey, privateKey) VALUES (?, ?)', [keys.publicKey, keys.privateKey], (err) => {
|
||||
if (err) reject(err);
|
||||
resolve(keys);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
async getVapidKeys(): Promise<VapidKeys[]> {
|
||||
return this.dbService.getVapidKeys();
|
||||
}
|
||||
|
||||
async createVapidAuthHeader(endpoint: string, expiration: number, subject: string): Promise<{ 'Authorization': string, 'Crypto-Key': string }> {
|
||||
const { publicKey, privateKey } = await this.getVapidKeys();
|
||||
const { publicKey, privateKey } = await this.getVapidKeys()[0];
|
||||
|
||||
const jwtInfo = {
|
||||
aud: new URL(endpoint).origin,
|
||||
|
||||
@@ -8,8 +8,9 @@ class WorkerThread {
|
||||
|
||||
constructor(interval: number) {
|
||||
this.interval = interval;
|
||||
|
||||
this.notificationService = new NotificationService();
|
||||
this.message.title = "Check the app.";
|
||||
this.message = { "title": "Check the app." };
|
||||
|
||||
this.startPeriodicTask();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user