- {{ $t('setup.messageSetupCreateAdminUser') }}
+ {{ 'Do you have a existing Setup?' }}
-
-
-
-
+
+ No
+ Yes
-
-
-
-
-
-
-
-
-
Create Account
diff --git a/src/app/stores/setup.ts b/src/app/stores/setup.ts
index 24307e8b..6ecde89f 100644
--- a/src/app/stores/setup.ts
+++ b/src/app/stores/setup.ts
@@ -4,8 +4,8 @@ export const useSetupStore = defineStore('Setup', () => {
/**
* @throws if unsuccessful
*/
- async function step4(username: string, password: string, accept: boolean) {
- const response = await $fetch('/api/setup/4', {
+ async function step3(username: string, password: string, accept: boolean) {
+ const response = await $fetch('/api/setup/3', {
method: 'post',
body: { username, password, accept },
});
@@ -41,7 +41,7 @@ export const useSetupStore = defineStore('Setup', () => {
}
return {
- step4,
+ step3,
step5,
runMigration,
step,
diff --git a/src/i18n/locales/en.json b/src/i18n/locales/en.json
index 10a12b0a..2ba7387c 100644
--- a/src/i18n/locales/en.json
+++ b/src/i18n/locales/en.json
@@ -145,6 +145,7 @@
"persistentKeepalive": "Persistent Keepalive",
"address": "IP Address",
"dns": "DNS",
- "allowedIps": "Allowed IPs"
+ "allowedIps": "Allowed IPs",
+ "file": "File"
}
}
diff --git a/src/server/api/setup/4.post.ts b/src/server/api/setup/3.post.ts
similarity index 89%
rename from src/server/api/setup/4.post.ts
rename to src/server/api/setup/3.post.ts
index 0869b07f..393a4deb 100644
--- a/src/server/api/setup/4.post.ts
+++ b/src/server/api/setup/3.post.ts
@@ -9,6 +9,6 @@ export default defineSetupEventHandler(async ({ event }) => {
// TODO: validate setup step
await Database.users.create(username, password);
- await Database.general.setSetupStep(5);
+ await Database.general.setSetupStep(4);
return { success: true };
});
diff --git a/src/server/api/setup/migrate.post.ts b/src/server/api/setup/migrate.post.ts
index d5256f9c..0e7b8642 100644
--- a/src/server/api/setup/migrate.post.ts
+++ b/src/server/api/setup/migrate.post.ts
@@ -1,21 +1,25 @@
-/*import { parseCidr } from 'cidr-tools';
+import { parseCidr } from 'cidr-tools';
import { stringifyIp } from 'ip-bigint';
-import { z } from 'zod';*/
+import { z } from 'zod';
-export default defineSetupEventHandler(async (/*{ event }*/) => {
- // TODO: Implement
- /*
+export default defineSetupEventHandler(async ({ event }) => {
+ const { file } = await readValidatedBody(
+ event,
+ validateZod(FileSchema, event)
+ );
- const { file } = await readValidatedBody(event, validateZod(fileType, event));
const schema = z.object({
server: z.object({
privateKey: z.string(),
publicKey: z.string(),
+ // only used for cidr
address: z.string(),
}),
clients: z.record(
z.string(),
z.object({
+ // not used
+ id: z.string(),
name: z.string(),
address: z.string(),
privateKey: z.string(),
@@ -31,49 +35,37 @@ export default defineSetupEventHandler(async (/*{ event }*/) => {
if (!res.success) {
throw new Error('Invalid Config');
}
- const system = await Database.system.get();
+
const oldConfig = res.data;
- const oldCidr = parseCidr(oldConfig.server.address + '/24');
- const db = {
- system: {
- ...system,
- // TODO: migrate to db calls
- interface: {
- ...system.interface,
- address4: oldConfig.server.address,
- privateKey: oldConfig.server.privateKey,
- publicKey: oldConfig.server.publicKey,
- },
- userConfig: {
- ...system.userConfig,
- defaultDns: [...system.userConfig.defaultDns],
- allowedIps: [...system.userConfig.allowedIps],
- address4Range:
- stringifyIp({ number: oldCidr.start, version: 4 }) + '/24',
- },
- } satisfies Partial
,
- clients: {} as Database['clients'],
- };
- for (const oldClient of Object.values(oldConfig.clients)) {
- const address6 = nextIPv6(db.system, db.clients);
+ await Database.interfaces.updateKeyPair(
+ oldConfig.server.privateKey,
+ oldConfig.server.publicKey
+ );
+
+ const ipv4Cidr = parseCidr(oldConfig.server.address + '/24');
+ const ipv6Cidr = parseCidr('fdcc:ad94:bacf:61a4::cafe:0/112');
+
+ await Database.interfaces.updateCidr({
+ ipv4Cidr:
+ stringifyIp({ number: ipv4Cidr.start, version: 4 }) +
+ `/${ipv4Cidr.prefix}`,
+ ipv6Cidr: ipv6Cidr.cidr,
+ });
- await Database.client.create({
- address4: oldClient.address,
- enabled: oldClient.enabled,
- name: oldClient.name,
- preSharedKey: oldClient.preSharedKey,
- privateKey: oldClient.privateKey,
- publicKey: oldClient.publicKey,
- expiresAt: null,
- oneTimeLink: null,
- allowedIps: [...db.system.userConfig.allowedIps],
- serverAllowedIPs: [],
- persistentKeepalive: 0,
- address6: address6,
- mtu: 1420,
+ for (const clientId in oldConfig.clients) {
+ const clientConfig = oldConfig.clients[clientId];
+ const clients = await Database.clients.getAll();
+
+ const ipv6Address = nextIP(6, ipv6Cidr, clients);
+
+ await Database.clients.createFromExisting({
+ ...clientConfig,
+ ipv4Address: clientConfig.address,
+ ipv6Address,
});
- }*/
+ }
+ await Database.general.setSetupStep(0);
return { success: true };
});
diff --git a/src/server/database/repositories/client/service.ts b/src/server/database/repositories/client/service.ts
index 10a75d2a..e00a3e72 100644
--- a/src/server/database/repositories/client/service.ts
+++ b/src/server/database/repositories/client/service.ts
@@ -1,7 +1,11 @@
import type { DBType } from '#db/sqlite';
import { eq, sql } from 'drizzle-orm';
import { client } from './schema';
-import type { ClientCreateType, UpdateClientType } from './types';
+import type {
+ ClientCreateFromExistingType,
+ ClientCreateType,
+ UpdateClientType,
+} from './types';
import type { ID } from '#db/schema';
import { wgInterface, userConfig } from '#db/schema';
import { parseCidr } from 'cidr-tools';
@@ -142,4 +146,35 @@ export class ClientService {
update(id: ID, data: UpdateClientType) {
return this.#db.update(client).set(data).where(eq(client.id, id)).execute();
}
+
+ async createFromExisting({
+ name,
+ enabled,
+ ipv4Address,
+ ipv6Address,
+ preSharedKey,
+ privateKey,
+ publicKey,
+ }: ClientCreateFromExistingType) {
+ const clientConfig = await Database.userConfigs.get();
+
+ return this.#db
+ .insert(client)
+ .values({
+ name,
+ userId: 1,
+ privateKey,
+ publicKey,
+ preSharedKey,
+ ipv4Address,
+ ipv6Address,
+ mtu: clientConfig.defaultMtu,
+ allowedIps: clientConfig.defaultAllowedIps,
+ dns: clientConfig.defaultDns,
+ persistentKeepalive: clientConfig.defaultPersistentKeepalive,
+ serverAllowedIps: [],
+ enabled,
+ })
+ .execute();
+ }
}
diff --git a/src/server/database/repositories/client/types.ts b/src/server/database/repositories/client/types.ts
index 849d6747..09bbce13 100644
--- a/src/server/database/repositories/client/types.ts
+++ b/src/server/database/repositories/client/types.ts
@@ -5,6 +5,8 @@ import type { client } from './schema';
export type ClientType = InferSelectModel;
+export type ClientNextIpType = Pick;
+
export type CreateClientType = Omit<
ClientType,
'createdAt' | 'updatedAt' | 'id'
@@ -68,3 +70,14 @@ const clientId = z.number({ message: t('zod.client.id'), coerce: true });
export const ClientGetSchema = z.object({
clientId: clientId,
});
+
+export type ClientCreateFromExistingType = Pick<
+ ClientType,
+ | 'name'
+ | 'ipv4Address'
+ | 'ipv6Address'
+ | 'privateKey'
+ | 'preSharedKey'
+ | 'publicKey'
+ | 'enabled'
+>;
diff --git a/src/server/database/repositories/oneTimeLink/types.ts b/src/server/database/repositories/oneTimeLink/types.ts
index 423a61d5..c1020d46 100644
--- a/src/server/database/repositories/oneTimeLink/types.ts
+++ b/src/server/database/repositories/oneTimeLink/types.ts
@@ -5,8 +5,8 @@ import { z } from 'zod';
export type OneTimeLinkType = InferSelectModel;
const oneTimeLinkType = z
- .string({ message: t('zod.otl.otl') })
- .min(1, t('zod.otl.otl'))
+ .string({ message: t('zod.otl') })
+ .min(1, t('zod.otl'))
.pipe(safeStringRefine);
export const OneTimeLinkGetSchema = z.object(
diff --git a/src/server/utils/ip.ts b/src/server/utils/ip.ts
index 0a5bb3dc..c5661337 100644
--- a/src/server/utils/ip.ts
+++ b/src/server/utils/ip.ts
@@ -1,14 +1,14 @@
import type { parseCidr } from 'cidr-tools';
import { stringifyIp } from 'ip-bigint';
-import type { ClientType } from '#db/repositories/client/types';
+import type { ClientNextIpType } from '#db/repositories/client/types';
type ParsedCidr = ReturnType;
export function nextIP(
version: 4 | 6,
cidr: ParsedCidr,
- clients: ClientType[]
+ clients: ClientNextIpType[]
) {
let address;
for (let i = cidr.start + 2n; i <= cidr.end - 1n; i++) {
diff --git a/src/server/utils/types.ts b/src/server/utils/types.ts
index a8dd0a7c..6fae6536 100644
--- a/src/server/utils/types.ts
+++ b/src/server/utils/types.ts
@@ -9,6 +9,7 @@ import type { H3Event, EventHandlerRequest } from 'h3';
*/
export const t = (v: string) => v;
+// TODO: use everywhere or remove
export const objectMessage = t('zod.body');
export const safeStringRefine = z
@@ -50,6 +51,13 @@ export const AllowedIpsSchema = z
.array(AddressSchema, { message: t('zod.allowedIps') })
.min(1, { message: t('zod.allowedIps') });
+export const FileSchema = z.object(
+ {
+ file: z.string({ message: t('zod.file') }),
+ },
+ { message: objectMessage }
+);
+
export const schemaForType =
() =>
// eslint-disable-next-line @typescript-eslint/no-explicit-any