Files
multiverse/jumpa-iam/app/api/auth/quantum_token/route.ts
T

119 lines
3.8 KiB
TypeScript

// [TSM.ID].[11031972] — All Rights Reserved. Proprietary & Confidential.
import { NextResponse } from 'next/server';
import { db } from "@/drizzle/db";
import { tenants, users } from "@/drizzle/schema";
import { eq } from 'drizzle-orm';
import { cookies } from 'next/headers';
import jwt from 'jsonwebtoken';
import { QuantumOrchestrator } from "@/lib/quantum-orchestrator";
export const dynamic = 'force-dynamic';
interface DecodedToken {
userId: string;
email: string;
role: string;
tenantId: string;
}
export async function GET() {
try {
const cookieStore = await cookies();
const token = cookieStore.get('jumpa_token')?.value;
if (!token) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
const decoded = jwt.verify(token, process.env.JWT_SECRET as string) as DecodedToken;
// Fetch tenant data to get BYOK settings and licenses
const tenantData = await db.select().from(tenants).where(eq(tenants.id, decoded.tenantId)).limit(1);
const userData = await db.select().from(users).where(eq(users.id, decoded.userId)).limit(1);
if (tenantData.length === 0) {
return NextResponse.json({ error: 'Tenant not found' }, { status: 404 });
}
const tenant = tenantData[0];
const user = userData[0];
// Parse licenses
const rawLicenses = tenant.licenses || '{}';
const tenantLicParsed = JSON.parse(rawLicenses);
let tenantLicNormalized: Record<string, string> = {};
if (Array.isArray(tenantLicParsed)) {
tenantLicParsed.forEach((k: string) => tenantLicNormalized[k] = 'GRANTED');
} else {
tenantLicNormalized = tenantLicParsed || {};
}
const userLicParsed = JSON.parse(user?.licenses || '{}');
let userLicNormalized: Record<string, string> = {};
if (Array.isArray(userLicParsed)) {
userLicParsed.forEach((k: string) => userLicNormalized[k] = 'GRANTED');
} else {
userLicNormalized = userLicParsed || {};
}
// Resolve 101-Module Matrix Capabilities
const capabilities = QuantumOrchestrator.resolve(
tenantLicNormalized,
userLicNormalized,
!!tenant.isActive
);
// Parse legacy modules string list
let modules: string[] = [];
try {
if (Array.isArray(tenantLicParsed)) {
modules = tenantLicParsed;
} else {
modules = Object.keys(tenantLicParsed).filter(k => (tenantLicParsed as Record<string, string>)[k] === 'GRANTED');
}
} catch (_e) {
modules = [];
}
// Determine the active BYOK Key
// Priority: User > Tenant
let activeByokKey = 'none';
let byokLevel = 'SYSTEM';
if (user?.byokEnabled && user?.byokKey) {
activeByokKey = user.byokKey;
byokLevel = 'USER';
} else if (tenant.byokEnabled && tenant.byokKey) {
activeByokKey = tenant.byokKey;
byokLevel = 'TENANT';
}
// Secret WAJIB sama dengan XCU_QCG_SECRET di XCU Core (PKX Rule #4)
const xcuSecret = process.env.XCU_QCG_SECRET || process.env.XCU_TOKEN_SECRET;
if (!xcuSecret) {
throw new Error('HUKUM MUTLAK: XCU_QCG_SECRET tidak ditemukan! Gerbang Anti-Jumping menolak akses.');
}
const quantumToken = jwt.sign({
sub: decoded.email,
tenantId: decoded.tenantId,
modules: modules,
capabilities: capabilities,
byok: activeByokKey,
byokLevel: byokLevel,
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + (60 * 60 * 12)
}, xcuSecret);
return NextResponse.json({
token: quantumToken,
modules: modules,
capabilities: capabilities,
byokActive: activeByokKey !== 'none',
byokLevel: byokLevel
});
} catch (error: unknown) {
console.error('[QUANTUM TOKEN ERROR]', error);
return NextResponse.json({ error: 'Quantum Sync Failed' }, { status: 500 });
}
}