Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4890bb28e5 | |||
| c3dbd3a815 | |||
| fc480df910 | |||
| b3bd2502af | |||
| eb5ad91022 | |||
| f2955a1278 | |||
| 1b76c066e0 | |||
| 5b68cc7311 |
@@ -24,6 +24,8 @@ This update is an entire rewrite to make it even easier to set up your own VPN.
|
|||||||
- Deprecated Dockerless Installations
|
- Deprecated Dockerless Installations
|
||||||
- Added Docker Volume Mount (`/lib/modules`)
|
- Added Docker Volume Mount (`/lib/modules`)
|
||||||
- Removed ARMv6 and ARMv7 support
|
- Removed ARMv6 and ARMv7 support
|
||||||
|
- Connections over HTTP require setting the `INSECURE` env var
|
||||||
|
- Changed license from CC BY-NC-SA 4.0 to AGPL-3.0-only
|
||||||
|
|
||||||
## [14.0.0] - 2024-09-04
|
## [14.0.0] - 2024-09-04
|
||||||
|
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ In the Admin Panel of your WireGuard server, go to the `Hooks` tab and add the f
|
|||||||
1. PostUp
|
1. PostUp
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
apk add nftables; nft add table inet wg_table; nft add chain inet wg_table postrouting { type nat hook postrouting priority 100 \; }; nft add rule inet wg_table postrouting ip saddr {{ipv4Cidr}} oifname {{device}} masquerade; nft add rule inet wg_table postrouting ip6 saddr {{ipv6Cidr}} oifname {{device}} masquerade; nft add chain inet wg_table input { type filter hook input priority 0 \; policy drop \; }; nft add rule inet wg_table input udp dport {{port}} accept; nft add chain inet wg_table forward { type filter hook forward priority 0 \; policy drop \; }; nft add rule inet wg_table forward iifname "wg0" accept; nft add rule inet wg_table forward oifname "wg0" accept;
|
apk add nftables; nft add table inet wg_table; nft add chain inet wg_table postrouting { type nat hook postrouting priority 100 \; }; nft add rule inet wg_table postrouting ip saddr {{ipv4Cidr}} oifname {{device}} masquerade; nft add rule inet wg_table postrouting ip6 saddr {{ipv6Cidr}} oifname {{device}} masquerade; nft add chain inet wg_table input { type filter hook input priority 0 \; policy drop \; }; nft add rule inet wg_table input udp dport {{port}} accept; nft add rule inet wg_table input tcp dport {{uiPort}} accept; nft add chain inet wg_table forward { type filter hook forward priority 0 \; policy drop \; }; nft add rule inet wg_table forward iifname "wg0" accept; nft add rule inet wg_table forward oifname "wg0" accept;
|
||||||
```
|
```
|
||||||
|
|
||||||
2. PostDown
|
2. PostDown
|
||||||
|
|||||||
+1
-1
@@ -7,5 +7,5 @@
|
|||||||
"docs:preview": "docker run --rm -it -p 8080:8080 -v ./docs:/docs squidfunk/mkdocs-material serve -a 0.0.0.0:8080",
|
"docs:preview": "docker run --rm -it -p 8080:8080 -v ./docs:/docs squidfunk/mkdocs-material serve -a 0.0.0.0:8080",
|
||||||
"scripts:version": "bash scripts/version.sh"
|
"scripts:version": "bash scripts/version.sh"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.5.2"
|
"packageManager": "pnpm@10.6.2"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
id="confirm-password"
|
id="confirm-password"
|
||||||
v-model="confirmPassword"
|
v-model="confirmPassword"
|
||||||
autocomplete="new-password"
|
autocomplete="new-password"
|
||||||
:label="$t('me.confirmPassword')"
|
:label="$t('general.confirmPassword')"
|
||||||
/>
|
/>
|
||||||
<FormActionField
|
<FormActionField
|
||||||
type="submit"
|
type="submit"
|
||||||
|
|||||||
@@ -20,6 +20,14 @@
|
|||||||
:label="$t('general.password')"
|
:label="$t('general.password')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="flex flex-col">
|
||||||
|
<FormPasswordField
|
||||||
|
id="confirmPassword"
|
||||||
|
v-model="confirmPassword"
|
||||||
|
autocomplete="new-password"
|
||||||
|
:label="$t('general.confirmPassword')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<BaseButton @click="submit">{{ $t('setup.createAccount') }}</BaseButton>
|
<BaseButton @click="submit">{{ $t('setup.createAccount') }}</BaseButton>
|
||||||
</div>
|
</div>
|
||||||
@@ -37,6 +45,7 @@ setupStore.setStep(2);
|
|||||||
|
|
||||||
const username = ref<null | string>(null);
|
const username = ref<null | string>(null);
|
||||||
const password = ref<string>('');
|
const password = ref<string>('');
|
||||||
|
const confirmPassword = ref<string>('');
|
||||||
|
|
||||||
const _submit = useSubmit(
|
const _submit = useSubmit(
|
||||||
'/api/setup/2',
|
'/api/setup/2',
|
||||||
@@ -54,6 +63,10 @@ const _submit = useSubmit(
|
|||||||
);
|
);
|
||||||
|
|
||||||
function submit() {
|
function submit() {
|
||||||
return _submit({ username: username.value, password: password.value });
|
return _submit({
|
||||||
|
username: username.value,
|
||||||
|
password: password.value,
|
||||||
|
confirmPassword: confirmPassword.value,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -14,8 +14,7 @@
|
|||||||
"email": "E-Mail"
|
"email": "E-Mail"
|
||||||
},
|
},
|
||||||
"me": {
|
"me": {
|
||||||
"currentPassword": "Current Password",
|
"currentPassword": "Current Password"
|
||||||
"confirmPassword": "Confirm Password"
|
|
||||||
},
|
},
|
||||||
"general": {
|
"general": {
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
@@ -32,7 +31,8 @@
|
|||||||
"host": "Host",
|
"host": "Host",
|
||||||
"port": "Port",
|
"port": "Port",
|
||||||
"yes": "Yes",
|
"yes": "Yes",
|
||||||
"no": "No"
|
"no": "No",
|
||||||
|
"confirmPassword": "Confirm Password"
|
||||||
},
|
},
|
||||||
"setup": {
|
"setup": {
|
||||||
"welcome": "Welcome to your first setup of wg-easy !",
|
"welcome": "Welcome to your first setup of wg-easy !",
|
||||||
|
|||||||
+8
-8
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "wg-easy",
|
"name": "wg-easy",
|
||||||
"version": "15.0.0-beta.7",
|
"version": "15.0.0-beta.8",
|
||||||
"description": "The easiest way to run WireGuard VPN + Web-based Admin UI.",
|
"description": "The easiest way to run WireGuard VPN + Web-based Admin UI.",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
@@ -20,8 +20,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eschricht/nuxt-color-mode": "^1.1.5",
|
"@eschricht/nuxt-color-mode": "^1.1.5",
|
||||||
"@libsql/client": "^0.14.0",
|
"@libsql/client": "^0.14.0",
|
||||||
"@nuxtjs/i18n": "^9.2.1",
|
"@nuxtjs/i18n": "^9.3.1",
|
||||||
"@nuxtjs/tailwindcss": "^6.13.1",
|
"@nuxtjs/tailwindcss": "^6.13.2",
|
||||||
"@pinia/nuxt": "^0.10.1",
|
"@pinia/nuxt": "^0.10.1",
|
||||||
"@tailwindcss/forms": "^0.5.10",
|
"@tailwindcss/forms": "^0.5.10",
|
||||||
"apexcharts": "^4.5.0",
|
"apexcharts": "^4.5.0",
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
"is-ip": "^5.0.1",
|
"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.15.4",
|
"nuxt": "^3.16.0",
|
||||||
"pinia": "^3.0.1",
|
"pinia": "^3.0.1",
|
||||||
"qrcode": "^1.5.4",
|
"qrcode": "^1.5.4",
|
||||||
"radix-vue": "^1.9.17",
|
"radix-vue": "^1.9.17",
|
||||||
@@ -48,17 +48,17 @@
|
|||||||
"zod": "^3.24.2"
|
"zod": "^3.24.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nuxt/eslint": "1.1.0",
|
"@nuxt/eslint": "1.2.0",
|
||||||
"@types/debug": "^4.1.12",
|
"@types/debug": "^4.1.12",
|
||||||
"@types/qrcode": "^1.5.5",
|
"@types/qrcode": "^1.5.5",
|
||||||
"@types/semver": "^7.5.8",
|
"@types/semver": "^7.5.8",
|
||||||
"drizzle-kit": "^0.30.5",
|
"drizzle-kit": "^0.30.5",
|
||||||
"eslint": "^9.21.0",
|
"eslint": "^9.22.0",
|
||||||
"eslint-config-prettier": "^10.0.2",
|
"eslint-config-prettier": "^10.1.1",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"prettier-plugin-tailwindcss": "^0.6.11",
|
"prettier-plugin-tailwindcss": "^0.6.11",
|
||||||
"typescript": "^5.8.2",
|
"typescript": "^5.8.2",
|
||||||
"vue-tsc": "^2.2.8"
|
"vue-tsc": "^2.2.8"
|
||||||
},
|
},
|
||||||
"packageManager": "pnpm@10.5.2"
|
"packageManager": "pnpm@10.6.2"
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+1225
-1602
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,5 @@
|
|||||||
import { eq, sql } from 'drizzle-orm';
|
import { eq, sql } from 'drizzle-orm';
|
||||||
import { parseCidr } from 'cidr-tools';
|
import { containsCidr, parseCidr } from 'cidr-tools';
|
||||||
import { client } from './schema';
|
import { client } from './schema';
|
||||||
import type {
|
import type {
|
||||||
ClientCreateFromExistingType,
|
ClientCreateFromExistingType,
|
||||||
@@ -132,7 +132,27 @@ export class ClientService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
update(id: ID, data: UpdateClientType) {
|
update(id: ID, data: UpdateClientType) {
|
||||||
return this.#db.update(client).set(data).where(eq(client.id, id)).execute();
|
return this.#db.transaction(async (tx) => {
|
||||||
|
const clientInterface = await tx.query.wgInterface
|
||||||
|
.findFirst({
|
||||||
|
where: eq(wgInterface.name, 'wg0'),
|
||||||
|
})
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
if (!clientInterface) {
|
||||||
|
throw new Error('WireGuard interface not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!containsCidr(clientInterface.ipv4Cidr, data.ipv4Address)) {
|
||||||
|
throw new Error('IPv4 address is not within the CIDR range');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!containsCidr(clientInterface.ipv6Cidr, data.ipv6Address)) {
|
||||||
|
throw new Error('IPv6 address is not within the CIDR range');
|
||||||
|
}
|
||||||
|
|
||||||
|
await tx.update(client).set(data).where(eq(client.id, id)).execute();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async createFromExisting({
|
async createFromExisting({
|
||||||
|
|||||||
@@ -26,10 +26,15 @@ export const UserLoginSchema = z.object({
|
|||||||
remember: remember,
|
remember: remember,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const UserSetupSchema = z.object({
|
export const UserSetupSchema = z
|
||||||
|
.object({
|
||||||
username: username,
|
username: username,
|
||||||
password: password,
|
password: password,
|
||||||
});
|
confirmPassword: password,
|
||||||
|
})
|
||||||
|
.refine((val) => val.password === val.confirmPassword, {
|
||||||
|
message: t('zod.user.passwordMatch'),
|
||||||
|
});
|
||||||
|
|
||||||
const name = z
|
const name = z
|
||||||
.string({ message: t('zod.user.name') })
|
.string({ message: t('zod.user.name') })
|
||||||
|
|||||||
@@ -15,4 +15,16 @@ export const OLD_ENV = {
|
|||||||
export const WG_ENV = {
|
export const WG_ENV = {
|
||||||
/** UI is hosted on HTTP instead of HTTPS */
|
/** UI is hosted on HTTP instead of HTTPS */
|
||||||
INSECURE: process.env.INSECURE === 'true',
|
INSECURE: process.env.INSECURE === 'true',
|
||||||
|
/** Port the UI is listening on */
|
||||||
|
PORT: assertEnv('PORT'),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function assertEnv<T extends string>(env: T) {
|
||||||
|
const val = process.env[env];
|
||||||
|
|
||||||
|
if (!val) {
|
||||||
|
throw new Error(`Missing environment variable: ${env}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export function template(templ: string, values: Record<string, string>) {
|
|||||||
* - ipv6Cidr: IPv6 CIDR
|
* - ipv6Cidr: IPv6 CIDR
|
||||||
* - device: Network device
|
* - device: Network device
|
||||||
* - port: Port number
|
* - port: Port number
|
||||||
|
* - uiPort: UI port number
|
||||||
*/
|
*/
|
||||||
export function iptablesTemplate(templ: string, wgInterface: InterfaceType) {
|
export function iptablesTemplate(templ: string, wgInterface: InterfaceType) {
|
||||||
return template(templ, {
|
return template(templ, {
|
||||||
@@ -22,5 +23,6 @@ export function iptablesTemplate(templ: string, wgInterface: InterfaceType) {
|
|||||||
ipv6Cidr: wgInterface.ipv6Cidr,
|
ipv6Cidr: wgInterface.ipv6Cidr,
|
||||||
device: wgInterface.device,
|
device: wgInterface.device,
|
||||||
port: wgInterface.port.toString(),
|
port: wgInterface.port.toString(),
|
||||||
|
uiPort: WG_ENV.PORT,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user