diff --git a/server/setup/migrationsPg.ts b/server/setup/migrationsPg.ts index 01ff36beb..0be22d492 100644 --- a/server/setup/migrationsPg.ts +++ b/server/setup/migrationsPg.ts @@ -25,6 +25,7 @@ import m16 from "./scriptsPg/1.17.0"; import m17 from "./scriptsPg/1.18.0"; import m18 from "./scriptsPg/1.18.3"; import m19 from "./scriptsPg/1.18.4"; +import m20 from "./scriptsPg/1.19.0"; // THIS CANNOT IMPORT ANYTHING FROM THE SERVER // EXCEPT FOR THE DATABASE AND THE SCHEMA @@ -49,7 +50,8 @@ const migrations = [ { version: "1.17.0", run: m16 }, { version: "1.18.0", run: m17 }, { version: "1.18.3", run: m18 }, - { version: "1.18.4", run: m19 } + { version: "1.18.4", run: m19 }, + { version: "1.19.0", run: m20 } // Add new migrations here as they are created ] as { version: string; diff --git a/server/setup/migrationsSqlite.ts b/server/setup/migrationsSqlite.ts index 83b5b9bc6..03dae4c81 100644 --- a/server/setup/migrationsSqlite.ts +++ b/server/setup/migrationsSqlite.ts @@ -43,6 +43,7 @@ import m37 from "./scriptsSqlite/1.17.0"; import m38 from "./scriptsSqlite/1.18.0"; import m39 from "./scriptsSqlite/1.18.3"; import m40 from "./scriptsSqlite/1.18.4"; +import m41 from "./scriptsSqlite/1.19.0"; // THIS CANNOT IMPORT ANYTHING FROM THE SERVER // EXCEPT FOR THE DATABASE AND THE SCHEMA @@ -83,7 +84,8 @@ const migrations = [ { version: "1.17.0", run: m37 }, { version: "1.18.0", run: m38 }, { version: "1.18.3", run: m39 }, - { version: "1.18.4", run: m40 } + { version: "1.18.4", run: m40 }, + { version: "1.19.0", run: m41 } // Add new migrations here as they are created ] as const; diff --git a/server/setup/scriptsPg/1.19.0.ts b/server/setup/scriptsPg/1.19.0.ts new file mode 100644 index 000000000..3691d43a0 --- /dev/null +++ b/server/setup/scriptsPg/1.19.0.ts @@ -0,0 +1,313 @@ +import { db } from "@server/db/pg/driver"; +import { APP_PATH } from "@server/lib/consts"; +import { sql } from "drizzle-orm"; +import fs from "fs"; +import yaml from "js-yaml"; +import path from "path"; +import z from "zod"; +import { fromZodError } from "zod-validation-error"; + +const version = "1.19.0"; + +export default async function migration() { + console.log(`Running setup script ${version}...`); + + try { + await db.execute(sql`BEGIN`); + + await db.execute(sql` + CREATE TABLE "browserGatewayTarget" ( + "browserGatewayTargetId" serial PRIMARY KEY NOT NULL, + "resourceId" integer NOT NULL, + "siteId" integer NOT NULL, + "authToken" varchar NOT NULL, + "type" varchar NOT NULL, + "destination" varchar NOT NULL, + "destinationPort" integer NOT NULL + ); + `); + + await db.execute(sql` + CREATE TABLE "clientLabels" ( + "clientLabelId" serial PRIMARY KEY NOT NULL, + "clientId" integer NOT NULL, + "labelId" integer NOT NULL, + CONSTRAINT "client_label_uniq" UNIQUE("clientId","labelId") + ); + `); + + await db.execute(sql` + CREATE TABLE "labels" ( + "labelId" serial PRIMARY KEY NOT NULL, + "name" varchar NOT NULL, + "color" varchar NOT NULL, + "orgId" varchar NOT NULL + ); + `); + + await db.execute(sql` + CREATE TABLE "resourceLabels" ( + "resourceLabelId" serial PRIMARY KEY NOT NULL, + "resourceId" integer NOT NULL, + "labelId" integer NOT NULL, + CONSTRAINT "resource_label_uniq" UNIQUE("resourceId","labelId") + ); + `); + + await db.execute(sql` + CREATE TABLE "resourcePolicies" ( + "resourcePolicyId" serial PRIMARY KEY NOT NULL, + "sso" boolean DEFAULT true NOT NULL, + "applyRules" boolean DEFAULT false NOT NULL, + "scope" varchar DEFAULT 'global' NOT NULL, + "emailWhitelistEnabled" boolean DEFAULT false NOT NULL, + "idpId" integer, + "niceId" text NOT NULL, + "name" varchar NOT NULL, + "orgId" varchar NOT NULL + ); + `); + + await db.execute(sql` + CREATE TABLE "resourcePolicyHeaderAuth" ( + "headerAuthId" serial PRIMARY KEY NOT NULL, + "headerAuthHash" varchar NOT NULL, + "extendedCompatibility" boolean DEFAULT true NOT NULL, + "resourcePolicyId" integer NOT NULL + ); + `); + + await db.execute(sql` + CREATE TABLE "resourcePolicyPassword" ( + "passwordId" serial PRIMARY KEY NOT NULL, + "passwordHash" varchar NOT NULL, + "resourcePolicyId" integer NOT NULL + ); + `); + + await db.execute(sql` + CREATE TABLE "resourcePolicyPincode" ( + "pincodeId" serial PRIMARY KEY NOT NULL, + "pincodeHash" varchar NOT NULL, + "digitLength" integer NOT NULL, + "resourcePolicyId" integer NOT NULL + ); + `); + + await db.execute(sql` + CREATE TABLE "resourcePolicyRules" ( + "ruleId" serial PRIMARY KEY NOT NULL, + "resourcePolicyId" integer NOT NULL, + "enabled" boolean DEFAULT true NOT NULL, + "priority" integer NOT NULL, + "action" varchar NOT NULL, + "match" varchar NOT NULL, + "value" varchar NOT NULL + ); + `); + + await db.execute(sql` + CREATE TABLE "resourcePolicyWhitelist" ( + "id" serial PRIMARY KEY NOT NULL, + "email" varchar NOT NULL, + "resourcePolicyId" integer NOT NULL + ); + `); + + await db.execute(sql` + CREATE TABLE "rolePolicies" ( + "roleId" integer NOT NULL, + "resourcePolicyId" integer NOT NULL + ); + `); + + await db.execute(sql` + CREATE TABLE "siteLabels" ( + "siteLabelId" serial PRIMARY KEY NOT NULL, + "siteId" integer NOT NULL, + "labelId" integer NOT NULL, + CONSTRAINT "site_label_uniq" UNIQUE("siteId","labelId") + ); + `); + + await db.execute(sql` + CREATE TABLE "siteResourceLabels" ( + "siteResourceLabelId" serial PRIMARY KEY NOT NULL, + "siteResourceId" integer NOT NULL, + "labelId" integer NOT NULL, + CONSTRAINT "site_resource_label_uniq" UNIQUE("siteResourceId","labelId") + ); + `); + + await db.execute(sql` + CREATE TABLE "userPolicies" ( + "userId" varchar NOT NULL, + "resourcePolicyId" integer NOT NULL + ); + `); + + await db.execute( + sql`ALTER TABLE "siteResources" ALTER COLUMN "destination" DROP NOT NULL;` + ); + await db.execute( + sql`ALTER TABLE "orgs" ADD COLUMN "settingsEnableGlobalNewtAutoUpdate" boolean DEFAULT false NOT NULL;` + ); + await db.execute( + sql`ALTER TABLE "resourceAccessToken" ADD COLUMN "path" varchar;` + ); + await db.execute( + sql`ALTER TABLE "resources" ADD COLUMN "resourcePolicyId" integer;` + ); + await db.execute( + sql`ALTER TABLE "resources" ADD COLUMN "defaultResourcePolicyId" integer;` + ); + await db.execute( + sql`ALTER TABLE "resources" ADD COLUMN "mode" text DEFAULT 'http' NOT NULL;` + ); + await db.execute( + sql`ALTER TABLE "resources" ADD COLUMN "pamMode" varchar(32) DEFAULT 'passthrough';` + ); + await db.execute( + sql`ALTER TABLE "resources" ADD COLUMN "authDaemonMode" varchar(32) DEFAULT 'site';` + ); + await db.execute( + sql`ALTER TABLE "resources" ADD COLUMN "authDaemonPort" integer DEFAULT 22123;` + ); + await db.execute( + sql`ALTER TABLE "siteResources" ADD COLUMN "pamMode" varchar(32) DEFAULT 'passthrough';` + ); + await db.execute( + sql`ALTER TABLE "sites" ADD COLUMN "autoUpdateEnabled" boolean DEFAULT false NOT NULL;` + ); + await db.execute( + sql`ALTER TABLE "sites" ADD COLUMN "autoUpdateOverrideOrg" boolean DEFAULT false NOT NULL;` + ); + await db.execute( + sql`ALTER TABLE "browserGatewayTarget" ADD CONSTRAINT "browserGatewayTarget_resourceId_resources_resourceId_fk" FOREIGN KEY ("resourceId") REFERENCES "public"."resources"("resourceId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "browserGatewayTarget" ADD CONSTRAINT "browserGatewayTarget_siteId_sites_siteId_fk" FOREIGN KEY ("siteId") REFERENCES "public"."sites"("siteId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "clientLabels" ADD CONSTRAINT "clientLabels_clientId_clients_clientId_fk" FOREIGN KEY ("clientId") REFERENCES "public"."clients"("clientId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "clientLabels" ADD CONSTRAINT "clientLabels_labelId_labels_labelId_fk" FOREIGN KEY ("labelId") REFERENCES "public"."labels"("labelId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "labels" ADD CONSTRAINT "labels_orgId_orgs_orgId_fk" FOREIGN KEY ("orgId") REFERENCES "public"."orgs"("orgId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "resourceLabels" ADD CONSTRAINT "resourceLabels_resourceId_resources_resourceId_fk" FOREIGN KEY ("resourceId") REFERENCES "public"."resources"("resourceId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "resourceLabels" ADD CONSTRAINT "resourceLabels_labelId_labels_labelId_fk" FOREIGN KEY ("labelId") REFERENCES "public"."labels"("labelId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "resourcePolicies" ADD CONSTRAINT "resourcePolicies_idpId_idp_idpId_fk" FOREIGN KEY ("idpId") REFERENCES "public"."idp"("idpId") ON DELETE set null ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "resourcePolicies" ADD CONSTRAINT "resourcePolicies_orgId_orgs_orgId_fk" FOREIGN KEY ("orgId") REFERENCES "public"."orgs"("orgId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "resourcePolicyHeaderAuth" ADD CONSTRAINT "resourcePolicyHeaderAuth_resourcePolicyId_resourcePolicies_resourcePolicyId_fk" FOREIGN KEY ("resourcePolicyId") REFERENCES "public"."resourcePolicies"("resourcePolicyId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "resourcePolicyPassword" ADD CONSTRAINT "resourcePolicyPassword_resourcePolicyId_resourcePolicies_resourcePolicyId_fk" FOREIGN KEY ("resourcePolicyId") REFERENCES "public"."resourcePolicies"("resourcePolicyId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "resourcePolicyPincode" ADD CONSTRAINT "resourcePolicyPincode_resourcePolicyId_resourcePolicies_resourcePolicyId_fk" FOREIGN KEY ("resourcePolicyId") REFERENCES "public"."resourcePolicies"("resourcePolicyId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "resourcePolicyRules" ADD CONSTRAINT "resourcePolicyRules_resourcePolicyId_resourcePolicies_resourcePolicyId_fk" FOREIGN KEY ("resourcePolicyId") REFERENCES "public"."resourcePolicies"("resourcePolicyId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "resourcePolicyWhitelist" ADD CONSTRAINT "resourcePolicyWhitelist_resourcePolicyId_resourcePolicies_resourcePolicyId_fk" FOREIGN KEY ("resourcePolicyId") REFERENCES "public"."resourcePolicies"("resourcePolicyId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "rolePolicies" ADD CONSTRAINT "rolePolicies_roleId_roles_roleId_fk" FOREIGN KEY ("roleId") REFERENCES "public"."roles"("roleId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "rolePolicies" ADD CONSTRAINT "rolePolicies_resourcePolicyId_resourcePolicies_resourcePolicyId_fk" FOREIGN KEY ("resourcePolicyId") REFERENCES "public"."resourcePolicies"("resourcePolicyId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "siteLabels" ADD CONSTRAINT "siteLabels_siteId_sites_siteId_fk" FOREIGN KEY ("siteId") REFERENCES "public"."sites"("siteId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "siteLabels" ADD CONSTRAINT "siteLabels_labelId_labels_labelId_fk" FOREIGN KEY ("labelId") REFERENCES "public"."labels"("labelId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "siteResourceLabels" ADD CONSTRAINT "siteResourceLabels_siteResourceId_siteResources_siteResourceId_fk" FOREIGN KEY ("siteResourceId") REFERENCES "public"."siteResources"("siteResourceId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "siteResourceLabels" ADD CONSTRAINT "siteResourceLabels_labelId_labels_labelId_fk" FOREIGN KEY ("labelId") REFERENCES "public"."labels"("labelId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "userPolicies" ADD CONSTRAINT "userPolicies_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "userPolicies" ADD CONSTRAINT "userPolicies_resourcePolicyId_resourcePolicies_resourcePolicyId_fk" FOREIGN KEY ("resourcePolicyId") REFERENCES "public"."resourcePolicies"("resourcePolicyId") ON DELETE cascade ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "resources" ADD CONSTRAINT "resources_resourcePolicyId_resourcePolicies_resourcePolicyId_fk" FOREIGN KEY ("resourcePolicyId") REFERENCES "public"."resourcePolicies"("resourcePolicyId") ON DELETE set null ON UPDATE no action;` + ); + await db.execute( + sql`ALTER TABLE "resources" ADD CONSTRAINT "resources_defaultResourcePolicyId_resourcePolicies_resourcePolicyId_fk" FOREIGN KEY ("defaultResourcePolicyId") REFERENCES "public"."resourcePolicies"("resourcePolicyId") ON DELETE restrict ON UPDATE no action;` + ); + await db.execute(sql`ALTER TABLE "resources" DROP COLUMN "http";`); + await db.execute(sql`ALTER TABLE "resources" DROP COLUMN "protocol";`); + + await db.execute(sql`COMMIT`); + console.log("Migrated database"); + } catch (e) { + await db.execute(sql`ROLLBACK`); + console.log("Unable to migrate database"); + console.log(e); + throw e; + } + + try { + const traefikPath = path.join( + APP_PATH, + "traefik", + "traefik_config.yml" + ); + + const schema = z.object({ + experimental: z.object({ + plugins: z.object({ + badger: z.object({ + moduleName: z.string(), + version: z.string() + }) + }) + }) + }); + + const traefikFileContents = fs.readFileSync(traefikPath, "utf8"); + const traefikConfig = yaml.load(traefikFileContents) as any; + + const parsedConfig = schema.safeParse(traefikConfig); + + if (!parsedConfig.success) { + throw new Error(fromZodError(parsedConfig.error).toString()); + } + + traefikConfig.experimental.plugins.badger.version = "v1.4.1"; + + const updatedTraefikYaml = yaml.dump(traefikConfig); + + fs.writeFileSync(traefikPath, updatedTraefikYaml, "utf8"); + + console.log( + "Updated the version of Badger in your Traefik configuration to v1.4.1" + ); + } catch (e) { + console.log( + "We were unable to update the version of Badger in your Traefik configuration. Please update it manually. Check the release notes for this version for more information." + ); + console.error(e); + } + + console.log(`${version} migration complete`); +} diff --git a/server/setup/scriptsSqlite/1.19.0.ts b/server/setup/scriptsSqlite/1.19.0.ts new file mode 100644 index 000000000..bafcd8222 --- /dev/null +++ b/server/setup/scriptsSqlite/1.19.0.ts @@ -0,0 +1,355 @@ +import { APP_PATH } from "@server/lib/consts"; +import Database from "better-sqlite3"; +import z from "zod"; +import { fromZodError } from "zod-validation-error"; +import fs from "fs"; +import yaml from "js-yaml"; +import path from "path"; + +const version = "1.19.0"; + +export default async function migration() { + console.log(`Running setup script ${version}...`); + + const location = path.join(APP_PATH, "db", "db.sqlite"); + const db = new Database(location); + + try { + db.transaction(() => { + db.prepare( + ` + CREATE TABLE 'browserGatewayTarget' ( + 'browserGatewayTargetId' integer PRIMARY KEY AUTOINCREMENT NOT NULL, + 'resourceId' integer NOT NULL, + 'siteId' integer NOT NULL, + 'authToken' text NOT NULL, + 'type' text NOT NULL, + 'destination' text NOT NULL, + 'destinationPort' integer NOT NULL, + FOREIGN KEY ('resourceId') REFERENCES 'resources'('resourceId') ON UPDATE no action ON DELETE cascade, + FOREIGN KEY ('siteId') REFERENCES 'sites'('siteId') ON UPDATE no action ON DELETE cascade + ); + ` + ).run(); + + db.prepare( + ` + CREATE TABLE 'clientLabels' ( + 'clientLabelId' integer PRIMARY KEY AUTOINCREMENT NOT NULL, + 'clientId' integer NOT NULL, + 'labelId' integer NOT NULL, + FOREIGN KEY ('clientId') REFERENCES 'clients'('clientId') ON UPDATE no action ON DELETE cascade, + FOREIGN KEY ('labelId') REFERENCES 'labels'('labelId') ON UPDATE no action ON DELETE cascade + ); + ` + ).run(); + + db.prepare( + ` + CREATE UNIQUE INDEX 'client_label_uniq' ON 'clientLabels' ('clientId','labelId'); + ` + ).run(); + db.prepare( + ` + CREATE TABLE 'labels' ( + 'labelId' integer PRIMARY KEY AUTOINCREMENT NOT NULL, + 'name' text NOT NULL, + 'color' text NOT NULL, + 'orgId' text NOT NULL, + FOREIGN KEY ('orgId') REFERENCES 'orgs'('orgId') ON UPDATE no action ON DELETE cascade + ); + ` + ).run(); + + db.prepare( + ` + CREATE TABLE 'resourceLabels' ( + 'resourceLabelId' integer PRIMARY KEY AUTOINCREMENT NOT NULL, + 'resourceId' integer NOT NULL, + 'labelId' integer NOT NULL, + FOREIGN KEY ('resourceId') REFERENCES 'resources'('resourceId') ON UPDATE no action ON DELETE cascade, + FOREIGN KEY ('labelId') REFERENCES 'labels'('labelId') ON UPDATE no action ON DELETE cascade + ); + ` + ).run(); + + db.prepare( + ` + CREATE UNIQUE INDEX 'resource_label_uniq' ON 'resourceLabels' ('resourceId','labelId'); + ` + ).run(); + db.prepare( + ` + CREATE TABLE 'resourcePolicies' ( + 'resourcePolicyId' integer PRIMARY KEY NOT NULL, + 'sso' integer DEFAULT true NOT NULL, + 'applyRules' integer DEFAULT false NOT NULL, + 'scope' text DEFAULT 'global' NOT NULL, + 'emailWhitelistEnabled' integer DEFAULT false NOT NULL, + 'niceId' text NOT NULL, + 'idpId' integer, + 'name' text NOT NULL, + 'orgId' text NOT NULL, + FOREIGN KEY ('idpId') REFERENCES 'idp'('idpId') ON UPDATE no action ON DELETE set null, + FOREIGN KEY ('orgId') REFERENCES 'orgs'('orgId') ON UPDATE no action ON DELETE cascade + ); + ` + ).run(); + + db.prepare( + ` + CREATE TABLE 'resourcePolicyHeaderAuth' ( + 'headerAuthId' integer PRIMARY KEY AUTOINCREMENT NOT NULL, + 'headerAuthHash' text NOT NULL, + 'extendedCompatibility' integer DEFAULT true NOT NULL, + 'resourcePolicyId' integer NOT NULL, + FOREIGN KEY ('resourcePolicyId') REFERENCES 'resourcePolicies'('resourcePolicyId') ON UPDATE no action ON DELETE cascade + ); + ` + ).run(); + + db.prepare( + ` + CREATE TABLE 'resourcePolicyPassword' ( + 'passwordId' integer PRIMARY KEY AUTOINCREMENT NOT NULL, + 'passwordHash' text NOT NULL, + 'resourcePolicyId' integer NOT NULL, + FOREIGN KEY ('resourcePolicyId') REFERENCES 'resourcePolicies'('resourcePolicyId') ON UPDATE no action ON DELETE cascade + ); + ` + ).run(); + + db.prepare( + ` + CREATE TABLE 'resourcePolicyPincode' ( + 'pincodeId' integer PRIMARY KEY AUTOINCREMENT NOT NULL, + 'pincodeHash' text NOT NULL, + 'digitLength' integer NOT NULL, + 'resourcePolicyId' integer NOT NULL, + FOREIGN KEY ('resourcePolicyId') REFERENCES 'resourcePolicies'('resourcePolicyId') ON UPDATE no action ON DELETE cascade + ); + ` + ).run(); + + db.prepare( + ` + CREATE TABLE 'resourcePolicyRules' ( + 'ruleId' integer PRIMARY KEY AUTOINCREMENT NOT NULL, + 'resourcePolicyId' integer NOT NULL, + 'enabled' integer DEFAULT true NOT NULL, + 'priority' integer NOT NULL, + 'action' text NOT NULL, + 'match' text NOT NULL, + 'value' text NOT NULL, + FOREIGN KEY ('resourcePolicyId') REFERENCES 'resourcePolicies'('resourcePolicyId') ON UPDATE no action ON DELETE cascade + ); + ` + ).run(); + + db.prepare( + ` + CREATE TABLE 'resourcePolicyWhitelist' ( + 'id' integer PRIMARY KEY AUTOINCREMENT NOT NULL, + 'email' text NOT NULL, + 'resourcePolicyId' integer NOT NULL, + FOREIGN KEY ('resourcePolicyId') REFERENCES 'resourcePolicies'('resourcePolicyId') ON UPDATE no action ON DELETE cascade + ); + ` + ).run(); + + db.prepare( + ` + CREATE TABLE 'rolePolicies' ( + 'roleId' integer NOT NULL, + 'resourcePolicyId' integer NOT NULL, + FOREIGN KEY ('roleId') REFERENCES 'roles'('roleId') ON UPDATE no action ON DELETE cascade, + FOREIGN KEY ('resourcePolicyId') REFERENCES 'resourcePolicies'('resourcePolicyId') ON UPDATE no action ON DELETE cascade + ); + ` + ).run(); + + db.prepare( + ` + CREATE TABLE 'siteLabels' ( + 'siteLabelId' integer PRIMARY KEY AUTOINCREMENT NOT NULL, + 'siteId' integer NOT NULL, + 'labelId' integer NOT NULL, + FOREIGN KEY ('siteId') REFERENCES 'sites'('siteId') ON UPDATE no action ON DELETE cascade, + FOREIGN KEY ('labelId') REFERENCES 'labels'('labelId') ON UPDATE no action ON DELETE cascade + ); + ` + ).run(); + + db.prepare( + ` + CREATE UNIQUE INDEX 'site_label_uniq' ON 'siteLabels' ('siteId','labelId'); + ` + ).run(); + db.prepare( + ` + CREATE TABLE 'siteResourceLabels' ( + 'siteResourceLabelId' integer PRIMARY KEY AUTOINCREMENT NOT NULL, + 'siteResourceId' integer NOT NULL, + 'labelId' integer NOT NULL, + FOREIGN KEY ('siteResourceId') REFERENCES 'siteResources'('siteResourceId') ON UPDATE no action ON DELETE cascade, + FOREIGN KEY ('labelId') REFERENCES 'labels'('labelId') ON UPDATE no action ON DELETE cascade + ); + ` + ).run(); + + db.prepare( + ` + CREATE UNIQUE INDEX 'site_resource_label_uniq' ON 'siteResourceLabels' ('siteResourceId','labelId'); + ` + ).run(); + db.prepare( + ` + CREATE TABLE 'userPolicies' ( + 'userId' text NOT NULL, + 'resourcePolicyId' integer NOT NULL, + FOREIGN KEY ('userId') REFERENCES 'user'('id') ON UPDATE no action ON DELETE cascade, + FOREIGN KEY ('resourcePolicyId') REFERENCES 'resourcePolicies'('resourcePolicyId') ON UPDATE no action ON DELETE cascade + ); + ` + ).run(); + + db.prepare( + ` + ALTER TABLE 'siteResources' ADD COLUMN 'destination2' text; + ` + ).run(); + db.prepare( + ` + UPDATE 'siteResources' SET 'destination2' = 'destination'; + ` + ).run(); + db.prepare( + ` + ALTER TABLE 'siteResources' DROP COLUMN 'destination'; + ` + ).run(); + db.prepare( + ` + ALTER TABLE 'siteResources' RENAME COLUMN 'destination2' TO 'destination'; + ` + ).run(); + db.prepare( + ` + + ALTER TABLE 'siteResources' ADD COLUMN 'pamMode' text DEFAULT 'passthrough'; + ` + ).run(); + db.prepare( + ` + + ALTER TABLE 'orgs' ADD 'settingsEnableGlobalNewtAutoUpdate' integer DEFAULT false NOT NULL; + ` + ).run(); + db.prepare( + ` + ALTER TABLE 'resourceAccessToken' ADD 'path' text; + ` + ).run(); + db.prepare( + ` + ALTER TABLE 'resources' ADD 'resourcePolicyId' integer REFERENCES resourcePolicies(resourcePolicyId); + ` + ).run(); + db.prepare( + ` + ALTER TABLE 'resources' ADD 'defaultResourcePolicyId' integer REFERENCES resourcePolicies(resourcePolicyId); + ` + ).run(); + db.prepare( + ` + ALTER TABLE 'resources' ADD 'mode' text DEFAULT 'http' NOT NULL; + ` + ).run(); + db.prepare( + ` + ALTER TABLE 'resources' ADD 'pamMode' text DEFAULT 'passthrough'; + ` + ).run(); + db.prepare( + ` + ALTER TABLE 'resources' ADD 'authDaemonMode' text DEFAULT 'site'; + ` + ).run(); + db.prepare( + ` + ALTER TABLE 'resources' ADD 'authDaemonPort' integer DEFAULT 22123; + ` + ).run(); + db.prepare( + ` + ALTER TABLE 'resources' DROP COLUMN 'http'; + ` + ).run(); + db.prepare( + ` + ALTER TABLE 'resources' DROP COLUMN 'protocol'; + ` + ).run(); + db.prepare( + ` + ALTER TABLE 'sites' ADD 'autoUpdateEnabled' integer DEFAULT false NOT NULL; + ` + ).run(); + db.prepare( + ` + ALTER TABLE 'sites' ADD 'autoUpdateOverrideOrg' integer DEFAULT false NOT NULL; + ` + ).run(); + })(); + + console.log("Migrated database"); + } catch (e) { + console.log("Failed to migrate db:", e); + throw e; + } + + try { + const traefikPath = path.join( + APP_PATH, + "traefik", + "traefik_config.yml" + ); + + const schema = z.object({ + experimental: z.object({ + plugins: z.object({ + badger: z.object({ + moduleName: z.string(), + version: z.string() + }) + }) + }) + }); + + const traefikFileContents = fs.readFileSync(traefikPath, "utf8"); + const traefikConfig = yaml.load(traefikFileContents) as any; + + const parsedConfig = schema.safeParse(traefikConfig); + + if (!parsedConfig.success) { + throw new Error(fromZodError(parsedConfig.error).toString()); + } + + traefikConfig.experimental.plugins.badger.version = "v1.4.1"; + + const updatedTraefikYaml = yaml.dump(traefikConfig); + + fs.writeFileSync(traefikPath, updatedTraefikYaml, "utf8"); + + console.log( + "Updated the version of Badger in your Traefik configuration to v1.4.1" + ); + } catch (e) { + console.log( + "We were unable to update the version of Badger in your Traefik configuration. Please update it manually. Check the release notes for this version for more information." + ); + console.error(e); + } + + console.log(`${version} migration complete`); +}