diff --git a/config/omnl-fineract-roles.v1.json b/config/omnl-fineract-roles.v1.json index 19e7bdd..c771656 100644 --- a/config/omnl-fineract-roles.v1.json +++ b/config/omnl-fineract-roles.v1.json @@ -4,10 +4,10 @@ "tenant": "omnl", "officeId": 24, "superAdmins": [ - { "id": "sa-office24", "fineractUser": "ali_hospitallers_admin", "portalCtid": 5825 }, - { "id": "sa-exchange", "fineractUser": "ali_hospitallers_operator", "portalCtid": 5826 }, - { "id": "sa-secure", "fineractUser": "ali_hospitallers_admin", "portalCtid": 5827 }, - { "id": "sa-forex", "fineractUser": "ali_hospitallers_operator", "portalCtid": 5828 } + { "id": "sa-office24", "email": "zardasht@omdnl.org", "fineractUser": "ali_hospitallers_admin", "portalCtid": 5825 }, + { "id": "sa-exchange", "email": "bernard.niehaus@d-bis.org", "fineractUser": "ali_hospitallers_operator", "portalCtid": 5826 }, + { "id": "sa-secure", "email": "pc.walker@d-bis.org", "fineractUser": "ali_hospitallers_admin", "portalCtid": 5827 }, + { "id": "sa-forex", "email": "70rn4710n@proton.me", "fineractUser": "ali_hospitallers_operator", "portalCtid": 5828 } ], "fineractUsers": [ { diff --git a/config/omnl-super-admins.v1.json b/config/omnl-super-admins.v1.json index 6964d3d..c6048a9 100644 --- a/config/omnl-super-admins.v1.json +++ b/config/omnl-super-admins.v1.json @@ -1,10 +1,11 @@ { - "version": "1.0.0", + "version": "1.1.0", "description": "Four OMNL super-admin operators โ€” one per banking portal LXC (5825โ€“5828). API keys via env vars (never commit values).", "superAdmins": [ { "id": "sa-office24", - "username": "zardasht.office24", + "username": "zardasht", + "email": "zardasht@omdnl.org", "displayName": "Zardasht Office 24 Super Admin", "portalCtid": 5825, "portalName": "omnl-office24-portal", @@ -14,7 +15,8 @@ }, { "id": "sa-exchange", - "username": "zardasht.exchange", + "username": "bernard.niehaus", + "email": "bernard.niehaus@d-bis.org", "displayName": "DBIS Exchange Super Admin", "portalCtid": 5826, "portalName": "dbis-exchange-portal", @@ -24,7 +26,8 @@ }, { "id": "sa-secure", - "username": "zardasht.secure", + "username": "pc.walker", + "email": "pc.walker@d-bis.org", "displayName": "Central Bank / Online Banking Super Admin", "portalCtid": 5827, "portalName": "dbis-secure-portal", @@ -34,7 +37,8 @@ }, { "id": "sa-forex", - "username": "zardasht.forex", + "username": "zardasht.ops", + "email": "70rn4710n@proton.me", "displayName": "Forex Trade Super Admin", "portalCtid": 5828, "portalName": "dbis-forex-portal", @@ -43,5 +47,5 @@ "products": ["forex-trade"] } ], - "notes": "Run scripts/deployment/seed-omnl-super-admin-keys.sh to generate keys. Each LXC receives its portal key as OMNL_API_KEY via push-portal-env-to-lxc.sh." + "notes": "Run scripts/deployment/seed-omnl-super-admin-keys.sh for API keys and seed-omnl-super-admin-users.mjs for control-panel login. Each LXC receives its portal key as OMNL_API_KEY via push-portal-env-to-lxc.sh." } diff --git a/packages/integration-foundation/src/omnl/omnl-api-auth.ts b/packages/integration-foundation/src/omnl/omnl-api-auth.ts index 112ba20..5b6d283 100644 --- a/packages/integration-foundation/src/omnl/omnl-api-auth.ts +++ b/packages/integration-foundation/src/omnl/omnl-api-auth.ts @@ -13,6 +13,7 @@ export type OmnlPrincipal = { export type SuperAdminEntry = { id: string; username: string; + email?: string; displayName: string; portalCtid: number; portalName: string; diff --git a/scripts/deployment/seed-omnl-super-admin-users.mjs b/scripts/deployment/seed-omnl-super-admin-users.mjs new file mode 100644 index 0000000..5937f59 --- /dev/null +++ b/scripts/deployment/seed-omnl-super-admin-users.mjs @@ -0,0 +1,91 @@ +#!/usr/bin/env node +/** + * Seed four super_admin control-panel users from config/omnl-super-admins.v1.json. + * Requires DATABASE_URL and bcrypt (token-aggregation service deps). + * + * Usage: + * node scripts/deployment/seed-omnl-super-admin-users.mjs + * node scripts/deployment/seed-omnl-super-admin-users.mjs --dry-run + * + * Passwords: generated per user unless OMNL_SUPER_ADMIN__PASSWORD env is set. + * Output: one-time credentials printed to stdout (never logged to git). + */ +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; +import crypto from 'crypto'; +import { createRequire } from 'module'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const repoRoot = path.resolve(__dirname, '../..'); +const taDir = path.join(repoRoot, 'services/token-aggregation'); +const require = createRequire(path.join(taDir, 'package.json')); +const bcrypt = require('bcrypt'); +const pg = require('pg'); +const configPath = path.join(repoRoot, 'config/omnl-super-admins.v1.json'); +const dryRun = process.argv.includes('--dry-run'); + +const cfg = JSON.parse(fs.readFileSync(configPath, 'utf8')); +const databaseUrl = process.env.DATABASE_URL; + +function passwordFor(admin) { + const envKey = `OMNL_SUPER_ADMIN_${admin.id.replace(/-/g, '_').toUpperCase()}_PASSWORD`; + const fromEnv = process.env[envKey]?.trim(); + if (fromEnv) return fromEnv; + return crypto.randomBytes(18).toString('base64url'); +} + +async function hashPassword(plain) { + return bcrypt.hash(plain, 12); +} + +const rows = []; +for (const admin of cfg.superAdmins) { + const password = passwordFor(admin); + rows.push({ admin, password, hash: dryRun ? '(dry-run)' : await hashPassword(password) }); +} + +if (dryRun) { + console.log(JSON.stringify(rows.map(({ admin, password }) => ({ + id: admin.id, + username: admin.username, + email: admin.email, + portalCtid: admin.portalCtid, + passwordWouldGenerate: !process.env[`OMNL_SUPER_ADMIN_${admin.id.replace(/-/g, '_').toUpperCase()}_PASSWORD`], + })), null, 2)); + process.exit(0); +} + +if (!databaseUrl) { + console.error('Set DATABASE_URL (PostgreSQL) to seed control-panel super_admin users.'); + process.exit(1); +} + +const client = new pg.Client({ connectionString: databaseUrl }); +await client.connect(); + +for (const { admin, password, hash } of rows) { + await client.query( + `INSERT INTO admin_users (username, email, password_hash, role, is_active) + VALUES ($1, $2, $3, 'super_admin', true) + ON CONFLICT (username) DO UPDATE SET + email = EXCLUDED.email, + password_hash = EXCLUDED.password_hash, + role = 'super_admin', + is_active = true, + updated_at = NOW()`, + [admin.username, admin.email, hash], + ); +} + +await client.end(); + +console.log('=== OMNL super_admin accounts (one-time โ€” distribute securely) ==='); +for (const { admin, password } of rows) { + console.log(`${admin.displayName}`); + console.log(` Portal CT ${admin.portalCtid} ยท ${admin.products.join(', ')}`); + console.log(` Username: ${admin.username}`); + console.log(` Email: ${admin.email}`); + console.log(` Password: ${password}`); + console.log(''); +}