'use strict'; const fs = require('fs').promises; const path = require('path'); const QRCode = require('qrcode'); const ServerError = require('./ServerError'); const { WG_PATH, WG_HOST, WG_PORT, WG_DEFAULT_ADDRESS, } = require('../config'); module.exports = class WireGuard { constructor() { Promise.resolve().then(async () => { try { const config = await fs.readFile(path.join(WG_PATH, 'wg0.json'), 'utf8'); this.config = JSON.parse(config); } catch (err) { this.config = { // TODO: Generate new config server: { address: WG_DEFAULT_ADDRESS, }, clients: {}, }; // TODO: Save JSON config } console.log('this.config', this.config); await this.saveConfig(); }).catch(err => { // eslint-disable-next-line no-console console.error(err); // eslint-disable-next-line no-process-exit process.exit(1); }); } async saveConfig() { let result = ` # Note: Do not edit this file directly. # Your changes will be overwritten! # Server [Interface] PrivateKey = ${this.config.server.privateKey} Address = ${this.config.server.address} ListenPort = ${this.config.server.port} DNS = ${this.config.server.dns}`; for (const [clientId, client] of Object.entries(this.config.clients)) { if (!client.enabled) continue; result += ` # Client: ${client.name} (${clientId}) [Peer] PublicKey = ${client.publicKey} PresharedKey = ${client.preSharedKey} AllowedIPs = ${client.allowedIPs}`; } await fs.writeFile(path.join(WG_PATH, 'wg0.json'), JSON.stringify(this.config, false, 2)); await fs.writeFile(path.join(WG_PATH, 'wg0.conf'), result); } async getClients() { return Object.entries(this.config.clients).map(([clientId, client]) => ({ id: clientId, name: client.name, enabled: client.enabled, publicKey: client.publicKey, createdAt: client.createdAt, updatedAt: client.updatedAt, allowedIPs: client.allowedIPs, // TODO: latestHandshake: new Date(), transferRx: 0, transferTx: 0, })); // const { stdout } = await Util.exec('sudo cat /etc/wireguard/configs/clients.txt'); // return stdout // .trim() // .split('\n') // .filter(line => { // return line.length > 0; // }) // .map(line => { // const [ name, publicKey, createdAt ] = line.split(' '); // return { // name, // publicKey, // createdAt: new Date(Number(createdAt + '000')), // }; // }); } async getClient({ clientId }) { const client = this.config.clients[clientId]; if (!client) { throw new ServerError(`Client Not Found: ${clientId}`, 404); } return client; } async getClientConfiguration({ clientId }) { const client = await this.getClient({ clientId }); return ` [Interface] PrivateKey = ${client.privateKey} Address = ${client.address} DNS = ${this.config.server.dns} [Peer] PublicKey = ${client.publicKey} PresharedKey = ${client.preSharedKey} AllowedIPs = ${client.allowedIPs} Endpoint = ${WG_HOST}:${WG_PORT}`; } async getClientQRCodeSVG({ clientId }) { const config = await this.getClientConfiguration({ clientId }); return QRCode.toString(config, { type: 'svg', width: 512, }); } async createClient({ name }) { if (!name) { throw new Error('Missing: Name'); } // try { // await this.getClient({ name }); // throw new Error(`Duplicate Client: ${name}`); // } catch( err ) { // if( err.message.startsWith('Duplicate Client') ) { // throw err; // } // } // // TODO: This is unsafe // await this.ssh.exec(`pivpn add -n ${name}`); // return this.getClient({ name }); await this.saveConfig(); } async deleteClient({ clientId }) { if (this.config.clients[clientId]) { delete this.config.clients[clientId]; await this.saveConfig(); } } async enableClient({ clientId }) { const client = await this.getClient({ clientId }); client.enabled = true; await this.saveConfig(); } async disableClient({ clientId }) { const client = await this.getClient({ clientId }); client.enabled = false; await this.saveConfig(); } };