You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
118 lines
4.2 KiB
118 lines
4.2 KiB
//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;
|
|
body?: string;
|
|
[key: string]: any;
|
|
}
|
|
|
|
|
|
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();
|
|
|
|
constructor() {
|
|
}
|
|
|
|
public static getInstance(): NotificationService {
|
|
if (!NotificationService.instance) {
|
|
NotificationService.instance = new NotificationService();
|
|
}
|
|
return NotificationService.instance;
|
|
}
|
|
|
|
private generateSalt(length = 16): Buffer {
|
|
return crypto.randomBytes(length);
|
|
}
|
|
|
|
async sendNotification(subscription: BrowserSubscription, message: Message) {
|
|
await this.pushToEndpoint(subscription, message);
|
|
}
|
|
|
|
private async pushToEndpoint(subscription: BrowserSubscription, message: Message): Promise<void> {
|
|
const payloadString = JSON.stringify(message);
|
|
const payloadBuffer = Buffer.from(payloadString, 'utf-8');
|
|
|
|
const encrypted = await this.encrypt(subscription.keys.p256dh, subscription.keys.auth, payloadBuffer);
|
|
const endpoint = subscription.endpoint;
|
|
|
|
const vapidHeaders = await this.vapidService.createVapidAuthHeader(endpoint, 12 * 60 * 60, 'mailto:example@example.com');
|
|
|
|
const parsedUrl = new URL(subscription.endpoint);
|
|
const options: https.RequestOptions = {
|
|
method: 'POST',
|
|
hostname: parsedUrl.hostname,
|
|
path: parsedUrl.pathname,
|
|
port: parsedUrl.port,
|
|
headers: {
|
|
...vapidHeaders,
|
|
'TTL': '60',
|
|
'Content-Encoding': 'aes128gcm',
|
|
'Content-Type': 'application/octet-stream',
|
|
'Content-Length': encrypted.length
|
|
},
|
|
};
|
|
|
|
return new Promise<void>((resolve, reject) => {
|
|
const req = https.request(options, (res) => {
|
|
if (res.statusCode! >= 200 && res.statusCode! < 300) {
|
|
resolve();
|
|
} else {
|
|
reject(new Error(`Failed to send push notification. Status code: ${res.statusCode}`));
|
|
}
|
|
});
|
|
|
|
req.on('error', (error) => {
|
|
reject(new Error(`Failed to send push notification. Error: ${error.message}`));
|
|
});
|
|
|
|
req.write(encrypted);
|
|
req.end();
|
|
});
|
|
}
|
|
|
|
|
|
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, {
|
|
'salt': this.generateSalt(),
|
|
'privateKey': ecdh, // Your VAPID private key
|
|
'publicKey': publicKeyBuffer, // Client's public key from the subscription object subscription.keys.p256dh
|
|
'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;
|
|
}
|
|
}
|
|
}
|
|
|