Browse Source

implement setup

pull/1619/head
Bernd Storath 3 months ago
parent
commit
5352a2ae29
  1. 2
      Dockerfile.dev
  2. 3
      src/server/api/session.post.ts
  3. 9
      src/server/api/setup/4.post.ts
  4. 8
      src/server/api/setup/5.post.ts
  5. 15
      src/server/api/setup/migrate.post.ts
  6. 99
      src/server/database/migrations/0000_fantastic_zemo.sql
  7. 3
      src/server/database/migrations/0001_lonely_tusk.sql
  8. 679
      src/server/database/migrations/meta/0000_snapshot.json
  9. 679
      src/server/database/migrations/meta/0001_snapshot.json
  10. 20
      src/server/database/migrations/meta/_journal.json
  11. 8
      src/server/database/repositories/client/service.ts
  12. 10
      src/server/database/repositories/general/schema.ts
  13. 57
      src/server/database/repositories/general/service.ts
  14. 26
      src/server/database/repositories/sessionConfig/service.ts
  15. 2
      src/server/database/repositories/user/schema.ts
  16. 31
      src/server/database/repositories/user/service.ts
  17. 32
      src/server/database/repositories/userConfig/service.ts
  18. 2
      src/server/database/schema.ts
  19. 9
      src/server/database/sqlite.ts
  20. 4
      src/server/middleware/auth.ts
  21. 6
      src/server/middleware/setup.ts
  22. 7
      src/server/utils/crypto.ts
  23. 10
      src/server/utils/session.ts

2
Dockerfile.dev

@ -28,7 +28,7 @@ ENV PORT=51821
ENV HOST=0.0.0.0
# Install Dependencies
COPY src/package.json src/pnpm-lock.yaml ./ ./
COPY src/package.json src/pnpm-lock.yaml ./
RUN pnpm install
# Copy Project

3
src/server/api/session.post.ts

