Debugged encrypt before sending notification
This commit is contained in:
@@ -3,6 +3,8 @@ FROM node:18.17.1-alpine3.17
|
|||||||
RUN mkdir -p /usr/src/app/data
|
RUN mkdir -p /usr/src/app/data
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
RUN apk add bash
|
||||||
|
|
||||||
COPY package*.json ./
|
COPY package*.json ./
|
||||||
COPY tsconfig.json ./
|
COPY tsconfig.json ./
|
||||||
COPY .eslintrc.json ./
|
COPY .eslintrc.json ./
|
||||||
|
|||||||
18
src/main.ts
18
src/main.ts
@@ -14,7 +14,7 @@ import { dirname, join } from 'path';
|
|||||||
const __filename = fileURLToPath(import.meta.url);
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
const __dirname = dirname(__filename);
|
const __dirname = dirname(__filename);
|
||||||
|
|
||||||
export interface Subscription {
|
export interface BrowserSubscription {
|
||||||
endpoint: string;
|
endpoint: string;
|
||||||
keys: {
|
keys: {
|
||||||
p256dh: string;
|
p256dh: string;
|
||||||
@@ -27,15 +27,13 @@ class Server {
|
|||||||
private port: number;
|
private port: number;
|
||||||
private worker?: Worker;
|
private worker?: Worker;
|
||||||
private subscriptionService: SubscriptionService = SubscriptionService.getInstance();
|
private subscriptionService: SubscriptionService = SubscriptionService.getInstance();
|
||||||
private notificationService: NotificationService;
|
private notificationService: NotificationService = NotificationService.getInstance();
|
||||||
dbService: DBService = DBService.getInstance();
|
dbService: DBService = DBService.getInstance();
|
||||||
vapidService: VapidService = VapidService.getInstance();
|
vapidService: VapidService = VapidService.getInstance();
|
||||||
private message: Message;
|
|
||||||
|
|
||||||
constructor(port: number) {
|
constructor(port: number) {
|
||||||
this.app = express();
|
this.app = express();
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.notificationService = new NotificationService();
|
|
||||||
|
|
||||||
this.setupRoutes();
|
this.setupRoutes();
|
||||||
this.startWorker();
|
this.startWorker();
|
||||||
@@ -46,21 +44,23 @@ class Server {
|
|||||||
private setupRoutes(): void {
|
private setupRoutes(): void {
|
||||||
this.app.use(express.json())
|
this.app.use(express.json())
|
||||||
this.app.post('/web-push/subscribe', async (req: Request, res: Response) => {
|
this.app.post('/web-push/subscribe', async (req: Request, res: Response) => {
|
||||||
const subscription = req.body as Subscription;
|
const subscription = req.body as BrowserSubscription;
|
||||||
|
const message = { "title": "You are subscribed." } as Message;
|
||||||
console.log("/web-push/subscribe", req.body);
|
console.log("/web-push/subscribe", req.body);
|
||||||
await this.subscriptionService.addSubscription(subscription);
|
await this.subscriptionService.addSubscription(subscription);
|
||||||
|
await this.notificationService.sendNotification(subscription, message);
|
||||||
res.status(201).send();
|
res.status(201).send();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.app.post('/web-push/unsubscribe', async (req: Request, res: Response) => {
|
this.app.post('/web-push/unsubscribe', async (req: Request, res: Response) => {
|
||||||
const subscription = req.body as Subscription;
|
const subscription = req.body as BrowserSubscription;
|
||||||
console.log(subscription);
|
console.log(subscription);
|
||||||
|
|
||||||
res.status(501).send();
|
res.status(501).send();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.app.post('/web-push/mute', async (req: Request, res: Response) => {
|
this.app.post('/web-push/mute', async (req: Request, res: Response) => {
|
||||||
const subscription = req.body as Subscription;
|
const subscription = req.body as BrowserSubscription;
|
||||||
console.log(subscription);
|
console.log(subscription);
|
||||||
|
|
||||||
res.status(501).send();
|
res.status(501).send();
|
||||||
@@ -88,8 +88,7 @@ class Server {
|
|||||||
|
|
||||||
this.worker.on('message', (message) => {
|
this.worker.on('message', (message) => {
|
||||||
console.log(message);
|
console.log(message);
|
||||||
this.message = { "title": "Check TimeSafari"} as Message;
|
|
||||||
this.notificationService.broadcast(this.message);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.worker.on('error', (error) => {
|
this.worker.on('error', (error) => {
|
||||||
@@ -137,6 +136,7 @@ const executeAsyncFunction = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
executeAsyncFunction().catch(error => {
|
executeAsyncFunction().catch(error => {
|
||||||
// Handle any errors here
|
// Handle any errors here
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
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';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import { Subscription } from "./Subscription.js"
|
//import { Subscription } from "./Subscription.js"
|
||||||
|
|
||||||
export interface Message {
|
export interface Message {
|
||||||
title: string;
|
title: string;
|
||||||
@@ -12,34 +12,44 @@ export interface Message {
|
|||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class NotificationService {
|
|
||||||
|
|
||||||
private subscriptionService: SubscriptionService = SubscriptionService.getInstance();
|
export interface BrowserSubscription {
|
||||||
|
endpoint: string;
|
||||||
|
keys: {
|
||||||
|
p256dh: string;
|
||||||
|
auth: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export class NotificationService {
|
||||||
|
private static instance: NotificationService;
|
||||||
|
// private subscriptionService: SubscriptionService = SubscriptionService.getInstance();
|
||||||
private vapidService: VapidService = VapidService.getInstance();
|
private vapidService: VapidService = VapidService.getInstance();
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static getInstance(): NotificationService {
|
||||||
|
if (!NotificationService.instance) {
|
||||||
|
NotificationService.instance = new NotificationService();
|
||||||
|
}
|
||||||
|
return NotificationService.instance;
|
||||||
|
}
|
||||||
|
|
||||||
private generateSalt(length = 16): Buffer {
|
private generateSalt(length = 16): Buffer {
|
||||||
return crypto.randomBytes(length);
|
return crypto.randomBytes(length);
|
||||||
}
|
}
|
||||||
|
|
||||||
async broadcast(message: Message): Promise<void> {
|
async sendNotification(subscription: BrowserSubscription, message: Message) {
|
||||||
const subscriptions = await this.subscriptionService.fetchSubscriptions();
|
|
||||||
|
|
||||||
for (const subscription of subscriptions) {
|
|
||||||
await this.pushToEndpoint(subscription, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async sendNotification(subscription: Subscription, message: Message) {
|
|
||||||
await this.pushToEndpoint(subscription, message);
|
await this.pushToEndpoint(subscription, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async pushToEndpoint(subscription: Subscription, message: Message): Promise<void> {
|
private async pushToEndpoint(subscription: BrowserSubscription, message: Message): Promise<void> {
|
||||||
const payload = JSON.stringify(message);
|
const payloadString = JSON.stringify(message);
|
||||||
|
const payloadBuffer = Buffer.from(payloadString, 'utf-8');
|
||||||
|
|
||||||
const encrypted = this.encrypt(subscription.keys_p256dh, subscription.keys_auth, payload);
|
const encrypted = await this.encrypt(subscription.keys.p256dh, subscription.keys.auth, payloadBuffer);
|
||||||
const endpoint = subscription.endpoint;
|
const endpoint = subscription.endpoint;
|
||||||
|
|
||||||
const vapidHeaders = await this.vapidService.createVapidAuthHeader(endpoint, 12 * 60 * 60, 'mailto:example@example.com');
|
const vapidHeaders = await this.vapidService.createVapidAuthHeader(endpoint, 12 * 60 * 60, 'mailto:example@example.com');
|
||||||
@@ -77,18 +87,32 @@ export class NotificationService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private encrypt(publicKey: string, auth: string, payload: string): Buffer {
|
|
||||||
http_ece.keys = {
|
|
||||||
'p256dh': publicKey,
|
|
||||||
'auth': auth
|
|
||||||
};
|
|
||||||
|
|
||||||
const vapidKeys: VapidKeys = this.vapidService.getVapidKeys()[0];
|
private async encrypt(publicKey: string, auth: string, payload: Buffer): Promise<Buffer> {
|
||||||
|
try {
|
||||||
|
console.log('Public Key:', publicKey);
|
||||||
|
console.log('Auth:', auth);
|
||||||
|
|
||||||
|
const vapidKeys: VapidKeys[] = await this.vapidService.getVapidKeys();
|
||||||
|
const vapidkey: VapidKeys = vapidKeys[0];
|
||||||
|
const vapidPrivateKeyBase64: string = vapidkey['privateKey'];
|
||||||
|
console.log(vapidPrivateKeyBase64);
|
||||||
|
const vapidPrivateKeyBuffer: Buffer = Buffer.from(vapidPrivateKeyBase64, 'base64');
|
||||||
|
const ecdh = crypto.createECDH('prime256v1');
|
||||||
|
ecdh.setPrivateKey(vapidPrivateKeyBuffer);
|
||||||
|
const publicKeyBuffer: Buffer = Buffer.from(publicKey, 'base64');
|
||||||
|
// const authBuffer: Buffer = Buffer.from(auth, 'base64');
|
||||||
|
|
||||||
return http_ece.encrypt(payload, {
|
return http_ece.encrypt(payload, {
|
||||||
'salt': this.generateSalt(),
|
'salt': this.generateSalt(),
|
||||||
'dh': vapidKeys.publicKey,
|
'privateKey': ecdh, // Your VAPID private key
|
||||||
'keyid': 'p256dh',
|
'publicKey': publicKeyBuffer, // Client's public key from the subscription object subscription.keys.p256dh
|
||||||
'contentEncoding': 'aes128gcm'
|
'authSecret': auth // Client's auth secret from the subscription object subscription.keys.auth
|
||||||
});
|
});
|
||||||
}
|
} catch (error) {
|
||||||
|
console.error('Error encrypting payload:', error);
|
||||||
|
// Handle the error as appropriate for your application
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ class VapidService {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
async getVapidKeys(): Promise<VapidKeys[]> {
|
async getVapidKeys(): Promise<VapidKeys[]> {
|
||||||
|
console.log("getVapidKeys");
|
||||||
let result = await this.dbService.getVapidKeys();
|
let result = await this.dbService.getVapidKeys();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user