Browse Source

Feat: IPv6 (#1354)

* start supporting ipv6

* add ipv6 support

* build server with es2020

es2019 doesn't support bigint

* fix issues, better naming
pull/1377/head
Bernd Storath 8 months ago
committed by Bernd Storath
parent
commit
458d90d41f
  1. 2
      Dockerfile
  2. 2
      Dockerfile.dev
  3. 3
      docker-compose.yml
  4. 60
      src/app/components/Client/Address.vue
  5. 60
      src/app/components/Client/Address4.vue
  6. 2
      src/app/components/Client/Client.vue
  7. 10
      src/app/utils/api.ts
  8. 7
      src/nuxt.config.ts
  9. 5
      src/package.json
  10. 96
      src/pnpm-lock.yaml
  11. 3
      src/server/api/release.get.ts
  12. 2
      src/server/api/session.post.ts
  13. 7
      src/server/api/wireguard/client/[clientId]/address4.put.ts
  14. 93
      src/server/utils/WireGuard.ts
  15. 3
      src/server/utils/config.ts
  16. 8
      src/server/utils/types.ts
  17. 13
      src/services/database/lowdb.ts
  18. 35
      src/services/database/migrations/1.ts
  19. 5
      src/services/database/repositories/client.ts
  20. 2
      src/services/database/repositories/database.ts
  21. 8
      src/services/database/repositories/system.ts
  22. 6
      src/services/database/repositories/user.ts

2
Dockerfile

@ -27,11 +27,13 @@ RUN apk add --no-cache \
dpkg \ dpkg \
dumb-init \ dumb-init \
iptables \ iptables \
ip6tables \
iptables-legacy \ iptables-legacy \
wireguard-tools wireguard-tools
# Use iptables-legacy # Use iptables-legacy
RUN update-alternatives --install /sbin/iptables iptables /sbin/iptables-legacy 10 --slave /sbin/iptables-restore iptables-restore /sbin/iptables-legacy-restore --slave /sbin/iptables-save iptables-save /sbin/iptables-legacy-save RUN update-alternatives --install /sbin/iptables iptables /sbin/iptables-legacy 10 --slave /sbin/iptables-restore iptables-restore /sbin/iptables-legacy-restore --slave /sbin/iptables-save iptables-save /sbin/iptables-legacy-save
RUN update-alternatives --install /sbin/ip6tables ip6tables /sbin/ip6tables-legacy 10 --slave /sbin/ip6tables-restore ip6tables-restore /sbin/ip6tables-legacy-restore --slave /sbin/ip6tables-save ip6tables-save /sbin/ip6tables-legacy-save
# Set Environment # Set Environment
ENV DEBUG=Server,WireGuard,LowDB ENV DEBUG=Server,WireGuard,LowDB

2
Dockerfile.dev

@ -17,11 +17,13 @@ RUN apk add --no-cache \
dpkg \ dpkg \
dumb-init \ dumb-init \
iptables \ iptables \
ip6tables \
iptables-legacy \ iptables-legacy \
wireguard-tools wireguard-tools
# Use iptables-legacy # Use iptables-legacy
RUN update-alternatives --install /sbin/iptables iptables /sbin/iptables-legacy 10 --slave /sbin/iptables-restore iptables-restore /sbin/iptables-legacy-restore --slave /sbin/iptables-save iptables-save /sbin/iptables-legacy-save RUN update-alternatives --install /sbin/iptables iptables /sbin/iptables-legacy 10 --slave /sbin/iptables-restore iptables-restore /sbin/iptables-legacy-restore --slave /sbin/iptables-save iptables-save /sbin/iptables-legacy-save
RUN update-alternatives --install /sbin/ip6tables ip6tables /sbin/ip6tables-legacy 10 --slave /sbin/ip6tables-restore ip6tables-restore /sbin/ip6tables-legacy-restore --slave /sbin/ip6tables-save ip6tables-save /sbin/ip6tables-legacy-save
# Set Environment # Set Environment
ENV DEBUG=Server,WireGuard,LowDB ENV DEBUG=Server,WireGuard,LowDB

3
docker-compose.yml

@ -24,3 +24,6 @@ services:
sysctls: sysctls:
- net.ipv4.ip_forward=1 - net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1 - net.ipv4.conf.all.src_valid_mark=1
- net.ipv6.conf.all.disable_ipv6=0
- net.ipv6.conf.all.forwarding=1
- net.ipv6.conf.default.forwarding=1

60
src/app/components/Client/Address.vue

@ -1,60 +0,0 @@
<template>
<span class="group">
<!-- Show -->
<input
v-show="clientEditAddressId === client.id"
ref="clientAddressInput"
v-model="clientEditAddress"
class="rounded border-2 dark:bg-neutral-700 border-gray-100 dark:border-neutral-600 focus:border-gray-200 dark:focus:border-neutral-500 outline-none w-20 text-black dark:text-neutral-300 dark:placeholder:text-neutral-500"
@keyup.enter="
updateClientAddress(client, clientEditAddress);
clientEditAddress = null;
clientEditAddressId = null;
"
@keyup.escape="
clientEditAddress = null;
clientEditAddressId = null;
"
/>
<span v-show="clientEditAddressId !== client.id" class="inline-block">{{
client.address
}}</span>
<!-- Edit -->
<span
v-show="clientEditAddressId !== client.id"
class="cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity"
@click="
clientEditAddress = client.address;
clientEditAddressId = client.id;
nextTick(() => clientAddressInput?.select());
"
>
<IconsEdit
class="h-4 w-4 inline align-middle opacity-25 hover:opacity-100"
/>
</span>
</span>
</template>
<script setup lang="ts">
defineProps<{
client: LocalClient;
}>();
const clientsStore = useClientsStore();
const clientAddressInput = ref<HTMLInputElement | null>(null);
const clientEditAddress = ref<null | string>(null);
const clientEditAddressId = ref<null | string>(null);
function updateClientAddress(client: WGClient, address: string | null) {
if (address === null) {
return;
}
api
.updateClientAddress({ clientId: client.id, address })
.catch((err) => alert(err.message || err.toString()))
.finally(() => clientsStore.refresh().catch(console.error));
}
</script>

60
src/app/components/Client/Address4.vue

@ -0,0 +1,60 @@
<template>
<span class="group">
<!-- Show -->
<input
v-show="clientEditAddress4Id === client.id"
ref="clientAddress4Input"
v-model="clientEditAddress4"
class="rounded border-2 dark:bg-neutral-700 border-gray-100 dark:border-neutral-600 focus:border-gray-200 dark:focus:border-neutral-500 outline-none w-20 text-black dark:text-neutral-300 dark:placeholder:text-neutral-500"
@keyup.enter="
updateClientAddress4(client, clientEditAddress4);
clientEditAddress4 = null;
clientEditAddress4Id = null;
"
@keyup.escape="
clientEditAddress4 = null;
clientEditAddress4Id = null;
"
/>
<span v-show="clientEditAddress4Id !== client.id" class="inline-block">{{
client.address4
}}</span>
<!-- Edit -->
<span
v-show="clientEditAddress4Id !== client.id"
class="cursor-pointer opacity-0 group-hover:opacity-100 transition-opacity"
@click="
clientEditAddress4 = client.address4;
clientEditAddress4Id = client.id;
nextTick(() => clientAddress4Input?.select());
"
>
<IconsEdit
class="h-4 w-4 inline align-middle opacity-25 hover:opacity-100"
/>
</span>
</span>
</template>
<script setup lang="ts">
defineProps<{
client: LocalClient;
}>();
const clientsStore = useClientsStore();
const clientAddress4Input = ref<HTMLInputElement | null>(null);
const clientEditAddress4 = ref<null | string>(null);
const clientEditAddress4Id = ref<null | string>(null);
function updateClientAddress4(client: WGClient, address4: string | null) {
if (address4 === null) {
return;
}
api
.updateClientAddress4({ clientId: client.id, address4 })
.catch((err) => alert(err.message || err.toString()))
.finally(() => clientsStore.refresh().catch(console.error));
}
</script>

2
src/app/components/Client/Client.vue

@ -12,7 +12,7 @@
<div <div
class="block md:inline-block pb-1 md:pb-0 text-gray-500 dark:text-neutral-400 text-xs" class="block md:inline-block pb-1 md:pb-0 text-gray-500 dark:text-neutral-400 text-xs"
> >
<ClientAddress :client="client" /> <ClientAddress4 :client="client" />
<ClientInlineTransfer <ClientInlineTransfer
v-if="!globalStore.features.trafficStats.enabled" v-if="!globalStore.features.trafficStats.enabled"
:client="client" :client="client"

10
src/app/utils/api.ts

@ -95,16 +95,16 @@ class API {
}); });
} }
async updateClientAddress({ async updateClientAddress4({
clientId, clientId,
address, address4,
}: { }: {
clientId: string; clientId: string;
address: string; address4: string;
}) { }) {
return $fetch(`/api/wireguard/client/${clientId}/address`, { return $fetch(`/api/wireguard/client/${clientId}/address4`, {
method: 'put', method: 'put',
body: { address }, body: { address4 },
}); });
} }

