Add PreUp, PostUp, PreDown, PostDown for client (#1714)
* Fix create client popup background is not white * Fix no Add button when client Allowed Ips or Server Allowed Ips is empty * Add preUp preDown postUp postDown for client * Add description of hooks for client config * Move hooks's label text into 'hooks' in en.json --------- Co-authored-by: yanghuanglin <yanghuanglin@qq.com> Co-authored-by: Bernd Storath <999999bst@gmail.com>
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
class="fixed inset-0 z-30 bg-gray-500 opacity-75 dark:bg-black dark:opacity-50"
|
class="fixed inset-0 z-30 bg-gray-500 opacity-75 dark:bg-black dark:opacity-50"
|
||||||
/>
|
/>
|
||||||
<DialogContent
|
<DialogContent
|
||||||
class="fixed left-1/2 top-1/2 z-[100] max-h-[85vh] w-[90vw] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-md p-6 shadow-2xl focus:outline-none dark:bg-neutral-700"
|
class="fixed left-1/2 top-1/2 z-[100] max-h-[85vh] w-[90vw] max-w-md -translate-x-1/2 -translate-y-1/2 rounded-md bg-white p-6 shadow-2xl focus:outline-none dark:bg-neutral-700"
|
||||||
>
|
>
|
||||||
<DialogTitle
|
<DialogTitle
|
||||||
class="m-0 text-lg font-semibold text-gray-900 dark:text-neutral-200"
|
class="m-0 text-lg font-semibold text-gray-900 dark:text-neutral-200"
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="data?.length === 0">
|
<div class="flex flex-col gap-2">
|
||||||
{{ emptyText || $t('form.noItems') }}
|
<div v-if="data?.length === 0">
|
||||||
</div>
|
{{ emptyText || $t('form.noItems') }}
|
||||||
<div v-else class="flex flex-col gap-2">
|
</div>
|
||||||
<div v-for="(item, i) in data" :key="i">
|
<div v-for="(item, i) in data" v-else :key="i">
|
||||||
<div class="flex flex-row gap-1">
|
<div class="mt-1 flex flex-row gap-1">
|
||||||
<input
|
<input
|
||||||
:value="item"
|
:value="item"
|
||||||
:name="name"
|
:name="name"
|
||||||
@@ -12,13 +12,20 @@
|
|||||||
class="rounded-lg border-2 border-gray-100 text-gray-500 focus:border-red-800 focus:outline-0 focus:ring-0 dark:border-neutral-800 dark:bg-neutral-700 dark:text-neutral-200 dark:placeholder:text-neutral-400"
|
class="rounded-lg border-2 border-gray-100 text-gray-500 focus:border-red-800 focus:outline-0 focus:ring-0 dark:border-neutral-800 dark:bg-neutral-700 dark:text-neutral-200 dark:placeholder:text-neutral-400"
|
||||||
@input="update($event, i)"
|
@input="update($event, i)"
|
||||||
/>
|
/>
|
||||||
<BaseButton as="input" type="button" value="-" @click="del(i)" />
|
<BaseButton
|
||||||
|
as="input"
|
||||||
|
type="button"
|
||||||
|
class="rounded-lg"
|
||||||
|
value="-"
|
||||||
|
@click="del(i)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="mt-2">
|
<div class="mt-2">
|
||||||
<BaseButton
|
<BaseButton
|
||||||
as="input"
|
as="input"
|
||||||
type="button"
|
type="button"
|
||||||
|
class="rounded-lg"
|
||||||
:value="$t('form.add')"
|
:value="$t('form.add')"
|
||||||
@click="add"
|
@click="add"
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -2,10 +2,26 @@
|
|||||||
<main v-if="data">
|
<main v-if="data">
|
||||||
<FormElement @submit.prevent="submit">
|
<FormElement @submit.prevent="submit">
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormTextField id="PreUp" v-model="data.preUp" label="PreUp" />
|
<FormTextField
|
||||||
<FormTextField id="PostUp" v-model="data.postUp" label="PostUp" />
|
id="PreUp"
|
||||||
<FormTextField id="PreDown" v-model="data.preDown" label="PreDown" />
|
v-model="data.preUp"
|
||||||
<FormTextField id="PostDown" v-model="data.postDown" label="PostDown" />
|
:label="$t('hooks.preUp')"
|
||||||
|
/>
|
||||||
|
<FormTextField
|
||||||
|
id="PostUp"
|
||||||
|
v-model="data.postUp"
|
||||||
|
:label="$t('hooks.postUp')"
|
||||||
|
/>
|
||||||
|
<FormTextField
|
||||||
|
id="PreDown"
|
||||||
|
v-model="data.preDown"
|
||||||
|
:label="$t('hooks.preDown')"
|
||||||
|
/>
|
||||||
|
<FormTextField
|
||||||
|
id="PostDown"
|
||||||
|
v-model="data.postDown"
|
||||||
|
:label="$t('hooks.postDown')"
|
||||||
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormHeading>{{ $t('form.actions') }}</FormHeading>
|
<FormHeading>{{ $t('form.actions') }}</FormHeading>
|
||||||
|
|||||||
@@ -71,6 +71,35 @@
|
|||||||
:label="$t('general.persistentKeepalive')"
|
:label="$t('general.persistentKeepalive')"
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
<FormGroup>
|
||||||
|
<FormHeading :description="$t('client.hooksDescription')">
|
||||||
|
{{ $t('client.hooks') }}
|
||||||
|
</FormHeading>
|
||||||
|
<FormTextField
|
||||||
|
id="PreUp"
|
||||||
|
v-model="data.preUp"
|
||||||
|
:description="$t('client.hooksLeaveEmpty')"
|
||||||
|
:label="$t('hooks.preUp')"
|
||||||
|
/>
|
||||||
|
<FormTextField
|
||||||
|
id="PostUp"
|
||||||
|
v-model="data.postUp"
|
||||||
|
:description="$t('client.hooksLeaveEmpty')"
|
||||||
|
:label="$t('hooks.postUp')"
|
||||||
|
/>
|
||||||
|
<FormTextField
|
||||||
|
id="PreDown"
|
||||||
|
v-model="data.preDown"
|
||||||
|
:description="$t('client.hooksLeaveEmpty')"
|
||||||
|
:label="$t('hooks.preDown')"
|
||||||
|
/>
|
||||||
|
<FormTextField
|
||||||
|
id="PostDown"
|
||||||
|
v-model="data.postDown"
|
||||||
|
:description="$t('client.hooksLeaveEmpty')"
|
||||||
|
:label="$t('hooks.postDown')"
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormHeading>{{ $t('form.actions') }}</FormHeading>
|
<FormHeading>{{ $t('form.actions') }}</FormHeading>
|
||||||
<FormActionField type="submit" :label="$t('form.save')" />
|
<FormActionField type="submit" :label="$t('form.save')" />
|
||||||
|
|||||||
@@ -98,7 +98,10 @@
|
|||||||
"allowedIpsDesc": "Which IPs will be routed through the VPN",
|
"allowedIpsDesc": "Which IPs will be routed through the VPN",
|
||||||
"serverAllowedIpsDesc": "Which IPs the server will route to the client",
|
"serverAllowedIpsDesc": "Which IPs the server will route to the client",
|
||||||
"mtuDesc": "Sets the maximum transmission unit (packet size) for the VPN tunnel",
|
"mtuDesc": "Sets the maximum transmission unit (packet size) for the VPN tunnel",
|
||||||
"persistentKeepaliveDesc": "Sets the interval (in seconds) for keep-alive packets. 0 disables it"
|
"persistentKeepaliveDesc": "Sets the interval (in seconds) for keep-alive packets. 0 disables it",
|
||||||
|
"hooks": "Hooks",
|
||||||
|
"hooksDescription": "Hooks only work with wg-quick",
|
||||||
|
"hooksLeaveEmpty": "Only for wg-quick. Otherwise, leave it empty"
|
||||||
},
|
},
|
||||||
"dialog": {
|
"dialog": {
|
||||||
"change": "Change",
|
"change": "Change",
|
||||||
@@ -208,5 +211,11 @@
|
|||||||
"dns": "DNS",
|
"dns": "DNS",
|
||||||
"allowedIps": "Allowed IPs",
|
"allowedIps": "Allowed IPs",
|
||||||
"file": "File"
|
"file": "File"
|
||||||
|
},
|
||||||
|
"hooks": {
|
||||||
|
"preUp": "PreUp",
|
||||||
|
"postUp": "PostUp",
|
||||||
|
"preDown": "PreDown",
|
||||||
|
"postDown": "PostDown"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,10 @@ CREATE TABLE `clients_table` (
|
|||||||
`name` text NOT NULL,
|
`name` text NOT NULL,
|
||||||
`ipv4_address` text NOT NULL,
|
`ipv4_address` text NOT NULL,
|
||||||
`ipv6_address` text NOT NULL,
|
`ipv6_address` text NOT NULL,
|
||||||
|
`pre_up` text DEFAULT '' NOT NULL,
|
||||||
|
`post_up` text DEFAULT '' NOT NULL,
|
||||||
|
`pre_down` text DEFAULT '' NOT NULL,
|
||||||
|
`post_down` text DEFAULT '' NOT NULL,
|
||||||
`private_key` text NOT NULL,
|
`private_key` text NOT NULL,
|
||||||
`public_key` text NOT NULL,
|
`public_key` text NOT NULL,
|
||||||
`pre_shared_key` text NOT NULL,
|
`pre_shared_key` text NOT NULL,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"version": "6",
|
"version": "6",
|
||||||
"dialect": "sqlite",
|
"dialect": "sqlite",
|
||||||
"id": "b1dde023-d141-4eab-9226-89a832b2ed2b",
|
"id": "2cabecf8-93d5-4d32-81b7-2e4369c1cb29",
|
||||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||||
"tables": {
|
"tables": {
|
||||||
"clients_table": {
|
"clients_table": {
|
||||||
@@ -42,6 +42,38 @@
|
|||||||
"notNull": true,
|
"notNull": true,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
|
"pre_up": {
|
||||||
|
"name": "pre_up",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "''"
|
||||||
|
},
|
||||||
|
"post_up": {
|
||||||
|
"name": "post_up",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "''"
|
||||||
|
},
|
||||||
|
"pre_down": {
|
||||||
|
"name": "pre_down",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "''"
|
||||||
|
},
|
||||||
|
"post_down": {
|
||||||
|
"name": "post_down",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "''"
|
||||||
|
},
|
||||||
"private_key": {
|
"private_key": {
|
||||||
"name": "private_key",
|
"name": "private_key",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"id": "720d420c-361f-4427-a45b-db0ca613934d",
|
"id": "9476c20a-509b-4cd7-b58b-a042600bafb1",
|
||||||
"prevId": "b1dde023-d141-4eab-9226-89a832b2ed2b",
|
"prevId": "2cabecf8-93d5-4d32-81b7-2e4369c1cb29",
|
||||||
"version": "6",
|
"version": "6",
|
||||||
"dialect": "sqlite",
|
"dialect": "sqlite",
|
||||||
"tables": {
|
"tables": {
|
||||||
@@ -42,6 +42,38 @@
|
|||||||
"notNull": true,
|
"notNull": true,
|
||||||
"autoincrement": false
|
"autoincrement": false
|
||||||
},
|
},
|
||||||
|
"pre_up": {
|
||||||
|
"name": "pre_up",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "''"
|
||||||
|
},
|
||||||
|
"post_up": {
|
||||||
|
"name": "post_up",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "''"
|
||||||
|
},
|
||||||
|
"pre_down": {
|
||||||
|
"name": "pre_down",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "''"
|
||||||
|
},
|
||||||
|
"post_down": {
|
||||||
|
"name": "post_down",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"autoincrement": false,
|
||||||
|
"default": "''"
|
||||||
|
},
|
||||||
"private_key": {
|
"private_key": {
|
||||||
"name": "private_key",
|
"name": "private_key",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
|
|||||||
@@ -5,14 +5,14 @@
|
|||||||
{
|
{
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"version": "6",
|
"version": "6",
|
||||||
"when": 1739266828300,
|
"when": 1741331552405,
|
||||||
"tag": "0000_short_skin",
|
"tag": "0000_short_skin",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idx": 1,
|
"idx": 1,
|
||||||
"version": "6",
|
"version": "6",
|
||||||
"when": 1739266837347,
|
"when": 1741331579259,
|
||||||
"tag": "0001_classy_the_stranger",
|
"tag": "0001_classy_the_stranger",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ export const client = sqliteTable('clients_table', {
|
|||||||
name: text().notNull(),
|
name: text().notNull(),
|
||||||
ipv4Address: text('ipv4_address').notNull().unique(),
|
ipv4Address: text('ipv4_address').notNull().unique(),
|
||||||
ipv6Address: text('ipv6_address').notNull().unique(),
|
ipv6Address: text('ipv6_address').notNull().unique(),
|
||||||
|
preUp: text('pre_up').default('').notNull(),
|
||||||
|
postUp: text('post_up').default('').notNull(),
|
||||||
|
preDown: text('pre_down').default('').notNull(),
|
||||||
|
postDown: text('post_down').default('').notNull(),
|
||||||
privateKey: text('private_key').notNull(),
|
privateKey: text('private_key').notNull(),
|
||||||
publicKey: text('public_key').notNull(),
|
publicKey: text('public_key').notNull(),
|
||||||
preSharedKey: text('pre_shared_key').notNull(),
|
preSharedKey: text('pre_shared_key').notNull(),
|
||||||
|
|||||||
@@ -57,6 +57,10 @@ export const ClientUpdateSchema = schemaForType<UpdateClientType>()(
|
|||||||
expiresAt: expiresAt,
|
expiresAt: expiresAt,
|
||||||
ipv4Address: address4,
|
ipv4Address: address4,
|
||||||
ipv6Address: address6,
|
ipv6Address: address6,
|
||||||
|
preUp: HookSchema,
|
||||||
|
postUp: HookSchema,
|
||||||
|
preDown: HookSchema,
|
||||||
|
postDown: HookSchema,
|
||||||
allowedIps: AllowedIpsSchema,
|
allowedIps: AllowedIpsSchema,
|
||||||
serverAllowedIps: serverAllowedIps,
|
serverAllowedIps: serverAllowedIps,
|
||||||
mtu: MtuSchema,
|
mtu: MtuSchema,
|
||||||
|
|||||||
@@ -6,13 +6,11 @@ export type HooksType = InferSelectModel<typeof hooks>;
|
|||||||
|
|
||||||
export type HooksUpdateType = Omit<HooksType, 'id' | 'createdAt' | 'updatedAt'>;
|
export type HooksUpdateType = Omit<HooksType, 'id' | 'createdAt' | 'updatedAt'>;
|
||||||
|
|
||||||
const hook = z.string({ message: t('zod.hook') }).pipe(safeStringRefine);
|
|
||||||
|
|
||||||
export const HooksUpdateSchema = schemaForType<HooksUpdateType>()(
|
export const HooksUpdateSchema = schemaForType<HooksUpdateType>()(
|
||||||
z.object({
|
z.object({
|
||||||
preUp: hook,
|
preUp: HookSchema,
|
||||||
postUp: hook,
|
postUp: HookSchema,
|
||||||
preDown: hook,
|
preDown: HookSchema,
|
||||||
postDown: hook,
|
postDown: HookSchema,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -52,6 +52,10 @@ export const FileSchema = z.object({
|
|||||||
file: z.string({ message: t('zod.file') }),
|
file: z.string({ message: t('zod.file') }),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const HookSchema = z
|
||||||
|
.string({ message: t('zod.hook') })
|
||||||
|
.pipe(safeStringRefine);
|
||||||
|
|
||||||
export const schemaForType =
|
export const schemaForType =
|
||||||
<T>() =>
|
<T>() =>
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
|||||||
@@ -49,12 +49,19 @@ PostDown = ${iptablesTemplate(hooks.postDown, wgInterface)}`;
|
|||||||
const cidr4Block = parseCidr(wgInterface.ipv4Cidr).prefix;
|
const cidr4Block = parseCidr(wgInterface.ipv4Cidr).prefix;
|
||||||
const cidr6Block = parseCidr(wgInterface.ipv6Cidr).prefix;
|
const cidr6Block = parseCidr(wgInterface.ipv6Cidr).prefix;
|
||||||
|
|
||||||
|
const hookLines = [
|
||||||
|
client.preUp ? `PreUp = ${client.preUp}` : null,
|
||||||
|
client.postUp ? `PostUp = ${client.postUp}` : null,
|
||||||
|
client.preDown ? `PreDown = ${client.preDown}` : null,
|
||||||
|
client.postDown ? `PostDown = ${client.postDown}` : null,
|
||||||
|
].filter((v) => v !== null);
|
||||||
|
|
||||||
return `[Interface]
|
return `[Interface]
|
||||||
PrivateKey = ${client.privateKey}
|
PrivateKey = ${client.privateKey}
|
||||||
Address = ${client.ipv4Address}/${cidr4Block}, ${client.ipv6Address}/${cidr6Block}
|
Address = ${client.ipv4Address}/${cidr4Block}, ${client.ipv6Address}/${cidr6Block}
|
||||||
DNS = ${client.dns.join(', ')}
|
DNS = ${client.dns.join(', ')}
|
||||||
MTU = ${client.mtu}
|
MTU = ${client.mtu}
|
||||||
|
${hookLines.length ? `${hookLines.join('\n')}\n` : ''}
|
||||||
[Peer]
|
[Peer]
|
||||||
PublicKey = ${wgInterface.publicKey}
|
PublicKey = ${wgInterface.publicKey}
|
||||||
PresharedKey = ${client.preSharedKey}
|
PresharedKey = ${client.preSharedKey}
|
||||||
|
|||||||
Reference in New Issue
Block a user