wg-easy/src/lib/WireGuard.js

213 lines
5.2 KiB
JavaScript
Raw Normal View History

2021-05-23 04:21:09 +08:00
'use strict';
const fs = require('fs').promises;
const path = require('path');
const QRCode = require('qrcode');
2021-05-23 04:40:11 +08:00
const Util = require('./Util');
2021-05-23 04:21:09 +08:00
const ServerError = require('./ServerError');
const {
WG_PATH,
WG_HOST,
WG_PORT,
2021-05-23 04:40:11 +08:00
WG_DEFAULT_DNS,
2021-05-23 04:21:09 +08:00
WG_DEFAULT_ADDRESS,
} = require('../config');
module.exports = class WireGuard {
2021-05-23 04:40:11 +08:00
async getConfig() {
if (!this.__configPromise) {
this.__configPromise = Promise.resolve().then(async () => {
let config;
try {
config = await fs.readFile(path.join(WG_PATH, 'wg0.json'), 'utf8');
config = JSON.parse(config);
} catch (err) {
config = {
server: {
// TODO: Generate new config
address: WG_DEFAULT_ADDRESS,
dns: WG_DEFAULT_DNS,
},
clients: {},
};
}
return config;
});
}
2021-05-23 04:21:09 +08:00
2021-05-23 04:40:11 +08:00
return this.__configPromise;
2021-05-23 04:21:09 +08:00
}
async saveConfig() {
2021-05-23 04:40:11 +08:00
const config = await this.getConfig();
2021-05-23 04:21:09 +08:00
let result = `
# Note: Do not edit this file directly.
# Your changes will be overwritten!
# Server
[Interface]
2021-05-23 04:40:11 +08:00
PrivateKey = ${config.server.privateKey}
Address = ${config.server.address}
ListenPort = ${config.server.port}
DNS = ${config.server.dns}`;
2021-05-23 04:21:09 +08:00
2021-05-23 04:40:11 +08:00
for (const [clientId, client] of Object.entries(config.clients)) {
2021-05-23 04:21:09 +08:00
if (!client.enabled) continue;
result += `
# Client: ${client.name} (${clientId})
[Peer]
PublicKey = ${client.publicKey}
PresharedKey = ${client.preSharedKey}
AllowedIPs = ${client.allowedIPs}`;
}
2021-05-23 04:40:11 +08:00
await fs.writeFile(path.join(WG_PATH, 'wg0.json'), JSON.stringify(config, false, 2));
2021-05-23 04:21:09 +08:00
await fs.writeFile(path.join(WG_PATH, 'wg0.conf'), result);
}
async getClients() {
2021-05-23 04:40:11 +08:00
const config = await this.getConfig();
const clients = Object.entries(config.clients).map(([clientId, client]) => ({
2021-05-23 04:21:09 +08:00
id: clientId,
name: client.name,
enabled: client.enabled,
publicKey: client.publicKey,
2021-05-23 04:40:11 +08:00
createdAt: new Date(client.createdAt),
updatedAt: new Date(client.updatedAt),
2021-05-23 04:21:09 +08:00
allowedIPs: client.allowedIPs,
2021-05-23 04:40:11 +08:00
persistentKeepalive: null,
latestHandshakeAt: null,
transferRx: null,
transferTx: null,
2021-05-23 04:21:09 +08:00
}));
2021-05-23 04:40:11 +08:00
// Loop WireGuard status
// const clientsDump = await Util.exec('wg show wg0 dump');
const clientsDump = `iOQJS7OUUGPYATsX6nqlL+sOODoiWiN5IOE8Msfw/0o= BkdntwYazhYZzEEHhcYayq6TGw9/YUDQ251s+5bTgC0= 51820 off
i8xWKqicnDkNL14I4B+I1zlB8od/booA1joIosWn7X4= MzplKtOQ44/IaAKri2VKqCoIlg4XiVH7TCp5bcYRTQU= 172.17.0.1:60475 10.8.0.2/32 1621679257 7920 7440 off`;
clientsDump
.trim()
.split('\n')
.slice(1)
.forEach(line => {
const [
publicKey,
preSharedKey,
endpoint,
allowedIps,
latestHandshakeAt,
transferRx,
transferTx,
persistentKeepalive,
] = line.split('\t');
const client = clients.find(client => client.publicKey === publicKey);
console.log({ publicKey, client });
if (!client) return;
client.endpoint = endpoint === '(none)'
? null
: endpoint;
client.latestHandshakeAt = latestHandshakeAt === '0'
? null
: new Date(Number(`${latestHandshakeAt}000`));
client.transferRx = Number(transferRx);
client.transferTx = Number(transferTx);
client.persistentKeepalive = persistentKeepalive;
});
console.log('clients', clients);
return clients;
2021-05-23 04:21:09 +08:00
}
async getClient({ clientId }) {
2021-05-23 04:40:11 +08:00
const config = await this.getConfig();
const client = config.clients[clientId];
2021-05-23 04:21:09 +08:00
if (!client) {
throw new ServerError(`Client Not Found: ${clientId}`, 404);
}
return client;
}
async getClientConfiguration({ clientId }) {
2021-05-23 04:40:11 +08:00
const config = await this.getConfig();
2021-05-23 04:21:09 +08:00
const client = await this.getClient({ clientId });
return `
[Interface]
PrivateKey = ${client.privateKey}
Address = ${client.address}
2021-05-23 04:40:11 +08:00
DNS = ${config.server.dns}
2021-05-23 04:21:09 +08:00
[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 }) {
2021-05-23 04:40:11 +08:00
const config = await this.getConfig();
if (config.clients[clientId]) {
delete config.clients[clientId];
2021-05-23 04:21:09 +08:00
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();
}
};