7
src/nuxt.config.ts

@ -23,4 +23,11 @@ export default defineNuxtConfig({
localeDetector: './localeDetector.ts', localeDetector: './localeDetector.ts',
}, },
}, },
nitro: {
esbuild: {
options: {
target: 'es2020',
},
},
},
}); });

5
src/package.json

@ -27,9 +27,11 @@
"apexcharts": "^3.53.0", "apexcharts": "^3.53.0",
"basic-auth": "^2.0.1", "basic-auth": "^2.0.1",
"bcryptjs": "^2.4.3", "bcryptjs": "^2.4.3",
"cidr-tools": "^11.0.2",
"crc-32": "^1.2.2", "crc-32": "^1.2.2",
"debug": "^4.3.7", "debug": "^4.3.7",
"ip": "^2.0.1", "ip-bigint": "^8.2.0",
"is-ip": "^5.0.1",
"js-sha256": "^0.11.0", "js-sha256": "^0.11.0",
"lowdb": "^7.0.1", "lowdb": "^7.0.1",
"nuxt": "^3.13.0", "nuxt": "^3.13.0",
@ -45,7 +47,6 @@
"@nuxt/eslint-config": "^0.5.5", "@nuxt/eslint-config": "^0.5.5",
"@types/bcryptjs": "^2.4.6", "@types/bcryptjs": "^2.4.6",
"@types/debug": "^4.1.12", "@types/debug": "^4.1.12",
"@types/ip": "^1.1.3",
"@types/qrcode": "^1.5.5", "@types/qrcode": "^1.5.5",
"eslint": "^9.9.1", "eslint": "^9.9.1",
"eslint-config-prettier": "^9.1.0", "eslint-config-prettier": "^9.1.0",

96
src/pnpm-lock.yaml

