forked from mirrors/amnezia-wg-easy
		
	Merge branch 'master' into remember-me
This commit is contained in:
		
						commit
						f5885e335c
					
				
					 13 changed files with 72 additions and 10 deletions
				
			
		| 
						 | 
					@ -24,6 +24,7 @@ You have found the easiest way to install & manage WireGuard on any Linux host!
 | 
				
			||||||
* Automatic Light / Dark Mode
 | 
					* Automatic Light / Dark Mode
 | 
				
			||||||
* Multilanguage Support
 | 
					* Multilanguage Support
 | 
				
			||||||
* UI_TRAFFIC_STATS (default off)
 | 
					* UI_TRAFFIC_STATS (default off)
 | 
				
			||||||
 | 
					* UI_SHOW_LINKS (default off)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Requirements
 | 
					## Requirements
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -120,6 +121,7 @@ These options can be configured by setting environment variables using `-e KEY="
 | 
				
			||||||
| `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, hi).                                        |
 | 
					| `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, hi).                                        |
 | 
				
			||||||
| `UI_TRAFFIC_STATS` | `false` | `true` | Enable detailed RX / TX client stats in Web UI                                                                                                       |
 | 
					| `UI_TRAFFIC_STATS` | `false` | `true` | Enable detailed RX / TX client stats in Web UI                                                                                                       |
 | 
				
			||||||
| `UI_CHART_TYPE` | `0` | `1` | UI_CHART_TYPE=0 # Charts disabled, UI_CHART_TYPE=1 # Line chart, UI_CHART_TYPE=2 # Area chart, UI_CHART_TYPE=3 # Bar chart                           |
 | 
					| `UI_CHART_TYPE` | `0` | `1` | UI_CHART_TYPE=0 # Charts disabled, UI_CHART_TYPE=1 # Line chart, UI_CHART_TYPE=2 # Area chart, UI_CHART_TYPE=3 # Bar chart                           |
 | 
				
			||||||
 | 
					| `UI_SHOW_LINKS` | `false` | `true` | Enable display of a short download link in Web UI                                                                                                       |
 | 
				
			||||||
| `MAX_AGE` | `0` | `1440` | The maximum age of Web UI sessions in minutes. `0` means that the session will exist until the browser is closed.                                  |
 | 
					| `MAX_AGE` | `0` | `1440` | The maximum age of Web UI sessions in minutes. `0` means that the session will exist until the browser is closed.                                  |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
> If you change `WG_PORT`, make sure to also change the exposed port.
 | 
					> If you change `WG_PORT`, make sure to also change the exposed port.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,7 @@ services:
 | 
				
			||||||
      # - WG_POST_DOWN=echo "Post Down" > /etc/wireguard/post-down.txt
 | 
					      # - WG_POST_DOWN=echo "Post Down" > /etc/wireguard/post-down.txt
 | 
				
			||||||
      # - UI_TRAFFIC_STATS=true
 | 
					      # - UI_TRAFFIC_STATS=true
 | 
				
			||||||
      # - UI_CHART_TYPE=0 # (0 Charts disabled, 1 # Line chart, 2 # Area chart, 3 # Bar chart)
 | 
					      # - UI_CHART_TYPE=0 # (0 Charts disabled, 1 # Line chart, 2 # Area chart, 3 # Bar chart)
 | 
				
			||||||
 | 
					      # - UI_SHOW_LINKS=true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    image: ghcr.io/wg-easy/wg-easy
 | 
					    image: ghcr.io/wg-easy/wg-easy
 | 
				
			||||||
    container_name: wg-easy
 | 
					    container_name: wg-easy
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,3 +38,4 @@ iptables -D FORWARD -o wg0 -j ACCEPT;
 | 
				
			||||||
module.exports.LANG = process.env.LANG || 'en';
 | 
					module.exports.LANG = process.env.LANG || 'en';
 | 
				
			||||||
module.exports.UI_TRAFFIC_STATS = process.env.UI_TRAFFIC_STATS || 'false';
 | 
					module.exports.UI_TRAFFIC_STATS = process.env.UI_TRAFFIC_STATS || 'false';
 | 
				
			||||||
module.exports.UI_CHART_TYPE = process.env.UI_CHART_TYPE || 0;
 | 
					module.exports.UI_CHART_TYPE = process.env.UI_CHART_TYPE || 0;
 | 
				
			||||||
 | 
					module.exports.UI_SHOW_LINKS = process.env.UI_SHOW_LINKS || 'false';
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,7 @@ const {
 | 
				
			||||||
  LANG,
 | 
					  LANG,
 | 
				
			||||||
  UI_TRAFFIC_STATS,
 | 
					  UI_TRAFFIC_STATS,
 | 
				
			||||||
  UI_CHART_TYPE,
 | 
					  UI_CHART_TYPE,
 | 
				
			||||||
 | 
					  UI_SHOW_LINKS,
 | 
				
			||||||
} = require('../config');
 | 
					} = require('../config');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const requiresPassword = !!PASSWORD_HASH;
 | 
					const requiresPassword = !!PASSWORD_HASH;
 | 
				
			||||||
| 
						 | 
					@ -98,6 +99,11 @@ module.exports = class Server {
 | 
				
			||||||
        return `"${UI_CHART_TYPE}"`;
 | 
					        return `"${UI_CHART_TYPE}"`;
 | 
				
			||||||
      }))
 | 
					      }))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      .get('/api/ui-show-links', defineEventHandler((event) => {
 | 
				
			||||||
 | 
					        setHeader(event, 'Content-Type', 'application/json');
 | 
				
			||||||
 | 
					        return `${UI_SHOW_LINKS}`;
 | 
				
			||||||
 | 
					      }))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      // Authentication
 | 
					      // Authentication
 | 
				
			||||||
      .get('/api/session', defineEventHandler((event) => {
 | 
					      .get('/api/session', defineEventHandler((event) => {
 | 
				
			||||||
        const authenticated = requiresPassword
 | 
					        const authenticated = requiresPassword
 | 
				
			||||||
| 
						 | 
					@ -109,6 +115,17 @@ module.exports = class Server {
 | 
				
			||||||
          authenticated,
 | 
					          authenticated,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
      }))
 | 
					      }))
 | 
				
			||||||
 | 
					      .get('/:clientHash', defineEventHandler(async (event) => {
 | 
				
			||||||
 | 
					        const clientHash = getRouterParam(event, 'clientHash');
 | 
				
			||||||
 | 
					        const clients = await WireGuard.getClients();
 | 
				
			||||||
 | 
					        const client = clients.find((client) => client.hash === clientHash);
 | 
				
			||||||
 | 
					        if (!client) return;
 | 
				
			||||||
 | 
					        const clientId = client.id;
 | 
				
			||||||
 | 
					        const config = await WireGuard.getClientConfiguration({ clientId });
 | 
				
			||||||
 | 
					        setHeader(event, 'Content-Disposition', `attachment; filename="${clientHash}.conf"`);
 | 
				
			||||||
 | 
					        setHeader(event, 'Content-Type', 'text/plain');
 | 
				
			||||||
 | 
					        return config;
 | 
				
			||||||
 | 
					      }))
 | 
				
			||||||
      .post('/api/session', defineEventHandler(async (event) => {
 | 
					      .post('/api/session', defineEventHandler(async (event) => {
 | 
				
			||||||
        const { password, remember } = await readBody(event);
 | 
					        const { password, remember } = await readBody(event);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,7 @@ const path = require('path');
 | 
				
			||||||
const debug = require('debug')('WireGuard');
 | 
					const debug = require('debug')('WireGuard');
 | 
				
			||||||
const crypto = require('node:crypto');
 | 
					const crypto = require('node:crypto');
 | 
				
			||||||
const QRCode = require('qrcode');
 | 
					const QRCode = require('qrcode');
 | 
				
			||||||
 | 
					const CRC32 = require('crc-32');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const Util = require('./Util');
 | 
					const Util = require('./Util');
 | 
				
			||||||
const ServerError = require('./ServerError');
 | 
					const ServerError = require('./ServerError');
 | 
				
			||||||
| 
						 | 
					@ -147,6 +148,7 @@ ${client.preSharedKey ? `PresharedKey = ${client.preSharedKey}\n` : ''
 | 
				
			||||||
      createdAt: new Date(client.createdAt),
 | 
					      createdAt: new Date(client.createdAt),
 | 
				
			||||||
      updatedAt: new Date(client.updatedAt),
 | 
					      updatedAt: new Date(client.updatedAt),
 | 
				
			||||||
      allowedIPs: client.allowedIPs,
 | 
					      allowedIPs: client.allowedIPs,
 | 
				
			||||||
 | 
					      hash: Math.abs(CRC32.str(clientId)).toString(16),
 | 
				
			||||||
      downloadableConfig: 'privateKey' in client,
 | 
					      downloadableConfig: 'privateKey' in client,
 | 
				
			||||||
      persistentKeepalive: null,
 | 
					      persistentKeepalive: null,
 | 
				
			||||||
      latestHandshakeAt: null,
 | 
					      latestHandshakeAt: null,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										21
									
								
								src/package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										21
									
								
								src/package-lock.json
									
										
									
										generated
									
									
									
								
							| 
						 | 
					@ -10,6 +10,7 @@
 | 
				
			||||||
      "license": "CC BY-NC-SA 4.0",
 | 
					      "license": "CC BY-NC-SA 4.0",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
        "bcryptjs": "^2.4.3",
 | 
					        "bcryptjs": "^2.4.3",
 | 
				
			||||||
 | 
					        "crc-32": "^1.2.2",
 | 
				
			||||||
        "debug": "^4.3.6",
 | 
					        "debug": "^4.3.6",
 | 
				
			||||||
        "express-session": "^1.18.0",
 | 
					        "express-session": "^1.18.0",
 | 
				
			||||||
        "h3": "^1.12.0",
 | 
					        "h3": "^1.12.0",
 | 
				
			||||||
| 
						 | 
					@ -18,7 +19,7 @@
 | 
				
			||||||
      "devDependencies": {
 | 
					      "devDependencies": {
 | 
				
			||||||
        "eslint-config-athom": "^3.1.3",
 | 
					        "eslint-config-athom": "^3.1.3",
 | 
				
			||||||
        "nodemon": "^3.1.4",
 | 
					        "nodemon": "^3.1.4",
 | 
				
			||||||
        "tailwindcss": "^3.4.9"
 | 
					        "tailwindcss": "^3.4.10"
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
      "engines": {
 | 
					      "engines": {
 | 
				
			||||||
        "node": ">=18"
 | 
					        "node": ">=18"
 | 
				
			||||||
| 
						 | 
					@ -1209,6 +1210,18 @@
 | 
				
			||||||
      "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
 | 
					      "integrity": "sha512-NXdYc3dLr47pBkpUCHtKSwIOQXLVn8dZEuywboCOJY/osA0wFSLlSawr3KN8qXJEyX66FcONTH8EIlVuK0yyFA==",
 | 
				
			||||||
      "license": "MIT"
 | 
					      "license": "MIT"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "node_modules/crc-32": {
 | 
				
			||||||
 | 
					      "version": "1.2.2",
 | 
				
			||||||
 | 
					      "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
 | 
				
			||||||
 | 
					      "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
 | 
				
			||||||
 | 
					      "license": "Apache-2.0",
 | 
				
			||||||
 | 
					      "bin": {
 | 
				
			||||||
 | 
					        "crc32": "bin/crc32.njs"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      "engines": {
 | 
				
			||||||
 | 
					        "node": ">=0.8"
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "node_modules/cross-spawn": {
 | 
					    "node_modules/cross-spawn": {
 | 
				
			||||||
      "version": "7.0.3",
 | 
					      "version": "7.0.3",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
 | 
				
			||||||
| 
						 | 
					@ -4687,9 +4700,9 @@
 | 
				
			||||||
      "peer": true
 | 
					      "peer": true
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "node_modules/tailwindcss": {
 | 
					    "node_modules/tailwindcss": {
 | 
				
			||||||
      "version": "3.4.9",
 | 
					      "version": "3.4.10",
 | 
				
			||||||
      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.9.tgz",
 | 
					      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.10.tgz",
 | 
				
			||||||
      "integrity": "sha512-1SEOvRr6sSdV5IDf9iC+NU4dhwdqzF4zKKq3sAbasUWHEM6lsMhX+eNN5gkPx1BvLFEnZQEUFbXnGj8Qlp83Pg==",
 | 
					      "integrity": "sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==",
 | 
				
			||||||
      "dev": true,
 | 
					      "dev": true,
 | 
				
			||||||
      "license": "MIT",
 | 
					      "license": "MIT",
 | 
				
			||||||
      "dependencies": {
 | 
					      "dependencies": {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,12 +19,13 @@
 | 
				
			||||||
    "debug": "^4.3.6",
 | 
					    "debug": "^4.3.6",
 | 
				
			||||||
    "express-session": "^1.18.0",
 | 
					    "express-session": "^1.18.0",
 | 
				
			||||||
    "h3": "^1.12.0",
 | 
					    "h3": "^1.12.0",
 | 
				
			||||||
    "qrcode": "^1.5.4"
 | 
					    "qrcode": "^1.5.4",
 | 
				
			||||||
 | 
					    "crc-32": "^1.2.2"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "devDependencies": {
 | 
					  "devDependencies": {
 | 
				
			||||||
    "eslint-config-athom": "^3.1.3",
 | 
					    "eslint-config-athom": "^3.1.3",
 | 
				
			||||||
    "nodemon": "^3.1.4",
 | 
					    "nodemon": "^3.1.4",
 | 
				
			||||||
    "tailwindcss": "^3.4.9"
 | 
					    "tailwindcss": "^3.4.10"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "nodemonConfig": {
 | 
					  "nodemonConfig": {
 | 
				
			||||||
    "ignore": [
 | 
					    "ignore": [
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
! tailwindcss v3.4.9 | MIT License | https://tailwindcss.com
 | 
					! tailwindcss v3.4.10 | MIT License | https://tailwindcss.com
 | 
				
			||||||
*/
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -242,6 +242,9 @@
 | 
				
			||||||
                          {{!uiTrafficStats ? " · " : ""}}{{new Date(client.latestHandshakeAt) | timeago}}
 | 
					                          {{!uiTrafficStats ? " · " : ""}}{{new Date(client.latestHandshakeAt) | timeago}}
 | 
				
			||||||
                        </span>
 | 
					                        </span>
 | 
				
			||||||
                      </div>
 | 
					                      </div>
 | 
				
			||||||
 | 
					                      <div v-if="uiShowLinks" :ref="'client-' + client.id + '-hash'" class="text-gray-400 text-xs">
 | 
				
			||||||
 | 
					                        <a :href="'./' + client.hash + ''">{{document.location.protocol}}//{{document.location.host}}/{{client.hash}}</a>
 | 
				
			||||||
 | 
					                      </div>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    <!-- Info -->
 | 
					                    <!-- Info -->
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,6 +64,13 @@ class API {
 | 
				
			||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  async getUIShowLinks() {
 | 
				
			||||||
 | 
					    return this.call({
 | 
				
			||||||
 | 
					      method: 'get',
 | 
				
			||||||
 | 
					      path: '/ui-show-links',
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async getSession() {
 | 
					  async getSession() {
 | 
				
			||||||
    return this.call({
 | 
					    return this.call({
 | 
				
			||||||
      method: 'get',
 | 
					      method: 'get',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -73,6 +73,7 @@ new Vue({
 | 
				
			||||||
    uiTrafficStats: false,
 | 
					    uiTrafficStats: false,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uiChartType: 0,
 | 
					    uiChartType: 0,
 | 
				
			||||||
 | 
					    uiShowLinks: false,
 | 
				
			||||||
    uiShowCharts: localStorage.getItem('uiShowCharts') === '1',
 | 
					    uiShowCharts: localStorage.getItem('uiShowCharts') === '1',
 | 
				
			||||||
    uiTheme: localStorage.theme || 'auto',
 | 
					    uiTheme: localStorage.theme || 'auto',
 | 
				
			||||||
    prefersDarkScheme: window.matchMedia('(prefers-color-scheme: dark)'),
 | 
					    prefersDarkScheme: window.matchMedia('(prefers-color-scheme: dark)'),
 | 
				
			||||||
| 
						 | 
					@ -392,6 +393,14 @@ new Vue({
 | 
				
			||||||
        this.uiChartType = 0;
 | 
					        this.uiChartType = 0;
 | 
				
			||||||
      });
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    this.api.getUIShowLinks()
 | 
				
			||||||
 | 
					      .then((res) => {
 | 
				
			||||||
 | 
					        this.uiShowLinks = res;
 | 
				
			||||||
 | 
					      })
 | 
				
			||||||
 | 
					      .catch(() => {
 | 
				
			||||||
 | 
					        this.uiShowLinks = false;
 | 
				
			||||||
 | 
					      });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Promise.resolve().then(async () => {
 | 
					    Promise.resolve().then(async () => {
 | 
				
			||||||
      const lang = await this.api.getLang();
 | 
					      const lang = await this.api.getLang();
 | 
				
			||||||
      if (lang !== localStorage.getItem('lang') && i18n.availableLocales.includes(lang)) {
 | 
					      if (lang !== localStorage.getItem('lang') && i18n.availableLocales.includes(lang)) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -342,6 +342,12 @@ const messages = { // eslint-disable-line no-unused-vars
 | 
				
			||||||
    downloadConfig: '구성 다운로드',
 | 
					    downloadConfig: '구성 다운로드',
 | 
				
			||||||
    madeBy: '만든 사람',
 | 
					    madeBy: '만든 사람',
 | 
				
			||||||
    donate: '기부',
 | 
					    donate: '기부',
 | 
				
			||||||
 | 
					    toggleCharts: '차트 표시/숨기기',
 | 
				
			||||||
 | 
					    theme: { dark: '어두운 테마', light: '밝은 테마', auto: '자동 테마' },
 | 
				
			||||||
 | 
					    restore: '복원',
 | 
				
			||||||
 | 
					    backup: '백업',
 | 
				
			||||||
 | 
					    titleRestoreConfig: '구성 파일 복원',
 | 
				
			||||||
 | 
					    titleBackupConfig: '구성 파일 백업',
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  vi: {
 | 
					  vi: {
 | 
				
			||||||
    name: 'Tên',
 | 
					    name: 'Tên',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue