Browse Source

Redid the TypeORM initialization. Adding new /vapid path

pull/1/head
Matthew Raymer 1 year ago
parent
commit
abb1673063
  1. 0
      push_server
  2. 58
      src/db.ts
  3. 22
      src/main.ts
  4. 12
      src/notificationService.ts
  5. 23
      src/subscriptionService.ts
  6. 45
      src/vapidService.ts

0
subscriptions.db → push_server

58
src/db.ts

@ -1,51 +1,71 @@
import { DataSource, Repository } from "typeorm"; import { DataSource, Repository } from "typeorm";
import {Subscription} from './Subscription.js' import { Subscription } from './Subscription.js'
import { VapidKeys } from './VapidKeys.js'; import { VapidKeys } from './VapidKeys.js';
export class DBService { class DBService {
private static instance: DBService;
private dataSource: DataSource; private dataSource: DataSource;
private vapidSource: DataSource;
private subscriptionRepository: Repository<Subscription>; private subscriptionRepository: Repository<Subscription>;
private vapidRepository: Repository<VapidKeys>; private vapidRepository: Repository<VapidKeys>;
public isReady = false;
constructor() {
private constructor() {
console.log("DBService constructor");
this.dataSource = new DataSource({ this.dataSource = new DataSource({
type: "sqlite", type: "sqlite",
database: "subscriptions", database: "push_server",
entities: [Subscription], entities: [VapidKeys, Subscription]
}); });
this.subscriptionRepository = this.dataSource.getRepository(Subscription) this.dataSource.initialize().then(()=>{
console.log("Initialized");
this.subscriptionRepository = this.dataSource.getRepository(Subscription);
this.vapidRepository = this.dataSource.getRepository(VapidKeys);
this.isReady = true;
}).catch((err)=>{console.error(err);});
}
this.vapidSource = new DataSource({
type: "sqlite", public static getInstance(): DBService {
database: "vapidKeys", if (!DBService.instance) {
entities: [VapidKeys], DBService.instance = new DBService();
}); }
return DBService.instance;
this.vapidRepository = this.vapidSource.getRepository(VapidKeys);
} }
async saveSubscription(endpoint: string, keys_p256dh: string, keys_auth: string) { async saveSubscription(endpoint: string, keys_p256dh: string, keys_auth: string) {
const subscription = new Subscription(); const subscription = new Subscription();
subscription.endpoint = endpoint; subscription.endpoint = endpoint;
subscription.keys_auth = keys_auth; subscription.keys_auth = keys_auth;
subscription.keys_p256dh = keys_p256dh; subscription.keys_p256dh = keys_p256dh;
return this.subscriptionRepository.save(subscription); return await this.dataSource.manager.save(subscription);
} }
async getSubscriptions(): Promise<Subscription[]> { async getSubscriptions(): Promise<Subscription[]> {
return this.subscriptionRepository.find(); return await this.subscriptionRepository.find();
} }
async getVapidKeys(): Promise<VapidKeys[]> { async getVapidKeys(): Promise<VapidKeys[]> {
return this.vapidRepository.find(); let result = [ new VapidKeys() ];
if ( this.vapidRepository && this.isReady) {
result = await this.vapidRepository.find();
} else {
console.log("vapidRepository is null or db is not ready");
}
return result
} }
async saveVapidKeys(publicKey: string, privateKey: string) { async saveVapidKeys(publicKey: string, privateKey: string) {
const vapidkeys = new VapidKeys(); const vapidkeys = new VapidKeys();
vapidkeys.privateKey = privateKey; vapidkeys.privateKey = privateKey;
vapidkeys.publicKey = publicKey; vapidkeys.publicKey = publicKey;
return this.vapidRepository.save(vapidkeys); return await this.dataSource.manager.save(vapidkeys);
} }
} }
export default DBService;

22
src/main.ts