@ -32,15 +32,21 @@ importers:
bcryptjs: bcryptjs:
specifier: ^2.4.3 specifier: ^2.4.3
version: 2.4.3 version: 2.4.3
cidr-tools:
specifier: ^11.0.2
version: 11.0.2
crc-32: crc-32:
specifier: ^1.2.2 specifier: ^1.2.2
version: 1.2.2 version: 1.2.2
debug: debug:
specifier: ^4.3.7 specifier: ^4.3.7
version: 4.3.7 version: 4.3.7
ip: ip-bigint:
specifier: ^2.0.1 specifier: ^8.2.0
version: 2.0.1 version: 8.2.0
is-ip:
specifier: ^5.0.1
version: 5.0.1
js-sha256: js-sha256:
specifier: ^0.11.0 specifier: ^0.11.0
version: 0.11.0 version: 0.11.0
@ -81,9 +87,6 @@ importers:
'@types/debug': '@types/debug':
specifier: ^4.1.12 specifier: ^4.1.12
version: 4.1.12 version: 4.1.12
'@types/ip':
specifier: ^1.1.3
version: 1.1.3
'@types/qrcode': '@types/qrcode':
specifier: ^1.5.5 specifier: ^1.5.5
version: 1.5.5 version: 1.5.5
@ -1223,9 +1226,6 @@ packages:
'@types/[email protected]': '@types/[email protected]':
resolution: {integrity: sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==} resolution: {integrity: sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==}
'@types/[email protected]':
resolution: {integrity: sha512-64waoJgkXFTYnCYDUWgSATJ/dXEBanVkaP5d4Sbk7P6U7cTTMhxVyROTckc6JKdwCrgnAjZMn0k3177aQxtDEA==}
'@types/[email protected]': '@types/[email protected]':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
@ -1678,6 +1678,10 @@ packages:
resolution: {integrity: sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==} resolution: {integrity: sha512-TdHqgGf9odd8SXNuxtUBVx8Nv+qZOejE6qyqiy5NtbYYQOeFa6zmHkxlPzmaLxWWHsU6nJmB7AETdVPi+2NBUg==}
engines: {node: '>=8'} engines: {node: '>=8'}
[email protected]:
resolution: {integrity: sha512-OLeM9EOXybbhMsGGBNRLCMjn8e+wFOXARIShF/sZwmJLsxWywqfE0By4BMftT6BFWpbcETWpW7TfM2KGCtrZDg==}
engines: {node: '>=18'}
[email protected]: [email protected]:
resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==}
@ -1699,6 +1703,10 @@ packages:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
[email protected]:
resolution: {integrity: sha512-ujdnoq2Kxb8s3ItNBtnYeXdm07FcU0u8ARAT1lQ2YdMwQC+cdiXX8KoqMVuglztILivceTtp4ivqGSmEmhBUJw==}
engines: {node: '>=12'}
[email protected]: [email protected]:
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@ -1784,6 +1792,10 @@ packages:
resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
[email protected]:
resolution: {integrity: sha512-lOETlkIeYSJWcbbcvjRKGxVMXJR+8+OQb/mTPbA4ObPMytYIsUbuOE0Jzy60hjARYszq1id0j8KgVhC+WGZVTg==}
engines: {node: '>=12'}
[email protected]: [email protected]:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
@ -2338,6 +2350,10 @@ packages:
[email protected]: [email protected]:
resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
[email protected]:
resolution: {integrity: sha512-0NVVC0TaP7dSTvn1yMiy6d6Q8gifzbvQafO46RtLG/kHJUBNd+pVRGOBoK44wNBvtSPUJRfdVvkFdD3p0xvyZg==}
engines: {node: '>=14.16'}
[email protected]: [email protected]:
resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -2555,8 +2571,13 @@ packages:
resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==} resolution: {integrity: sha512-2YZsvl7jopIa1gaePkeMtd9rAcSjOOjPtpcLlOeusyO+XH2SK5ZcT+UCrElPP+WVIInh2TzeI4XW9ENaSLVVHA==}
engines: {node: '>=12.22.0'} engines: {node: '>=12.22.0'}
[email protected]: [email protected]:
resolution: {integrity: sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==} resolution: {integrity: sha512-46EAEKzGNxojH5JaGEeCix49tL4h1W8ia5mhogZ68HroVAfyLj1E+SFFid4GuyK0mdIKjwcAITLqwg1wlkx2iQ==}
engines: {node: '>=18'}
[email protected]:
resolution: {integrity: sha512-fOCG6lhoKKakwv+C6KdsOnGvgXnmgfmp0myi3bcNwj3qfwPAxRKWEuFhvEFF7ceYIz6+1jRZ+yguLFAmUNPEfw==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
[email protected]: [email protected]:
resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==}
@ -2614,6 +2635,10 @@ packages:
resolution: {integrity: sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==} resolution: {integrity: sha512-K55T22lfpQ63N4KEN57jZUAaAYqYHEe8veb/TycJRk9DdSCLLcovXz/mL6mOnhQaZsQGwPhuFopdQIlqGSEjiQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
[email protected]:
resolution: {integrity: sha512-FCsGHdlrOnZQcp0+XT5a+pYowf33itBalCl+7ovNXC/7o5BhIpG14M3OrpPPdBSIQJCm+0M5+9mO7S9VVTTCFw==}
engines: {node: '>=14.16'}
[email protected]: [email protected]:
resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==}
@ -2632,6 +2657,10 @@ packages:
[email protected]: [email protected]:
resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==}
[email protected]:
resolution: {integrity: sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==}
engines: {node: '>=12'}
[email protected]: [email protected]:
resolution: {integrity: sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==} resolution: {integrity: sha512-x7+VxdxOdlV3CYpjvRLBv5Lo9OJerlYanjwFrPR9fuGPjCiNiCzFgAWpiLAohSbsnH4ZAys3SBh+hq5rJosxUQ==}
@ -3840,6 +3869,10 @@ packages:
engines: {node: '>=16 || 14 >=14.17'} engines: {node: '>=16 || 14 >=14.17'}
hasBin: true hasBin: true
[email protected]:
resolution: {integrity: sha512-WZzIx3rC1CvbMDloLsVw0lkZVKJWbrkJ0k1ghKFmcnPrW1+jWbgTkTEWVtD9lMdmI4jZEz40+naBxl1dCUhXXw==}
engines: {node: '>=14.16'}
[email protected]: [email protected]:
resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==} resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==}
engines: {node: '>=16'} engines: {node: '>=16'}
@ -3948,6 +3981,10 @@ packages:
[email protected]: [email protected]:
resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
[email protected]:
resolution: {integrity: sha512-75voc/9G4rDIJleOo4jPvN4/YC4GRZrY8yy1uU4lwrB3XEQbWve8zXoO5No4eFrGcTAMYyoY67p8jRQdtA1HbA==}
engines: {node: '>=12'}
[email protected]: [email protected]:
resolution: {integrity: sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w==} resolution: {integrity: sha512-a7wPxPdVlQL7lqvitHGGRsofhdwtkoSXPGATFuSOA2i1ZNQEPLrGnj68vOp2sOJTCFAQVXPeNMX/GctBaO9L2w==}
@ -5631,10 +5668,6 @@ snapshots:
dependencies: dependencies:
'@types/node': 22.5.2 '@types/node': 22.5.2
'@types/[email protected]':
dependencies:
'@types/node': 22.5.2
'@types/[email protected]': {} '@types/[email protected]': {}
'@types/[email protected]': {} '@types/[email protected]': {}
@ -6211,6 +6244,10 @@ snapshots:
[email protected]: {} [email protected]: {}
[email protected]:
dependencies:
ip-bigint: 8.2.0
[email protected]: [email protected]:
dependencies: dependencies:
consola: 3.2.3 consola: 3.2.3
@ -6239,6 +6276,10 @@ snapshots:
strip-ansi: 6.0.1 strip-ansi: 6.0.1
wrap-ansi: 7.0.0 wrap-ansi: 7.0.0
[email protected]:
dependencies:
is-regexp: 3.1.0
[email protected]: {} [email protected]: {}
[email protected]: {} [email protected]: {}
@ -6299,6 +6340,8 @@ snapshots:
[email protected]: {} [email protected]: {}
[email protected]: {}
[email protected]: {} [email protected]: {}
[email protected]: {} [email protected]: {}
@ -6948,6 +6991,8 @@ snapshots:
[email protected]: {} [email protected]: {}
[email protected]: {}
[email protected]: [email protected]:
dependencies: dependencies:
aproba: 2.0.0 aproba: 2.0.0
@ -7187,7 +7232,9 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
[email protected]: {} [email protected]: {}
[email protected]: {}
[email protected]: {} [email protected]: {}
@ -7232,6 +7279,11 @@ snapshots:
global-directory: 4.0.1 global-directory: 4.0.1
is-path-inside: 4.0.0 is-path-inside: 4.0.0
[email protected]:
dependencies:
ip-regex: 5.0.0
super-regex: 0.2.0
[email protected]: {} [email protected]: {}
[email protected]: {} [email protected]: {}
@ -7244,6 +7296,8 @@ snapshots:
dependencies: dependencies:
'@types/estree': 1.0.5 '@types/estree': 1.0.5
[email protected]: {}
[email protected]: [email protected]:
dependencies: dependencies:
protocols: 2.0.1 protocols: 2.0.1
@ -8593,6 +8647,12 @@ snapshots:
pirates: 4.0.6 pirates: 4.0.6
ts-interface-checker: 0.1.13 ts-interface-checker: 0.1.13
[email protected]:
dependencies:
clone-regexp: 3.0.0
function-timeout: 0.1.1
time-span: 5.1.0
[email protected]: [email protected]:
dependencies: dependencies:
copy-anything: 3.0.5 copy-anything: 3.0.5
@ -8738,6 +8798,10 @@ snapshots:
dependencies: dependencies:
any-promise: 1.3.0 any-promise: 1.3.0
[email protected]:
dependencies:
convert-hrtime: 5.0.0
[email protected]: {} [email protected]: {}
[email protected]: {} [email protected]: {}

