feat: Fleet Forge UEM - device management, agent, remote desktop (VNC), TLS reverse proxy

This commit is contained in:
Pepe44DEV
2026-09-06 22:09:28 +00:00
commit db16ad5cc1
154 changed files with 22920 additions and 0 deletions
+80
View File
@@ -0,0 +1,80 @@
import type { Request, Response, NextFunction } from "express";
import jwt from "jsonwebtoken";
import type { AuthenticatedUser, Role } from "@fleetforge/shared";
const JWT_SECRET = process.env.JWT_SECRET || "dev-secret";
const ROLE_HIERARCHY: Record<Role, number> = {
owner: 4,
admin: 3,
operator: 2,
read_only: 1,
};
export function generateToken(user: AuthenticatedUser): string {
return jwt.sign(
{
userId: user.userId,
organizationId: user.organizationId,
role: user.role,
email: user.email,
},
JWT_SECRET,
{ expiresIn: (process.env.JWT_EXPIRES_IN || "24h") as any }
);
}
export function verifyToken(token: string): AuthenticatedUser {
return jwt.verify(token, JWT_SECRET) as AuthenticatedUser;
}
export function authenticate(req: Request, res: Response, next: NextFunction) {
const authHeader = req.headers.authorization;
if (!authHeader?.startsWith("Bearer ")) {
res.status(401).json({
success: false,
error: { code: "UNAUTHORIZED", message: "Missing or invalid token" },
});
return;
}
try {
const token = authHeader.substring(7);
const user = verifyToken(token);
(req as any).user = user;
next();
} catch {
res.status(401).json({
success: false,
error: { code: "UNAUTHORIZED", message: "Invalid or expired token" },
});
}
}
export function authorize(...allowedRoles: Role[]) {
return (req: Request, res: Response, next: NextFunction) => {
const user = (req as any).user as AuthenticatedUser;
if (!user) {
res.status(401).json({
success: false,
error: { code: "UNAUTHORIZED", message: "Not authenticated" },
});
return;
}
if (allowedRoles.length > 0) {
const hasRole = allowedRoles.some(
(role) => ROLE_HIERARCHY[user.role] >= ROLE_HIERARCHY[role]
);
if (!hasRole) {
res.status(403).json({
success: false,
error: { code: "FORBIDDEN", message: "Insufficient permissions" },
});
return;
}
}
next();
};
}
+13
View File
@@ -0,0 +1,13 @@
import type { Request, Response, NextFunction } from "express";
import { v4 as uuidv4 } from "uuid";
export function correlationMiddleware(
req: Request,
_res: Response,
next: NextFunction
) {
const correlationId =
(req.headers["x-correlation-id"] as string) || uuidv4();
(req as any).correlationId = correlationId;
next();
}
+21
View File
@@ -0,0 +1,21 @@
export const corsConfig = {
origin: process.env.CORS_ORIGINS
? process.env.CORS_ORIGINS.split(",")
: [
"http://localhost:3000",
"http://localhost:3001",
"http://localhost:3002",
"http://localhost:3003",
"http://localhost:3004",
"http://localhost:3005",
"http://10.0.0.194:3000",
"http://10.0.0.194:3001",
"http://10.0.0.194:3002",
"http://10.0.0.194:3003",
"http://10.0.0.194:3004",
"http://10.0.0.194:3005",
],
credentials: true,
methods: ["GET", "POST", "PUT", "PATCH", "DELETE"],
allowedHeaders: ["Content-Type", "Authorization", "X-Correlation-ID"],
};
+21
View File
@@ -0,0 +1,21 @@
import type { Request, Response, NextFunction } from "express";
export function errorHandler(
err: Error,
_req: Request,
res: Response,
_next: NextFunction
) {
console.error("Unhandled error:", err);
res.status(500).json({
success: false,
error: { code: "INTERNAL_ERROR", message: "An internal error occurred" },
});
}
export function notFoundHandler(_req: Request, res: Response) {
res.status(404).json({
success: false,
error: { code: "NOT_FOUND", message: "Endpoint not found" },
});
}
+57
View File
@@ -0,0 +1,57 @@
import { RateLimiterMemory } from "rate-limiter-flexible";
const authLimiter = new RateLimiterMemory({
points: 10,
duration: 60,
});
const apiLimiter = new RateLimiterMemory({
points: 100,
duration: 60,
});
const enrollLimiter = new RateLimiterMemory({
points: 5,
duration: 300,
});
export async function rateLimitAuth(req: any, res: any, next: any) {
try {
const ip = req.ip || req.socket?.remoteAddress || "unknown";
await authLimiter.consume(`auth:${ip}`);
next();
} catch {
res.status(429).json({
success: false,
error: { code: "RATE_LIMITED", message: "Too many authentication attempts. Please try again later." },
});
}
}
export async function rateLimitApi(req: any, res: any, next: any) {
try {
const ip = req.ip || req.socket?.remoteAddress || "unknown";
const user = (req as any).user;
const key = user ? `api:${user.userId}` : `api:${ip}`;
await apiLimiter.consume(key);
next();
} catch {
res.status(429).json({
success: false,
error: { code: "RATE_LIMITED", message: "Rate limit exceeded. Please slow down." },
});
}
}
export async function rateLimitEnroll(req: any, res: any, next: any) {
try {
const ip = req.ip || req.socket?.remoteAddress || "unknown";
await enrollLimiter.consume(`enroll:${ip}`);
next();
} catch {
res.status(429).json({
success: false,
error: { code: "RATE_LIMITED", message: "Too many enrollment attempts." },
});
}
}