thelounge/src/plugins/webpush.js
Reto d4cc2dd361
Refactor config out of Helper (#4558)
* Remove config from Helper

Helper is the usual util grab bag of useful stuff.
Somehow the config ended up there historically but
structurally that doesn't make any sense.

* Add cert folder to prettier ignore file
2022-05-01 12:12:39 -07:00

101 lines
2.5 KiB
JavaScript

"use strict";
const _ = require("lodash");
const log = require("../log");
const fs = require("fs");
const path = require("path");
const WebPushAPI = require("web-push");
const Config = require("../config");
class WebPush {
constructor() {
const vapidPath = path.join(Config.getHomePath(), "vapid.json");
let vapidStat = undefined;
try {
vapidStat = fs.statSync(vapidPath);
} catch {
// ignored on purpose, node v14.17.0 will give us {throwIfNoEntry: false}
}
if (vapidStat) {
const isWorldReadable = (vapidStat.mode & 0o004) !== 0;
if (isWorldReadable) {
log.warn(
vapidPath,
"is world readable. The file contains secrets. Please fix the permissions"
);
if (require("os").platform() !== "win32") {
log.warn(`run \`chmod o= ${vapidPath}\` to correct it`);
}
}
const data = fs.readFileSync(vapidPath, "utf-8");
const parsedData = JSON.parse(data);
if (
typeof parsedData.publicKey === "string" &&
typeof parsedData.privateKey === "string"
) {
this.vapidKeys = {
publicKey: parsedData.publicKey,
privateKey: parsedData.privateKey,
};
}
}
if (!this.vapidKeys) {
this.vapidKeys = WebPushAPI.generateVAPIDKeys();
fs.writeFileSync(vapidPath, JSON.stringify(this.vapidKeys, null, "\t"), {
mode: 0o600,
});
log.info("New VAPID key pair has been generated for use with push subscription.");
}
WebPushAPI.setVapidDetails(
"https://github.com/thelounge/thelounge",
this.vapidKeys.publicKey,
this.vapidKeys.privateKey
);
}
push(client, payload, onlyToOffline) {
_.forOwn(client.config.sessions, ({pushSubscription}, token) => {
if (pushSubscription) {
if (onlyToOffline && _.find(client.attachedClients, {token}) !== undefined) {
return;
}
this.pushSingle(client, pushSubscription, payload);
}
});
}
pushSingle(client, subscription, payload) {
WebPushAPI.sendNotification(subscription, JSON.stringify(payload)).catch((error) => {
if (error.statusCode >= 400 && error.statusCode < 500) {
log.warn(
`WebPush subscription for ${client.name} returned an error (${error.statusCode}), removing subscription`
);
_.forOwn(client.config.sessions, ({pushSubscription}, token) => {
if (pushSubscription && pushSubscription.endpoint === subscription.endpoint) {
client.unregisterPushSubscription(token);
}
});
return;
}
log.error(`WebPush Error (${error})`);
});
}
}
module.exports = WebPush;