import { join } from "path"; import { readFileSync } from "fs"; import { clients, db, resources, siteResources } from "@server/db"; import { randomInt } from "crypto"; import { exitNodes, sites } from "@server/db"; import { eq, and } from "drizzle-orm"; import { __DIRNAME } from "@server/lib/consts"; // Load the names from the names.json file 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")); // Load iOS and Mac model mappings let iosModelsFile: string; let macModelsFile: string; if (!dev) { iosModelsFile = join(__DIRNAME, "ios_models.json"); macModelsFile = join(__DIRNAME, "mac_models.json"); } else { iosModelsFile = join("server/db/ios_models.json"); macModelsFile = join("server/db/mac_models.json"); } const iosModels: Record = JSON.parse( readFileSync(iosModelsFile, "utf-8") ); const macModels: Record = JSON.parse( readFileSync(macModelsFile, "utf-8") ); export async function getUniqueClientName(orgId: string): Promise { let loops = 0; while (true) { if (loops > 100) { throw new Error("Could not generate a unique name"); } const name = generateName(); const count = await db .select({ niceId: clients.niceId, orgId: clients.orgId }) .from(clients) .where(and(eq(clients.niceId, name), eq(clients.orgId, orgId))); if (count.length === 0) { return name; } loops++; } } export async function getUniqueSiteName(orgId: string): Promise { let loops = 0; while (true) { if (loops > 100) { throw new Error("Could not generate a unique name"); } const name = generateName(); const count = await db .select({ niceId: sites.niceId, orgId: sites.orgId }) .from(sites) .where(and(eq(sites.niceId, name), eq(sites.orgId, orgId))); if (count.length === 0) { return name; } loops++; } } export async function getUniqueResourceName(orgId: string): Promise { let loops = 0; while (true) { if (loops > 100) { throw new Error("Could not generate a unique name"); } const name = generateName(); const [resourceCount, siteResourceCount] = await Promise.all([ db .select({ niceId: resources.niceId, orgId: resources.orgId }) .from(resources) .where( and(eq(resources.niceId, name), eq(resources.orgId, orgId)) ), db .select({ niceId: siteResources.niceId, orgId: siteResources.orgId }) .from(siteResources) .where( and( eq(siteResources.niceId, name), eq(siteResources.orgId, orgId) ) ) ]); if (resourceCount.length === 0 && siteResourceCount.length === 0) { return name; } loops++; } } export async function getUniqueSiteResourceName( orgId: string ): Promise { let loops = 0; while (true) { if (loops > 100) { throw new Error("Could not generate a unique name"); } const name = generateName(); const [resourceCount, siteResourceCount] = await Promise.all([ db .select({ niceId: resources.niceId, orgId: resources.orgId }) .from(resources) .where( and(eq(resources.niceId, name), eq(resources.orgId, orgId)) ), db .select({ niceId: siteResources.niceId, orgId: siteResources.orgId }) .from(siteResources) .where( and( eq(siteResources.niceId, name), eq(siteResources.orgId, orgId) ) ) ]); if (resourceCount.length === 0 && siteResourceCount.length === 0) { return name; } loops++; } } export async function getUniqueExitNodeEndpointName(): Promise { let loops = 0; const count = await db.select().from(exitNodes); while (true) { if (loops > 100) { throw new Error("Could not generate a unique name"); } const name = generateName(); for (const node of count) { if (node.endpoint.includes(name)) { loops++; continue; } } return name; } } export function generateName(): string { const name = ( names.descriptors[randomInt(names.descriptors.length)] + "-" + names.animals[randomInt(names.animals.length)] ) .toLowerCase() .replace(/\s/g, "-"); // clean out any non-alphanumeric characters except for dashes return name.replace(/[^a-z0-9-]/g, ""); } export function getMacDeviceName(macIdentifier?: string | null): string | null { if (macIdentifier && macModels[macIdentifier]) { return macModels[macIdentifier]; } return null; } export function getIosDeviceName(iosIdentifier?: string | null): string | null { if (iosIdentifier && iosModels[iosIdentifier]) { return iosModels[iosIdentifier]; } return null; } export function getUserDeviceName( model: string | null, fallBack: string | null ): string { return ( getMacDeviceName(model) || getIosDeviceName(model) || fallBack || "Unknown Device" ); }