diff --git a/.github/workflows/deploy-development.yml b/.github/workflows/deploy-development.yml index fa912f77..21547c7e 100644 --- a/.github/workflows/deploy-development.yml +++ b/.github/workflows/deploy-development.yml @@ -2,6 +2,7 @@ name: Build & Publish Development on: workflow_dispatch: + pull_request: jobs: deploy: diff --git a/.github/workflows/npm-update-bot.yml b/.github/workflows/npm-update-bot.yml index 41ddfe3f..ab5e0fba 100644 --- a/.github/workflows/npm-update-bot.yml +++ b/.github/workflows/npm-update-bot.yml @@ -4,7 +4,7 @@ on: push: branches: [ "master" ] schedule: - - cron: "0 0 * * *" + - cron: "0 0 * * 1" jobs: npmupbot: diff --git a/Dockerfile b/Dockerfile index baf9941b..4e410b8e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,7 +6,8 @@ FROM docker.io/library/node:18-alpine AS build_node_modules # Copy Web UI COPY src/ /app/ WORKDIR /app -RUN npm ci --omit=dev +RUN npm ci --omit=dev &&\ + mv node_modules /node_modules # Copy build result to a new image. # This saves a lot of disk space. @@ -20,13 +21,15 @@ 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. -RUN mv /app/node_modules /node_modules - -# Enable this to run `npm run serve` -RUN npm i -g nodemon - -# Workaround CVE-2023-42282 -RUN npm uninstall -g ip +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 # Install Linux packages RUN apk add --no-cache \ diff --git a/README.md b/README.md index 61eda10f..95810441 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,8 @@ These options can be configured by setting environment variables using `-e KEY=" | `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, ru, tr, no, pl, fr, de, ca, es, vi, nl, is, chs, cht,). | +| `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 | > If you change `WG_PORT`, make sure to also change the exposed port. diff --git a/docker-compose.yml b/docker-compose.yml index 2c529a68..a6738832 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, pt, chs, cht) + # (Supports: en, ua, ru, tr, no, pl, fr, de, ca, es, ko, vi, nl, is, pt, chs, cht, it, th) - LANG=de # ⚠️ Required: # Change this to your host's public address @@ -24,6 +24,7 @@ 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 09fbcf3e..a8fe2c38 100644 --- a/src/config.js +++ b/src/config.js @@ -3,15 +3,15 @@ const { release } = require('./package.json'); module.exports.RELEASE = release; -module.exports.PORT = process.env.PORT || 51821; +module.exports.PORT = process.env.PORT || '51821'; module.exports.WEBUI_HOST = process.env.WEBUI_HOST || '0.0.0.0'; module.exports.PASSWORD = process.env.PASSWORD; module.exports.WG_PATH = process.env.WG_PATH || '/etc/wireguard/'; module.exports.WG_DEVICE = process.env.WG_DEVICE || 'eth0'; module.exports.WG_HOST = process.env.WG_HOST; -module.exports.WG_PORT = process.env.WG_PORT || 51820; +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_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_DNS = typeof process.env.WG_DEFAULT_DNS === 'string' ? process.env.WG_DEFAULT_DNS @@ -27,5 +27,11 @@ 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 || ''; +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.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 1f00a6b4..13a5d51d 100644 --- a/src/lib/Server.js +++ b/src/lib/Server.js @@ -18,6 +18,7 @@ const { RELEASE, PASSWORD, LANG, + UI_TRAFFIC_STATS, } = require('../config'); module.exports = class Server { @@ -44,6 +45,9 @@ 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/WireGuard.js b/src/lib/WireGuard.js index f72c3a23..739676fb 100644 --- a/src/lib/WireGuard.js +++ b/src/lib/WireGuard.js @@ -110,8 +110,8 @@ PostDown = ${WG_POST_DOWN} # Client: ${client.name} (${clientId}) [Peer] PublicKey = ${client.publicKey} -PresharedKey = ${client.preSharedKey} -AllowedIPs = ${client.address}/32`; +${client.preSharedKey ? `PresharedKey = ${client.preSharedKey}\n` : '' +}AllowedIPs = ${client.address}/32`; } debug('Config saving...'); @@ -141,7 +141,7 @@ AllowedIPs = ${client.address}/32`; createdAt: new Date(client.createdAt), updatedAt: new Date(client.updatedAt), allowedIPs: client.allowedIPs, - + downloadableConfig: 'privateKey' in client, persistentKeepalive: null, latestHandshakeAt: null, transferRx: null, @@ -196,16 +196,17 @@ AllowedIPs = ${client.address}/32`; const config = await this.getConfig(); const client = await this.getClient({ clientId }); - return `[Interface] -PrivateKey = ${client.privateKey} + 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` : ''}\ [Peer] PublicKey = ${config.server.publicKey} -PresharedKey = ${client.preSharedKey} -AllowedIPs = ${WG_ALLOWED_IPS} +${client.preSharedKey ? `PresharedKey = ${client.preSharedKey}\n` : '' +}AllowedIPs = ${WG_ALLOWED_IPS} PersistentKeepalive = ${WG_PERSISTENT_KEEPALIVE} Endpoint = ${WG_HOST}:${WG_PORT}`; } @@ -318,4 +319,9 @@ 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 1c1ef429..836cc747 100644 --- a/src/package-lock.json +++ b/src/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "bcryptjs": "^2.4.3", "debug": "^4.3.4", - "express": "^4.18.2", + "express": "^4.18.3", "express-session": "^1.18.0", "qrcode": "^1.5.3", "uuid": "^9.0.1" @@ -381,14 +381,14 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" @@ -404,9 +404,9 @@ } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "engines": { "node": ">=6.0.0" @@ -419,9 +419,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.22", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", - "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -486,9 +486,9 @@ "dev": true }, "node_modules/@types/semver": { - "version": "7.5.7", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.7.tgz", - "integrity": "sha512-/wdoPq1QqkSj9/QOeKkFquEuPzQbHTWAMPH/PaUMB+JuR31lXhlWXRZ52IpfDYVlDOUBvX09uBrPwxGT1hjNBg==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { @@ -991,12 +991,12 @@ } }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -1004,7 +1004,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -1425,18 +1425,18 @@ } }, "node_modules/es-abstract": { - "version": "1.22.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.4.tgz", - "integrity": "sha512-vZYJlk2u6qHYxBOTjAeg7qUxHdNfih64Uu2J8QqWgXZ2cri0ZpJAkzDUK/q593+mvKwlxyaxr6F1Q+3LKoQRgg==", + "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==", "dev": true, "dependencies": { "array-buffer-byte-length": "^1.0.1", "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.6", + "available-typed-arrays": "^1.0.7", "call-bind": "^1.0.7", "es-define-property": "^1.0.0", "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.2", + "es-set-tostringtag": "^2.0.3", "es-to-primitive": "^1.2.1", "function.prototype.name": "^1.1.6", "get-intrinsic": "^1.2.4", @@ -1444,15 +1444,15 @@ "globalthis": "^1.0.3", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.1", + "has-proto": "^1.0.3", "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.2", + "is-negative-zero": "^2.0.3", "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.2", + "is-shared-array-buffer": "^1.0.3", "is-string": "^1.0.7", "is-typed-array": "^1.1.13", "is-weakref": "^1.0.2", @@ -1465,10 +1465,10 @@ "string.prototype.trim": "^1.2.8", "string.prototype.trimend": "^1.0.7", "string.prototype.trimstart": "^1.0.7", - "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", + "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", "unbox-primitive": "^1.0.2", "which-typed-array": "^1.1.14" }, @@ -1681,9 +1681,9 @@ } }, "node_modules/eslint-module-utils": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", - "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", "dev": true, "dependencies": { "debug": "^3.2.7" @@ -2107,13 +2107,13 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.18.3", + "resolved": "https://registry.npmjs.org/express/-/express-4.18.3.tgz", + "integrity": "sha512-6VyCijWQ+9O7WuVMTRBTl+cjNNIzD5cY5mQ1WM8r/LEkI2u8EYpOotESNwzNlyCn3g+dmjKYI6BmNneSr/FSRw==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", "cookie": "0.5.0", @@ -2691,9 +2691,9 @@ } }, "node_modules/hasown": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz", - "integrity": "sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dependencies": { "function-bind": "^1.1.2" }, @@ -3986,9 +3986,9 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "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==", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -4150,13 +4150,13 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", - "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", "dev": true, "dependencies": { - "call-bind": "^1.0.5", - "get-intrinsic": "^1.2.2", + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", "has-symbols": "^1.0.3", "isarray": "^2.0.5" }, @@ -4284,16 +4284,16 @@ "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, "node_modules/set-function-length": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", - "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dependencies": { - "define-data-property": "^1.1.2", + "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.3", + "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.1" + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -4341,11 +4341,11 @@ } }, "node_modules/side-channel": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", - "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "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==", "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.7", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.4", "object-inspect": "^1.13.1" @@ -4735,9 +4735,9 @@ } }, "node_modules/ts-api-utils": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", - "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", "dev": true, "engines": { "node": ">=16" @@ -5010,16 +5010,16 @@ "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==" }, "node_modules/which-typed-array": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz", - "integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", "dev": true, "dependencies": { - "available-typed-arrays": "^1.0.6", - "call-bind": "^1.0.5", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", "for-each": "^0.3.3", "gopd": "^1.0.1", - "has-tostringtag": "^1.0.1" + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -5078,10 +5078,13 @@ "dev": true }, "node_modules/yaml": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", - "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz", + "integrity": "sha512-pIXzoImaqmfOrL7teGUBt/T7ZDnyeGBWyXQBvOVhLkWLN37GXv8NMLK406UY6dS51JfcQHsmcW5cJ441bHg6Lg==", "dev": true, + "bin": { + "yaml": "bin.mjs" + }, "engines": { "node": ">= 14" } diff --git a/src/package.json b/src/package.json index 68056acb..14cf5183 100644 --- a/src/package.json +++ b/src/package.json @@ -15,7 +15,7 @@ "dependencies": { "bcryptjs": "^2.4.3", "debug": "^4.3.4", - "express": "^4.18.2", + "express": "^4.18.3", "express-session": "^1.18.0", "qrcode": "^1.5.3", "uuid": "^9.0.1" diff --git a/src/server.js b/src/server.js index 0bc2c985..1ad06b34 100644 --- a/src/server.js +++ b/src/server.js @@ -12,3 +12,18 @@ 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 0594481d..33ba6746 100644 --- a/src/tailwind.config.js +++ b/src/tailwind.config.js @@ -5,4 +5,26 @@ module.exports = { darkMode: 'media', content: ['./www/**/*.{html,js}'], + theme: { + screens: { + xxs: '450px', + xs: '576px', + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px', + '2xl': '1536px', + }, + }, + plugins: [ + function addDisabledClass({ addUtilities }) { + const newUtilities = { + '.is-disabled': { + opacity: '0.25', + cursor: 'default', + }, + }; + addUtilities(newUtilities); + }, + ], }; diff --git a/src/www/css/app.css b/src/www/css/app.css index 4f4e21dd..00837d4c 100644 --- a/src/www/css/app.css +++ b/src/www/css/app.css @@ -548,6 +548,18 @@ 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; @@ -700,8 +712,12 @@ video { margin-right: 0.5rem; } -.mr-5 { - margin-right: 1.25rem; +.mt-0 { + margin-top: 0px; +} + +.mt-0\.5 { + margin-top: 0.125rem; } .mt-10 { @@ -720,6 +736,10 @@ video { margin-top: 1.25rem; } +.mt-px { + margin-top: 1px; +} + .block { display: block; } @@ -768,10 +788,6 @@ video { height: 3rem; } -.h-14 { - height: 3.5rem; -} - .h-2 { height: 0.5rem; } @@ -784,10 +800,6 @@ video { height: 0.75rem; } -.h-32 { - height: 8rem; -} - .h-4 { height: 1rem; } @@ -840,6 +852,10 @@ video { width: 100%; } +.min-w-20 { + min-width: 5rem; +} + .max-w-3xl { max-width: 48rem; } @@ -852,6 +868,10 @@ video { flex-shrink: 0; } +.shrink-0 { + flex-shrink: 0; +} + .flex-grow { flex-grow: 1; } @@ -925,6 +945,18 @@ video { gap: 0.25rem; } +.gap-2 { + gap: 0.5rem; +} + +.gap-3 { + gap: 0.75rem; +} + +.self-start { + align-self: flex-start; +} + .overflow-hidden { overflow: hidden; } @@ -939,6 +971,10 @@ video { white-space: nowrap; } +.whitespace-nowrap { + white-space: nowrap; +} + .rounded { border-radius: 0.25rem; } @@ -1105,6 +1141,11 @@ video { padding-bottom: 0.75rem; } +.py-5 { + padding-top: 1.25rem; + padding-bottom: 1.25rem; +} + .pb-1 { padding-bottom: 0.25rem; } @@ -1113,10 +1154,6 @@ video { padding-bottom: 3rem; } -.pb-2 { - padding-bottom: 0.5rem; -} - .pb-20 { padding-bottom: 5rem; } @@ -1350,6 +1387,11 @@ video { transition-timing-function: cubic-bezier(0, 0, 0.2, 1); } +.is-disabled { + opacity: 0.25; + cursor: default; +} + .last\:border-b-0:last-child { border-bottom-width: 0px; } @@ -1421,6 +1463,12 @@ video { opacity: 1; } +@media (min-width: 450px) { + .xxs\:flex-row { + flex-direction: row; + } +} + @media (min-width: 640px) { .sm\:mx-0 { margin-left: 0px; @@ -1488,6 +1536,10 @@ 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; } @@ -1532,8 +1584,12 @@ video { display: inline-block; } - .md\:flex-row { - flex-direction: row; + .md\:min-w-24 { + min-width: 6rem; + } + + .md\:gap-4 { + gap: 1rem; } .md\:px-0 { @@ -1544,6 +1600,11 @@ 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 2edf3c70..826cf526 100644 --- a/src/www/index.html +++ b/src/www/index.html @@ -17,11 +17,8 @@
-