diff --git a/config/db/db.sqlite.bak b/config/db/db.sqlite.bak deleted file mode 100644 index 9d0b3db3..00000000 Binary files a/config/db/db.sqlite.bak and /dev/null differ diff --git a/server/setup/scriptsSqlite/1.9.0.ts b/server/setup/scriptsSqlite/1.9.0.ts index 83dbf9d0..490f9585 100644 --- a/server/setup/scriptsSqlite/1.9.0.ts +++ b/server/setup/scriptsSqlite/1.9.0.ts @@ -10,26 +10,175 @@ export default async function migration() { const location = path.join(APP_PATH, "db", "db.sqlite"); const db = new Database(location); + const resourceSiteMap = new Map(); + + try { + const resources = db + .prepare( + "SELECT resourceId, siteId FROM resources WHERE siteId IS NOT NULL" + ) + .all() as Array<{ resourceId: number; siteId: number }>; + for (const resource of resources) { + resourceSiteMap.set(resource.resourceId, resource.siteId); + } + } catch (e) { + console.log("Error getting resources:", e); + } + try { db.pragma("foreign_keys = OFF"); db.transaction(() => { - db.exec(` - CREATE TABLE 'setupTokens' ( - 'tokenId' text PRIMARY KEY NOT NULL, - 'token' text NOT NULL, - 'used' integer DEFAULT 0 NOT NULL, - 'dateCreated' text NOT NULL, - 'dateUsed' text + db.exec(`CREATE TABLE 'setupTokens' ( + 'tokenId' text PRIMARY KEY NOT NULL, + 'token' text NOT NULL, + 'used' integer DEFAULT false NOT NULL, + 'dateCreated' text NOT NULL, + 'dateUsed' text +); +--> statement-breakpoint +CREATE TABLE 'siteResources' ( + 'siteResourceId' integer PRIMARY KEY AUTOINCREMENT NOT NULL, + 'siteId' integer NOT NULL, + 'orgId' text NOT NULL, + 'name' text NOT NULL, + 'protocol' text NOT NULL, + 'proxyPort' integer NOT NULL, + 'destinationPort' integer NOT NULL, + 'destinationIp' text NOT NULL, + 'enabled' integer DEFAULT true NOT NULL, + FOREIGN KEY ('siteId') REFERENCES 'sites'('siteId') ON UPDATE no action ON DELETE cascade, + FOREIGN KEY ('orgId') REFERENCES 'orgs'('orgId') ON UPDATE no action ON DELETE cascade +); +--> statement-breakpoint +PRAGMA foreign_keys=OFF;--> statement-breakpoint +CREATE TABLE '__new_resources' ( + 'resourceId' integer PRIMARY KEY AUTOINCREMENT NOT NULL, + 'orgId' text NOT NULL, + 'name' text NOT NULL, + 'subdomain' text, + 'fullDomain' text, + 'domainId' text, + 'ssl' integer DEFAULT false NOT NULL, + 'blockAccess' integer DEFAULT false NOT NULL, + 'sso' integer DEFAULT true NOT NULL, + 'http' integer DEFAULT true NOT NULL, + 'protocol' text NOT NULL, + 'proxyPort' integer, + 'emailWhitelistEnabled' integer DEFAULT false NOT NULL, + 'applyRules' integer DEFAULT false NOT NULL, + 'enabled' integer DEFAULT true NOT NULL, + 'stickySession' integer DEFAULT false NOT NULL, + 'tlsServerName' text, + 'setHostHeader' text, + 'enableProxy' integer DEFAULT true, + 'skipToIdpId' integer, + FOREIGN KEY ('orgId') REFERENCES 'orgs'('orgId') ON UPDATE no action ON DELETE cascade, + FOREIGN KEY ('domainId') REFERENCES 'domains'('domainId') ON UPDATE no action ON DELETE set null, + FOREIGN KEY ('skipToIdpId') REFERENCES 'idp'('idpId') ON UPDATE no action ON DELETE cascade +); +--> statement-breakpoint +INSERT INTO '__new_resources'("resourceId", "orgId", "name", "subdomain", "fullDomain", "domainId", "ssl", "blockAccess", "sso", "http", "protocol", "proxyPort", "emailWhitelistEnabled", "applyRules", "enabled", "stickySession", "tlsServerName", "setHostHeader", "enableProxy", "skipToIdpId") SELECT "resourceId", "orgId", "name", "subdomain", "fullDomain", "domainId", "ssl", "blockAccess", "sso", "http", "protocol", "proxyPort", "emailWhitelistEnabled", "applyRules", "enabled", "stickySession", "tlsServerName", "setHostHeader", "enableProxy", null FROM 'resources';--> statement-breakpoint +DROP TABLE 'resources';--> statement-breakpoint +ALTER TABLE '__new_resources' RENAME TO 'resources';--> statement-breakpoint +PRAGMA foreign_keys=ON;--> statement-breakpoint +CREATE TABLE '__new_clients' ( + 'id' integer PRIMARY KEY AUTOINCREMENT NOT NULL, + 'orgId' text NOT NULL, + 'exitNode' integer, + 'name' text NOT NULL, + 'pubKey' text, + 'subnet' text NOT NULL, + 'bytesIn' integer, + 'bytesOut' integer, + 'lastBandwidthUpdate' text, + 'lastPing' integer, + 'type' text NOT NULL, + 'online' integer DEFAULT false NOT NULL, + 'lastHolePunch' integer, + FOREIGN KEY ('orgId') REFERENCES 'orgs'('orgId') ON UPDATE no action ON DELETE cascade, + FOREIGN KEY ('exitNode') REFERENCES 'exitNodes'('exitNodeId') ON UPDATE no action ON DELETE set null +); +--> statement-breakpoint +INSERT INTO '__new_clients'("id", "orgId", "exitNode", "name", "pubKey", "subnet", "bytesIn", "bytesOut", "lastBandwidthUpdate", "lastPing", "type", "online", "lastHolePunch") SELECT "id", "orgId", "exitNode", "name", "pubKey", "subnet", "bytesIn", "bytesOut", "lastBandwidthUpdate", "lastPing", "type", "online", "lastHolePunch" FROM 'clients';--> statement-breakpoint +DROP TABLE 'clients';--> statement-breakpoint +ALTER TABLE '__new_clients' RENAME TO 'clients';--> statement-breakpoint +ALTER TABLE 'clientSites' ADD 'endpoint' text;--> statement-breakpoint +ALTER TABLE 'exitNodes' ADD 'online' integer DEFAULT false NOT NULL;--> statement-breakpoint +ALTER TABLE 'exitNodes' ADD 'lastPing' integer;--> statement-breakpoint +ALTER TABLE 'exitNodes' ADD 'type' text DEFAULT 'gerbil';--> statement-breakpoint +ALTER TABLE 'olms' ADD 'version' text;--> statement-breakpoint +ALTER TABLE 'orgs' ADD 'createdAt' text;--> statement-breakpoint +ALTER TABLE 'targets' ADD 'siteId' integer NOT NULL DEFAULT 1 REFERENCES sites(siteId);`); + + // for each resource, get all of its targets, and update the siteId to be the previously stored siteId + for (const [resourceId, siteId] of resourceSiteMap) { + const targets = db + .prepare( + "SELECT targetId FROM targets WHERE resourceId = ?" + ) + .all(resourceId) as Array<{ targetId: number }>; + for (const target of targets) { + db.prepare( + "UPDATE targets SET siteId = ? WHERE targetId = ?" + ).run(siteId, target.targetId); + } + } + + // list resources that have enableProxy false + // move them to the siteResources table + // remove them from the resources table + const proxyFalseResources = db + .prepare("SELECT * FROM resources WHERE enableProxy = 0") + .all() as Array; + + for (const resource of proxyFalseResources) { + // Get the first target to derive destination IP and port + const firstTarget = db + .prepare( + "SELECT ip, port FROM targets WHERE resourceId = ? LIMIT 1" + ) + .get(resource.resourceId) as + | { ip: string; port: number } + | undefined; + + if (!firstTarget) { + continue; + } + + // Insert into siteResources table + const stmt = db.prepare(` + INSERT INTO siteResources (siteId, orgId, name, protocol, proxyPort, destinationPort, destinationIp, enabled) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) + `); + stmt.run( + resourceSiteMap.get(resource.resourceId), + resource.orgId, + resource.name, + resource.protocol, + resource.proxyPort, + firstTarget.port, + firstTarget.ip, + resource.enabled ); - `); + + // Delete from resources table + db.prepare("DELETE FROM resources WHERE resourceId = ?").run( + resource.resourceId + ); + + // Delete the targets for this resource + db.prepare("DELETE FROM targets WHERE resourceId = ?").run( + resource.resourceId + ); + } })(); db.pragma("foreign_keys = ON"); - console.log(`Added setupTokens table`); + console.log(`Migrated database`); } catch (e) { - console.log("Unable to add setupTokens table:", e); + console.log("Failed to migrate db:", e); throw e; } }