From 4030ac5133aa6902b11e7eb03d1f56d60c7ffe02 Mon Sep 17 00:00:00 2001 From: arsam Date: Fri, 18 Sep 2026 23:09:10 +0330 Subject: [PATCH] Import source: backend/scripts/bootstrap-admin.mjs Import the existing local project snapshot. This commit organizes existing files; it does not represent newly developed functionality. --- backend/scripts/bootstrap-admin.mjs | 122 ++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 backend/scripts/bootstrap-admin.mjs diff --git a/backend/scripts/bootstrap-admin.mjs b/backend/scripts/bootstrap-admin.mjs new file mode 100644 index 0000000..0b7786f --- /dev/null +++ b/backend/scripts/bootstrap-admin.mjs @@ -0,0 +1,122 @@ +import fs from "fs"; +import crypto from "crypto"; +import { PrismaClient } from "@prisma/client"; + +const prisma = new PrismaClient(); + +const allPermissions = [ + "dashboard_read", + "tools_read", + "websites_manage", + "domains_manage", + "files_manage", + "databases_manage", + "email_manage", + "metrics_read", + "security_manage", + "software_manage", + "advanced_manage", + "servers_manage", + "users_manage", + "resellers_manage", + "backups_manage", + "automation_manage", + "notifications_read", + "audit_read", + "support_manage", + "settings_manage", +]; + +function hashPassword(password) { + const salt = crypto.randomBytes(24).toString("hex"); + const hash = crypto.scryptSync(password, salt, 64).toString("hex"); + return `scrypt$${salt}$${hash}`; +} + +function initials(name) { + return name + .split(/\s+/) + .filter(Boolean) + .map((part) => part[0]) + .join("") + .slice(0, 2) + .toUpperCase(); +} + +async function main() { + const email = process.env.ADMIN_EMAIL || "admin@cp.asabbagh.com"; + const password = process.env.ADMIN_PASSWORD || crypto.randomBytes(30).toString("base64url"); + const name = process.env.ADMIN_NAME || "CoaxysPanel Administrator"; + const accountId = process.env.ADMIN_ACCOUNT_ID || "acct-main"; + + await prisma.hostingAccount.upsert({ + where: { id: accountId }, + create: { + id: accountId, + username: "coaxys", + primaryDomain: "example.com", + homeDirectory: "/home/coaxys", + sharedIp: "127.0.0.1", + theme: "dark", + }, + update: {}, + }); + + const user = await prisma.user.upsert({ + where: { email }, + create: { + name, + email, + passwordHash: hashPassword(password), + role: "owner", + avatarInitials: initials(name), + twoFactorEnabled: false, + permissions: { + create: allPermissions.map((permission) => ({ permission })), + }, + accounts: { + create: { accountId }, + }, + }, + update: { + name, + passwordHash: hashPassword(password), + role: "owner", + avatarInitials: initials(name), + twoFactorEnabled: false, + }, + }); + + await prisma.accountUser.upsert({ + where: { userId_accountId: { userId: user.id, accountId } }, + create: { userId: user.id, accountId }, + update: {}, + }); + await prisma.userPermission.deleteMany({ where: { userId: user.id } }); + await prisma.userPermission.createMany({ + data: allPermissions.map((permission) => ({ userId: user.id, permission })), + }); + + const credentialPath = ".admin-credentials"; + const content = [ + "CoaxysPanel admin credentials", + `Generated: ${new Date().toISOString()}`, + `URL: https://cp.asabbagh.com/login`, + `Email: ${email}`, + `Password: ${password}`, + "", + ].join("\n"); + fs.writeFileSync(credentialPath, content, { mode: 0o600 }); + fs.chmodSync(credentialPath, 0o600); + console.log(`Admin account ready: ${email}`); + console.log(`Credentials written to ${credentialPath}`); +} + +main() + .catch((error) => { + console.error(error); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + });