fix one time links (#1304)

Closes #1302
Co-authored-by: Bernd Storath <999999bst@gmail.com>
This commit is contained in:
Bernd Storath 2024-08-21 15:55:35 +02:00 committed by GitHub
parent 968d2b90a0
commit 86f968499a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 48 additions and 19 deletions

View file

@ -38,6 +38,6 @@ iptables -D FORWARD -o wg0 -j ACCEPT;
module.exports.LANG = process.env.LANG || 'en';
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_SHOW_LINKS = process.env.UI_SHOW_LINKS || 'false';
module.exports.WG_ENABLE_ONE_TIME_LINKS = process.env.WG_ENABLE_ONE_TIME_LINKS || 'false';
module.exports.UI_ENABLE_SORT_CLIENTS = process.env.UI_ENABLE_SORT_CLIENTS || 'false';
module.exports.WG_ENABLE_EXPIRES_TIME = process.env.WG_ENABLE_EXPIRES_TIME || 'false';

View file

@ -33,7 +33,7 @@ const {
LANG,
UI_TRAFFIC_STATS,
UI_CHART_TYPE,
UI_SHOW_LINKS,
WG_ENABLE_ONE_TIME_LINKS,
UI_ENABLE_SORT_CLIENTS,
WG_ENABLE_EXPIRES_TIME,
} = require('../config');
@ -106,9 +106,9 @@ module.exports = class Server {
return `"${UI_CHART_TYPE}"`;
}))
.get('/api/ui-show-links', defineEventHandler((event) => {
.get('/api/wg-enable-one-time-links', defineEventHandler((event) => {
setHeader(event, 'Content-Type', 'application/json');
return `${UI_SHOW_LINKS}`;
return `${WG_ENABLE_ONE_TIME_LINKS}`;
}))
.get('/api/ui-sort-clients', defineEventHandler((event) => {
@ -133,6 +133,12 @@ module.exports = class Server {
};
}))
.get('/cnf/:clientOneTimeLink', defineEventHandler(async (event) => {
if (WG_ENABLE_ONE_TIME_LINKS === 'false') {
throw createError({
status: 404,
message: 'Invalid state',
});
}
const clientOneTimeLink = getRouterParam(event, 'clientOneTimeLink');
const clients = await WireGuard.getClients();
const client = clients.find((client) => client.oneTimeLink === clientOneTimeLink);
@ -254,6 +260,12 @@ module.exports = class Server {
return { success: true };
}))
.post('/api/wireguard/client/:clientId/generateOneTimeLink', defineEventHandler(async (event) => {
if (WG_ENABLE_ONE_TIME_LINKS === 'false') {
throw createError({
status: 404,
message: 'Invalid state',
});
}
const clientId = getRouterParam(event, 'clientId');
if (clientId === '__proto__' || clientId === 'constructor' || clientId === 'prototype') {
throw createError({ status: 403 });

View file

@ -25,6 +25,7 @@ const {
WG_PRE_DOWN,
WG_POST_DOWN,
WG_ENABLE_EXPIRES_TIME,
WG_ENABLE_ONE_TIME_LINKS,
} = require('../config');
module.exports = class WireGuard {
@ -152,7 +153,8 @@ ${client.preSharedKey ? `PresharedKey = ${client.preSharedKey}\n` : ''
? new Date(client.expiredAt)
: null,
allowedIPs: client.allowedIPs,
oneTimeLink: client.oneTimeLink ? client.oneTimeLink : null,
oneTimeLink: client.oneTimeLink ?? null,
oneTimeLinkExpiresAt: client.oneTimeLinkExpiresAt ?? null,
downloadableConfig: 'privateKey' in client,
persistentKeepalive: null,
latestHandshakeAt: null,
@ -310,6 +312,7 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`;
const client = await this.getClient({ clientId });
const key = `${clientId}-${Math.floor(Math.random() * 1000)}`;
client.oneTimeLink = Math.abs(CRC32.str(key)).toString(16);
client.oneTimeLinkExpiresAt = new Date(Date.now() + 5 * 60 * 1000);
client.updatedAt = new Date();
await this.saveConfig();
}
@ -317,6 +320,7 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`;
async eraseOneTimeLink({ clientId }) {
const client = await this.getClient({ clientId });
client.oneTimeLink = null;
client.oneTimeLinkExpiresAt = null;
client.updatedAt = new Date();
await this.saveConfig();
}
@ -396,8 +400,9 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`;
async cronJobEveryMinute() {
const config = await this.getConfig();
let needSaveConfig = false;
// Expires Feature
if (WG_ENABLE_EXPIRES_TIME === 'true') {
let needSaveConfig = false;
for (const client of Object.values(config.clients)) {
if (client.enabled !== true) continue;
if (client.expiredAt !== null && new Date() > new Date(client.expiredAt)) {
@ -407,10 +412,22 @@ Endpoint = ${WG_HOST}:${WG_CONFIG_PORT}`;
client.updatedAt = new Date();
}
}
if (needSaveConfig) {
await this.saveConfig();
}
// One Time Link Feature
if (WG_ENABLE_ONE_TIME_LINKS === 'true') {
for (const client of Object.values(config.clients)) {
if (client.oneTimeLink !== null && new Date() > new Date(client.oneTimeLinkExpiresAt)) {
debug(`Client ${client.id} One Time Link expired.`);
needSaveConfig = true;
client.oneTimeLink = null;
client.oneTimeLinkExpiresAt = null;
client.updatedAt = new Date();
}
}
}
if (needSaveConfig) {
await this.saveConfig();
}
}
};

View file

@ -256,7 +256,7 @@
{{!uiTrafficStats ? " · " : ""}}{{new Date(client.latestHandshakeAt) | timeago}}
</span>
</div>
<div v-if="uiShowLinks && client.oneTimeLink !== null && client.oneTimeLink !== ''" :ref="'client-' + client.id + '-link'" class="text-gray-400 text-xs">
<div v-if="enableOneTimeLinks && client.oneTimeLink !== null && client.oneTimeLink !== ''" :ref="'client-' + client.id + '-link'" class="text-gray-400 text-xs">
<a :href="'./cnf/' + client.oneTimeLink + ''">{{document.location.protocol}}//{{document.location.host}}/cnf/{{client.oneTimeLink}}</a>
</div>
<!-- Expire Date -->
@ -385,7 +385,7 @@
</a>
<!-- Short OneTime Link -->
<button v-if="uiShowLinks" :disabled="!client.downloadableConfig"
<button v-if="enableOneTimeLinks" :disabled="!client.downloadableConfig"
class="align-middle inline-block bg-gray-100 dark:bg-neutral-600 dark:text-neutral-300 p-2 rounded transition"
:class="{
'hover:bg-red-800 dark:hover:bg-red-800 hover:text-white dark:hover:text-white': client.downloadableConfig,

View file

@ -64,10 +64,10 @@ class API {
});
}
async getUIShowLinks() {
async getWGEnableOneTimeLinks() {
return this.call({
method: 'get',
path: '/ui-show-links',
path: '/wg-enable-one-time-links',
});
}

View file

@ -92,7 +92,7 @@ new Vue({
uiTrafficStats: false,
uiChartType: 0,
uiShowLinks: false,
enableOneTimeLinks: false,
enableSortClient: false,
sortClient: true, // Sort clients by name, true = asc, false = desc
enableExpireTime: false,
@ -441,12 +441,12 @@ new Vue({
this.uiChartType = 0;
});
this.api.getUIShowLinks()
this.api.getWGEnableOneTimeLinks()
.then((res) => {
this.uiShowLinks = res;
this.enableOneTimeLinks = res;
})
.catch(() => {
this.uiShowLinks = false;
this.enableOneTimeLinks = false;
});
this.api.getUiSortClients()