@ -1,10 +1,13 @@
import { SubscriptionService } from './subscriptionService.js'; import SubscriptionService from './subscriptionService.js';
import { Message, NotificationService } from './notificationService.js'; import { Message, NotificationService } from './notificationService.js';
import { VapidKeys } from './VapidKeys.js';
import VapidService from './vapidService.js';
import express, { Express, Request, Response } from 'express'; import express, { Express, Request, Response } from 'express';
import { Worker } from 'worker_threads'; import { Worker } from 'worker_threads';
import { fileURLToPath } from 'url'; import { fileURLToPath } from 'url';
import { dirname, join } from 'path'; import { dirname, join } from 'path';
import { networkInterfaces } from 'os';
const __filename = fileURLToPath(import.meta.url); const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename); const __dirname = dirname(__filename);
@ -21,14 +24,14 @@ class Server {
private app: Express; private app: Express;
private port: number; private port: number;
private worker?: Worker; private worker?: Worker;
private subscriptionService: SubscriptionService; private subscriptionService: SubscriptionService = SubscriptionService.getInstance();
private notificationService: NotificationService; private notificationService: NotificationService;
private vapidService: VapidService = VapidService.getInstance();
private message: Message; private message: Message;
constructor(port: number) { constructor(port: number) {
this.app = express(); this.app = express();
this.port = port; this.port = port;
this.subscriptionService = new SubscriptionService();
this.notificationService = new NotificationService(); this.notificationService = new NotificationService();
this.setupRoutes(); this.setupRoutes();
@ -36,15 +39,22 @@ class Server {
this.setupWorkerListeners(); this.setupWorkerListeners();
} }
private setupRoutes(): void { private setupRoutes(): void {
this.app.post('/subscribe', async (req: Request, res: Response) => { this.app.post('/subscribe', async (req: Request, res: Response) => {
const subscription = req.body as Subscription; const subscription = req.body as Subscription;
const subscriptionService = new SubscriptionService(); await this.subscriptionService.addSubscription(subscription);
await subscriptionService.addSubscription(subscription);
res.status(201).send(); res.status(201).send();
}); });
this.app.get('/vapid', async (_: Request, res: Response) => {
const vapidkeys: VapidKeys = await this.vapidService.getVapidKeys()[0];
console.log(vapidkeys);
res.send({});
});
} }
private startWorker(): void { private startWorker(): void {
const workerPath = join(__dirname,'./worker.js'); const workerPath = join(__dirname,'./worker.js');

12
src/notificationService.ts

@ -1,5 +1,5 @@
import { SubscriptionService } from './subscriptionService.js'; import SubscriptionService from './subscriptionService.js';
import { VapidService } from './vapidService.js'; import VapidService from './vapidService.js';
import { VapidKeys } from './VapidKeys.js'; import { VapidKeys } from './VapidKeys.js';
import * as https from 'https'; import * as https from 'https';
import * as http_ece from 'http_ece'; import * as http_ece from 'http_ece';
@ -14,12 +14,12 @@ export interface Message {
export class NotificationService { export class NotificationService {
private subscriptionService: SubscriptionService; private subscriptionService: SubscriptionService = SubscriptionService.getInstance();
private vapidService: VapidService; private vapidService: VapidService = VapidService.getInstance();
constructor() { constructor() {
this.subscriptionService = new SubscriptionService(); console.log("NotificationService constructor");
this.vapidService = new VapidService();
} }
private generateSalt(length = 16): Buffer { private generateSalt(length = 16): Buffer {

23
src/subscriptionService.ts

@ -1,4 +1,4 @@
import { DBService } from './db.js'; import DBService from './db.js';
import { Subscription } from './Subscription.js'; import { Subscription } from './Subscription.js';
export interface SubscriptionData { export interface SubscriptionData {
@ -9,13 +9,23 @@ export interface SubscriptionData {
}; };
} }
export class SubscriptionService { class SubscriptionService {
private dbService: DBService; private static instance: SubscriptionService;
private dbService: DBService = DBService.getInstance();
constructor() { private constructor() {
this.dbService = new DBService(); console.log("SubscriptionService constructor");
} }
public static getInstance(): SubscriptionService {
if (!SubscriptionService.instance) {
SubscriptionService.instance = new SubscriptionService();
}
return SubscriptionService.instance;
}
async addSubscription(subscription: SubscriptionData): Promise<void> { async addSubscription(subscription: SubscriptionData): Promise<void> {
await this.dbService.saveSubscription( await this.dbService.saveSubscription(
subscription.endpoint, subscription.endpoint,
@ -24,7 +34,10 @@ export class SubscriptionService {
); );
} }
async fetchSubscriptions(): Promise<Subscription[]> { async fetchSubscriptions(): Promise<Subscription[]> {
return this.dbService.getSubscriptions(); return this.dbService.getSubscriptions();
} }
} }
export default SubscriptionService;

45
src/vapidService.ts

@ -1,44 +1,63 @@
import { VapidKeys } from './VapidKeys.js';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
import crypto from 'crypto'; import crypto from 'crypto';
import { DBService } from './db.js'; import DBService from './db.js';
import { VapidKeys } from './VapidKeys.js';
export interface VapidKeyData { export interface VapidKeyData {
publicKey: string; publicKey: string;
privateKey: string; privateKey: string;
} }
export class VapidService { class VapidService {
private dbService: DBService; private static instance: VapidService;
private dbService: DBService = DBService.getInstance();
constructor() { private constructor() {
this.dbService = new DBService(); if (this.dbService.isReady) {
const keys = this.generateVAPIDKeys(); const keys = this.generateVAPIDKeys();
this.addVapidKeys(keys); this.addVapidKeys(keys);
} else {
console.log("Not ready.");
}
}
public static getInstance(): VapidService {
if (!VapidService.instance) {
VapidService.instance = new VapidService();
}
return VapidService.instance;
} }
private generateVAPIDKeys(): VapidKeyData { private generateVAPIDKeys(): VapidKeyData {
const ecdh = crypto.createECDH('prime256v1'); const ecdh = crypto.createECDH('prime256v1');
ecdh.generateKeys(); ecdh.generateKeys();
const result = {
return {
publicKey: ecdh.getPublicKey().toString('base64'), publicKey: ecdh.getPublicKey().toString('base64'),
privateKey: ecdh.getPrivateKey().toString('base64') privateKey: ecdh.getPrivateKey().toString('base64')
}; };
console.log(result);
return result;
} }
async addVapidKeys(vapidkeys: VapidKeyData) {
private async addVapidKeys(vapidkeys: VapidKeyData) {
const keys = await this.getVapidKeys(); const keys = await this.getVapidKeys();
if (keys.length == 0) { console.log(keys);
if (keys.length == 1 && typeof(keys[0].publicKey) == "undefined" ) {
this.dbService.saveVapidKeys(vapidkeys.publicKey, vapidkeys.privateKey); this.dbService.saveVapidKeys(vapidkeys.publicKey, vapidkeys.privateKey);
} }
} }
async getVapidKeys(): Promise<VapidKeys[]> { async getVapidKeys(): Promise<VapidKeys[]> {
return this.dbService.getVapidKeys(); return this.dbService.getVapidKeys();
} }
async createVapidAuthHeader(endpoint: string, expiration: number, subject: string): Promise<{ 'Authorization': string, 'Crypto-Key': string }> { async createVapidAuthHeader(endpoint: string, expiration: number, subject: string): Promise<{ 'Authorization': string, 'Crypto-Key': string }> {
const { publicKey, privateKey } = await this.getVapidKeys()[0]; const { publicKey, privateKey } = await this.getVapidKeys()[0];
@ -56,3 +75,5 @@ export class VapidService {
}; };
} }
} }
export default VapidService;
Loading…
Cancel
Save