Redid the TypeORM initialization. Adding new /vapid path
This commit is contained in:
58
src/db.ts
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.vapidSource = new DataSource({
|
this.subscriptionRepository = this.dataSource.getRepository(Subscription);
|
||||||
type: "sqlite",
|
this.vapidRepository = this.dataSource.getRepository(VapidKeys);
|
||||||
database: "vapidKeys",
|
this.isReady = true;
|
||||||
entities: [VapidKeys],
|
}).catch((err)=>{console.error(err);});
|
||||||
});
|
|
||||||
|
|
||||||
this.vapidRepository = this.vapidSource.getRepository(VapidKeys);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static getInstance(): DBService {
|
||||||
|
if (!DBService.instance) {
|
||||||
|
DBService.instance = new DBService();
|
||||||
|
}
|
||||||
|
return DBService.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
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
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');
|
||||||
|
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -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;
|
||||||
Reference in New Issue
Block a user