|
@ -2,6 +2,7 @@ import fs from 'node:fs/promises'; |
|
|
import debug from 'debug'; |
|
|
import debug from 'debug'; |
|
|
import QRCode from 'qrcode'; |
|
|
import QRCode from 'qrcode'; |
|
|
import type { ID } from '#db/schema'; |
|
|
import type { ID } from '#db/schema'; |
|
|
|
|
|
import type { InterfaceType } from '#db/repositories/interface/types'; |
|
|
|
|
|
|
|
|
const WG_DEBUG = debug('WireGuard'); |
|
|
const WG_DEBUG = debug('WireGuard'); |
|
|
|
|
|
|
|
@ -10,21 +11,17 @@ class WireGuard { |
|
|
* Save and sync config |
|
|
* Save and sync config |
|
|
*/ |
|
|
*/ |
|
|
async saveConfig() { |
|
|
async saveConfig() { |
|
|
await this.#saveWireguardConfig('wg0'); |
|
|
const wgInterface = await Database.interfaces.get(); |
|
|
await this.#syncWireguardConfig('wg0'); |
|
|
await this.#saveWireguardConfig(wgInterface); |
|
|
|
|
|
await this.#syncWireguardConfig(wgInterface); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
/** |
|
|
/** |
|
|
* Generates and saves WireGuard config from database as wg0 |
|
|
* Generates and saves WireGuard config from database |
|
|
*/ |
|
|
*/ |
|
|
async #saveWireguardConfig(infName: string) { |
|
|
async #saveWireguardConfig(wgInterface: InterfaceType) { |
|
|
const wgInterface = await Database.interfaces.get(infName); |
|
|
|
|
|
const clients = await Database.clients.getAll(); |
|
|
const clients = await Database.clients.getAll(); |
|
|
const hooks = await Database.hooks.get(infName); |
|
|
const hooks = await Database.hooks.get(); |
|
|
|
|
|
|
|
|
if (!wgInterface || !hooks) { |
|
|
|
|
|
throw new Error('Interface or Hooks not found'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const result = []; |
|
|
const result = []; |
|
|
result.push(wg.generateServerInterface(wgInterface, hooks)); |
|
|
result.push(wg.generateServerInterface(wgInterface, hooks)); |
|
@ -37,19 +34,24 @@ class WireGuard { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
WG_DEBUG('Saving Config...'); |
|
|
WG_DEBUG('Saving Config...'); |
|
|
await fs.writeFile(`/etc/wireguard/${infName}.conf`, result.join('\n\n'), { |
|
|
await fs.writeFile( |
|
|
|
|
|
`/etc/wireguard/${wgInterface.name}.conf`, |
|
|
|
|
|
result.join('\n\n'), |
|
|
|
|
|
{ |
|
|
mode: 0o600, |
|
|
mode: 0o600, |
|
|
}); |
|
|
} |
|
|
|
|
|
); |
|
|
WG_DEBUG('Config saved successfully.'); |
|
|
WG_DEBUG('Config saved successfully.'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
async #syncWireguardConfig(infName: string) { |
|
|
async #syncWireguardConfig(wgInterface: InterfaceType) { |
|
|
WG_DEBUG('Syncing Config...'); |
|
|
WG_DEBUG('Syncing Config...'); |
|
|
await wg.sync(infName); |
|
|
await wg.sync(wgInterface.name); |
|
|
WG_DEBUG('Config synced successfully.'); |
|
|
WG_DEBUG('Config synced successfully.'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
async getClients() { |
|
|
async getClients() { |
|
|
|
|
|
const wgInterface = await Database.interfaces.get(); |
|
|
const dbClients = await Database.clients.getAll(); |
|
|
const dbClients = await Database.clients.getAll(); |
|
|
const clients = dbClients.map((client) => ({ |
|
|
const clients = dbClients.map((client) => ({ |
|
|
...client, |
|
|
...client, |
|
@ -60,7 +62,7 @@ class WireGuard { |
|
|
})); |
|
|
})); |
|
|
|
|
|
|
|
|
// Loop WireGuard status
|
|
|
// Loop WireGuard status
|
|
|
const dump = await wg.dump('wg0'); |
|
|
const dump = await wg.dump(wgInterface.name); |
|
|
dump.forEach( |
|
|
dump.forEach( |
|
|
({ publicKey, latestHandshakeAt, endpoint, transferRx, transferTx }) => { |
|
|
({ publicKey, latestHandshakeAt, endpoint, transferRx, transferTx }) => { |
|
|
const client = clients.find((client) => client.publicKey === publicKey); |
|
|
const client = clients.find((client) => client.publicKey === publicKey); |
|
@ -79,12 +81,8 @@ class WireGuard { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
async getClientConfiguration({ clientId }: { clientId: ID }) { |
|
|
async getClientConfiguration({ clientId }: { clientId: ID }) { |
|
|
const wgInterface = await Database.interfaces.get('wg0'); |
|
|
const wgInterface = await Database.interfaces.get(); |
|
|
const userConfig = await Database.userConfigs.get('wg0'); |
|
|
const userConfig = await Database.userConfigs.get(); |
|
|
|
|
|
|
|
|
if (!wgInterface || !userConfig) { |
|
|
|
|
|
throw new Error('Interface or UserConfig not found'); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const client = await Database.clients.get(clientId); |
|
|
const client = await Database.clients.get(clientId); |
|
|
|
|
|
|
|
@ -124,11 +122,8 @@ class WireGuard { |
|
|
|
|
|
|
|
|
async Startup() { |
|
|
async Startup() { |
|
|
WG_DEBUG('Starting WireGuard...'); |
|
|
WG_DEBUG('Starting WireGuard...'); |
|
|
const wgInterfaces = await Database.interfaces.getAll(); |
|
|
const wgInterface = await Database.interfaces.get(); |
|
|
for (const wgInterface of wgInterfaces) { |
|
|
|
|
|
if (wgInterface.enabled !== true) { |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
// default interface has no keys
|
|
|
// default interface has no keys
|
|
|
if ( |
|
|
if ( |
|
|
wgInterface.privateKey === '---default---' && |
|
|
wgInterface.privateKey === '---default---' && |
|
@ -138,15 +133,11 @@ class WireGuard { |
|
|
const privateKey = await wg.generatePrivateKey(); |
|
|
const privateKey = await wg.generatePrivateKey(); |
|
|
const publicKey = await wg.getPublicKey(privateKey); |
|
|
const publicKey = await wg.getPublicKey(privateKey); |
|
|
|
|
|
|
|
|
await Database.interfaces.updateKeyPair( |
|
|
await Database.interfaces.updateKeyPair(privateKey, publicKey); |
|
|
wgInterface.name, |
|
|
|
|
|
privateKey, |
|
|
|
|
|
publicKey |
|
|
|
|
|
); |
|
|
|
|
|
WG_DEBUG('New Wireguard Keys generated successfully.'); |
|
|
WG_DEBUG('New Wireguard Keys generated successfully.'); |
|
|
} |
|
|
} |
|
|
WG_DEBUG(`Starting Wireguard Interface ${wgInterface.name}...`); |
|
|
WG_DEBUG(`Starting Wireguard Interface ${wgInterface.name}...`); |
|
|
await this.#saveWireguardConfig(wgInterface.name); |
|
|
await this.#saveWireguardConfig(wgInterface); |
|
|
await wg.down(wgInterface.name).catch(() => {}); |
|
|
await wg.down(wgInterface.name).catch(() => {}); |
|
|
await wg.up(wgInterface.name).catch((err) => { |
|
|
await wg.up(wgInterface.name).catch((err) => { |
|
|
if ( |
|
|
if ( |
|
@ -162,9 +153,8 @@ class WireGuard { |
|
|
|
|
|
|
|
|
throw err; |
|
|
throw err; |
|
|
}); |
|
|
}); |
|
|
await this.#syncWireguardConfig(wgInterface.name); |
|
|
await this.#syncWireguardConfig(wgInterface); |
|
|
WG_DEBUG(`Wireguard Interface ${wgInterface.name} started successfully.`); |
|
|
WG_DEBUG(`Wireguard Interface ${wgInterface.name} started successfully.`); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
WG_DEBUG('Starting Cron Job...'); |
|
|
WG_DEBUG('Starting Cron Job...'); |
|
|
await this.startCronJob(); |
|
|
await this.startCronJob(); |
|
@ -184,11 +174,9 @@ class WireGuard { |
|
|
|
|
|
|
|
|
// Shutdown wireguard
|
|
|
// Shutdown wireguard
|
|
|
async Shutdown() { |
|
|
async Shutdown() { |
|
|
const wgInterfaces = await Database.interfaces.getAll(); |
|
|
const wgInterface = await Database.interfaces.get(); |
|
|
for (const wgInterface of wgInterfaces) { |
|
|
|
|
|
await wg.down(wgInterface.name).catch(() => {}); |
|
|
await wg.down(wgInterface.name).catch(() => {}); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
async cronJob() { |
|
|
async cronJob() { |
|
|
const clients = await Database.clients.getAll(); |
|
|
const clients = await Database.clients.getAll(); |
|
|