From fcb5049dab303843f40152f39470806b56d25285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E9=BB=84=E6=9E=97?= Date: Fri, 7 Mar 2025 15:17:33 +0800 Subject: [PATCH] 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 Co-authored-by: Bernd Storath <999999bst@gmail.com> --- src/app/components/Base/Dialog.vue | 2 +- src/app/components/Form/ArrayField.vue | 21 +++++++---- src/app/pages/admin/hooks.vue | 24 ++++++++++--- src/app/pages/clients/[id].vue | 29 +++++++++++++++ src/i18n/locales/en.json | 11 +++++- .../database/migrations/0000_short_skin.sql | 4 +++ .../migrations/meta/0000_snapshot.json | 34 +++++++++++++++++- .../migrations/meta/0001_snapshot.json | 36 +++++++++++++++++-- .../database/migrations/meta/_journal.json | 4 +-- .../database/repositories/client/schema.ts | 4 +++ .../database/repositories/client/types.ts | 4 +++ .../database/repositories/hooks/types.ts | 10 +++--- src/server/utils/types.ts | 4 +++ src/server/utils/wgHelper.ts | 9 ++++- 14 files changed, 171 insertions(+), 25 deletions(-) diff --git a/src/app/components/Base/Dialog.vue b/src/app/components/Base/Dialog.vue index eea4fa56..c6d6db5f 100644 --- a/src/app/components/Base/Dialog.vue +++ b/src/app/components/Base/Dialog.vue @@ -6,7 +6,7 @@ class="fixed inset-0 z-30 bg-gray-500 opacity-75 dark:bg-black dark:opacity-50" /> -
- {{ emptyText || $t('form.noItems') }} -
-
-
-
+
+
+ {{ emptyText || $t('form.noItems') }} +
+
+
- +
diff --git a/src/app/pages/admin/hooks.vue b/src/app/pages/admin/hooks.vue index c0a201c8..9330c822 100644 --- a/src/app/pages/admin/hooks.vue +++ b/src/app/pages/admin/hooks.vue @@ -2,10 +2,26 @@
- - - - + + + + {{ $t('form.actions') }} diff --git a/src/app/pages/clients/[id].vue b/src/app/pages/clients/[id].vue index 4b7a9575..72060349 100644 --- a/src/app/pages/clients/[id].vue +++ b/src/app/pages/clients/[id].vue @@ -71,6 +71,35 @@ :label="$t('general.persistentKeepalive')" /> + + + {{ $t('client.hooks') }} + + + + + + {{ $t('form.actions') }} diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 212b162a..3723a09d 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -98,7 +98,10 @@ "allowedIpsDesc": "Which IPs will be routed through the VPN", "serverAllowedIpsDesc": "Which IPs the server will route to the client", "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": { "change": "Change", @@ -208,5 +211,11 @@ "dns": "DNS", "allowedIps": "Allowed IPs", "file": "File" + }, + "hooks": { + "preUp": "PreUp", + "postUp": "PostUp", + "preDown": "PreDown", + "postDown": "PostDown" } } diff --git a/src/server/database/migrations/0000_short_skin.sql b/src/server/database/migrations/0000_short_skin.sql index 38283554..a0cb0a3b 100644 --- a/src/server/database/migrations/0000_short_skin.sql +++ b/src/server/database/migrations/0000_short_skin.sql @@ -4,6 +4,10 @@ CREATE TABLE `clients_table` ( `name` text NOT NULL, `ipv4_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, `public_key` text NOT NULL, `pre_shared_key` text NOT NULL, diff --git a/src/server/database/migrations/meta/0000_snapshot.json b/src/server/database/migrations/meta/0000_snapshot.json index 1b217e6c..b7574079 100644 --- a/src/server/database/migrations/meta/0000_snapshot.json +++ b/src/server/database/migrations/meta/0000_snapshot.json @@ -1,7 +1,7 @@ { "version": "6", "dialect": "sqlite", - "id": "b1dde023-d141-4eab-9226-89a832b2ed2b", + "id": "2cabecf8-93d5-4d32-81b7-2e4369c1cb29", "prevId": "00000000-0000-0000-0000-000000000000", "tables": { "clients_table": { @@ -42,6 +42,38 @@ "notNull": true, "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": { "name": "private_key", "type": "text", diff --git a/src/server/database/migrations/meta/0001_snapshot.json b/src/server/database/migrations/meta/0001_snapshot.json index f04104fa..432a5f10 100644 --- a/src/server/database/migrations/meta/0001_snapshot.json +++ b/src/server/database/migrations/meta/0001_snapshot.json @@ -1,6 +1,6 @@ { - "id": "720d420c-361f-4427-a45b-db0ca613934d", - "prevId": "b1dde023-d141-4eab-9226-89a832b2ed2b", + "id": "9476c20a-509b-4cd7-b58b-a042600bafb1", + "prevId": "2cabecf8-93d5-4d32-81b7-2e4369c1cb29", "version": "6", "dialect": "sqlite", "tables": { @@ -42,6 +42,38 @@ "notNull": true, "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": { "name": "private_key", "type": "text", diff --git a/src/server/database/migrations/meta/_journal.json b/src/server/database/migrations/meta/_journal.json index 3ce83e4a..6a81e90c 100644 --- a/src/server/database/migrations/meta/_journal.json +++ b/src/server/database/migrations/meta/_journal.json @@ -5,14 +5,14 @@ { "idx": 0, "version": "6", - "when": 1739266828300, + "when": 1741331552405, "tag": "0000_short_skin", "breakpoints": true }, { "idx": 1, "version": "6", - "when": 1739266837347, + "when": 1741331579259, "tag": "0001_classy_the_stranger", "breakpoints": true } diff --git a/src/server/database/repositories/client/schema.ts b/src/server/database/repositories/client/schema.ts index 882f49e6..f1dd4163 100644 --- a/src/server/database/repositories/client/schema.ts +++ b/src/server/database/repositories/client/schema.ts @@ -14,6 +14,10 @@ export const client = sqliteTable('clients_table', { name: text().notNull(), ipv4Address: text('ipv4_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(), publicKey: text('public_key').notNull(), preSharedKey: text('pre_shared_key').notNull(), diff --git a/src/server/database/repositories/client/types.ts b/src/server/database/repositories/client/types.ts index 3be4b572..06bffc00 100644 --- a/src/server/database/repositories/client/types.ts +++ b/src/server/database/repositories/client/types.ts @@ -57,6 +57,10 @@ export const ClientUpdateSchema = schemaForType()( expiresAt: expiresAt, ipv4Address: address4, ipv6Address: address6, + preUp: HookSchema, + postUp: HookSchema, + preDown: HookSchema, + postDown: HookSchema, allowedIps: AllowedIpsSchema, serverAllowedIps: serverAllowedIps, mtu: MtuSchema, diff --git a/src/server/database/repositories/hooks/types.ts b/src/server/database/repositories/hooks/types.ts index c42a05bf..f9bba9a4 100644 --- a/src/server/database/repositories/hooks/types.ts +++ b/src/server/database/repositories/hooks/types.ts @@ -6,13 +6,11 @@ export type HooksType = InferSelectModel; export type HooksUpdateType = Omit; -const hook = z.string({ message: t('zod.hook') }).pipe(safeStringRefine); - export const HooksUpdateSchema = schemaForType()( z.object({ - preUp: hook, - postUp: hook, - preDown: hook, - postDown: hook, + preUp: HookSchema, + postUp: HookSchema, + preDown: HookSchema, + postDown: HookSchema, }) ); diff --git a/src/server/utils/types.ts b/src/server/utils/types.ts index 14157549..898cf957 100644 --- a/src/server/utils/types.ts +++ b/src/server/utils/types.ts @@ -52,6 +52,10 @@ export const FileSchema = z.object({ file: z.string({ message: t('zod.file') }), }); +export const HookSchema = z + .string({ message: t('zod.hook') }) + .pipe(safeStringRefine); + export const schemaForType = () => // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/src/server/utils/wgHelper.ts b/src/server/utils/wgHelper.ts index 4b13afb7..5fdb8604 100644 --- a/src/server/utils/wgHelper.ts +++ b/src/server/utils/wgHelper.ts @@ -49,12 +49,19 @@ PostDown = ${iptablesTemplate(hooks.postDown, wgInterface)}`; const cidr4Block = parseCidr(wgInterface.ipv4Cidr).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] PrivateKey = ${client.privateKey} Address = ${client.ipv4Address}/${cidr4Block}, ${client.ipv6Address}/${cidr6Block} DNS = ${client.dns.join(', ')} MTU = ${client.mtu} - +${hookLines.length ? `${hookLines.join('\n')}\n` : ''} [Peer] PublicKey = ${wgInterface.publicKey} PresharedKey = ${client.preSharedKey}