diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 625946b..038e23d 100644 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -12,7 +12,7 @@ ulimit -c 0 # Checking if there is /data folder if [ ! -d "/data" ]; then mkdir -p /data - chmod 744 /data + chmod 700 /data fi # Starting Redis server in detached mode @@ -26,4 +26,7 @@ if [ ! -z "$WG_HOST" ]; then export NEXT_PUBLIC_WG_HOST=$WG_HOST fi +# After 5 seconds, export the database to the WireGuard config file +screen -dm bash -c "sleep 5; curl -s -o /dev/null http://127.0.0.1:3000/api/wireguard/regen" + exec "$@" diff --git a/src/lib/shell.ts b/src/lib/shell.ts index ec005f4..4b100dc 100644 --- a/src/lib/shell.ts +++ b/src/lib/shell.ts @@ -4,7 +4,7 @@ export default class Shell { public static async exec(command: string, safe: boolean = false, ...args: string[]): Promise { if (process.platform !== 'linux') { - throw new Error('This program is not meant to run on UNIX systems'); + throw new Error('This program is not meant to run non UNIX systems'); } return new Promise(async (resolve, reject) => { const cmd = `${command}${args.length > 0 ? ` ${args.join(' ')}` : ''}`; diff --git a/src/lib/utils.ts b/src/lib/utils.ts index 3ef41e1..a4f3a3d 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -39,3 +39,7 @@ export function isPrivateIP(ip: string) { const ipRegex = /^(127\.)|(10\.)|(172\.1[6-9]\.)|(172\.2[0-9]\.)|(172\.3[0-1]\.)|(192\.168\.)/ return ipRegex.test(ip) } + +export function dynaJoin(lines: (string | 0 | null | undefined)[]): string[] { + return lines.filter((d) => typeof d === 'string') as string[] +} \ No newline at end of file diff --git a/src/lib/wireguard-utils.ts b/src/lib/wireguard-utils.ts index 6bbd91a..e6917cb 100644 --- a/src/lib/wireguard-utils.ts +++ b/src/lib/wireguard-utils.ts @@ -13,16 +13,16 @@ export function getServerConf(server: WgServer): string { `${server.postUp ? `PostUp = ${server.postUp}` : 'OMIT'}`, `${server.preDown ? `PreDown = ${server.preDown}` : 'OMIT'}`, `${server.postDown ? `PostDown = ${server.postDown}` : 'OMIT'}`, - ...server.peers.map((peer, index) => ([ - '', - `## ${peer.name || `Peer #${index + 1}`}`, - '[Peer]', - `PublicKey = ${peer.publicKey}`, - `${peer.preSharedKey ? `PresharedKey = ${peer.preSharedKey}` : 'OMIT'}`, - `AllowedIPs = ${peer.allowedIps}/32`, - `${peer.persistentKeepalive ? `PersistentKeepalive = ${peer.persistentKeepalive}` : 'OMIT'}` - ])) ] + server.peers.forEach((peer, index) => { + lines.push('') + lines.push(`## ${peer.name || `Peer #${index + 1}`}`) + lines.push('[Peer]') + lines.push(`PublicKey = ${peer.publicKey}`) + lines.push(`${peer.preSharedKey ? `PresharedKey = ${peer.preSharedKey}` : 'OMIT'}`) + lines.push(`AllowedIPs = ${peer.allowedIps}/32`) + lines.push(`${peer.persistentKeepalive ? `PersistentKeepalive = ${peer.persistentKeepalive}` : 'OMIT'}`) + }) return lines .filter((l) => l !== 'OMIT') .join('\n') diff --git a/src/lib/wireguard.ts b/src/lib/wireguard.ts index e8494c1..022e9fb 100644 --- a/src/lib/wireguard.ts +++ b/src/lib/wireguard.ts @@ -4,7 +4,7 @@ import { WG_PATH } from "@lib/constants"; import Shell from "@lib/shell"; import { WgKey, WgServer } from "@lib/typings"; import { client, WG_SEVER_PATH } from "@lib/redis"; -import { isJson } from "@lib/utils"; +import { dynaJoin, isJson } from "@lib/utils"; import deepmerge from "deepmerge"; import { getPeerConf, getServerConf } from "@lib/wireguard-utils"; @@ -66,6 +66,7 @@ export class WGServer { } const res = await client.lset(WG_SEVER_PATH, index, JSON.stringify({ ...deepmerge(server, update), + peers: update?.peers || server?.peers || [], updatedAt: new Date().toISOString() })) return res === 'OK' @@ -82,27 +83,32 @@ export class WGServer { console.error('server could not be updated (reason: not exists)') return false } - const peerLines = [ - `[Peer]`, - `PublicKey = ${peer.publicKey}`, - `AllowedIPs = ${peer.allowedIps}/32` - ] - if (peer.persistentKeepalive) { - peerLines.push(`PersistentKeepalive = ${peer.persistentKeepalive}`) - } - if (peer.preSharedKey) { - peerLines.push(`PresharedKey = ${peer.preSharedKey}`) - } + const confPath = path.join(WG_PATH, `wg${server.confId}.conf`) const conf = await fs.readFile(confPath, 'utf-8') const lines = conf.split('\n') - lines.push(...peerLines) + + lines.push(...dynaJoin([ + `[Peer]`, + `PublicKey = ${peer.publicKey}`, + peer.preSharedKey && `PresharedKey = ${peer.preSharedKey}`, + `AllowedIPs = ${peer.allowedIps}/32`, + peer.persistentKeepalive && `PersistentKeepalive = ${peer.persistentKeepalive}` + ])) await fs.writeFile(confPath, lines.join('\n')) - await WGServer.update(server.id, { + + const index = await findServerIndex(id) + if (typeof index !== 'number') { + console.warn('findServerIndex: index not found') + return true + } + await client.lset(WG_SEVER_PATH, index, JSON.stringify({ + ...server, peers: [ ...server.peers, peer ] - }) - await WGServer.stop(server.id) - await WGServer.start(server.id) + })) + + await this.stop(server.id) + await this.start(server.id) return true } @@ -327,6 +333,7 @@ export async function generateWgServer(config: { port: number dns?: string mtu?: number + insertDb?: boolean }): Promise { const { privateKey, publicKey } = await generateWgKey(); @@ -369,7 +376,9 @@ export async function generateWgServer(config: { } // save server config - await client.lpush(WG_SEVER_PATH, JSON.stringify(server)) + if (false !== config.insertDb) { + await client.lpush(WG_SEVER_PATH, JSON.stringify(server)) + } const CONFIG_PATH = path.join(WG_PATH, `wg${confId}.conf`) diff --git a/src/pages/[serverId]/index.tsx b/src/pages/[serverId]/index.tsx index 9cbd5c1..f80e0f5 100644 --- a/src/pages/[serverId]/index.tsx +++ b/src/pages/[serverId]/index.tsx @@ -252,11 +252,15 @@ function Client(props: ClientProps) { ) return ( - +
-
- {props.name} +
+ {props.name} +
+
+ {props.allowedIps} +
{/* QRCode */} diff --git a/src/pages/api/wireguard/regen.ts b/src/pages/api/wireguard/regen.ts new file mode 100644 index 0000000..083c14d --- /dev/null +++ b/src/pages/api/wireguard/regen.ts @@ -0,0 +1,30 @@ +import type { NextApiRequest, NextApiResponse } from 'next' +import safeServe from "@lib/safe-serve"; +import { getServers } from "@lib/wireguard"; +import { getServerConf } from "@lib/wireguard-utils"; +import fs from "fs"; +import path from "path"; +import { WG_PATH } from "@lib/constants"; + +/** + * This API Endpoint is for recreating WireGuard's configs from the database. + * + * @param req + * @param res + */ +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + return safeServe(res, async () => { + + const servers = await getServers() + + servers.forEach((s) => { + const CONFIG_PATH = path.join(WG_PATH, `wg${s.confId}.conf`) + fs.writeFileSync(CONFIG_PATH, getServerConf(s), { mode: 0o600 }) + }) + + return res + .status(200) + .end('OK') + + }) +}