From 609fc20913c5b039aee08949a426dadf497e9a98 Mon Sep 17 00:00:00 2001 From: MicaelSMC Date: Tue, 5 Mar 2024 12:32:59 +0000 Subject: [PATCH] cidr suport --- Dockerfile | 16 ++-- README.md | 5 +- docker-compose.yml | 5 +- src/config.js | 40 +++++++-- src/lib/Server.js | 4 - src/lib/Util.js | 13 --- src/lib/WireGuard.js | 30 ++++--- src/package-lock.json | 107 ++++++++++++----------- src/package.json | 3 +- src/server.js | 15 ---- src/tailwind.config.js | 11 --- src/www/css/app.css | 80 ++--------------- src/www/index.html | 194 ++++++++++++++++------------------------- src/www/js/api.js | 7 -- src/www/js/app.js | 12 +-- src/www/js/i18n.js | 54 ------------ wg-easy.service | 2 +- 17 files changed, 200 insertions(+), 398 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4e410b8e..985b03e7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,8 +6,7 @@ FROM docker.io/library/node:18-alpine AS build_node_modules # Copy Web UI COPY src/ /app/ WORKDIR /app -RUN npm ci --omit=dev &&\ - mv node_modules /node_modules +RUN npm ci --omit=dev # Copy build result to a new image. # This saves a lot of disk space. @@ -21,15 +20,10 @@ COPY --from=build_node_modules /app /app # Also, some node_modules might be native, and # the architecture & OS of your development machine might differ # than what runs inside of docker. -COPY --from=build_node_modules /node_modules /node_modules - -RUN \ - # Enable this to run `npm run serve` - npm i -g nodemon &&\ - # Workaround CVE-2023-42282 - npm uninstall -g ip &&\ - # Delete unnecessary files - npm cache clean --force && rm -rf ~/.npm +RUN mv /app/node_modules /node_modules + +# Enable this to run `npm run serve` +RUN npm i -g nodemon # Install Linux packages RUN apk add --no-cache \ diff --git a/README.md b/README.md index 95810441..5358898f 100644 --- a/README.md +++ b/README.md @@ -90,15 +90,14 @@ These options can be configured by setting environment variables using `-e KEY=" | `WG_PORT` | `51820` | `12345` | The public UDP port of your VPN server. WireGuard will always listen on 51820 inside the Docker container. | | `WG_MTU` | `null` | `1420` | The MTU the clients will use. Server uses default WG MTU. | | `WG_PERSISTENT_KEEPALIVE` | `0` | `25` | Value in seconds to keep the "connection" open. If this value is 0, then connections won't be kept alive. | -| `WG_DEFAULT_ADDRESS` | `10.8.0.x` | `10.6.0.x` | Clients IP address range. | +| `WG_DEFAULT_ADDRESS` | `10.8.0.0/24` | `10.6.0.0/24` | Clients IP address range. (For Legacy reasons x in last place is supported and will be replaced with 0/24 (e.g. 10.8.0.x)) | | `WG_DEFAULT_DNS` | `1.1.1.1` | `8.8.8.8, 8.8.4.4` | DNS server clients will use. If set to blank value, clients will not use any DNS. | | `WG_ALLOWED_IPS` | `0.0.0.0/0, ::/0` | `192.168.15.0/24, 10.0.1.0/24` | Allowed IPs clients will use. | | `WG_PRE_UP` | `...` | - | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L19) for the default value. | | `WG_POST_UP` | `...` | `iptables ...` | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L20) for the default value. | | `WG_PRE_DOWN` | `...` | - | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L27) for the default value. | | `WG_POST_DOWN` | `...` | `iptables ...` | See [config.js](https://github.com/wg-easy/wg-easy/blob/master/src/config.js#L28) for the default value. | -| `LANG` | `en` | `de` | Web UI language (Supports: en, ua, ru, tr, no, pl, fr, de, ca, es, ko, vi, nl, is, pt, chs, cht, it, th). | -| `UI_TRAFFIC_STATS` | `false` | `true` | Enable detailed RX / TX client stats in Web UI | +| `LANG` | `en` | `de` | Web UI language (Supports: en, ru, tr, no, pl, fr, de, ca, es, vi, nl, is, chs, cht,). | > If you change `WG_PORT`, make sure to also change the exposed port. diff --git a/docker-compose.yml b/docker-compose.yml index a6738832..afb47284 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,7 +6,7 @@ services: wg-easy: environment: # Change Language: - # (Supports: en, ua, ru, tr, no, pl, fr, de, ca, es, ko, vi, nl, is, pt, chs, cht, it, th) + # (Supports: en, ua, ru, tr, no, pl, fr, de, ca, es, pt, chs, cht) - LANG=de # ⚠️ Required: # Change this to your host's public address @@ -15,7 +15,7 @@ services: # Optional: # - PASSWORD=foobar123 # - WG_PORT=51820 - # - WG_DEFAULT_ADDRESS=10.8.0.x + # - WG_DEFAULT_ADDRESS=10.8.0.0/24 # - WG_DEFAULT_DNS=1.1.1.1 # - WG_MTU=1420 # - WG_ALLOWED_IPS=192.168.15.0/24, 10.0.1.0/24 @@ -24,7 +24,6 @@ services: # - WG_POST_UP=echo "Post Up" > /etc/wireguard/post-up.txt # - WG_PRE_DOWN=echo "Pre Down" > /etc/wireguard/pre-down.txt # - WG_POST_DOWN=echo "Post Down" > /etc/wireguard/post-down.txt - # - UI_TRAFFIC_STATS=true image: ghcr.io/wg-easy/wg-easy container_name: wg-easy diff --git a/src/config.js b/src/config.js index 33ff7832..ed70082b 100644 --- a/src/config.js +++ b/src/config.js @@ -1,7 +1,29 @@ 'use strict'; +const ip = require('ip'); + const { release } = require('./package.json'); +function parseDefaultAddress(defaultAddress) { + // Set the default full address with subnet if it's not provided + const defaultFullAddress = defaultAddress || '10.8.0.0/24'; + + // Check if the address ends with '.x', if so, replace with '.0/24' + const addressWithSubnet = defaultFullAddress.endsWith('.x') + ? defaultFullAddress.replace('.x', '.0/24') + : defaultFullAddress; + + const [ipAddress, subnetRange] = addressWithSubnet.split('/'); + + return { + ipAddress, + subnetRange: subnetRange || '24', // Default subnet range to 24 if not provided + }; +} + +// Use the function to parse the environment variable or default to '10.8.0.0/24' +const { ipAddress, subnetRange } = parseDefaultAddress(process.env.WG_DEFAULT_ADDRESS); + module.exports.RELEASE = release; module.exports.PORT = process.env.PORT || 51821; module.exports.WEBUI_HOST = process.env.WEBUI_HOST || '0.0.0.0'; @@ -12,26 +34,26 @@ module.exports.WG_HOST = process.env.WG_HOST; module.exports.WG_PORT = process.env.WG_PORT || 51820; module.exports.WG_MTU = process.env.WG_MTU || null; module.exports.WG_PERSISTENT_KEEPALIVE = process.env.WG_PERSISTENT_KEEPALIVE || 0; -module.exports.WG_DEFAULT_ADDRESS = process.env.WG_DEFAULT_ADDRESS || '10.8.0.x'; +module.exports.WG_DEFAULT_ADDRESS = ipAddress; +module.exports.WG_DEFAULT_ADDRESS_RANGE = subnetRange; module.exports.WG_DEFAULT_DNS = typeof process.env.WG_DEFAULT_DNS === 'string' ? process.env.WG_DEFAULT_DNS : '1.1.1.1'; module.exports.WG_ALLOWED_IPS = process.env.WG_ALLOWED_IPS || '0.0.0.0/0, ::/0'; +module.exports.WG_SUBNET = ip.subnet(module.exports.WG_DEFAULT_ADDRESS, `255.255.255.${256 - 2 ** (32 - module.exports.WG_DEFAULT_ADDRESS_RANGE)}`); +module.exports.WG_SERVER_ADDRESS = module.exports.WG_SUBNET.firstAddress; +module.exports.WG_CLIENT_FIRST_ADDRESS = ip.toLong(module.exports.WG_SERVER_ADDRESS) + 1; +module.exports.WG_CLIENT_LAST_ADDRESS = ip.toLong(module.exports.WG_SUBNET.lastAddress) - 1; // Exclude the broadcast address + module.exports.WG_PRE_UP = process.env.WG_PRE_UP || ''; module.exports.WG_POST_UP = process.env.WG_POST_UP || ` -iptables -t nat -A POSTROUTING -s ${module.exports.WG_DEFAULT_ADDRESS.replace('x', '0')}/24 -o ${module.exports.WG_DEVICE} -j MASQUERADE; +iptables -t nat -A POSTROUTING -s ${module.exports.WG_SERVER_ADDRESS}/${module.exports.WG_DEFAULT_ADDRESS_RANGE} -o ${module.exports.WG_DEVICE} -j MASQUERADE; iptables -A INPUT -p udp -m udp --dport 51820 -j ACCEPT; iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; `.split('\n').join(' '); module.exports.WG_PRE_DOWN = process.env.WG_PRE_DOWN || ''; -module.exports.WG_POST_DOWN = process.env.WG_POST_DOWN || ` -iptables -t nat -D POSTROUTING -s ${module.exports.WG_DEFAULT_ADDRESS.replace('x', '0')}/24 -o ${module.exports.WG_DEVICE} -j MASQUERADE; -iptables -D INPUT -p udp -m udp --dport 51820 -j ACCEPT; -iptables -D FORWARD -i wg0 -j ACCEPT; -iptables -D FORWARD -o wg0 -j ACCEPT; -`.split('\n').join(' '); +module.exports.WG_POST_DOWN = process.env.WG_POST_DOWN || ''; module.exports.LANG = process.env.LANG || 'en'; -module.exports.UI_TRAFFIC_STATS = process.env.UI_TRAFFIC_STATS || 'false'; diff --git a/src/lib/Server.js b/src/lib/Server.js index 13a5d51d..1f00a6b4 100644 --- a/src/lib/Server.js +++ b/src/lib/Server.js @@ -18,7 +18,6 @@ const { RELEASE, PASSWORD, LANG, - UI_TRAFFIC_STATS, } = require('../config'); module.exports = class Server { @@ -45,9 +44,6 @@ module.exports = class Server { .get('/api/lang', (Util.promisify(async () => { return LANG; }))) - .get('/api/ui-traffic-stats', (Util.promisify(async () => { - return UI_TRAFFIC_STATS === 'true'; - }))) // Authentication .get('/api/session', Util.promisify(async (req) => { diff --git a/src/lib/Util.js b/src/lib/Util.js index cc6e89c2..82942599 100644 --- a/src/lib/Util.js +++ b/src/lib/Util.js @@ -4,19 +4,6 @@ const childProcess = require('child_process'); module.exports = class Util { - static isValidIPv4(str) { - const blocks = str.split('.'); - if (blocks.length !== 4) return false; - - for (let value of blocks) { - value = parseInt(value, 10); - if (Number.isNaN(value)) return false; - if (value < 0 || value > 255) return false; - } - - return true; - } - static promisify(fn) { // eslint-disable-next-line func-names return function(req, res) { diff --git a/src/lib/WireGuard.js b/src/lib/WireGuard.js index 8377f6f6..c614e6e6 100644 --- a/src/lib/WireGuard.js +++ b/src/lib/WireGuard.js @@ -4,6 +4,7 @@ const fs = require('fs').promises; const path = require('path'); const debug = require('debug')('WireGuard'); +const ip = require('ip'); const uuid = require('uuid'); const QRCode = require('qrcode'); @@ -16,9 +17,12 @@ const { WG_PORT, WG_MTU, WG_DEFAULT_DNS, - WG_DEFAULT_ADDRESS, + WG_DEFAULT_ADDRESS_RANGE, WG_PERSISTENT_KEEPALIVE, WG_ALLOWED_IPS, + WG_SERVER_ADDRESS, + WG_CLIENT_FIRST_ADDRESS, + WG_CLIENT_LAST_ADDRESS, WG_PRE_UP, WG_POST_UP, WG_PRE_DOWN, @@ -45,13 +49,15 @@ module.exports = class WireGuard { const publicKey = await Util.exec(`echo ${privateKey} | wg pubkey`, { log: 'echo ***hidden*** | wg pubkey', }); - const address = WG_DEFAULT_ADDRESS.replace('x', '1'); + const address = WG_SERVER_ADDRESS; + const cidrBlock = WG_DEFAULT_ADDRESS_RANGE; config = { server: { privateKey, publicKey, address, + cidrBlock, }, clients: {}, }; @@ -67,7 +73,7 @@ module.exports = class 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 -t nat -A POSTROUTING -s ${WG_SERVER_ADDRESS/${WG_DEFAULT_ADDRESS_RANGE} -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'); @@ -94,7 +100,7 @@ module.exports = class WireGuard { # Server [Interface] PrivateKey = ${config.server.privateKey} -Address = ${config.server.address}/24 +Address = ${config.server.address}/${config.server.cidrBlock} ListenPort = 51820 PreUp = ${WG_PRE_UP} PostUp = ${WG_POST_UP} @@ -229,15 +235,16 @@ Endpoint = ${WG_HOST}:${WG_PORT}`; const publicKey = await Util.exec(`echo ${privateKey} | wg pubkey`); const preSharedKey = await Util.exec('wg genpsk'); - // Calculate next IP + // find next IP let address; - for (let i = 2; i < 255; i++) { + for (let i = WG_CLIENT_FIRST_ADDRESS; i <= WG_CLIENT_LAST_ADDRESS; i++) { + const currentIp = ip.fromLong(i); const client = Object.values(config.clients).find((client) => { - return client.address === WG_DEFAULT_ADDRESS.replace('x', i); + return client.address === currentIp; }); if (!client) { - address = WG_DEFAULT_ADDRESS.replace('x', i); + address = currentIp; break; } } @@ -308,7 +315,7 @@ Endpoint = ${WG_HOST}:${WG_PORT}`; async updateClientAddress({ clientId, address }) { const client = await this.getClient({ clientId }); - if (!Util.isValidIPv4(address)) { + if (!ip.isV4Format(address)) { throw new ServerError(`Invalid Address: ${address}`, 400); } @@ -318,9 +325,4 @@ Endpoint = ${WG_HOST}:${WG_PORT}`; await this.saveConfig(); } - // Shutdown wireguard - async Shutdown() { - await Util.exec('wg-quick down wg0').catch(() => { }); - } - }; diff --git a/src/package-lock.json b/src/package-lock.json index 532fa5bb..56d76932 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -11,8 +11,9 @@ "dependencies": { "bcryptjs": "^2.4.3", "debug": "^4.3.4", - "express": "^4.18.3", + "express": "^4.18.2", "express-session": "^1.18.0", + "ip": "^2.0.1", "qrcode": "^1.5.3", "uuid": "^9.0.1" }, @@ -381,14 +382,14 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.2.1", + "@jridgewell/set-array": "^1.0.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" + "@jridgewell/trace-mapping": "^0.3.9" }, "engines": { "node": ">=6.0.0" @@ -404,9 +405,9 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", "dev": true, "engines": { "node": ">=6.0.0" @@ -419,9 +420,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", + "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -486,9 +487,9 @@ "dev": true }, "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "version": "7.5.7", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.7.tgz", + "integrity": "sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { @@ -991,12 +992,12 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.1", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", + "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.5", + "content-type": "~1.0.4", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -1004,7 +1005,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.2", + "raw-body": "2.5.1", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -1425,18 +1426,18 @@ } }, "node_modules/es-abstract": { - "version": "1.22.5", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.5.tgz", - "integrity": "sha512-oW69R+4q2wG+Hc3KZePPZxOiisRIqfKBVo/HLx94QcJeWGU/8sZhCvc829rd1kS366vlJbzBfXf9yWwf0+Ko7w==", + "version": "1.22.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.4.tgz", + "integrity": "sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.1", "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.7", + "available-typed-arrays": "^1.0.6", "call-bind": "^1.0.7", "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", + "es-set-tostringtag": "^2.0.2", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.6", "get-intrinsic": "^1.2.4", @@ -1444,15 +1445,15 @@ "globalthis": "^1.0.3", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", + "has-proto": "^1.0.1", "has-symbols": "^1.0.3", "hasown": "^2.0.1", "internal-slot": "^1.0.7", "is-array-buffer": "^3.0.4", "is-callable": "^1.2.7", - "is-negative-zero": "^2.0.3", + "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", + "is-shared-array-buffer": "^1.0.2", "is-string": "^1.0.7", "is-typed-array": "^1.1.13", "is-weakref": "^1.0.2", @@ -1465,10 +1466,10 @@ "string.prototype.trim": "^1.2.8", "string.prototype.trimend": "^1.0.7", "string.prototype.trimstart": "^1.0.7", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.5", + "typed-array-buffer": "^1.0.1", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", "unbox-primitive": "^1.0.2", "which-typed-array": "^1.1.14" }, @@ -1681,9 +1682,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", - "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", "dev": true, "dependencies": { "debug": "^3.2.7" @@ -2107,13 +2108,13 @@ } }, "node_modules/express": { - "version": "4.18.3", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", - "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", + "version": "4.18.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", + "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.1", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.5.0", @@ -2793,6 +2794,11 @@ "node": ">= 0.4" } }, + "node_modules/ip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==" + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -3986,9 +3992,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", + "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -4341,11 +4347,11 @@ } }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", + "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.6", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.4", "object-inspect": "^1.13.1" @@ -5078,13 +5084,10 @@ "dev": true }, "node_modules/yaml": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.0.tgz", - "integrity": "sha512-j9iR8g+/t0lArF4V6NE/QCfT+CO7iLqrXAHZbJdo+LfjqP1vR8Fg5bSiaq6Q2lOD1AUEVrEVIgABvBFYojJVYQ==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", "dev": true, - "bin": { - "yaml": "bin.mjs" - }, "engines": { "node": ">= 14" } diff --git a/src/package.json b/src/package.json index 14cf5183..295cb37f 100644 --- a/src/package.json +++ b/src/package.json @@ -15,8 +15,9 @@ "dependencies": { "bcryptjs": "^2.4.3", "debug": "^4.3.4", - "express": "^4.18.3", + "express": "^4.18.2", "express-session": "^1.18.0", + "ip": "^2.0.1", "qrcode": "^1.5.3", "uuid": "^9.0.1" }, diff --git a/src/server.js b/src/server.js index 1ad06b34..0bc2c985 100644 --- a/src/server.js +++ b/src/server.js @@ -12,18 +12,3 @@ WireGuard.getConfig() // eslint-disable-next-line no-process-exit process.exit(1); }); - -// Handle terminate signal -process.on('SIGTERM', async () => { - // eslint-disable-next-line no-console - console.log('SIGTERM signal received.'); - await WireGuard.Shutdown(); - // eslint-disable-next-line no-process-exit - process.exit(0); -}); - -// Handle interupt signal -process.on('SIGINT', () => { - // eslint-disable-next-line no-console - console.log('SIGINT signal received.'); -}); diff --git a/src/tailwind.config.js b/src/tailwind.config.js index 8070b0cd..0594481d 100644 --- a/src/tailwind.config.js +++ b/src/tailwind.config.js @@ -5,15 +5,4 @@ module.exports = { darkMode: 'media', content: ['./www/**/*.{html,js}'], - theme: { - screens: { - xxs: '450px', - xs: '576px', - sm: '640px', - md: '768px', - lg: '1024px', - xl: '1280px', - '2xl': '1536px', - }, - }, }; diff --git a/src/www/css/app.css b/src/www/css/app.css index 3064646a..5157bdbe 100644 --- a/src/www/css/app.css +++ b/src/www/css/app.css @@ -548,18 +548,6 @@ video { width: 100%; } -@media (min-width: 450px) { - .container { - max-width: 450px; - } -} - -@media (min-width: 576px) { - .container { - max-width: 576px; - } -} - @media (min-width: 640px) { .container { max-width: 640px; @@ -712,12 +700,8 @@ video { margin-right: 0.5rem; } -.mt-0 { - margin-top: 0px; -} - -.mt-0\.5 { - margin-top: 0.125rem; +.mr-5 { + margin-right: 1.25rem; } .mt-10 { @@ -736,10 +720,6 @@ video { margin-top: 1.25rem; } -.mt-px { - margin-top: 1px; -} - .block { display: block; } @@ -852,10 +832,6 @@ video { width: 100%; } -.min-w-20 { - min-width: 5rem; -} - .max-w-3xl { max-width: 48rem; } @@ -868,10 +844,6 @@ video { flex-shrink: 0; } -.shrink-0 { - flex-shrink: 0; -} - .flex-grow { flex-grow: 1; } @@ -945,18 +917,6 @@ video { gap: 0.25rem; } -.gap-2 { - gap: 0.5rem; -} - -.gap-3 { - gap: 0.75rem; -} - -.self-start { - align-self: flex-start; -} - .overflow-hidden { overflow: hidden; } @@ -971,10 +931,6 @@ video { white-space: nowrap; } -.whitespace-nowrap { - white-space: nowrap; -} - .rounded { border-radius: 0.25rem; } @@ -1141,11 +1097,6 @@ video { padding-bottom: 0.75rem; } -.py-5 { - padding-top: 1.25rem; - padding-bottom: 1.25rem; -} - .pb-1 { padding-bottom: 0.25rem; } @@ -1154,6 +1105,10 @@ video { padding-bottom: 3rem; } +.pb-2 { + padding-bottom: 0.5rem; +} + .pb-20 { padding-bottom: 5rem; } @@ -1458,12 +1413,6 @@ video { opacity: 1; } -@media (min-width: 450px) { - .xxs\:flex-row { - flex-direction: row; - } -} - @media (min-width: 640px) { .sm\:mx-0 { margin-left: 0px; @@ -1531,10 +1480,6 @@ video { transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); } - .sm\:flex-row { - flex-direction: row; - } - .sm\:flex-row-reverse { flex-direction: row-reverse; } @@ -1579,12 +1524,8 @@ video { display: inline-block; } - .md\:min-w-24 { - min-width: 6rem; - } - - .md\:gap-4 { - gap: 1rem; + .md\:flex-row { + flex-direction: row; } .md\:px-0 { @@ -1595,11 +1536,6 @@ video { .md\:pb-0 { padding-bottom: 0px; } - - .md\:text-base { - font-size: 1rem; - line-height: 1.5rem; - } } @media (prefers-color-scheme: dark) { diff --git a/src/www/index.html b/src/www/index.html index 9311ef0c..5f8c653f 100644 --- a/src/www/index.html +++ b/src/www/index.html @@ -17,8 +17,11 @@ +
-
+ +
+
- -
-
- - -
- +
+
+
+ @@ -108,26 +108,52 @@
- -
+
-
-
+
+ + + + {{client.name}} + + + + + + + +
+ + +
+ + + - - {{client.name}} + + {{client.address}} - -
- -
- - - - {{client.address}} - - - - - - - - - - - · - - - - {{client.transferTxCurrent | bytes}}/s - - - - - · - - - - {{client.transferRxCurrent | bytes}}/s - - - - {{!uiTrafficStats ? " · " : ""}}{{new Date(client.latestHandshakeAt) | timeago}} - -
-
- - -
+ -
- - - - -
- {{client.transferTxCurrent | - bytes}}/s - -
{{bytes(client.transferTx)}} -
-
- -
+ + · + + + + {{client.transferTxCurrent | bytes}}/s + -
- - - - - -
- {{client.transferRxCurrent | - bytes}}/s - -
{{bytes(client.transferRx)}} -
-
-
- + + · + + + + {{client.transferRxCurrent | bytes}}/s + + + + + · {{new Date(client.latestHandshakeAt) | timeago}} +
-
@@ -549,4 +509,4 @@ - \ No newline at end of file + diff --git a/src/www/js/api.js b/src/www/js/api.js index e69e5a3a..366aeaa1 100644 --- a/src/www/js/api.js +++ b/src/www/js/api.js @@ -43,13 +43,6 @@ class API { }); } - async getuiTrafficStats() { - return this.call({ - method: 'get', - path: '/ui-traffic-stats', - }); - } - async getSession() { return this.call({ method: 'get', diff --git a/src/www/js/app.js b/src/www/js/app.js index 22fe3bfc..66dae9c1 100644 --- a/src/www/js/app.js +++ b/src/www/js/app.js @@ -53,7 +53,6 @@ new Vue({ latestRelease: null, isDark: null, - uiTrafficStats: false, chartOptions: { chart: { @@ -293,15 +292,6 @@ new Vue({ }).catch(console.error); }, 1000); - this.api.getuiTrafficStats() - .then((res) => { - this.uiTrafficStats = res; - }) - .catch(() => { - console.log('Failed to get ui-traffic-stats'); - this.uiTrafficStats = false; - }); - Promise.resolve().then(async () => { const lang = await this.api.getLang(); if (lang !== localStorage.getItem('lang') && i18n.availableLocales.includes(lang)) { @@ -331,6 +321,6 @@ new Vue({ this.currentRelease = currentRelease; this.latestRelease = latestRelease; - }).catch((err) => console.error(err)); + }).catch(console.error); }, }); diff --git a/src/www/js/i18n.js b/src/www/js/i18n.js index 76102022..04e1b490 100644 --- a/src/www/js/i18n.js +++ b/src/www/js/i18n.js @@ -461,58 +461,4 @@ const messages = { // eslint-disable-line no-unused-vars madeBy: '由', donate: '捐贈', }, - it: { - name: 'Nome', - password: 'Password', - signIn: 'Accedi', - logout: 'Esci', - updateAvailable: 'È disponibile un aggiornamento!', - update: 'Aggiorna', - clients: 'Client', - new: 'Nuovo', - deleteClient: 'Elimina Client', - deleteDialog1: 'Sei sicuro di voler eliminare', - deleteDialog2: 'Questa azione non può essere annullata.', - cancel: 'Annulla', - create: 'Crea', - createdOn: 'Creato il ', - lastSeen: 'Visto l\'ultima volta il ', - totalDownload: 'Totale Download: ', - totalUpload: 'Totale Upload: ', - newClient: 'Nuovo Client', - disableClient: 'Disabilita Client', - enableClient: 'Abilita Client', - noClients: 'Non ci sono ancora client.', - showQR: 'Mostra codice QR', - downloadConfig: 'Scarica configurazione', - madeBy: 'Realizzato da', - donate: 'Donazione', - }, - th: { - name: 'ชื่อ', - password: 'รหัสผ่าน', - signIn: 'ลงชื่อเข้าใช้', - logout: 'ออกจากระบบ', - updateAvailable: 'มีอัปเดตพร้อมใช้งาน!', - update: 'อัปเดต', - clients: 'Clients', - new: 'ใหม่', - deleteClient: 'ลบ Client', - deleteDialog1: 'คุณแน่ใจหรือไม่ว่าต้องการลบ', - deleteDialog2: 'การกระทำนี้;ไม่สามารถยกเลิกได้', - cancel: 'ยกเลิก', - create: 'สร้าง', - createdOn: 'สร้างเมื่อ ', - lastSeen: 'เห็นครั้งสุดท้ายเมื่อ ', - totalDownload: 'ดาวน์โหลดทั้งหมด: ', - totalUpload: 'อัพโหลดทั้งหมด: ', - newClient: 'Client ใหม่', - disableClient: 'ปิดการใช้งาน Client', - enableClient: 'เปิดการใช้งาน Client', - noClients: 'ยังไม่มี Clients เลย', - showQR: 'แสดงรหัส QR', - downloadConfig: 'ดาวน์โหลดการตั้งค่า', - madeBy: 'สร้างโดย', - donate: 'บริจาค', - }, }; diff --git a/wg-easy.service b/wg-easy.service index bcdf72fd..6adee95e 100644 --- a/wg-easy.service +++ b/wg-easy.service @@ -5,7 +5,7 @@ After=network-online.target nss-lookup.target [Service] Environment="WG_HOST=raspberrypi.local" # Change this to your host's public address or static public ip. Environment="PASSWORD=REPLACEME" # When set, requires a password when logging in to the Web UI, to disable add a hashtag -#Environment="WG_DEFAULT_ADDRESS=10.0.8.x" #Clients IP address range. +#Environment="WG_DEFAULT_ADDRESS=10.0.8.0/24" # Clients IP address range. #Environment="WG_DEFAULT_DNS=10.0.8.1, 1.1.1.1" #DNS server clients will use. If set to blank value, clients will not use any DNS. #Environment="WG_ALLOWED_IPS=0.0.0.0/0,::/0" #Allowed IPs clients will use. #Environment="WG_DEVICE=ens1" #Ethernet device the wireguard traffic should be forwarded through.