This commit is contained in:
Emile Nijssen 2021-05-22 22:40:11 +02:00
parent d7bb645470
commit d8f45476da
6 changed files with 104 additions and 63 deletions

View File

@ -6,3 +6,4 @@ module.exports.WG_PATH = process.env.WG_PATH || '/etc/wireguard/';
module.exports.WG_HOST = process.env.WG_HOST || '127.0.0.1';
module.exports.WG_PORT = process.env.WG_PORT || 51820;
module.exports.WG_DEFAULT_ADDRESS = process.env.WG_DEFAULT_ADDRESS || '10.6.0.1/32';
module.exports.WG_DEFAULT_DNS = process.env.WG_DEFAULT_DNS || '1.1.1.1';

View File

@ -15,11 +15,13 @@ const {
PASSWORD,
} = require('../config');
WireGuard.getClients().then(console.log);
module.exports = class Server {
constructor() {
// Express
this.app = express()
.disable('etag')
.use('/', express.static(path.join(__dirname, '..', 'www')))
.use(express.json())
.use(expressSession({

View File

@ -5,58 +5,58 @@ const path = require('path');
const QRCode = require('qrcode');
const Util = require('./Util');
const ServerError = require('./ServerError');
const {
WG_PATH,
WG_HOST,
WG_PORT,
WG_DEFAULT_DNS,
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
}
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: {},
};
}
console.log('this.config', this.config);
return 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);
});
return this.__configPromise;
}
async saveConfig() {
const config = await this.getConfig();
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}`;
PrivateKey = ${config.server.privateKey}
Address = ${config.server.address}
ListenPort = ${config.server.port}
DNS = ${config.server.dns}`;
for (const [clientId, client] of Object.entries(this.config.clients)) {
for (const [clientId, client] of Object.entries(config.clients)) {
if (!client.enabled) continue;
result += `
@ -68,44 +68,70 @@ 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.json'), JSON.stringify(config, false, 2));
await fs.writeFile(path.join(WG_PATH, 'wg0.conf'), result);
}
async getClients() {
return Object.entries(this.config.clients).map(([clientId, client]) => ({
const config = await this.getConfig();
const clients = Object.entries(config.clients).map(([clientId, client]) => ({
id: clientId,
name: client.name,
enabled: client.enabled,
publicKey: client.publicKey,
createdAt: client.createdAt,
updatedAt: client.updatedAt,
createdAt: new Date(client.createdAt),
updatedAt: new Date(client.updatedAt),
allowedIPs: client.allowedIPs,
// TODO:
latestHandshake: new Date(),
transferRx: 0,
transferTx: 0,
persistentKeepalive: null,
latestHandshakeAt: null,
transferRx: null,
transferTx: null,
}));
// 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')),
// };
// });
// 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;
}
async getClient({ clientId }) {
const client = this.config.clients[clientId];
const config = await this.getConfig();
const client = config.clients[clientId];
if (!client) {
throw new ServerError(`Client Not Found: ${clientId}`, 404);
}
@ -114,13 +140,14 @@ AllowedIPs = ${client.allowedIPs}`;
}
async getClientConfiguration({ clientId }) {
const config = await this.getConfig();
const client = await this.getClient({ clientId });
return `
[Interface]
PrivateKey = ${client.privateKey}
Address = ${client.address}
DNS = ${this.config.server.dns}
DNS = ${config.server.dns}
[Peer]
PublicKey = ${client.publicKey}
@ -160,8 +187,10 @@ Endpoint = ${WG_HOST}:${WG_PORT}`;
}
async deleteClient({ clientId }) {
if (this.config.clients[clientId]) {
delete this.config.clients[clientId];
const config = await this.getConfig();
if (config.clients[clientId]) {
delete config.clients[clientId];
await this.saveConfig();
}
}

View File

@ -51,7 +51,8 @@
</svg>
<img v-if="client.avatar" :src="client.avatar" class="w-10 rounded-full absolute top-0 left-0" />
<div v-if="client.latestHandshake && ((new Date() - new Date(client.latestHandshake) < 1000 * 60 * 10))">
<div
v-if="client.latestHandshakeAt && ((new Date() - new Date(client.latestHandshakeAt) < 1000 * 60 * 10))">
<div class="animate-ping w-4 h-4 p-1 bg-green-100 rounded-full absolute -bottom-1 -right-1"></div>
<div class="w-2 h-2 bg-green-300 rounded-full absolute bottom-0 right-0"></div>
</div>
@ -60,8 +61,7 @@
<div class="flex-grow">
<div class="text-gray-700" :title="'Created at ' + dateTime(new Date(client.createdAt))">{{client.name}}
</div>
<div v-if="client.allowedIps" class="text-gray-300 text-xs">{{client.iface}}
· {{client.allowedIps.split('/')[0]}}
<div v-if="client.allowedIPs" class="text-gray-300 text-xs">{{client.allowedIPs.split('/')[0]}}
<span v-if="client.transferTx" title="Download">
·
<svg class="align-middle h-3 inline" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"
@ -82,9 +82,9 @@
</svg>
{{client.transferRx | bytes}}
</span>
<span v-if="client.latestHandshake"
:title="'Last seen at ' + dateTime(new Date(client.latestHandshake))">
· {{new Date(client.latestHandshake) | timeago}}
<span v-if="client.latestHandshakeAt"
:title="'Last seen at ' + dateTime(new Date(client.latestHandshakeAt))">
· {{new Date(client.latestHandshakeAt) | timeago}}
</span>
</div>
</div>

View File

@ -55,7 +55,14 @@ class API {
return this.call({
method: 'get',
path: '/wireguard/client',
});
}).then(clients => clients.map(client => ({
...client,
createdAt: new Date(client.createdAt),
updatedAt: new Date(client.updatedAt),
latestHandshakeAt: client.latestHandshakeAt !== null
? new Date(client.latestHandshakeAt)
: null,
})));
}
async createClient({ name }) {

View File

@ -39,6 +39,8 @@ new Vue({
return client;
});
console.log(clients);
},
login(e) {
e.preventDefault();