3
src/server/api/release.get.ts

@ -1,8 +1,7 @@
export default defineEventHandler(async () => { export default defineEventHandler(async () => {
const system = await Database.getSystem();
const latestRelease = await fetchLatestRelease(); const latestRelease = await fetchLatestRelease();
return { return {
currentRelease: system.release, currentRelease: RELEASE,
latestRelease: latestRelease, latestRelease: latestRelease,
}; };
}); });

2
src/server/api/session.post.ts

@ -29,7 +29,7 @@ export default defineEventHandler(async (event) => {
if (remember) { if (remember) {
conf.cookie = { conf.cookie = {
...(system.sessionConfig.cookie ?? {}), ...(system.sessionConfig.cookie ?? {}),
maxAge: system.cookieMaxAge * 60, maxAge: system.sessionTimeout,
}; };
} }

7
src/server/api/wireguard/client/[clientId]/address.put.ts → src/server/api/wireguard/client/[clientId]/address4.put.ts

@ -3,7 +3,10 @@ export default defineEventHandler(async (event) => {
event, event,
validateZod(clientIdType) validateZod(clientIdType)
); );
const { address } = await readValidatedBody(event, validateZod(addressType)); const { address4 } = await readValidatedBody(
await WireGuard.updateClientAddress({ clientId, address }); event,
validateZod(address4Type)
);
await WireGuard.updateClientAddress({ clientId, address4 });
return { success: true }; return { success: true };
}); });

