diff --git a/src/server/database/migrations/0006_clear_leech.sql b/src/server/database/migrations/0006_clear_leech.sql new file mode 100644 index 00000000..f31d4882 --- /dev/null +++ b/src/server/database/migrations/0006_clear_leech.sql @@ -0,0 +1,2 @@ +CREATE UNIQUE INDEX `public_key_interface_unique` ON `clients_table` (`public_key`,`interface_id`);--> statement-breakpoint +CREATE UNIQUE INDEX `users_table_email_unique` ON `users_table` (`email`); \ No newline at end of file diff --git a/src/server/database/migrations/meta/0006_snapshot.json b/src/server/database/migrations/meta/0006_snapshot.json new file mode 100644 index 00000000..391b660a --- /dev/null +++ b/src/server/database/migrations/meta/0006_snapshot.json @@ -0,0 +1,1024 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "8a38844d-02cb-4fce-8692-db05920c91a5", + "prevId": "d41b21e2-3977-4e94-8250-d26a26678703", + "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 + }, + "firewall_ips": { + "name": "firewall_ips", + "type": "text", + "primaryKey": false, + "notNull": false, + "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 + }, + "public_key_interface_unique": { + "name": "public_key_interface_unique", + "columns": [ + "public_key", + "interface_id" + ], + "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 + }, + "firewall_enabled": { + "name": "firewall_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 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": false, + "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 + }, + "oauth_provider": { + "name": "oauth_provider", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "oauth_id": { + "name": "oauth_id", + "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": { + "users_table_username_unique": { + "name": "users_table_username_unique", + "columns": [ + "username" + ], + "isUnique": true + }, + "users_table_email_unique": { + "name": "users_table_email_unique", + "columns": [ + "email" + ], + "isUnique": true + }, + "oauth_provider_id_unique": { + "name": "oauth_provider_id_unique", + "columns": [ + "oauth_provider", + "oauth_id" + ], + "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 4650fa31..0ae8c800 100644 --- a/src/server/database/migrations/meta/_journal.json +++ b/src/server/database/migrations/meta/_journal.json @@ -43,6 +43,13 @@ "when": 1780035570366, "tag": "0005_clumsy_korg", "breakpoints": true + }, + { + "idx": 6, + "version": "6", + "when": 1782122902196, + "tag": "0006_clear_leech", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/server/database/repositories/client/schema.ts b/src/server/database/repositories/client/schema.ts index 827f59a9..eb3a707e 100644 --- a/src/server/database/repositories/client/schema.ts +++ b/src/server/database/repositories/client/schema.ts @@ -1,64 +1,75 @@ import { sql, relations } from 'drizzle-orm'; -import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { int, sqliteTable, text, uniqueIndex } from 'drizzle-orm/sqlite-core'; -import { wgInterface } from '#db/repositories/interface/schema'; -import { oneTimeLink } from '#db/repositories/oneTimeLink/schema'; -import { user } from '#db/repositories/user/schema'; +import { wgInterface } from '../interface/schema'; +import { oneTimeLink } from '../oneTimeLink/schema'; +import { user } from '../user/schema'; /** null means use value from userConfig */ -export const client = sqliteTable('clients_table', { - id: int().primaryKey({ autoIncrement: true }), - userId: int('user_id') - .notNull() - .references(() => user.id, { - onDelete: 'restrict', - onUpdate: 'cascade', - }), - interfaceId: text('interface_id') - .notNull() - .references(() => wgInterface.name, { - onDelete: 'cascade', - onUpdate: 'cascade', - }), - 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(), - expiresAt: text('expires_at'), - allowedIps: text('allowed_ips', { mode: 'json' }).$type(), - serverAllowedIps: text('server_allowed_ips', { mode: 'json' }) - .$type() - .notNull(), - // Firewall-enforced allowed IPs (null = use allowedIps) - firewallIps: text('firewall_ips', { mode: 'json' }).$type(), - persistentKeepalive: int('persistent_keepalive').notNull(), - mtu: int().notNull(), - jC: int('j_c'), - jMin: int('j_min'), - jMax: int('j_max'), - i1: text(), - i2: text(), - i3: text(), - i4: text(), - i5: text(), - dns: text({ mode: 'json' }).$type(), - serverEndpoint: text('server_endpoint'), - enabled: int({ mode: 'boolean' }).notNull(), - createdAt: text('created_at') - .notNull() - .default(sql`(CURRENT_TIMESTAMP)`), - updatedAt: text('updated_at') - .notNull() - .default(sql`(CURRENT_TIMESTAMP)`) - .$onUpdate(() => sql`(CURRENT_TIMESTAMP)`), -}); +export const client = sqliteTable( + 'clients_table', + { + id: int().primaryKey({ autoIncrement: true }), + userId: int('user_id') + .notNull() + .references(() => user.id, { + onDelete: 'restrict', + onUpdate: 'cascade', + }), + interfaceId: text('interface_id') + .notNull() + .references(() => wgInterface.name, { + onDelete: 'cascade', + onUpdate: 'cascade', + }), + 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(), + expiresAt: text('expires_at'), + allowedIps: text('allowed_ips', { mode: 'json' }).$type(), + serverAllowedIps: text('server_allowed_ips', { mode: 'json' }) + .$type() + .notNull(), + // Firewall-enforced allowed IPs (null = use allowedIps) + firewallIps: text('firewall_ips', { mode: 'json' }).$type< + string[] | null + >(), + persistentKeepalive: int('persistent_keepalive').notNull(), + mtu: int().notNull(), + jC: int('j_c'), + jMin: int('j_min'), + jMax: int('j_max'), + i1: text(), + i2: text(), + i3: text(), + i4: text(), + i5: text(), + dns: text({ mode: 'json' }).$type(), + serverEndpoint: text('server_endpoint'), + enabled: int({ mode: 'boolean' }).notNull(), + createdAt: text('created_at') + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`), + updatedAt: text('updated_at') + .notNull() + .default(sql`(CURRENT_TIMESTAMP)`) + .$onUpdate(() => sql`(CURRENT_TIMESTAMP)`), + }, + (table) => [ + uniqueIndex('public_key_interface_unique').on( + table.publicKey, + table.interfaceId + ), + ] +); export const clientsRelations = relations(client, ({ one }) => ({ oneTimeLink: one(oneTimeLink, { diff --git a/src/server/database/repositories/hooks/schema.ts b/src/server/database/repositories/hooks/schema.ts index 5db89ae2..99883bc8 100644 --- a/src/server/database/repositories/hooks/schema.ts +++ b/src/server/database/repositories/hooks/schema.ts @@ -1,7 +1,7 @@ import { sql } from 'drizzle-orm'; import { sqliteTable, text } from 'drizzle-orm/sqlite-core'; -import { wgInterface } from '#db/repositories/interface/schema'; +import { wgInterface } from '../interface/schema'; export const hooks = sqliteTable('hooks_table', { /** same as `wgInterface.name` */ diff --git a/src/server/database/repositories/interface/schema.ts b/src/server/database/repositories/interface/schema.ts index b7c221de..d4c21264 100644 --- a/src/server/database/repositories/interface/schema.ts +++ b/src/server/database/repositories/interface/schema.ts @@ -1,8 +1,8 @@ import { sql, relations } from 'drizzle-orm'; import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; -import { hooks } from '#db/repositories/hooks/schema'; -import { userConfig } from '#db/repositories/userConfig/schema'; +import { hooks } from '../hooks/schema'; +import { userConfig } from '../userConfig/schema'; // maybe support multiple interfaces in the future export const wgInterface = sqliteTable('interfaces_table', { diff --git a/src/server/database/repositories/oneTimeLink/schema.ts b/src/server/database/repositories/oneTimeLink/schema.ts index ccd6aa84..83a0eef1 100644 --- a/src/server/database/repositories/oneTimeLink/schema.ts +++ b/src/server/database/repositories/oneTimeLink/schema.ts @@ -1,7 +1,7 @@ import { sql, relations } from 'drizzle-orm'; import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; -import { client } from '#db/repositories/client/schema'; +import { client } from '../client/schema'; export const oneTimeLink = sqliteTable('one_time_links_table', { /** same as `client.id` */ diff --git a/src/server/database/repositories/user/schema.ts b/src/server/database/repositories/user/schema.ts index 3e83f80f..e1d70679 100644 --- a/src/server/database/repositories/user/schema.ts +++ b/src/server/database/repositories/user/schema.ts @@ -1,7 +1,8 @@ import { sql, relations } from 'drizzle-orm'; import { int, sqliteTable, text, uniqueIndex } from 'drizzle-orm/sqlite-core'; -import { client } from '#db/repositories/client/schema'; +import { client } from '../client/schema'; + import type { Role } from '#shared/utils/permissions'; import type { OAUTH_PROVIDER } from '#server/utils/oauth'; @@ -12,7 +13,7 @@ export const user = sqliteTable( username: text().notNull().unique(), /** `password == null` means password login disabled */ password: text(), - email: text(), + email: text().unique(), name: text().notNull(), role: int().$type().notNull(), totpKey: text('totp_key'), diff --git a/src/server/database/repositories/userConfig/schema.ts b/src/server/database/repositories/userConfig/schema.ts index fed957a1..01dd6baf 100644 --- a/src/server/database/repositories/userConfig/schema.ts +++ b/src/server/database/repositories/userConfig/schema.ts @@ -1,7 +1,7 @@ import { sql } from 'drizzle-orm'; import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core'; -import { wgInterface } from '#db/repositories/interface/schema'; +import { wgInterface } from '../interface/schema'; // default* means clients store it themselves export const userConfig = sqliteTable('user_configs_table', { diff --git a/src/server/database/schema.ts b/src/server/database/schema.ts index 028de639..8527bcfa 100644 --- a/src/server/database/schema.ts +++ b/src/server/database/schema.ts @@ -1,7 +1,8 @@ -export * from '#db/repositories/client/schema'; -export * from '#db/repositories/general/schema'; -export * from '#db/repositories/hooks/schema'; -export * from '#db/repositories/interface/schema'; -export * from '#db/repositories/oneTimeLink/schema'; -export * from '#db/repositories/user/schema'; -export * from '#db/repositories/userConfig/schema'; +// ! Do not use Path Aliases in this or any of these files +export * from './repositories/client/schema'; +export * from './repositories/general/schema'; +export * from './repositories/hooks/schema'; +export * from './repositories/interface/schema'; +export * from './repositories/oneTimeLink/schema'; +export * from './repositories/user/schema'; +export * from './repositories/userConfig/schema'; diff --git a/src/server/database/sqlite.ts b/src/server/database/sqlite.ts index 89e64f34..59469ccc 100644 --- a/src/server/database/sqlite.ts +++ b/src/server/database/sqlite.ts @@ -69,6 +69,7 @@ async function migrate() { if (e instanceof Error) { DB_DEBUG('Failed to migrate database:', e.message); } + throw e; } } diff --git a/src/server/utils/Database.ts b/src/server/utils/Database.ts index e2b578dd..7231d1c0 100644 --- a/src/server/utils/Database.ts +++ b/src/server/utils/Database.ts @@ -17,9 +17,14 @@ const nullObject = new Proxy( // eslint-disable-next-line import/no-mutable-exports let provider = nullObject as never as DBServiceType; -connect().then((db) => { - provider = db; - WireGuard.Startup(); -}); +connect() + .then((db) => { + provider = db; + WireGuard.Startup(); + }) + .catch((err) => { + console.log('Failed to connect to Database:', err); + process.exit(1); + }); export default provider;