136 lines
4.8 KiB
TypeScript
136 lines
4.8 KiB
TypeScript
import { __DIRNAME, APP_PATH } from "@server/lib/consts";
|
|
import Database from "better-sqlite3";
|
|
import { readFileSync } from "fs";
|
|
import path, { join } from "path";
|
|
|
|
const version = "1.10.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 {
|
|
const resources = db
|
|
.prepare(
|
|
"SELECT resourceId FROM resources"
|
|
)
|
|
.all() as Array<{ resourceId: number }>;
|
|
|
|
const siteResources = db
|
|
.prepare(
|
|
"SELECT siteResourceId FROM siteResources"
|
|
)
|
|
.all() as Array<{ siteResourceId: number }>;
|
|
|
|
db.transaction(() => {
|
|
db.exec(`
|
|
ALTER TABLE 'exitNodes' ADD 'region' text;
|
|
ALTER TABLE 'idpOidcConfig' ADD 'variant' text DEFAULT 'oidc' NOT NULL;
|
|
ALTER TABLE 'resources' ADD 'niceId' text DEFAULT '' NOT NULL;
|
|
ALTER TABLE 'siteResources' ADD 'niceId' text DEFAULT '' NOT NULL;
|
|
ALTER TABLE 'userOrgs' ADD 'autoProvisioned' integer DEFAULT false;
|
|
ALTER TABLE 'targets' ADD 'pathMatchType' text;
|
|
ALTER TABLE 'targets' ADD 'path' text;
|
|
ALTER TABLE 'resources' ADD 'headers' text;
|
|
`); // this diverges from the schema a bit because the schema does not have a default on niceId but was required for the migration and I dont think it will effect much down the line...
|
|
|
|
const usedNiceIds: string[] = [];
|
|
|
|
for (const resourceId of resources) {
|
|
// Generate a unique name and ensure it's unique
|
|
let niceId = "";
|
|
let loops = 0;
|
|
while (true) {
|
|
if (loops > 100) {
|
|
throw new Error("Could not generate a unique name");
|
|
}
|
|
|
|
niceId = generateName();
|
|
if (!usedNiceIds.includes(niceId)) {
|
|
usedNiceIds.push(niceId);
|
|
break;
|
|
}
|
|
loops++;
|
|
}
|
|
db.prepare(
|
|
`UPDATE resources SET niceId = ? WHERE resourceId = ?`
|
|
).run(niceId, resourceId.resourceId);
|
|
}
|
|
|
|
for (const resourceId of siteResources) {
|
|
// Generate a unique name and ensure it's unique
|
|
let niceId = "";
|
|
let loops = 0;
|
|
while (true) {
|
|
if (loops > 100) {
|
|
throw new Error("Could not generate a unique name");
|
|
}
|
|
|
|
niceId = generateName();
|
|
if (!usedNiceIds.includes(niceId)) {
|
|
usedNiceIds.push(niceId);
|
|
break;
|
|
}
|
|
loops++;
|
|
}
|
|
db.prepare(
|
|
`UPDATE siteResources SET niceId = ? WHERE siteResourceId = ?`
|
|
).run(niceId, resourceId.siteResourceId);
|
|
}
|
|
|
|
// Handle auto-provisioned users for identity providers
|
|
const autoProvisionIdps = db
|
|
.prepare(
|
|
"SELECT idpId FROM idp WHERE autoProvision = 1"
|
|
)
|
|
.all() as Array<{ idpId: number }>;
|
|
|
|
for (const idp of autoProvisionIdps) {
|
|
// Get all users with this identity provider
|
|
const usersWithIdp = db
|
|
.prepare(
|
|
"SELECT id FROM user WHERE idpId = ?"
|
|
)
|
|
.all(idp.idpId) as Array<{ id: string }>;
|
|
|
|
// Update userOrgs to set autoProvisioned to true for these users
|
|
for (const user of usersWithIdp) {
|
|
db.prepare(
|
|
"UPDATE userOrgs SET autoProvisioned = 1 WHERE userId = ?"
|
|
).run(user.id);
|
|
}
|
|
}
|
|
})();
|
|
|
|
console.log(`Migrated database`);
|
|
} catch (e) {
|
|
console.log("Failed to migrate db:", e);
|
|
throw e;
|
|
}
|
|
}
|
|
|
|
const dev = process.env.ENVIRONMENT !== "prod";
|
|
let file;
|
|
if (!dev) {
|
|
file = join(__DIRNAME, "names.json");
|
|
} else {
|
|
file = join("server/db/names.json");
|
|
}
|
|
export const names = JSON.parse(readFileSync(file, "utf-8"));
|
|
|
|
export function generateName(): string {
|
|
const name = (
|
|
names.descriptors[
|
|
Math.floor(Math.random() * names.descriptors.length)
|
|
] +
|
|
"-" +
|
|
names.animals[Math.floor(Math.random() * names.animals.length)]
|
|
)
|
|
.toLowerCase()
|
|
.replace(/\s/g, "-");
|
|
|
|
// clean out any non-alphanumeric characters except for dashes
|
|
return name.replace(/[^a-z0-9-]/g, "");
|
|
}
|