initial commit
This commit is contained in:
134
src/index.ts
Normal file
134
src/index.ts
Normal file
@@ -0,0 +1,134 @@
|
||||
// src/index.ts
|
||||
import express, { Express } from 'express';
|
||||
import dotenv from 'dotenv';
|
||||
import { json } from 'body-parser';
|
||||
import webpush from 'web-push';
|
||||
import crypto from 'crypto';
|
||||
import sqlite3 from 'sqlite3';
|
||||
import cors from 'cors';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
interface Subscription {
|
||||
id: string;
|
||||
endpoint: string;
|
||||
keys: string;
|
||||
}
|
||||
|
||||
const app: Express = express();
|
||||
const port = process.env.PORT || 3000;
|
||||
let secret = process.env.SECRET;
|
||||
let vapidKeys = {
|
||||
publicKey: process.env.VAPID_PUBLIC_KEY,
|
||||
privateKey: process.env.VAPID_PRIVATE_KEY,
|
||||
};
|
||||
|
||||
if (!vapidKeys.publicKey || !vapidKeys.privateKey || secret === undefined) {
|
||||
console.log(
|
||||
'SECRET, VAPID_PUBLIC_KEY, or VAPID_PRIVATE_KEY is not defined. Please run `npx run generate-keys` to generate VAPID keys, server secret, and store them in a `.env` file at the root of the project.',
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
webpush.setVapidDetails(
|
||||
`mailto:${process.env.VAPID_EMAIL}`,
|
||||
vapidKeys.publicKey,
|
||||
vapidKeys.privateKey,
|
||||
);
|
||||
|
||||
const db = new sqlite3.Database('subscriptions.db');
|
||||
db.serialize(() => {
|
||||
db.run(`
|
||||
CREATE TABLE IF NOT EXISTS subscriptions (
|
||||
id TEXT,
|
||||
endpoint TEXT NOT NULL,
|
||||
keys TEXT NOT NULL,
|
||||
PRIMARY KEY (id, endpoint)
|
||||
)
|
||||
`);
|
||||
});
|
||||
|
||||
function createHash(publicKey: string, secret: string): string {
|
||||
const publicKeyBuffer = Buffer.from(publicKey, 'base64');
|
||||
const hash = crypto.createHmac('sha256', secret);
|
||||
hash.update(publicKeyBuffer);
|
||||
return hash.digest('hex');
|
||||
}
|
||||
|
||||
app.use(json());
|
||||
app.use(
|
||||
cors({
|
||||
origin:
|
||||
process.env.NODE_ENV === 'production' ? process.env.PROD_ORIGIN : '*',
|
||||
}),
|
||||
);
|
||||
app.post('/api/subscribe', async (req, res) => {
|
||||
let { subscription, publicKey } = req.body;
|
||||
const id = await createHash(publicKey, secret!);
|
||||
|
||||
await db.run(
|
||||
'INSERT OR REPLACE INTO subscriptions (id, endpoint, keys) VALUES (?, ?, ?)',
|
||||
id,
|
||||
subscription.endpoint,
|
||||
JSON.stringify(subscription.keys),
|
||||
);
|
||||
|
||||
res.status(201).json({});
|
||||
});
|
||||
|
||||
app.get('/api/public-key', (req, res) => {
|
||||
res.status(200).json({ publicKey: vapidKeys.publicKey });
|
||||
});
|
||||
|
||||
app.post('/api/send-notification', async (req, res) => {
|
||||
let { publicKey, url } = req.body;
|
||||
|
||||
const id = createHash(publicKey, secret!);
|
||||
|
||||
// get the subscription from the database
|
||||
db.all(
|
||||
'SELECT * FROM subscriptions WHERE id = ?',
|
||||
id,
|
||||
(err, subscriptions: Subscription[]) => {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return res
|
||||
.status(500)
|
||||
.send({ error: 'Failed to retrieve subscriptions' });
|
||||
}
|
||||
if (subscriptions) {
|
||||
const payload = JSON.stringify({
|
||||
body: 'You have a new encrypted message! Click here to view it.',
|
||||
data: {
|
||||
url: url,
|
||||
},
|
||||
});
|
||||
|
||||
Promise.all(
|
||||
subscriptions.map((subscription) => {
|
||||
const keys = JSON.parse(subscription.keys);
|
||||
return webpush.sendNotification(
|
||||
{ endpoint: subscription.endpoint, keys },
|
||||
payload,
|
||||
);
|
||||
}),
|
||||
)
|
||||
.then(() => res.status(200).send({ success: true }))
|
||||
.catch((error) => {
|
||||
console.error(error);
|
||||
res.status(500).send({ error: 'Failed to send notification' });
|
||||
});
|
||||
} else {
|
||||
res.status(404).send({ error: 'No subscriptions found for this id' });
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(
|
||||
`[server]: Server is running at ${
|
||||
process.env.NODE_ENV ? process.env.PROD_ORIGIN : process.env.DEV_ORIGIN
|
||||
}`,
|
||||
);
|
||||
});
|
Reference in New Issue
Block a user