From 9d847da4621beff8b3ce2a14810cf4ebf815a398 Mon Sep 17 00:00:00 2001 From: CthulhuVRN Date: Sun, 15 Feb 2026 19:14:07 +0300 Subject: [PATCH] AmneziaWG 2.0: support for H1-H4 ranges ## Changes: ``` - [+] Added support for H1-H4 ranges - [!] Fixed interface fields order (H1-H4 goes before I1-I5) ``` ## Known issues: ``` - [!] no check for unique/overlap of H1-H4 values on settings apply: settings will be applied but wg interface will crash with "Invalid argument" error ``` --- src/app/pages/admin/interface.vue | 48 +- src/i18n/locales/en.json | 17 +- .../migrations/0003_breezy_colossus.sql | 36 + .../migrations/meta/0003_snapshot.json | 972 ++++++++++++++++++ .../database/migrations/meta/_journal.json | 7 + .../database/repositories/interface/schema.ts | 8 +- .../database/repositories/interface/types.ts | 8 +- src/server/utils/WireGuard.ts | 10 +- src/server/utils/types.ts | 28 +- src/server/utils/wgHelper.ts | 16 +- 10 files changed, 1096 insertions(+), 54 deletions(-) create mode 100644 src/server/database/migrations/0003_breezy_colossus.sql create mode 100644 src/server/database/migrations/meta/0003_snapshot.json diff --git a/src/app/pages/admin/interface.vue b/src/app/pages/admin/interface.vue index fd4d7eeb..f14ad60d 100644 --- a/src/app/pages/admin/interface.vue +++ b/src/app/pages/admin/interface.vue @@ -69,6 +69,30 @@ :label="$t('awg.s4Label')" :description="$t('awg.s4Description')" /> + + + + - - - - {{ $t('form.actions') }} diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json index 17fc3f7f..dbed156d 100644 --- a/src/i18n/locales/en.json +++ b/src/i18n/locales/en.json @@ -183,6 +183,7 @@ "generic": { "required": "{0} is required", "validNumber": "{0} must be a valid number", + "validNumberRange": "{0} must be a valid number or number range", "validString": "{0} must be a valid string", "validBoolean": "{0} must be a valid boolean", "validArray": "{0} must be a valid array", @@ -262,6 +263,14 @@ "s3Description": "Cookie reply packet junk size", "s4Label": "Transport packet junk size (S4)", "s4Description": "Transport packet junk size", + "h1Label": "Init magic header (H1)", + "h1Description": "Init packet header value or range (X or X-Y, where X", "i2Label": "Special junk packet 2 (I2)", @@ -272,14 +281,6 @@ "i4Description": "Protocol mimic packet in hex format: ", "i5Label": "Special junk packet 5 (I5)", "i5Description": "Protocol mimic packet in hex format: ", - "h1Label": "Init magic header (H1)", - "h1Description": "Init packet header value (5-2147483647, must be unique from H2-H4)", - "h2Label": "Response magic header (H2)", - "h2Description": "Response packet header value (5-2147483647, must be unique from H1, H3, H4)", - "h3Label": "Cookie reply magic header (H3)", - "h3Description": "Cookie reply packet header value (5-2147483647, must be unique from H1, H2, H4)", - "h4Label": "Transport magic header (H4)", - "h4Description": "Transport packet header value (5-2147483647, must be unique from H1-H3)", "mtuNote": "Values depend on the MTU", "obfuscationParameters": "AmneziaWG Obfuscation Parameters" } diff --git a/src/server/database/migrations/0003_breezy_colossus.sql b/src/server/database/migrations/0003_breezy_colossus.sql new file mode 100644 index 00000000..b5987a13 --- /dev/null +++ b/src/server/database/migrations/0003_breezy_colossus.sql @@ -0,0 +1,36 @@ +PRAGMA foreign_keys=OFF;--> statement-breakpoint +CREATE TABLE `__new_interfaces_table` ( + `name` text PRIMARY KEY NOT NULL, + `device` text NOT NULL, + `port` integer NOT NULL, + `private_key` text NOT NULL, + `public_key` text NOT NULL, + `ipv4_cidr` text NOT NULL, + `ipv6_cidr` text NOT NULL, + `mtu` integer NOT NULL, + `j_c` integer DEFAULT 7, + `j_min` integer DEFAULT 10, + `j_max` integer DEFAULT 1000, + `s1` integer DEFAULT 128, + `s2` integer DEFAULT 56, + `s3` integer, + `s4` integer, + `h1` text, + `h2` text, + `h3` text, + `h4` text, + `i1` text, + `i2` text, + `i3` text, + `i4` text, + `i5` text, + `enabled` integer NOT NULL, + `created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL, + `updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL +); +--> statement-breakpoint +INSERT INTO `__new_interfaces_table`("name", "device", "port", "private_key", "public_key", "ipv4_cidr", "ipv6_cidr", "mtu", "j_c", "j_min", "j_max", "s1", "s2", "s3", "s4", "h1", "h2", "h3", "h4", "i1", "i2", "i3", "i4", "i5", "enabled", "created_at", "updated_at") SELECT "name", "device", "port", "private_key", "public_key", "ipv4_cidr", "ipv6_cidr", "mtu", "j_c", "j_min", "j_max", "s1", "s2", "s3", "s4", "h1", "h2", "h3", "h4", "i1", "i2", "i3", "i4", "i5", "enabled", "created_at", "updated_at" FROM `interfaces_table`;--> statement-breakpoint +DROP TABLE `interfaces_table`;--> statement-breakpoint +ALTER TABLE `__new_interfaces_table` RENAME TO `interfaces_table`;--> statement-breakpoint +PRAGMA foreign_keys=ON;--> statement-breakpoint +CREATE UNIQUE INDEX `interfaces_table_port_unique` ON `interfaces_table` (`port`); \ No newline at end of file diff --git a/src/server/database/migrations/meta/0003_snapshot.json b/src/server/database/migrations/meta/0003_snapshot.json new file mode 100644 index 00000000..708657e8 --- /dev/null +++ b/src/server/database/migrations/meta/0003_snapshot.json @@ -0,0 +1,972 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "68c43b7a-772d-4c34-8278-e9fce5b53df1", + "prevId": "e09bc17a-dab6-45a3-a09c-57af222b08fb", + "tables": { + "clients_table": { + "name": "clients_table", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "interface_id": { + "name": "interface_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ipv4_address": { + "name": "ipv4_address", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ipv6_address": { + "name": "ipv6_address", + "type": "text", + "primaryKey": false, + "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", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "pre_shared_key": { + "name": "pre_shared_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "allowed_ips": { + "name": "allowed_ips", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "server_allowed_ips": { + "name": "server_allowed_ips", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "persistent_keepalive": { + "name": "persistent_keepalive", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "mtu": { + "name": "mtu", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "j_c": { + "name": "j_c", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "j_min": { + "name": "j_min", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "j_max": { + "name": "j_max", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "i1": { + "name": "i1", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "i2": { + "name": "i2", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "i3": { + "name": "i3", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "i4": { + "name": "i4", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "i5": { + "name": "i5", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dns": { + "name": "dns", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "server_endpoint": { + "name": "server_endpoint", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": { + "clients_table_ipv4_address_unique": { + "name": "clients_table_ipv4_address_unique", + "columns": [ + "ipv4_address" + ], + "isUnique": true + }, + "clients_table_ipv6_address_unique": { + "name": "clients_table_ipv6_address_unique", + "columns": [ + "ipv6_address" + ], + "isUnique": true + } + }, + "foreignKeys": { + "clients_table_user_id_users_table_id_fk": { + "name": "clients_table_user_id_users_table_id_fk", + "tableFrom": "clients_table", + "tableTo": "users_table", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "cascade" + }, + "clients_table_interface_id_interfaces_table_name_fk": { + "name": "clients_table_interface_id_interfaces_table_name_fk", + "tableFrom": "clients_table", + "tableTo": "interfaces_table", + "columnsFrom": [ + "interface_id" + ], + "columnsTo": [ + "name" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "general_table": { + "name": "general_table", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "setup_step": { + "name": "setup_step", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "session_password": { + "name": "session_password", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "session_timeout": { + "name": "session_timeout", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "metrics_prometheus": { + "name": "metrics_prometheus", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "metrics_json": { + "name": "metrics_json", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "metrics_password": { + "name": "metrics_password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "hooks_table": { + "name": "hooks_table", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "pre_up": { + "name": "pre_up", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "post_up": { + "name": "post_up", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "pre_down": { + "name": "pre_down", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "post_down": { + "name": "post_down", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": {}, + "foreignKeys": { + "hooks_table_id_interfaces_table_name_fk": { + "name": "hooks_table_id_interfaces_table_name_fk", + "tableFrom": "hooks_table", + "tableTo": "interfaces_table", + "columnsFrom": [ + "id" + ], + "columnsTo": [ + "name" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "interfaces_table": { + "name": "interfaces_table", + "columns": { + "name": { + "name": "name", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "device": { + "name": "device", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "private_key": { + "name": "private_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ipv4_cidr": { + "name": "ipv4_cidr", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ipv6_cidr": { + "name": "ipv6_cidr", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "mtu": { + "name": "mtu", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "j_c": { + "name": "j_c", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 7 + }, + "j_min": { + "name": "j_min", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 10 + }, + "j_max": { + "name": "j_max", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 1000 + }, + "s1": { + "name": "s1", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 128 + }, + "s2": { + "name": "s2", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 56 + }, + "s3": { + "name": "s3", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "s4": { + "name": "s4", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "h1": { + "name": "h1", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "h2": { + "name": "h2", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "h3": { + "name": "h3", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "h4": { + "name": "h4", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "i1": { + "name": "i1", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "i2": { + "name": "i2", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "i3": { + "name": "i3", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "i4": { + "name": "i4", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "i5": { + "name": "i5", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": { + "interfaces_table_port_unique": { + "name": "interfaces_table_port_unique", + "columns": [ + "port" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "one_time_links_table": { + "name": "one_time_links_table", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "one_time_link": { + "name": "one_time_link", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": { + "one_time_links_table_one_time_link_unique": { + "name": "one_time_links_table_one_time_link_unique", + "columns": [ + "one_time_link" + ], + "isUnique": true + } + }, + "foreignKeys": { + "one_time_links_table_id_clients_table_id_fk": { + "name": "one_time_links_table_id_clients_table_id_fk", + "tableFrom": "one_time_links_table", + "tableTo": "clients_table", + "columnsFrom": [ + "id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "users_table": { + "name": "users_table", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "totp_key": { + "name": "totp_key", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "totp_verified": { + "name": "totp_verified", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "enabled": { + "name": "enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": { + "users_table_username_unique": { + "name": "users_table_username_unique", + "columns": [ + "username" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_configs_table": { + "name": "user_configs_table", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "default_mtu": { + "name": "default_mtu", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "default_persistent_keepalive": { + "name": "default_persistent_keepalive", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "default_dns": { + "name": "default_dns", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "default_allowed_ips": { + "name": "default_allowed_ips", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "default_j_c": { + "name": "default_j_c", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 7 + }, + "default_j_min": { + "name": "default_j_min", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 10 + }, + "default_j_max": { + "name": "default_j_max", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 1000 + }, + "default_i1": { + "name": "default_i1", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "default_i2": { + "name": "default_i2", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "default_i3": { + "name": "default_i3", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "default_i4": { + "name": "default_i4", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "default_i5": { + "name": "default_i5", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "host": { + "name": "host", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "port": { + "name": "port", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + }, + "updated_at": { + "name": "updated_at", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(CURRENT_TIMESTAMP)" + } + }, + "indexes": {}, + "foreignKeys": { + "user_configs_table_id_interfaces_table_name_fk": { + "name": "user_configs_table_id_interfaces_table_name_fk", + "tableFrom": "user_configs_table", + "tableTo": "interfaces_table", + "columnsFrom": [ + "id" + ], + "columnsTo": [ + "name" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/src/server/database/migrations/meta/_journal.json b/src/server/database/migrations/meta/_journal.json index 9e4a5f4c..8a95d1af 100644 --- a/src/server/database/migrations/meta/_journal.json +++ b/src/server/database/migrations/meta/_journal.json @@ -22,6 +22,13 @@ "when": 1761298328460, "tag": "0002_keen_sleepwalker", "breakpoints": true + }, + { + "idx": 3, + "version": "6", + "when": 1770902426367, + "tag": "0003_breezy_colossus", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/server/database/repositories/interface/schema.ts b/src/server/database/repositories/interface/schema.ts index c0ee71c0..d465ebf3 100644 --- a/src/server/database/repositories/interface/schema.ts +++ b/src/server/database/repositories/interface/schema.ts @@ -20,15 +20,15 @@ export const wgInterface = sqliteTable('interfaces_table', { s2: int().default(56), s3: int(), s4: int(), + h1: text(), + h2: text(), + h3: text(), + h4: text(), i1: text(), i2: text(), i3: text(), i4: text(), i5: text(), - h1: int().default(0), - h2: int().default(0), - h3: int().default(0), - h4: int().default(0), // does nothing yet enabled: int({ mode: 'boolean' }).notNull(), createdAt: text('created_at') diff --git a/src/server/database/repositories/interface/types.ts b/src/server/database/repositories/interface/types.ts index 3051d3b3..306f6546 100644 --- a/src/server/database/repositories/interface/types.ts +++ b/src/server/database/repositories/interface/types.ts @@ -38,15 +38,15 @@ export const InterfaceUpdateSchema = schemaForType()( s2: SSchema, s3: SSchema, s4: SSchema, + h1: HSchema, + h2: HSchema, + h3: HSchema, + h4: HSchema, i1: ISchema, i2: ISchema, i3: ISchema, i4: ISchema, i5: ISchema, - h1: HSchema, - h2: HSchema, - h3: HSchema, - h4: HSchema, port: PortSchema, device: device, enabled: EnabledSchema, diff --git a/src/server/utils/WireGuard.ts b/src/server/utils/WireGuard.ts index 8b4ade14..c73b8fdc 100644 --- a/src/server/utils/WireGuard.ts +++ b/src/server/utils/WireGuard.ts @@ -213,7 +213,7 @@ class WireGuard { WG_DEBUG('New Wireguard Keys generated successfully.'); } - if (wgInterface.h1 === 0) { + if (!wgInterface.h1) { WG_DEBUG('Generating random AmneziaWG obfuscation parameters...'); const headers = new Set(); @@ -222,10 +222,10 @@ class WireGuard { } const [h1, h2, h3, h4] = Array.from(headers); - wgInterface.h1 = h1!; - wgInterface.h2 = h2!; - wgInterface.h3 = h3!; - wgInterface.h4 = h4!; + wgInterface.h1 = String(h1)!; + wgInterface.h2 = String(h2)!; + wgInterface.h3 = String(h3)!; + wgInterface.h4 = String(h4)!; Database.interfaces.update(wgInterface); } diff --git a/src/server/utils/types.ts b/src/server/utils/types.ts index 46eb80e2..b604c47b 100644 --- a/src/server/utils/types.ts +++ b/src/server/utils/types.ts @@ -34,7 +34,33 @@ export const JmaxSchema = z.number().max(1280).nullable(); export const SSchema = z.number().max(1132).nullable(); -export const HSchema = z.number().min(5).max(2147483647).nullable(); +const H_MIN = 5; +const H_MAX = 2 ** 31 - 1; + +export const HSchema = z + .string() + .transform(v => v.replace(/\s+/g, '')) + .refine(v => v === '' || /^\d+(-\d+)?$/.test(v), { + message: t('zod.generic.validNumberRange') + }) + .refine(v => { + // if single number + if (!v.includes('-')) { + const num = Number(v); + if ( num < H_MIN || num > H_MAX ) + return false; + return `${num}`; + } + + // if number range + const [min, max] = v.split('-').map(Number); + if ( min < H_MIN || max > H_MAX || min > max ) + return false; + return min === max ? `${min}` : `${min}-${max}`; + }, { + message: t('zod.generic.validNumberRange') + }) + .nullable(); export const ISchema = z.string().nullable(); diff --git a/src/server/utils/wgHelper.ts b/src/server/utils/wgHelper.ts index 607a0c51..7f69d6c5 100644 --- a/src/server/utils/wgHelper.ts +++ b/src/server/utils/wgHelper.ts @@ -63,15 +63,15 @@ AllowedIPs = ${allowedIps.join(', ')}${extraLines.length ? `\n${extraLines.join( S2: wgInterface.s2, S3: wgInterface.s3, S4: wgInterface.s4, + H1: wgInterface.h1, + H2: wgInterface.h2, + H3: wgInterface.h3, + H4: wgInterface.h4, I1: wgInterface.i1, I2: wgInterface.i2, I3: wgInterface.i3, I4: wgInterface.i4, I5: wgInterface.i5, - H1: wgInterface.h1, - H2: wgInterface.h2, - H3: wgInterface.h3, - H4: wgInterface.h4, } as const; awgLines = Object.entries(parameters) @@ -131,15 +131,15 @@ PostDown = ${iptablesTemplate(hooks.postDown, wgInterface)}`; S2: wgInterface.s2, S3: wgInterface.s3, S4: wgInterface.s4, + H1: wgInterface.h1, + H2: wgInterface.h2, + H3: wgInterface.h3, + H4: wgInterface.h4, I1: client.i1, I2: client.i2, I3: client.i3, I4: client.i4, I5: client.i5, - H1: wgInterface.h1, - H2: wgInterface.h2, - H3: wgInterface.h3, - H4: wgInterface.h4, } as const; awgLines = Object.entries(parameters)