bytelyst-devops-tools/dashboard/backend/src/lib/auth.ts
root fbaaa71a66 feat(devops): adopt trading web deployment model with docker-compose
- Add docker-compose.yml following trading web pattern
- Update web Dockerfile to use multi-stage build with metadata
- Add build metadata (commit SHA, branch, timestamp, author, message)
- Rewrite deploy.sh to use docker compose with build metadata
- Add hotcopy deployment script for quick updates
- Add comprehensive backend API with deployment orchestration
- Add health checks, service management, and monitoring endpoints
- Add CI/CD workflow configuration
- Add deployment documentation and guides

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-11 03:24:11 +00:00

76 lines
2.3 KiB
TypeScript

import { jwtVerify } from 'jose';
import type { FastifyRequest } from 'fastify';
import { config, productId } from './config.js';
export interface AuthenticatedRequest extends FastifyRequest {
authUserId?: string;
authRole?: string;
authEmail?: string;
authProductId?: string;
}
export async function extractAuth(req: FastifyRequest): Promise<{ userId: string; role: string; email?: string; productId?: string } | null> {
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith('Bearer ')) {
return null;
}
const token = authHeader.slice(7);
try {
const { payload } = await jwtVerify(
token,
new TextEncoder().encode(config.JWT_SECRET),
{ issuer: 'bytelyst-platform' }
);
// Check if user has admin role for the devops product
// If they have global admin role, they can access
// Otherwise, check their per-product membership
const globalRole = (payload.role as string) || 'user';
const currentProductId = payload.productId as string;
const targetProductId = productId; // This dashboard's product ID
let effectiveRole = globalRole;
// If not global admin, check per-product membership
if (globalRole !== 'admin' && payload.products) {
const products = payload.products as Array<{ productId: string; role: string; plan: string }>;
const devopsMembership = products.find(p => p.productId === targetProductId);
if (devopsMembership && devopsMembership.role === 'admin') {
effectiveRole = 'admin';
}
}
return {
userId: payload.sub as string,
role: effectiveRole,
email: payload.email as string,
productId: currentProductId,
};
} catch {
return null;
}
}
export class AuthError extends Error {
constructor(message: string, public statusCode: number = 401) {
super(message);
this.name = 'AuthError';
}
}
export class BadRequestError extends Error {
constructor(message: string) {
super(message);
this.name = 'BadRequestError';
}
}
export function requireAdmin(req: FastifyRequest): { userId: string } {
const authReq = req as AuthenticatedRequest;
if (!authReq.authUserId || authReq.authRole !== 'admin') {
throw new AuthError('Admin access required', 403);
}
return { userId: authReq.authUserId };
}