|
|
@ -1,127 +1,39 @@ |
|
|
|
import fs from 'node:fs/promises'; |
|
|
|
import path from 'path'; |
|
|
|
import debug_logger from 'debug'; |
|
|
|
import debug from 'debug'; |
|
|
|
import crypto from 'node:crypto'; |
|
|
|
import QRCode from 'qrcode'; |
|
|
|
import CRC32 from 'crc-32'; |
|
|
|
|
|
|
|
const debug = debug_logger('WireGuard'); |
|
|
|
|
|
|
|
type Server = { |
|
|
|
privateKey: string; |
|
|
|
publicKey: string; |
|
|
|
address: string; |
|
|
|
}; |
|
|
|
|
|
|
|
type Client = { |
|
|
|
id: string; |
|
|
|
name: string; |
|
|
|
address: string; |
|
|
|
privateKey: string; |
|
|
|
publicKey: string; |
|
|
|
preSharedKey: string; |
|
|
|
createdAt: string; |
|
|
|
updatedAt: string; |
|
|
|
expireAt: string | null; |
|
|
|
endpoint: string | null; |
|
|
|
enabled: boolean; |
|
|
|
allowedIPs?: never; |
|
|
|
oneTimeLink: string | null; |
|
|
|
oneTimeLinkExpiresAt: string | null; |
|
|
|
}; |
|
|
|
|
|
|
|
type Config = { |
|
|
|
server: Server; |
|
|
|
clients: Record<string, Client>; |
|
|
|
}; |
|
|
|
import type { NewClient } from '~~/services/database/repositories/client'; |
|
|
|
|
|
|
|
class WireGuard { |
|
|
|
#configCache: Config | null = null; |
|
|
|
async __buildConfig() { |
|
|
|
if (!WG_HOST) { |
|
|
|
throw new Error('WG_HOST Environment Variable Not Set!'); |
|
|
|
} |
|
|
|
|
|
|
|
debug('Loading configuration...'); |
|
|
|
this.#configCache = null; |
|
|
|
try { |
|
|
|
const config = await fs.readFile(path.join(WG_PATH, 'wg0.json'), 'utf8'); |
|
|
|
const parsedConfig = JSON.parse(config); |
|
|
|
debug('Configuration loaded.'); |
|
|
|
return parsedConfig as Config; |
|
|
|
} catch { |
|
|
|
const privateKey = await exec('wg genkey'); |
|
|
|
const publicKey = await exec(`echo ${privateKey} | wg pubkey`, { |
|
|
|
log: 'echo ***hidden*** | wg pubkey', |
|
|
|
}); |
|
|
|
const address = WG_DEFAULT_ADDRESS.replace('x', '1'); |
|
|
|
|
|
|
|
const config: Config = { |
|
|
|
server: { |
|
|
|
privateKey, |
|
|
|
publicKey, |
|
|
|
address, |
|
|
|
}, |
|
|
|
clients: {}, |
|
|
|
}; |
|
|
|
debug('Configuration generated.'); |
|
|
|
return config; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async getConfig(): Promise<Config> { |
|
|
|
if (this.#configCache !== null) { |
|
|
|
return this.#configCache; |
|
|
|
} |
|
|
|
const config = await this.__buildConfig(); |
|
|
|
|
|
|
|
await this.__saveConfig(config); |
|
|
|
await exec('wg-quick down wg0').catch(() => {}); |
|
|
|
await exec('wg-quick up wg0').catch((err) => { |
|
|
|
if ( |
|
|
|
err && |
|
|
|
err.message && |
|
|
|
err.message.includes('Cannot find device "wg0"') |
|
|
|
) { |
|
|
|
throw new Error( |
|
|
|
'WireGuard exited with the error: Cannot find device "wg0"\nThis usually means that your host\'s kernel does not support WireGuard!' |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
throw err; |
|
|
|
}); |
|
|
|
// await Util.exec(`iptables -t nat -A POSTROUTING -s ${WG_DEFAULT_ADDRESS.replace('x', '0')}/24 -o ' + WG_DEVICE + ' -j MASQUERADE`);
|
|
|
|
// await Util.exec('iptables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT');
|
|
|
|
// await Util.exec('iptables -A FORWARD -i wg0 -j ACCEPT');
|
|
|
|
// await Util.exec('iptables -A FORWARD -o wg0 -j ACCEPT');
|
|
|
|
await this.__syncConfig(); |
|
|
|
this.#configCache = config; |
|
|
|
return this.#configCache; |
|
|
|
} |
|
|
|
const DEBUG = debug('WireGuard'); |
|
|
|
|
|
|
|
class WireGuard { |
|
|
|
async saveConfig() { |
|
|
|
const config = await this.getConfig(); |
|
|
|
await this.__saveConfig(config); |
|
|
|
await this.__syncConfig(); |
|
|
|
await this.#saveWireguardConfig(); |
|
|
|
await this.#syncWireguardConfig(); |
|
|
|
} |
|
|
|
|
|
|
|
async __saveConfig(config: Config) { |
|
|
|
async #saveWireguardConfig() { |
|
|
|
const system = await Database.getSystem(); |
|
|
|
const clients = await Database.getClients(); |
|
|
|
let result = ` |
|
|
|
# Note: Do not edit this file directly. |
|
|
|
# Your changes will be overwritten! |
|
|
|
|
|
|
|
# Server |
|
|
|
[Interface] |
|
|
|
PrivateKey = ${config.server.privateKey} |
|
|
|
Address = ${config.server.address}/24 |
|
|
|
ListenPort = ${WG_PORT} |
|
|
|
PreUp = ${WG_PRE_UP} |
|
|
|
PostUp = ${WG_POST_UP} |
|
|
|
PreDown = ${WG_PRE_DOWN} |
|
|
|
PostDown = ${WG_POST_DOWN} |
|
|
|
PrivateKey = ${system.interface.privateKey} |
|
|
|
Address = ${system.interface.address}/24 |
|
|
|
ListenPort = ${system.wgPort} |
|
|
|
PreUp = ${system.iptables.PreUp} |
|
|
|
PostUp = ${system.iptables.PostUp} |
|
|
|
PreDown = ${system.iptables.PreDown} |
|
|
|
PostDown = ${system.iptables.PostDown} |
|
|
|
`;
|
|
|
|
|
|
|
|
for (const [clientId, client] of Object.entries(config.clients)) { |
|
|
|
for (const [clientId, client] of Object.entries(clients)) { |
|
|
|
if (!client.enabled) continue; |
|
|
|
|
|
|
|
result += ` |
|
|
@ -134,49 +46,39 @@ ${ |
|
|
|
}AllowedIPs = ${client.address}/32`;
|
|
|
|
} |
|
|
|
|
|
|
|
debug('Config saving...'); |
|
|
|
await fs.writeFile( |
|
|
|
path.join(WG_PATH, 'wg0.json'), |
|
|
|
JSON.stringify(config, undefined, 2), |
|
|
|
{ |
|
|
|
mode: 0o660, |
|
|
|
} |
|
|
|
); |
|
|
|
await fs.writeFile(path.join(WG_PATH, 'wg0.conf'), result, { |
|
|
|
DEBUG('Config saving...'); |
|
|
|
await fs.writeFile(path.join('/etc/wireguard', 'wg0.conf'), result, { |
|
|
|
mode: 0o600, |
|
|
|
}); |
|
|
|
debug('Config saved.'); |
|
|
|
DEBUG('Config saved.'); |
|
|
|
} |
|
|
|
|
|
|
|
async __syncConfig() { |
|
|
|
debug('Config syncing...'); |
|
|
|
async #syncWireguardConfig() { |
|
|
|
DEBUG('Config syncing...'); |
|
|
|
await exec('wg syncconf wg0 <(wg-quick strip wg0)'); |
|
|
|
debug('Config synced.'); |
|
|
|
DEBUG('Config synced.'); |
|
|
|
} |
|
|
|
|
|
|
|
async getClients() { |
|
|
|
const config = await this.getConfig(); |
|
|
|
const clients = Object.entries(config.clients).map( |
|
|
|
([clientId, client]) => ({ |
|
|
|
id: clientId, |
|
|
|
name: client.name, |
|
|
|
enabled: client.enabled, |
|
|
|
address: client.address, |
|
|
|
publicKey: client.publicKey, |
|
|
|
createdAt: new Date(client.createdAt), |
|
|
|
updatedAt: new Date(client.updatedAt), |
|
|
|
expireAt: client.expireAt !== null ? new Date(client.expireAt) : null, |
|
|
|
allowedIPs: client.allowedIPs, |
|
|
|
oneTimeLink: client.oneTimeLink ?? null, |
|
|
|
oneTimeLinkExpiresAt: client.oneTimeLinkExpiresAt ?? null, |
|
|
|
downloadableConfig: 'privateKey' in client, |
|
|
|
persistentKeepalive: null as string | null, |
|
|
|
latestHandshakeAt: null as Date | null, |
|
|
|
endpoint: null as string | null, |
|
|
|
transferRx: null as number | null, |
|
|
|
transferTx: null as number | null, |
|
|
|
}) |
|
|
|
); |
|
|
|
const dbClients = await Database.getClients(); |
|
|
|
const clients = Object.entries(dbClients).map(([clientId, client]) => ({ |
|
|
|
id: clientId, |
|
|
|
name: client.name, |
|
|
|
enabled: client.enabled, |
|
|
|
address: client.address, |
|
|
|
publicKey: client.publicKey, |
|
|
|
createdAt: new Date(client.createdAt), |
|
|
|
updatedAt: new Date(client.updatedAt), |
|
|
|
expiresAt: client.expiresAt, |
|
|
|
allowedIPs: client.allowedIPs, |
|
|
|
oneTimeLink: client.oneTimeLink, |
|
|
|
downloadableConfig: 'privateKey' in client, |
|
|
|
persistentKeepalive: null as string | null, |
|
|
|
latestHandshakeAt: null as Date | null, |
|
|
|
endpoint: null as string | null, |
|
|
|
transferRx: null as number | null, |
|
|
|
transferTx: null as number | null, |
|
|
|
})); |
|
|
|
|
|
|
|
// Loop WireGuard status
|
|
|
|
const dump = await exec('wg show wg0 dump', { |
|
|
@ -215,8 +117,7 @@ ${ |
|
|
|
} |
|
|
|
|
|
|
|
async getClient({ clientId }: { clientId: string }) { |
|
|
|
const config = await this.getConfig(); |
|
|
|
const client = config.clients[clientId]; |
|
|
|
const client = await Database.getClient(clientId); |
|
|
|
if (!client) { |
|
|
|
throw createError({ |
|
|
|
statusCode: 404, |
|
|
@ -228,23 +129,22 @@ ${ |
|
|
|
} |
|
|
|
|
|
|
|
async getClientConfiguration({ clientId }: { clientId: string }) { |
|
|
|
const config = await this.getConfig(); |
|
|
|
const system = await Database.getSystem(); |
|
|
|
const client = await this.getClient({ clientId }); |
|
|
|
|
|
|
|
return ` |
|
|
|
[Interface] |
|
|
|
PrivateKey = ${client.privateKey ? `${client.privateKey}` : 'REPLACE_ME'} |
|
|
|
Address = ${client.address}/24 |
|
|
|
${WG_DEFAULT_DNS ? `DNS = ${WG_DEFAULT_DNS}\n` : ''}\ |
|
|
|
${WG_MTU ? `MTU = ${WG_MTU}\n` : ''}\ |
|
|
|
DNS = ${system.userConfig.defaultDns.join(',')} |
|
|
|
MTU = ${system.userConfig.mtu} |
|
|
|
|
|
|
|
[Peer] |
|
|
|
PublicKey = ${config.server.publicKey} |
|
|
|
${ |
|
|
|
client.preSharedKey ? `PresharedKey = ${client.preSharedKey}\n` : '' |
|
|
|
}AllowedIPs = ${WG_ALLOWED_IPS} |
|
|
|
PersistentKeepalive = ${WG_PERSISTENT_KEEPALIVE} |
|
|
|
Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`;
|
|
|
|
PublicKey = ${system.interface.publicKey} |
|
|
|
PresharedKey = ${client.preSharedKey} |
|
|
|
AllowedIPs = ${client.allowedIPs} |
|
|
|
PersistentKeepalive = ${client.persistentKeepalive} |
|
|
|
Endpoint = ${system.wgHost}:${system.wgConfigPort}`;
|
|
|
|
} |
|
|
|
|
|
|
|
async getClientQRCodeSVG({ clientId }: { clientId: string }) { |
|
|
@ -266,7 +166,8 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`; |
|
|
|
throw new Error('Missing: Name'); |
|
|
|
} |
|
|
|
|
|
|
|
const config = await this.getConfig(); |
|
|
|
const system = await Database.getSystem(); |
|
|
|
const clients = await Database.getClients(); |
|
|
|
|
|
|
|
const privateKey = await exec('wg genkey'); |
|
|
|
const publicKey = await exec(`echo ${privateKey} | wg pubkey`, { |
|
|
@ -274,15 +175,19 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`; |
|
|
|
}); |
|
|
|
const preSharedKey = await exec('wg genpsk'); |
|
|
|
|
|
|
|
// TODO: cidr
|
|
|
|
// Calculate next IP
|
|
|
|
let address; |
|
|
|
for (let i = 2; i < 255; i++) { |
|
|
|
const client = Object.values(config.clients).find((client) => { |
|
|
|
return client.address === WG_DEFAULT_ADDRESS.replace('x', i.toString()); |
|
|
|
const client = Object.values(clients).find((client) => { |
|
|
|
return ( |
|
|
|
client.address === |
|
|
|
system.userConfig.addressRange.replace('x', i.toString()) |
|
|
|
); |
|
|
|
}); |
|
|
|
|
|
|
|
if (!client) { |
|
|
|
address = WG_DEFAULT_ADDRESS.replace('x', i.toString()); |
|
|
|
address = system.userConfig.addressRange.replace('x', i.toString()); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
@ -293,22 +198,20 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`; |
|
|
|
|
|
|
|
// Create Client
|
|
|
|
const id = crypto.randomUUID(); |
|
|
|
const client: Client = { |
|
|
|
|
|
|
|
const client: NewClient = { |
|
|
|
id, |
|
|
|
name, |
|
|
|
address, |
|
|
|
privateKey, |
|
|
|
publicKey, |
|
|
|
preSharedKey, |
|
|
|
|
|
|
|
createdAt: new Date().toISOString(), |
|
|
|
updatedAt: new Date().toISOString(), |
|
|
|
|
|
|
|
endpoint: null, |
|
|
|
oneTimeLink: null, |
|
|
|
oneTimeLinkExpiresAt: null, |
|
|
|
expireAt: null, |
|
|
|
expiresAt: null, |
|
|
|
enabled: true, |
|
|
|
allowedIPs: system.userConfig.allowedIps, |
|
|
|
persistentKeepalive: system.userConfig.persistentKeepalive, |
|
|
|
}; |
|
|
|
|
|
|
|
if (expireDate) { |
|
|
@ -316,10 +219,10 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`; |
|
|
|
date.setHours(23); |
|
|
|
date.setMinutes(59); |
|
|
|
date.setSeconds(59); |
|
|
|
client.expireAt = date.toISOString(); |
|
|
|
client.expiresAt = date; |
|
|
|
} |
|
|
|
|
|
|
|
config.clients[id] = client; |
|
|
|
await Database.createClient(client); |
|
|
|
|
|
|
|
await this.saveConfig(); |
|
|
|
|
|
|
@ -327,48 +230,34 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`; |
|
|
|
} |
|
|
|
|
|
|
|
async deleteClient({ clientId }: { clientId: string }) { |
|
|
|
const config = await this.getConfig(); |
|
|
|
|
|
|
|
if (config.clients[clientId]) { |
|
|
|
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
|
|
|
|
delete config.clients[clientId]; |
|
|
|
await this.saveConfig(); |
|
|
|
} |
|
|
|
await Database.deleteClient(clientId); |
|
|
|
await this.saveConfig(); |
|
|
|
} |
|
|
|
|
|
|
|
async enableClient({ clientId }: { clientId: string }) { |
|
|
|
const client = await this.getClient({ clientId }); |
|
|
|
|
|
|
|
client.enabled = true; |
|
|
|
client.updatedAt = new Date().toISOString(); |
|
|
|
await Database.toggleClient(clientId, true); |
|
|
|
|
|
|
|
await this.saveConfig(); |
|
|
|
} |
|
|
|
|
|
|
|
async generateOneTimeLink({ clientId }: { clientId: string }) { |
|
|
|
const client = await this.getClient({ clientId }); |
|
|
|
const key = `${clientId}-${Math.floor(Math.random() * 1000)}`; |
|
|
|
client.oneTimeLink = Math.abs(CRC32.str(key)).toString(16); |
|
|
|
client.oneTimeLinkExpiresAt = new Date( |
|
|
|
Date.now() + 5 * 60 * 1000 |
|
|
|
).toISOString(); |
|
|
|
client.updatedAt = new Date().toISOString(); |
|
|
|
const oneTimeLink = Math.abs(CRC32.str(key)).toString(16); |
|
|
|
const expiresAt = new Date(Date.now() + 5 * 60 * 1000); |
|
|
|
await Database.createOneTimeLink(clientId, { |
|
|
|
oneTimeLink, |
|
|
|
expiresAt, |
|
|
|
}); |
|
|
|
await this.saveConfig(); |
|
|
|
} |
|
|
|
|
|
|
|
async eraseOneTimeLink({ clientId }: { clientId: string }) { |
|
|
|
const client = await this.getClient({ clientId }); |
|
|
|
client.oneTimeLink = null; |
|
|
|
client.oneTimeLinkExpiresAt = null; |
|
|
|
client.updatedAt = new Date().toISOString(); |
|
|
|
await Database.deleteOneTimeLink(clientId); |
|
|
|
await this.saveConfig(); |
|
|
|
} |
|
|
|
|
|
|
|
async disableClient({ clientId }: { clientId: string }) { |
|
|
|
const client = await this.getClient({ clientId }); |
|
|
|
|
|
|
|
client.enabled = false; |
|
|
|
client.updatedAt = new Date().toISOString(); |
|
|
|
await Database.toggleClient(clientId, false); |
|
|
|
|
|
|
|
await this.saveConfig(); |
|
|
|
} |
|
|
@ -380,10 +269,7 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`; |
|
|
|
clientId: string; |
|
|
|
name: string; |
|
|
|
}) { |
|
|
|
const client = await this.getClient({ clientId }); |
|
|
|
|
|
|
|
client.name = name; |
|
|
|
client.updatedAt = new Date().toISOString(); |
|
|
|
await Database.updateClientName(clientId, name); |
|
|
|
|
|
|
|
await this.saveConfig(); |
|
|
|
} |
|
|
@ -395,8 +281,6 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`; |
|
|
|
clientId: string; |
|
|
|
address: string; |
|
|
|
}) { |
|
|
|
const client = await this.getClient({ clientId }); |
|
|
|
|
|
|
|
if (!isValidIPv4(address)) { |
|
|
|
throw createError({ |
|
|
|
statusCode: 400, |
|
|
@ -404,8 +288,7 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`; |
|
|
|
}); |
|
|
|
} |
|
|
|
|
|
|
|
client.address = address; |
|
|
|
client.updatedAt = new Date().toISOString(); |
|
|
|
await Database.updateClientAddress(clientId, address); |
|
|
|
|
|
|
|
await this.saveConfig(); |
|
|
|
} |
|
|
@ -417,42 +300,81 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`; |
|
|
|
clientId: string; |
|
|
|
expireDate: string | null; |
|
|
|
}) { |
|
|
|
const client = await this.getClient({ clientId }); |
|
|
|
let updatedDate: Date | null = null; |
|
|
|
|
|
|
|
if (expireDate) { |
|
|
|
const date = new Date(expireDate); |
|
|
|
date.setHours(23); |
|
|
|
date.setMinutes(59); |
|
|
|
date.setSeconds(59); |
|
|
|
client.expireAt = date.toISOString(); |
|
|
|
} else { |
|
|
|
client.expireAt = null; |
|
|
|
updatedDate = date; |
|
|
|
} |
|
|
|
client.updatedAt = new Date().toISOString(); |
|
|
|
|
|
|
|
await this.saveConfig(); |
|
|
|
} |
|
|
|
await Database.updateClientExpirationDate(clientId, updatedDate); |
|
|
|
|
|
|
|
async __reloadConfig() { |
|
|
|
await this.__buildConfig(); |
|
|
|
await this.__syncConfig(); |
|
|
|
await this.saveConfig(); |
|
|
|
} |
|
|
|
|
|
|
|
async restoreConfiguration(config: string) { |
|
|
|
debug('Starting configuration restore process.'); |
|
|
|
// TODO: reimplement database restore
|
|
|
|
async restoreConfiguration(_config: string) { |
|
|
|
/* DEBUG('Starting configuration restore process.'); |
|
|
|
// TODO: sanitize config
|
|
|
|
const _config = JSON.parse(config); |
|
|
|
await this.__saveConfig(_config); |
|
|
|
await this.__reloadConfig(); |
|
|
|
debug('Configuration restore process completed.'); |
|
|
|
DEBUG('Configuration restore process completed.'); */ |
|
|
|
} |
|
|
|
|
|
|
|
// TODO: reimplement database restore
|
|
|
|
async backupConfiguration() { |
|
|
|
debug('Starting configuration backup.'); |
|
|
|
/* DEBUG('Starting configuration backup.'); |
|
|
|
const config = await this.getConfig(); |
|
|
|
const backup = JSON.stringify(config, null, 2); |
|
|
|
debug('Configuration backup completed.'); |
|
|
|
return backup; |
|
|
|
DEBUG('Configuration backup completed.'); |
|
|
|
return backup; */ |
|
|
|
} |
|
|
|
|
|
|
|
async Startup() { |
|
|
|
// TODO: improve this
|
|
|
|
await new Promise((res) => { |
|
|
|
function wait() { |
|
|
|
if (Database.connected) { |
|
|
|
return res(true); |
|
|
|
} |
|
|
|
} |
|
|
|
setTimeout(wait, 1000); |
|
|
|
}); |
|
|
|
DEBUG('Starting Wireguard'); |
|
|
|
await this.#saveWireguardConfig(); |
|
|
|
await exec('wg-quick down wg0').catch(() => {}); |
|
|
|
await exec('wg-quick up wg0').catch((err) => { |
|
|
|
if ( |
|
|
|
err && |
|
|
|
err.message && |
|
|
|
err.message.includes('Cannot find device "wg0"') |
|
|
|
) { |
|
|
|
throw new Error( |
|
|
|
'WireGuard exited with the error: Cannot find device "wg0"\nThis usually means that your host\'s kernel does not support WireGuard!' |
|
|
|
); |
|
|
|
} |
|
|
|
|
|
|
|
throw err; |
|
|
|
}); |
|
|
|
await this.#syncWireguardConfig(); |
|
|
|
DEBUG('Wireguard started successfully'); |
|
|
|
|
|
|
|
DEBUG('Starting Cron Job'); |
|
|
|
await this.startCronJob(); |
|
|
|
} |
|
|
|
|
|
|
|
async startCronJob() { |
|
|
|
await this.cronJob().catch((err) => { |
|
|
|
DEBUG('Running Cron Job failed.'); |
|
|
|
console.error(err); |
|
|
|
}); |
|
|
|
setTimeout(() => { |
|
|
|
this.startCronJob(); |
|
|
|
}, 60 * 1000); |
|
|
|
} |
|
|
|
|
|
|
|
// Shutdown wireguard
|
|
|
@ -460,47 +382,31 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`; |
|
|
|
await exec('wg-quick down wg0').catch(() => {}); |
|
|
|
} |
|
|
|
|
|
|
|
async cronJobEveryMinute() { |
|
|
|
const config = await this.getConfig(); |
|
|
|
async cronJob() { |
|
|
|
const clients = await Database.getClients(); |
|
|
|
const system = await Database.getSystem(); |
|
|
|
if (!system) { |
|
|
|
throw new Error('Invalid Database'); |
|
|
|
} |
|
|
|
let needSaveConfig = false; |
|
|
|
// Expires Feature
|
|
|
|
if (system.clientExpiration.enabled) { |
|
|
|
for (const client of Object.values(config.clients)) { |
|
|
|
for (const client of Object.values(clients)) { |
|
|
|
if (client.enabled !== true) continue; |
|
|
|
if ( |
|
|
|
client.expireAt !== null && |
|
|
|
new Date() > new Date(client.expireAt) |
|
|
|
) { |
|
|
|
debug(`Client ${client.id} expired.`); |
|
|
|
needSaveConfig = true; |
|
|
|
client.enabled = false; |
|
|
|
client.updatedAt = new Date().toISOString(); |
|
|
|
if (client.expiresAt !== null && new Date() > client.expiresAt) { |
|
|
|
DEBUG(`Client ${client.id} expired.`); |
|
|
|
await Database.toggleClient(client.id, false); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
// One Time Link Feature
|
|
|
|
if (system.oneTimeLinks.enabled) { |
|
|
|
for (const client of Object.values(config.clients)) { |
|
|
|
for (const client of Object.values(clients)) { |
|
|
|
if ( |
|
|
|
client.oneTimeLink !== null && |
|
|
|
client.oneTimeLinkExpiresAt !== null && |
|
|
|
new Date() > new Date(client.oneTimeLinkExpiresAt) |
|
|
|
new Date() > client.oneTimeLink.expiresAt |
|
|
|
) { |
|
|
|
debug(`Client ${client.id} One Time Link expired.`); |
|
|
|
needSaveConfig = true; |
|
|
|
client.oneTimeLink = null; |
|
|
|
client.oneTimeLinkExpiresAt = null; |
|
|
|
client.updatedAt = new Date().toISOString(); |
|
|
|
DEBUG(`Client ${client.id} One Time Link expired.`); |
|
|
|
await Database.deleteOneTimeLink(client.id); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (needSaveConfig) { |
|
|
|
await this.saveConfig(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
async getMetrics() { |
|
|
@ -578,15 +484,9 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`; |
|
|
|
} |
|
|
|
|
|
|
|
const inst = new WireGuard(); |
|
|
|
|
|
|
|
// This also has to also start the WireGuard Server
|
|
|
|
async function cronJobEveryMinute() { |
|
|
|
await inst.cronJobEveryMinute().catch((err) => { |
|
|
|
debug('Running Cron Job failed.'); |
|
|
|
console.error(err); |
|
|
|
}); |
|
|
|
setTimeout(cronJobEveryMinute, 60 * 1000); |
|
|
|
} |
|
|
|
cronJobEveryMinute(); |
|
|
|
inst.Startup().catch((v) => { |
|
|
|
console.error(v); |
|
|
|
process.exit(1); |
|
|
|
}); |
|
|
|
|
|
|
|
export default inst; |
|
|
|