diff --git a/config/config.example.yml b/config/config.example.yml index 9311514e..c2a09451 100644 --- a/config/config.example.yml +++ b/config/config.example.yml @@ -22,6 +22,7 @@ gerbil: start_port: 51820 base_endpoint: localhost block_size: 16 + site_block_size: 29 subnet_group: 10.0.0.0/8 use_subdomain: true diff --git a/install/fs/config.yml b/install/fs/config.yml index 7145ccb4..9d4210a2 100644 --- a/install/fs/config.yml +++ b/install/fs/config.yml @@ -24,6 +24,7 @@ gerbil: base_endpoint: {{.Domain}} use_subdomain: false block_size: 16 + site_block_size: 29 subnet_group: 10.0.0.0/8 rate_limits: diff --git a/package.json b/package.json index ed104bb0..744b65c9 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,6 @@ { "name": "@fosrl/pangolin", -<<<<<<< HEAD - "version": "1.0.0-beta.2", -======= "version": "1.0.0-beta.3", ->>>>>>> c3d19454f7f5c5546a7efb47c23fc040dbbf94d2 "private": true, "type": "module", "description": "Tunneled Reverse Proxy Management Server with Identity and Access Control and Dashboard UI", diff --git a/server/lib/config.ts b/server/lib/config.ts index 468f0e2c..3da4ea36 100644 --- a/server/lib/config.ts +++ b/server/lib/config.ts @@ -3,15 +3,7 @@ import yaml from "js-yaml"; import path from "path"; import { z } from "zod"; import { fromError } from "zod-validation-error"; -<<<<<<< HEAD import { __DIRNAME, APP_PATH, configFilePath1, configFilePath2 } from "@server/lib/consts"; -======= -import { - __DIRNAME, - configFilePath1, - configFilePath2 -} from "@server/lib/consts"; ->>>>>>> c3d19454f7f5c5546a7efb47c23fc040dbbf94d2 import { loadAppVersion } from "@server/lib/loadAppVersion"; import { passwordSchema } from "@server/auth/passwordSchema"; @@ -19,15 +11,9 @@ const portSchema = z.number().positive().gt(0).lte(65535); const hostnameSchema = z .string() .regex( -<<<<<<< HEAD /^(?!-)[a-zA-Z0-9-]{1,63}(?>>>>>> c3d19454f7f5c5546a7efb47c23fc040dbbf94d2 const environmentSchema = z.object({ app: z.object({ @@ -59,7 +45,8 @@ const environmentSchema = z.object({ base_endpoint: z.string().transform((url) => url.toLowerCase()), use_subdomain: z.boolean(), subnet_group: z.string(), - block_size: z.number().positive().gt(0) + block_size: z.number().positive().gt(0), + site_block_size: z.number().positive().gt(0) }), rate_limits: z.object({ global: z.object({ diff --git a/server/routers/site/pickSiteDefaults.ts b/server/routers/site/pickSiteDefaults.ts index 5a111faa..56d072e0 100644 --- a/server/routers/site/pickSiteDefaults.ts +++ b/server/routers/site/pickSiteDefaults.ts @@ -8,6 +8,7 @@ import createHttpError from "http-errors"; import logger from "@server/logger"; import { findNextAvailableCidr } from "@server/lib/ip"; import { generateId } from "@server/auth/sessions/app"; +import config from "@server/lib/config"; export type PickSiteDefaultsResponse = { exitNodeId: number; @@ -51,9 +52,9 @@ export async function pickSiteDefaults( // TODO: we need to lock this subnet for some time so someone else does not take it let subnets = sitesQuery.map((site) => site.subnet); - // exclude the exit node address by replacing after the / with a /28 - subnets.push(exitNode.address.replace(/\/\d+$/, "/29")); - const newSubnet = findNextAvailableCidr(subnets, 29, exitNode.address); + // exclude the exit node address by replacing after the / with a site block size + subnets.push(exitNode.address.replace(/\/\d+$/, `/${config.getRawConfig().gerbil.site_block_size}`)); + const newSubnet = findNextAvailableCidr(subnets, config.getRawConfig().gerbil.site_block_size, exitNode.address); if (!newSubnet) { return next( createHttpError( diff --git a/server/setup/migrations.ts b/server/setup/migrations.ts index 7b1ad8ce..c0fe6216 100644 --- a/server/setup/migrations.ts +++ b/server/setup/migrations.ts @@ -8,6 +8,7 @@ import { __DIRNAME } from "@server/lib/consts"; import { loadAppVersion } from "@server/lib/loadAppVersion"; import m1 from "./scripts/1.0.0-beta1"; import m2 from "./scripts/1.0.0-beta2"; +import m3 from "./scripts/1.0.0-beta3"; // THIS CANNOT IMPORT ANYTHING FROM THE SERVER // EXCEPT FOR THE DATABASE AND THE SCHEMA @@ -15,7 +16,8 @@ import m2 from "./scripts/1.0.0-beta2"; // Define the migration list with versions and their corresponding functions const migrations = [ { version: "1.0.0-beta.1", run: m1 }, - { version: "1.0.0-beta.2", run: m2 } + { version: "1.0.0-beta.2", run: m2 }, + { version: "1.0.0-beta.3", run: m3 } // Add new migrations here as they are created ] as const; diff --git a/server/setup/scripts/1.0.0-beta3.ts b/server/setup/scripts/1.0.0-beta3.ts new file mode 100644 index 00000000..3bbaae81 --- /dev/null +++ b/server/setup/scripts/1.0.0-beta3.ts @@ -0,0 +1,42 @@ +import { configFilePath1, configFilePath2 } from "@server/lib/consts"; +import fs from "fs"; +import yaml from "js-yaml"; + +export default async function migration() { + console.log("Running setup script 1.0.0-beta.3..."); + + // Determine which config file exists + const filePaths = [configFilePath1, configFilePath2]; + let filePath = ""; + for (const path of filePaths) { + if (fs.existsSync(path)) { + filePath = path; + break; + } + } + + if (!filePath) { + throw new Error( + `No config file found (expected config.yml or config.yaml).` + ); + } + + // Read and parse the YAML file + let rawConfig: any; + const fileContents = fs.readFileSync(filePath, "utf8"); + rawConfig = yaml.load(fileContents); + + // Validate the structure + if (!rawConfig.gerbil) { + throw new Error(`Invalid config file: gerbil is missing.`); + } + + // Update the config + rawConfig.gerbil.site_block_size = 29; + + // Write the updated YAML back to the file + const updatedYaml = yaml.dump(rawConfig); + fs.writeFileSync(filePath, updatedYaml, "utf8"); + + console.log("Done."); +} \ No newline at end of file