@ -4,8 +4,7 @@ export default defineEventHandler(async (event) => {
validateZod(credentialsType, event)
);
const users = await Database.users.getAll();
const user = users.find((user) => user.username == username);
const user = await Database.users.getByUsername(username);
if (!user)
throw createError({
statusCode: 400,

9
src/server/api/setup/4.post.ts

@ -1,6 +1,6 @@
export default defineEventHandler(async (event) => {
const setupDone = await Database.setup.done();
if (setupDone) {
const { done } = await Database.general.getSetupStep();
if (done) {
throw createError({
statusCode: 400,
statusMessage: 'Invalid state',
@ -11,7 +11,8 @@ export default defineEventHandler(async (event) => {
event,
validateZod(passwordSetupType, event)
);
await Database.user.create(username, password);
await Database.setup.set(5);
await Database.users.create(username, password);
await Database.general.setSetupStep(5);
return { success: true };
});

8
src/server/api/setup/5.post.ts

@ -1,6 +1,6 @@
export default defineEventHandler(async (event) => {
const setupDone = await Database.setup.done();
if (setupDone) {
const { done } = await Database.general.getSetupStep();
if (done) {
throw createError({
statusCode: 400,
statusMessage: 'Invalid state',
@ -11,7 +11,7 @@ export default defineEventHandler(async (event) => {
event,
validateZod(hostPortType, event)
);
await Database.system.updateClientsHostPort(host, port);
await Database.setup.set('success');
await Database.userConfigs.updateHostPort('wg0', host, port);
await Database.general.setSetupStep(0);
return { success: true };
});

15
src/server/api/setup/migrate.post.ts

@ -1,16 +1,17 @@
import { parseCidr } from 'cidr-tools';
/*import { parseCidr } from 'cidr-tools';
import { stringifyIp } from 'ip-bigint';
import { z } from 'zod';
import type { Database } from '~~/services/database/repositories/database';
import { z } from 'zod';*/
export default defineEventHandler(async (event) => {
const setupDone = await Database.setup.done();
if (setupDone) {
export default defineEventHandler(async (/*event*/) => {
const { done } = await Database.general.getSetupStep();
if (done) {
throw createError({
statusCode: 400,
statusMessage: 'Invalid state',
});
}
// TODO: Implement
/*
const { file } = await readValidatedBody(event, validateZod(fileType, event));
const schema = z.object({
@ -79,7 +80,7 @@ export default defineEventHandler(async (event) => {
address6: address6,
mtu: 1420,
});
}
}*/
return { success: true };
});

99
src/server/database/migrations/0000_fantastic_zemo.sql

@ -0,0 +1,99 @@
CREATE TABLE `clients_table` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`name` text NOT NULL,
`ipv4_address` text NOT NULL,
`ipv6_address` text NOT NULL,
`private_key` text NOT NULL,
`public_key` text NOT NULL,
`pre_shared_key` text NOT NULL,
`expires_at` text,
`allowed_ips` text NOT NULL,
`server_allowed_ips` text NOT NULL,
`persistent_keepalive` integer NOT NULL,
`mtu` integer NOT NULL,
`dns` text NOT NULL,
`enabled` integer NOT NULL,
`created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
`updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL
);
--> statement-breakpoint
CREATE UNIQUE INDEX `clients_table_ipv4_address_unique` ON `clients_table` (`ipv4_address`);--> statement-breakpoint
CREATE UNIQUE INDEX `clients_table_ipv6_address_unique` ON `clients_table` (`ipv6_address`);--> statement-breakpoint
CREATE TABLE `general_table` (
`id` integer PRIMARY KEY DEFAULT 1 NOT NULL,
`setupStep` integer NOT NULL,
`session_password` text NOT NULL,
`session_timeout` integer NOT NULL,
`created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
`updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL
);
--> statement-breakpoint
CREATE TABLE `hooks_table` (
`id` text PRIMARY KEY NOT NULL,
`pre_up` text NOT NULL,
`post_up` text NOT NULL,
`pre_down` text NOT NULL,
`post_down` text NOT NULL,
`created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
`updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
FOREIGN KEY (`id`) REFERENCES `interfaces_table`(`name`) ON UPDATE cascade ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `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,
`enabled` integer NOT NULL,
`created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
`updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL
);
--> statement-breakpoint
CREATE UNIQUE INDEX `interfaces_table_port_unique` ON `interfaces_table` (`port`);--> statement-breakpoint
CREATE TABLE `prometheus_table` (
`id` text PRIMARY KEY NOT NULL,
`password` text NOT NULL,
`created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
`updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
FOREIGN KEY (`id`) REFERENCES `interfaces_table`(`name`) ON UPDATE cascade ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `one_time_links_table` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`one_time_link` text NOT NULL,
`expires_at` text NOT NULL,
`clientId` integer NOT NULL,
`created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
`updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
FOREIGN KEY (`clientId`) REFERENCES `clients_table`(`id`) ON UPDATE cascade ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `users_table` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`username` text NOT NULL,
`password` text NOT NULL,
`email` text,
`name` text NOT NULL,
`role` integer NOT NULL,
`enabled` integer DEFAULT 1 NOT NULL,
`created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
`updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL
);
--> statement-breakpoint
CREATE UNIQUE INDEX `users_table_username_unique` ON `users_table` (`username`);--> statement-breakpoint
CREATE TABLE `user_configs_table` (
`id` text PRIMARY KEY NOT NULL,
`default_mtu` integer NOT NULL,
`default_persistent_keepalive` integer NOT NULL,
`default_dns` text NOT NULL,
`default_allowed_ips` text NOT NULL,
`host` text NOT NULL,
`port` integer NOT NULL,
`created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
`updated_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
FOREIGN KEY (`id`) REFERENCES `interfaces_table`(`name`) ON UPDATE cascade ON DELETE cascade
);

3
src/server/database/migrations/0001_lonely_tusk.sql

@ -0,0 +1,3 @@
-- Custom SQL migration file, put your code below! --
INSERT INTO `general_table` (`setupStep`, `session_password`, `session_timeout`)
VALUES (1, hex(randomblob(256)), 3600);

679
src/server/database/migrations/meta/0000_snapshot.json

@ -0,0 +1,679 @@
{
"version": "6",
"dialect": "sqlite",
"id": "52812a10-9028-40dc-b1dc-69e4e641aa9e",
"prevId": "00000000-0000-0000-0000-000000000000",
"tables": {
"clients_table": {
"name": "clients_table",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"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
},
"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": true,
"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
},
"dns": {
"name": "dns",
"type": "text",
"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": {
"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": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"general_table": {
"name": "general_table",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": false,
"default": 1
},
"setupStep": {
"name": "setupStep",
"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
},
"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
},
"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": {}
},
"prometheus_table": {
"name": "prometheus_table",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"password": {
"name": "password",
"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": {
"prometheus_table_id_interfaces_table_name_fk": {
"name": "prometheus_table_id_interfaces_table_name_fk",
"tableFrom": "prometheus_table",
"tableTo": "interfaces_table",
"columnsFrom": [
"id"
],
"columnsTo": [
"name"
],
"onDelete": "cascade",
"onUpdate": "cascade"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"one_time_links_table": {
"name": "one_time_links_table",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"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
},
"clientId": {
"name": "clientId",
"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": {
"one_time_links_table_clientId_clients_table_id_fk": {
"name": "one_time_links_table_clientId_clients_table_id_fk",
"tableFrom": "one_time_links_table",
"tableTo": "clients_table",
"columnsFrom": [
"clientId"
],
"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
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 1
},
"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
},
"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": {}
}
}

679
src/server/database/migrations/meta/0001_snapshot.json

@ -0,0 +1,679 @@
{
"id": "5eee8e4e-69d5-4c68-b5cd-a221ad7649de",
"prevId": "52812a10-9028-40dc-b1dc-69e4e641aa9e",
"version": "6",
"dialect": "sqlite",
"tables": {
"clients_table": {
"name": "clients_table",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"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
},
"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": true,
"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
},
"dns": {
"name": "dns",
"type": "text",
"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": {
"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": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"general_table": {
"name": "general_table",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": false,
"default": 1
},
"setupStep": {
"name": "setupStep",
"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
},
"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",
"columnsFrom": [
"id"
],
"tableTo": "interfaces_table",
"columnsTo": [
"name"
],
"onUpdate": "cascade",
"onDelete": "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
},
"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": {}
},
"prometheus_table": {
"name": "prometheus_table",
"columns": {
"id": {
"name": "id",
"type": "text",
"primaryKey": true,
"notNull": true,
"autoincrement": false
},
"password": {
"name": "password",
"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": {
"prometheus_table_id_interfaces_table_name_fk": {
"name": "prometheus_table_id_interfaces_table_name_fk",
"tableFrom": "prometheus_table",
"columnsFrom": [
"id"
],
"tableTo": "interfaces_table",
"columnsTo": [
"name"
],
"onUpdate": "cascade",
"onDelete": "cascade"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
},
"one_time_links_table": {
"name": "one_time_links_table",
"columns": {
"id": {
"name": "id",
"type": "integer",
"primaryKey": true,
"notNull": true,
"autoincrement": true
},
"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
},
"clientId": {
"name": "clientId",
"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": {
"one_time_links_table_clientId_clients_table_id_fk": {
"name": "one_time_links_table_clientId_clients_table_id_fk",
"tableFrom": "one_time_links_table",
"columnsFrom": [
"clientId"
],
"tableTo": "clients_table",
"columnsTo": [
"id"
],
"onUpdate": "cascade",
"onDelete": "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
},
"enabled": {
"name": "enabled",
"type": "integer",
"primaryKey": false,
"notNull": true,
"autoincrement": false,
"default": 1
},
"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
},
"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",
"columnsFrom": [
"id"
],
"tableTo": "interfaces_table",
"columnsTo": [
"name"
],
"onUpdate": "cascade",
"onDelete": "cascade"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {},
"checkConstraints": {}
}
},
"views": {},
"enums": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
},
"internal": {
"indexes": {}
}
}

20
src/server/database/migrations/meta/_journal.json

@ -0,0 +1,20 @@
{
"version": "7",
"dialect": "sqlite",
"entries": [
{
"idx": 0,
"version": "6",
"when": 1737101897688,
"tag": "0000_fantastic_zemo",
"breakpoints": true
},
{
"idx": 1,
"version": "6",
"when": 1737101904944,
"tag": "0001_lonely_tusk",
"breakpoints": true
}
]
}

8
src/server/database/repositories/client/service.ts

@ -30,7 +30,7 @@ export class ClientService {
}
async getAll() {
const result = await this.#statements.findAll.all();
const result = await this.#statements.findAll.execute();
return result.map((row) => ({
...row,
createdAt: new Date(row.createdAt),
@ -39,7 +39,7 @@ export class ClientService {
}
async get(id: number) {
return this.#statements.findById.all({ id });
return this.#statements.findById.execute({ id });
}
async create({ name, expiresAt }: ClientCreateType) {
@ -56,7 +56,7 @@ export class ClientService {
parsedExpiresAt = expiresAtDate.toISOString();
}
await this.#db.transaction(async (tx) => {
return this.#db.transaction(async (tx) => {
const clients = await tx.query.client.findMany().execute();
const clientInterface = await tx.query.wgInterface
.findFirst({
@ -83,7 +83,7 @@ export class ClientService {
const ipv6Cidr = parseCidr(clientInterface.ipv6Cidr);
const ipv6Address = nextIP(6, ipv6Cidr, clients);
return await tx
await tx
.insert(client)
.values({
name,

10
src/server/database/repositories/sessionConfig/schema.ts → src/server/database/repositories/general/schema.ts

@ -1,11 +1,11 @@
import { sql } from 'drizzle-orm';
import { int, sqliteTable, text } from 'drizzle-orm/sqlite-core';
import { sqliteTable, text, int } from 'drizzle-orm/sqlite-core';
export const sessionConfig = sqliteTable('session_config_table', {
// limit to one entry
export const general = sqliteTable('general_table', {
id: int().primaryKey({ autoIncrement: false }).default(1),
password: text().notNull(),
timeout: int().notNull(),
setupStep: int().notNull(),
sessionPassword: text('session_password').notNull(),
sessionTimeout: int('session_timeout').notNull(),
createdAt: text('created_at')
.notNull()
.default(sql`(CURRENT_TIMESTAMP)`),

57
src/server/database/repositories/general/service.ts

@ -0,0 +1,57 @@
import type { DBType } from '#db/sqlite';
import { sql } from 'drizzle-orm';
import { general } from './schema';
function createPreparedStatement(db: DBType) {
return {
find: db.query.general.findFirst().prepare(),
updateSetupStep: db
.update(general)
.set({
setupStep: sql.placeholder('setupStep') as never as number,
})
.prepare(),
};
}
export class GeneralService {
#statements: ReturnType<typeof createPreparedStatement>;
constructor(db: DBType) {
this.#statements = createPreparedStatement(db);
}
/**
* @throws
*/
private async get() {
const result = await this.#statements.find.execute();
if (!result) {
throw new Error('General Config not found');
}
return result;
}
/**
* @throws
*/
async getSetupStep() {
const result = await this.get();
return { step: result.setupStep, done: result.setupStep === 0 };
}
setSetupStep(step: number) {
return this.#statements.updateSetupStep.execute({ setupStep: step });
}
/**
* @throws
*/
async getSessionConfig() {
const result = await this.get();
return {
sessionPassword: result.sessionPassword,
sessionTimeout: result.sessionTimeout,
};
}
}

26
src/server/database/repositories/sessionConfig/service.ts

@ -1,26 +0,0 @@
import type { DBType } from '#db/sqlite';
function createPreparedStatement(db: DBType) {
return {
find: db.query.sessionConfig.findFirst().prepare(),
};
}
export class SessionConfigService {
#statements: ReturnType<typeof createPreparedStatement>;
constructor(db: DBType) {
this.#statements = createPreparedStatement(db);
}
/**
* @throws
*/
async get() {
const result = await this.#statements.find.all();
if (!result) {
throw new Error('Session Config not found');
}
return result;
}
}

2
src/server/database/repositories/user/schema.ts

@ -8,7 +8,7 @@ export const user = sqliteTable('users_table', {
email: text(),
name: text().notNull(),
role: int().$type<Role>().notNull(),
enabled: int().notNull().default(1),
enabled: int({ mode: 'boolean' }).notNull(),
createdAt: text('created_at')
.notNull()
.default(sql`(CURRENT_TIMESTAMP)`),

31
src/server/database/repositories/user/service.ts

@ -18,21 +18,46 @@ function createPreparedStatement(db: DBType) {
}
export class UserService {
#db: DBType;
#statements: ReturnType<typeof createPreparedStatement>;
constructor(db: DBType) {
this.#db = db;
this.#statements = createPreparedStatement(db);
}
async getAll() {
return this.#statements.findAll.all();
return this.#statements.findAll.execute();
}
async get(id: ID) {
return this.#statements.findById.all({ id });
return this.#statements.findById.execute({ id });
}
async getByUsername(username: string) {
return this.#statements.findByUsername.all({ username });
return this.#statements.findByUsername.execute({ username });
}
async create(username: string, password: string) {
const hash = await hashPassword(password);
return this.#db.transaction(async (tx) => {
const oldUser = await this.getByUsername(username);
if (oldUser) {
throw new Error('User already exists');
}
const userCount = await tx.$count(user);
await tx.insert(user).values({
password: hash,
username,
email: null,
name: 'Administrator',
role: userCount === 0 ? roles.ADMIN : roles.CLIENT,
enabled: true,
});
});
}
}

32
src/server/database/repositories/userConfig/service.ts

@ -0,0 +1,32 @@
import type { DBType } from '#db/sqlite';
import { eq, sql } from 'drizzle-orm';
import { userConfig } from './schema';
function createPreparedStatement(db: DBType) {
return {
updateHostPort: db
.update(userConfig)
.set({
host: sql.placeholder('host') as never as string,
port: sql.placeholder('port') as never as number,
})
.where(eq(userConfig.id, sql.placeholder('interface')))
.prepare(),
};
}
export class UserConfigService {
#statements: ReturnType<typeof createPreparedStatement>;
constructor(db: DBType) {
this.#statements = createPreparedStatement(db);
}
async updateHostPort(wgInterface: string, host: string, port: number) {
return await this.#statements.updateHostPort.execute({
interface: wgInterface,
host,
port,
});
}
}

2
src/server/database/schema.ts

@ -1,10 +1,10 @@
// Make sure to not use any Path Aliases in 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/metrics/schema';
export * from './repositories/oneTimeLink/schema';
export * from './repositories/sessionConfig/schema';
export * from './repositories/user/schema';
export * from './repositories/userConfig/schema';

9
src/server/database/sqlite.ts

@ -4,8 +4,9 @@ import { createClient } from '@libsql/client';
import * as schema from './schema';
import { ClientService } from './repositories/client/service';
import { SessionConfigService } from './repositories/sessionConfig/service';
import { GeneralService } from './repositories/general/service';
import { UserService } from './repositories/user/service';
import { UserConfigService } from './repositories/userConfig/service';
const client = createClient({ url: 'file:/etc/wireguard/wg0.db' });
const db = drizzle({ client, schema });
@ -17,12 +18,14 @@ export async function connect() {
class DBService {
clients: ClientService;
sessionConfig: SessionConfigService;
general: GeneralService;
users: UserService;
userConfigs: UserConfigService;
constructor(db: DBType) {
this.clients = new ClientService(db);
this.sessionConfig = new SessionConfigService(db);
this.general = new GeneralService(db);
this.users = new UserService(db);
this.userConfigs = new UserConfigService(db);
}
}

4
src/server/middleware/auth.ts

@ -1,5 +1,5 @@
export default defineEventHandler(async (event) => {
const url = getRequestURL(event);
/*const url = getRequestURL(event);
const session = await useWGSession(event);
// Api handled by session, Setup handled with setup middleware
@ -31,5 +31,5 @@ export default defineEventHandler(async (event) => {
statusMessage: 'Not allowed to access Admin Panel',
});
}
}
}*/
});

6
src/server/middleware/setup.ts

@ -7,14 +7,14 @@ export default defineEventHandler(async (event) => {
return;
}
const setupDone = await Database.setup.done();
if (!setupDone) {
const { step, done } = await Database.general.getSetupStep();
if (!done) {
const parsedSetup = url.pathname.match(/\/setup\/(\d)/);
if (!parsedSetup) {
return sendRedirect(event, `/setup/1`, 302);
}
const [_, currentSetup] = parsedSetup;
const step = await Database.setup.get();
if (step.toString() === currentSetup) {
return;
}

7
src/server/utils/crypto.ts

@ -1,7 +0,0 @@
export function getRandomHex(size: number) {
const array = new Uint8Array(size);
crypto.getRandomValues(array);
return Array.from(array, (byte) => byte.toString(16).padStart(2, '0')).join(
''
);
}

10
src/server/utils/session.ts

@ -9,18 +9,18 @@ export type WGSession = Partial<{
const name = 'wg-easy';
export async function useWGSession(event: H3Event, rememberMe = false) {
const sessionConfig = await Database.sessionConfig.get();
const sessionConfig = await Database.general.getSessionConfig();
return useSession<WGSession>(event, {
password: sessionConfig.password,
password: sessionConfig.sessionPassword,
name,
cookie: { maxAge: rememberMe ? sessionConfig.timeout : undefined },
cookie: { maxAge: rememberMe ? sessionConfig.sessionTimeout : undefined },
});
}
export async function getWGSession(event: H3Event) {
const sessionConfig = await Database.sessionConfig.get();
const sessionConfig = await Database.general.getSessionConfig();
return getSession<WGSession>(event, {
password: sessionConfig.password,
password: sessionConfig.sessionPassword,
name,
cookie: {},
});

Loading…
Cancel
Save