93
src/server/utils/WireGuard.ts

@ -6,7 +6,9 @@ import QRCode from 'qrcode';
import CRC32 from 'crc-32'; import CRC32 from 'crc-32';
import type { NewClient } from '~~/services/database/repositories/client'; import type { NewClient } from '~~/services/database/repositories/client';
import ip from 'ip'; import { parseCidr } from 'cidr-tools';
import { stringifyIp } from 'ip-bigint';
import { isIPv4 } from 'is-ip';
const DEBUG = debug('WireGuard'); const DEBUG = debug('WireGuard');
@ -19,9 +21,8 @@ class WireGuard {
async #saveWireguardConfig() { async #saveWireguardConfig() {
const system = await Database.getSystem(); const system = await Database.getSystem();
const clients = await Database.getClients(); const clients = await Database.getClients();
const cidrBlock = ip.cidrSubnet( const cidr4Block = parseCidr(system.userConfig.address4Range).prefix;
system.userConfig.addressRange const cidr6Block = parseCidr(system.userConfig.address6Range).prefix;
).subnetMaskLength;
let result = ` let result = `
# Note: Do not edit this file directly. # Note: Do not edit this file directly.
# Your changes will be overwritten! # Your changes will be overwritten!
@ -29,7 +30,7 @@ class WireGuard {
# Server # Server
[Interface] [Interface]
PrivateKey = ${system.interface.privateKey} PrivateKey = ${system.interface.privateKey}
Address = ${system.interface.address}/${cidrBlock} Address = ${system.interface.address4}/${cidr4Block}, ${system.interface.address6}/${cidr6Block}
ListenPort = ${system.wgPort} ListenPort = ${system.wgPort}
PreUp = ${system.iptables.PreUp} PreUp = ${system.iptables.PreUp}
PostUp = ${system.iptables.PostUp} PostUp = ${system.iptables.PostUp}
@ -46,7 +47,7 @@ PostDown = ${system.iptables.PostDown}
[Peer] [Peer]
PublicKey = ${client.publicKey} PublicKey = ${client.publicKey}
PresharedKey = ${client.preSharedKey} PresharedKey = ${client.preSharedKey}
AllowedIPs = ${client.address}/32`; AllowedIPs = ${client.address4}/32, ${client.address6}/128`;
} }
DEBUG('Config saving...'); DEBUG('Config saving...');
@ -68,7 +69,8 @@ AllowedIPs = ${client.address}/32`;
id: clientId, id: clientId,
name: client.name, name: client.name,
enabled: client.enabled, enabled: client.enabled,
address: client.address, address4: client.address4,
address6: client.address6,
publicKey: client.publicKey, publicKey: client.publicKey,
createdAt: new Date(client.createdAt), createdAt: new Date(client.createdAt),
updatedAt: new Date(client.updatedAt), updatedAt: new Date(client.updatedAt),
@ -134,18 +136,20 @@ AllowedIPs = ${client.address}/32`;
async getClientConfiguration({ clientId }: { clientId: string }) { async getClientConfiguration({ clientId }: { clientId: string }) {
const system = await Database.getSystem(); const system = await Database.getSystem();
const client = await this.getClient({ clientId }); const client = await this.getClient({ clientId });
const cidr4Block = parseCidr(system.userConfig.address4Range).prefix;
const cidr6Block = parseCidr(system.userConfig.address6Range).prefix;
return ` return `
[Interface] [Interface]
PrivateKey = ${client.privateKey} PrivateKey = ${client.privateKey}
Address = ${client.address} Address = ${client.address4}/${cidr4Block}, ${client.address6}/${cidr6Block}
DNS = ${system.userConfig.defaultDns.join(',')} DNS = ${system.userConfig.defaultDns.join(', ')}
MTU = ${system.userConfig.mtu} MTU = ${system.userConfig.mtu}
[Peer] [Peer]
PublicKey = ${system.interface.publicKey} PublicKey = ${system.interface.publicKey}
PresharedKey = ${client.preSharedKey} PresharedKey = ${client.preSharedKey}
AllowedIPs = ${client.allowedIPs} AllowedIPs = ${client.allowedIPs.join(', ')}
PersistentKeepalive = ${client.persistentKeepalive} PersistentKeepalive = ${client.persistentKeepalive}
Endpoint = ${system.wgHost}:${system.wgConfigPort}`; Endpoint = ${system.wgHost}:${system.wgConfigPort}`;
} }
@ -165,10 +169,6 @@ Endpoint = ${system.wgHost}:${system.wgConfigPort}`;
name: string; name: string;
expireDate: string | null; expireDate: string | null;
}) { }) {
if (!name) {
throw new Error('Missing: Name');
}
const system = await Database.getSystem(); const system = await Database.getSystem();
const clients = await Database.getClients(); const clients = await Database.getClients();
@ -179,26 +179,48 @@ Endpoint = ${system.wgHost}:${system.wgConfigPort}`;
const preSharedKey = await exec('wg genpsk'); const preSharedKey = await exec('wg genpsk');
// Calculate next IP // Calculate next IP
const cidr = ip.cidrSubnet(system.userConfig.addressRange); const cidr4 = parseCidr(system.userConfig.address4Range);
let address; let address4;
for ( for (let i = cidr4.start + 2n; i <= cidr4.end - 1n; i++) {
let i = ip.toLong(cidr.firstAddress) + 1; const currentIp4 = stringifyIp({ number: i, version: 4 });
i <= ip.toLong(cidr.lastAddress) - 1; const client = Object.values(clients).find((client) => {
i++ return client.address4 === currentIp4;
) { });
const currentIp = ip.fromLong(i);
if (!client) {
address4 = currentIp4;
break;
}
}
if (!address4) {
throw createError({
statusCode: 409,
statusMessage: 'Maximum number of clients reached.',
data: { cause: 'IPv4 Address Pool exhausted' },
});
}
const cidr6 = parseCidr(system.userConfig.address6Range);
let address6;
for (let i = cidr6.start + 2n; i <= cidr6.end - 1n; i++) {
const currentIp6 = stringifyIp({ number: i, version: 6 });
const client = Object.values(clients).find((client) => { const client = Object.values(clients).find((client) => {
return client.address === currentIp; return client.address6 === currentIp6;
}); });
if (!client) { if (!client) {
address = currentIp; address6 = currentIp6;
break; break;
} }
} }
if (!address) { if (!address6) {
throw new Error('Maximum number of clients reached.'); throw createError({
statusCode: 409,
statusMessage: 'Maximum number of clients reached.',
data: { cause: 'IPv6 Address Pool exhausted' },
});
} }
// Create Client // Create Client
@ -207,7 +229,8 @@ Endpoint = ${system.wgHost}:${system.wgConfigPort}`;
const client: NewClient = { const client: NewClient = {
id, id,
name, name,
address, address4,
address6,
privateKey, privateKey,
publicKey, publicKey,
preSharedKey, preSharedKey,
@ -281,19 +304,19 @@ Endpoint = ${system.wgHost}:${system.wgConfigPort}`;
async updateClientAddress({ async updateClientAddress({
clientId, clientId,
address, address4,
}: { }: {
clientId: string; clientId: string;
address: string; address4: string;
}) { }) {
if (!ip.isV4Format(address)) { if (!isIPv4(address4)) {
throw createError({ throw createError({
statusCode: 400, statusCode: 400,
statusMessage: `Invalid Address: ${address}`, statusMessage: `Invalid Address: ${address4}`,
}); });
} }
await Database.updateClientAddress(clientId, address); await Database.updateClientAddress4(clientId, address4);
await this.saveConfig(); await this.saveConfig();
} }
@ -433,9 +456,9 @@ Endpoint = ${system.wgHost}:${system.wgConfigPort}`;
if (client.endpoint !== null) { if (client.endpoint !== null) {
wireguardConnectedPeersCount++; wireguardConnectedPeersCount++;
} }
wireguardSentBytes += `wireguard_sent_bytes{interface="wg0",enabled="${client.enabled}",address="${client.address}",name="${client.name}"} ${Number(client.transferTx)}\n`; wireguardSentBytes += `wireguard_sent_bytes{interface="wg0",enabled="${client.enabled}",address4="${client.address4}",address6="${client.address6}",name="${client.name}"} ${Number(client.transferTx)}\n`;
wireguardReceivedBytes += `wireguard_received_bytes{interface="wg0",enabled="${client.enabled}",address="${client.address}",name="${client.name}"} ${Number(client.transferRx)}\n`; wireguardReceivedBytes += `wireguard_received_bytes{interface="wg0",enabled="${client.enabled}",address4="${client.address4}",address6="${client.address6}",name="${client.name}"} ${Number(client.transferRx)}\n`;
wireguardLatestHandshakeSeconds += `wireguard_latest_handshake_seconds{interface="wg0",enabled="${client.enabled}",address="${client.address}",name="${client.name}"} ${client.latestHandshakeAt ? (new Date().getTime() - new Date(client.latestHandshakeAt).getTime()) / 1000 : 0}\n`; wireguardLatestHandshakeSeconds += `wireguard_latest_handshake_seconds{interface="wg0",enabled="${client.enabled}",address4="${client.address4}",address6="${client.address6}",name="${client.name}"} ${client.latestHandshakeAt ? (new Date().getTime() - new Date(client.latestHandshakeAt).getTime()) / 1000 : 0}\n`;
} }
let returnText = '# HELP wg-easy and wireguard metrics\n'; let returnText = '# HELP wg-easy and wireguard metrics\n';

3
src/server/utils/config.ts

@ -1,5 +1,8 @@
import debug from 'debug'; import debug from 'debug';
import packageJson from '@@/package.json';
export const WG_PATH = process.env.WG_PATH || '/etc/wireguard/'; export const WG_PATH = process.env.WG_PATH || '/etc/wireguard/';
export const RELEASE = packageJson.release.version;
export const SERVER_DEBUG = debug('Server'); export const SERVER_DEBUG = debug('Server');

8
src/server/utils/types.ts

@ -13,8 +13,8 @@ const id = z
.uuid('Client ID must be a valid UUID') .uuid('Client ID must be a valid UUID')
.pipe(safeStringRefine); .pipe(safeStringRefine);
const address = z const address4 = z
.string({ message: 'Address must be a valid string' }) .string({ message: 'IPv4 Address must be a valid string' })
.pipe(safeStringRefine); .pipe(safeStringRefine);
const name = z const name = z
@ -54,9 +54,9 @@ export const clientIdType = z.object(
{ message: "This shouldn't happen" } { message: "This shouldn't happen" }
); );
export const addressType = z.object( export const address4Type = z.object(
{ {
address: address, address4: address4,
}, },
{ message: 'Body must be a valid object' } { message: 'Body must be a valid object' }
); );

13
src/services/database/lowdb.ts

@ -102,6 +102,7 @@ export default class LowDB extends DatabaseProvider {
id: crypto.randomUUID(), id: crypto.randomUUID(),
password: hashPassword(password), password: hashPassword(password),
username, username,
name: 'Administrator',
role: isUserEmpty ? 'ADMIN' : 'CLIENT', role: isUserEmpty ? 'ADMIN' : 'CLIENT',
enabled: true, enabled: true,
createdAt: now, createdAt: now,
@ -175,17 +176,17 @@ export default class LowDB extends DatabaseProvider {
}); });
} }
async updateClientAddress(id: string, address: string) { async updateClientAddress4(id: string, address4: string) {
DEBUG('Update Client Address'); DEBUG('Update Client Address4');
await this.#db.update((data) => { await this.#db.update((data) => {
if (data.clients[id]) { if (data.clients[id]) {
data.clients[id].address = address; data.clients[id].address4 = address4;
} }
}); });
} }
async updateClientExpirationDate(id: string, expirationDate: string | null) { async updateClientExpirationDate(id: string, expirationDate: string | null) {
DEBUG('Update Client Address'); DEBUG('Update Client Expiration Date');
await this.#db.update((data) => { await this.#db.update((data) => {
if (data.clients[id]) { if (data.clients[id]) {
data.clients[id].expiresAt = expirationDate; data.clients[id].expiresAt = expirationDate;
@ -194,7 +195,7 @@ export default class LowDB extends DatabaseProvider {
} }
async deleteOneTimeLink(id: string) { async deleteOneTimeLink(id: string) {
DEBUG('Update Client Address'); DEBUG('Delete Client One Time Link');
await this.#db.update((data) => { await this.#db.update((data) => {
if (data.clients[id]) { if (data.clients[id]) {
if (data.clients[id].oneTimeLink) { if (data.clients[id].oneTimeLink) {
@ -208,7 +209,7 @@ export default class LowDB extends DatabaseProvider {
} }
async createOneTimeLink(id: string, oneTimeLink: OneTimeLink) { async createOneTimeLink(id: string, oneTimeLink: OneTimeLink) {
DEBUG('Update Client Address'); DEBUG('Create Client One Time Link');
await this.#db.update((data) => { await this.#db.update((data) => {
if (data.clients[id]) { if (data.clients[id]) {
data.clients[id].oneTimeLink = oneTimeLink; data.clients[id].oneTimeLink = oneTimeLink;

35
src/services/database/migrations/1.ts

@ -1,33 +1,35 @@
import type { Low } from 'lowdb'; import type { Low } from 'lowdb';
import type { Database } from '../repositories/database'; import type { Database } from '../repositories/database';
import packageJson from '@@/package.json';
import { ChartType } from '../repositories/system'; import { ChartType } from '../repositories/system';
import ip from 'ip'; import { parseCidr } from 'cidr-tools';
import { stringifyIp } from 'ip-bigint';
export async function run1(db: Low<Database>) { export async function run1(db: Low<Database>) {
const privateKey = await exec('wg genkey'); const privateKey = await exec('wg genkey');
const publicKey = await exec(`echo ${privateKey} | wg pubkey`, { const publicKey = await exec(`echo ${privateKey} | wg pubkey`, {
log: 'echo ***hidden*** | wg pubkey', log: 'echo ***hidden*** | wg pubkey',
}); });
const addressRange = '10.8.0.0/24'; const address4Range = '10.8.0.0/24';
const cidr = ip.cidrSubnet(addressRange); const address6Range = 'fdcc:ad94:bacf:61a4::cafe:0/112';
const cidr4 = parseCidr(address4Range);
const cidr6 = parseCidr(address6Range);
const database: Database = { const database: Database = {
migrations: [], migrations: [],
system: { system: {
// TODO: move to var, no need for database
release: packageJson.release.version,
interface: { interface: {
privateKey: privateKey, privateKey: privateKey,
publicKey: publicKey, publicKey: publicKey,
address: cidr.firstAddress, address4: stringifyIp({ number: cidr4.start + 1n, version: 4 }),
address6: stringifyIp({ number: cidr6.start + 1n, version: 6 }),
}, },
sessionTimeout: 3600, // 1 hour sessionTimeout: 3600, // 1 hour
lang: 'en', lang: 'en',
userConfig: { userConfig: {
mtu: 1420, mtu: 1420,
persistentKeepalive: 0, persistentKeepalive: 0,
addressRange: addressRange, address4Range: address4Range,
defaultDns: ['1.1.1.1'], address6Range: address6Range,
defaultDns: ['1.1.1.1', '2606:4700:4700::1111'],
allowedIps: ['0.0.0.0/0', '::/0'], allowedIps: ['0.0.0.0/0', '::/0'],
}, },
wgDevice: 'eth0', wgDevice: 'eth0',
@ -63,26 +65,35 @@ export async function run1(db: Low<Database>) {
name: 'wg-easy', name: 'wg-easy',
cookie: {}, cookie: {},
}, },
cookieMaxAge: 24 * 60,
}, },
users: [], users: [],
clients: {}, clients: {},
}; };
// TODO: use variables inside up/down script // TODO: use variables inside up/down script
// TODO: properly check if ipv6 support
database.system.iptables.PostUp = ` database.system.iptables.PostUp = `
iptables -t nat -A POSTROUTING -s ${database.system.userConfig.addressRange} -o ${database.system.wgDevice} -j MASQUERADE; iptables -t nat -A POSTROUTING -s ${database.system.userConfig.address4Range} -o ${database.system.wgDevice} -j MASQUERADE;
iptables -A INPUT -p udp -m udp --dport ${database.system.wgPort} -j ACCEPT; iptables -A INPUT -p udp -m udp --dport ${database.system.wgPort} -j ACCEPT;
iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -i wg0 -j ACCEPT;
iptables -A FORWARD -o wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT;
ip6tables -t nat -A POSTROUTING -s ${database.system.userConfig.address6Range} -o ${database.system.wgDevice} -j MASQUERADE;
ip6tables -A INPUT -p udp -m udp --dport ${database.system.wgPort} -j ACCEPT;
ip6tables -A FORWARD -i wg0 -j ACCEPT;
ip6tables -A FORWARD -o wg0 -j ACCEPT;
` `
.split('\n') .split('\n')
.join(' '); .join(' ');
database.system.iptables.PostDown = ` database.system.iptables.PostDown = `
iptables -t nat -D POSTROUTING -s ${database.system.userConfig.addressRange} -o ${database.system.wgDevice} -j MASQUERADE; iptables -t nat -D POSTROUTING -s ${database.system.userConfig.address4Range} -o ${database.system.wgDevice} -j MASQUERADE;
iptables -D INPUT -p udp -m udp --dport ${database.system.wgPort} -j ACCEPT; iptables -D INPUT -p udp -m udp --dport ${database.system.wgPort} -j ACCEPT;
iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -i wg0 -j ACCEPT;
iptables -D FORWARD -o wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT;
ip6tables -t nat -D POSTROUTING -s ${database.system.userConfig.address6Range} -o ${database.system.wgDevice} -j MASQUERADE;
ip6tables -D INPUT -p udp -m udp --dport ${database.system.wgPort} -j ACCEPT;
ip6tables -D FORWARD -i wg0 -j ACCEPT;
ip6tables -D FORWARD -o wg0 -j ACCEPT;
` `
.split('\n') .split('\n')
.join(' '); .join(' ');

5
src/services/database/repositories/client.ts

@ -7,7 +7,8 @@ export type OneTimeLink = {
export type Client = { export type Client = {
id: string; id: string;
name: string; name: string;
address: string; address4: string;
address6: string;
privateKey: string; privateKey: string;
publicKey: string; publicKey: string;
preSharedKey: string; preSharedKey: string;
@ -37,7 +38,7 @@ export interface ClientRepository {
deleteClient(id: string): Promise<void>; deleteClient(id: string): Promise<void>;
toggleClient(id: string, enable: boolean): Promise<void>; toggleClient(id: string, enable: boolean): Promise<void>;
updateClientName(id: string, name: string): Promise<void>; updateClientName(id: string, name: string): Promise<void>;
updateClientAddress(id: string, address: string): Promise<void>; updateClientAddress4(id: string, address4: string): Promise<void>;
updateClientExpirationDate( updateClientExpirationDate(
id: string, id: string,
expirationDate: string | null expirationDate: string | null

2
src/services/database/repositories/database.ts

@ -59,7 +59,7 @@ export abstract class DatabaseProvider
abstract deleteClient(id: string): Promise<void>; abstract deleteClient(id: string): Promise<void>;
abstract toggleClient(id: string, enable: boolean): Promise<void>; abstract toggleClient(id: string, enable: boolean): Promise<void>;
abstract updateClientName(id: string, name: string): Promise<void>; abstract updateClientName(id: string, name: string): Promise<void>;
abstract updateClientAddress(id: string, address: string): Promise<void>; abstract updateClientAddress4(id: string, address4: string): Promise<void>;
abstract updateClientExpirationDate( abstract updateClientExpirationDate(
id: string, id: string,
expirationDate: string | null expirationDate: string | null

8
src/services/database/repositories/system.ts

@ -12,13 +12,15 @@ export type IpTables = {
export type WGInterface = { export type WGInterface = {
privateKey: string; privateKey: string;
publicKey: string; publicKey: string;
address: string; address4: string;
address6: string;
}; };
export type WGConfig = { export type WGConfig = {
mtu: number; mtu: number;
persistentKeepalive: number; persistentKeepalive: number;
addressRange: string; address4Range: string;
address6Range: string;
defaultDns: string[]; defaultDns: string[];
allowedIps: string[]; allowedIps: string[];
}; };
@ -50,7 +52,6 @@ export type Feature = {
export type System = { export type System = {
interface: WGInterface; interface: WGInterface;
release: string;
// maxAge // maxAge
sessionTimeout: number; sessionTimeout: number;
lang: Lang; lang: Lang;
@ -71,7 +72,6 @@ export type System = {
prometheus: Prometheus; prometheus: Prometheus;
sessionConfig: SessionConfig; sessionConfig: SessionConfig;
cookieMaxAge: number;
}; };
/** /**

6
src/services/database/repositories/user.ts

@ -16,11 +16,7 @@ export type User = {
role: ROLE; role: ROLE;
username: string; username: string;
password: string; password: string;
name?: string; name: string;
address?: string;
privateKey?: string;
publicKey?: string;
preSharedKey?: string;
/** ISO String */ /** ISO String */
createdAt: string; createdAt: string;
/** ISO String */ /** ISO String */

Loading…
Cancel
Save