Supports displaying short links, for easy downloading on TVs and Android TVs
This commit is contained in:
parent
2ea37dd7ba
commit
0a33b1f7df
|
@ -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 |
|
||||||
|
|
||||||
> 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
|
||||||
|
|
|
@ -37,3 +37,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';
|
||||||
|
|
|
@ -32,6 +32,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;
|
||||||
|
@ -92,6 +93,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
|
||||||
|
@ -103,6 +109,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 } = await readBody(event);
|
const { password } = 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,
|
||||||
|
|
|
@ -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 -->
|
||||||
|
|
|
@ -57,6 +57,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',
|
||||||
|
|
|
@ -71,6 +71,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)'),
|
||||||
|
@ -384,6 +385,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)) {
|
||||||
|
|
Loading…
Reference in New Issue