WIP: OMNL compliance console, relay rpc pool, zedxion relay service
This commit is contained in:
@@ -4,7 +4,25 @@ function extractBearerOrQuery(req: Request, key: string): boolean {
|
||||
const auth = String(req.headers.authorization || '');
|
||||
const bearer = auth.startsWith('Bearer ') ? auth.slice(7).trim() : '';
|
||||
const q = String(req.query.access_token ?? '').trim();
|
||||
return bearer === key || q === key;
|
||||
const dashHeader = String(req.headers['x-omnl-dashboard-token'] ?? '').trim();
|
||||
return bearer === key || q === key || dashHeader === key;
|
||||
}
|
||||
|
||||
function hasOmnlOperatorAuth(req: Request): boolean {
|
||||
const apiKey = process.env.OMNL_API_KEY?.trim();
|
||||
if (apiKey && extractBearerOrQuery(req, apiKey)) return true;
|
||||
const dashKey = process.env.OMNL_DASHBOARD_TOKEN?.trim();
|
||||
if (dashKey && extractBearerOrQuery(req, dashKey)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Read-only compliance console API (GET). */
|
||||
function isComplianceConsolePath(path: string): boolean {
|
||||
return (
|
||||
path.endsWith('/omnl/compliance/console') ||
|
||||
path.endsWith('/omnl/compliance/safe-notary-gate-tx') ||
|
||||
path.endsWith('/omnl/compliance/web3')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -17,7 +35,7 @@ export function omnlSensitiveRouteGuard(req: Request, res: Response, next: NextF
|
||||
next();
|
||||
return;
|
||||
}
|
||||
if (extractBearerOrQuery(req, key)) {
|
||||
if (hasOmnlOperatorAuth(req)) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
@@ -28,7 +46,10 @@ export function omnlSensitiveRouteGuard(req: Request, res: Response, next: NextF
|
||||
const OMNL_PUBLIC_PATH_SUFFIXES = ['/omnl/openapi.json', '/omnl/catalog', '/omnl/integration-status'];
|
||||
|
||||
function isPublicOmnlPath(path: string): boolean {
|
||||
return OMNL_PUBLIC_PATH_SUFFIXES.some((s) => path.endsWith(s));
|
||||
if (OMNL_PUBLIC_PATH_SUFFIXES.some((s) => path.endsWith(s))) return true;
|
||||
// Compliance console is read-only; allow without API key when explicitly enabled (LAN operator UI).
|
||||
if (process.env.OMNL_COMPLIANCE_CONSOLE_PUBLIC === '1' && isComplianceConsolePath(path)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -59,5 +80,9 @@ export function omnlRequireApiKeyInProduction(req: Request, res: Response, next:
|
||||
next();
|
||||
return;
|
||||
}
|
||||
if (isComplianceConsolePath(req.path) && hasOmnlOperatorAuth(req)) {
|
||||
next();
|
||||
return;
|
||||
}
|
||||
res.status(401).json({ error: 'Unauthorized' });
|
||||
}
|
||||
|
||||
@@ -20,6 +20,10 @@ import {
|
||||
import { verifyOmnlWebhookSignature } from '../../services/omnl-webhooks';
|
||||
import { appendOmnlAudit } from '../../services/omnl-audit-log';
|
||||
import { getWeb3ComplianceSummary, buildNotarizationIntent } from '../../services/omnl-web3-compliance';
|
||||
import {
|
||||
buildComplianceConsoleSnapshot,
|
||||
} from '../../services/omnl-compliance-console';
|
||||
import { buildSafeNotaryGateTransaction } from '../../services/omnl-safe-notary-gate-tx';
|
||||
import { readFileSync, existsSync } from 'fs';
|
||||
import { resolve } from 'path';
|
||||
|
||||
@@ -67,6 +71,30 @@ router.get('/omnl/compliance/web3', omnlSensitiveRouteGuard, (_req, res) => {
|
||||
res.json(getWeb3ComplianceSummary());
|
||||
});
|
||||
|
||||
router.get('/omnl/compliance/console', omnlSensitiveRouteGuard, async (req: Request, res: Response) => {
|
||||
try {
|
||||
const lineId = String(req.query.lineId || '').trim() || undefined;
|
||||
res.json(await buildComplianceConsoleSnapshot(lineId));
|
||||
} catch (e) {
|
||||
res.status(500).json({ error: e instanceof Error ? e.message : String(e) });
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/omnl/compliance/safe-notary-gate-tx', omnlSensitiveRouteGuard, (_req, res) => {
|
||||
const tx = buildSafeNotaryGateTransaction();
|
||||
if (!tx) {
|
||||
res.status(404).json({
|
||||
error: 'Safe notary gate transaction unavailable',
|
||||
hint: 'Set PROXMOX_ROOT and ensure config/compliance/*.v1.json exist',
|
||||
});
|
||||
return;
|
||||
}
|
||||
res
|
||||
.type('application/json')
|
||||
.attachment('omnl-safe-notary-gate-tx.json')
|
||||
.send(JSON.stringify(tx, null, 2));
|
||||
});
|
||||
|
||||
router.post('/omnl/compliance/notarization-intent', omnlSensitiveRouteGuard, (req, res) => {
|
||||
const body = req.body as {
|
||||
jurisdictionId?: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import express, { Express, Request, Response, NextFunction } from 'express';
|
||||
import express, { Express, Request, Response, NextFunction, type RequestHandler } from 'express';
|
||||
import { Server } from 'http';
|
||||
import path from 'path';
|
||||
import { readFileSync, existsSync } from 'fs';
|
||||
@@ -91,8 +91,8 @@ export class ApiServer {
|
||||
// CORS
|
||||
this.app.use(cors());
|
||||
|
||||
// Compression
|
||||
this.app.use(compression());
|
||||
// Compression (Express 5 typings — runtime-compatible)
|
||||
this.app.use(compression() as unknown as RequestHandler);
|
||||
|
||||
// Body parsing
|
||||
this.app.use(express.json());
|
||||
@@ -114,10 +114,12 @@ export class ApiServer {
|
||||
|
||||
const publicPath = path.join(__dirname, '../../public');
|
||||
if (existsSync(publicPath)) {
|
||||
this.app.use('/static', express.static(publicPath, {
|
||||
const staticOpts = {
|
||||
immutable: true,
|
||||
maxAge: '1d',
|
||||
}));
|
||||
} as const;
|
||||
this.app.use('/static', express.static(publicPath, staticOpts));
|
||||
this.app.use('/omnl/static', express.static(publicPath, staticOpts));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,16 +149,31 @@ export class ApiServer {
|
||||
});
|
||||
|
||||
const dashboardPath = path.join(__dirname, '../../public/omnl-dashboard.html');
|
||||
this.app.get('/omnl/dashboard', (req: Request, res: Response) => {
|
||||
const complianceConsolePath = path.join(__dirname, '../../public/omnl-compliance-console.html');
|
||||
|
||||
const authorizeOmnlHtml = (req: Request, res: Response): boolean => {
|
||||
const tok = process.env.OMNL_DASHBOARD_TOKEN?.trim();
|
||||
if (tok) {
|
||||
const q = String(req.query.access_token ?? '').trim();
|
||||
const h = String(req.headers['x-omnl-dashboard-token'] ?? '').trim();
|
||||
if (q !== tok && h !== tok) {
|
||||
res.status(401).type('text/plain').send('Unauthorized: set access_token query or X-OMNL-Dashboard-Token header');
|
||||
return;
|
||||
}
|
||||
if (!tok) return true;
|
||||
const q = String(req.query.access_token ?? '').trim();
|
||||
const h = String(req.headers['x-omnl-dashboard-token'] ?? '').trim();
|
||||
if (q !== tok && h !== tok) {
|
||||
res.status(401).type('text/plain').send('Unauthorized: set access_token query or X-OMNL-Dashboard-Token header');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
this.app.get('/omnl/compliance', (req: Request, res: Response) => {
|
||||
if (!authorizeOmnlHtml(req, res)) return;
|
||||
if (!existsSync(complianceConsolePath)) {
|
||||
res.status(404).type('text/plain').send('omnl-compliance-console.html missing');
|
||||
return;
|
||||
}
|
||||
res.type('html').send(readFileSync(complianceConsolePath, 'utf8'));
|
||||
});
|
||||
|
||||
this.app.get('/omnl/dashboard', (req: Request, res: Response) => {
|
||||
if (!authorizeOmnlHtml(req, res)) return;
|
||||
if (!existsSync(dashboardPath)) {
|
||||
res.status(404).type('text/plain').send('omnl-dashboard.html missing');
|
||||
return;
|
||||
@@ -210,9 +227,9 @@ export class ApiServer {
|
||||
this.app.use('/api/v1', aggregatorRouteMatrixRoutes);
|
||||
this.app.use('/api/v1', partnerPayloadRoutes);
|
||||
this.app.use('/api/v1', checkpointRoutes);
|
||||
this.app.use('/api/v1', omnlComplianceRoutes);
|
||||
this.app.use('/api/v1', omnlRoutes);
|
||||
this.app.use('/api/v1', omnlIpsasRoutes);
|
||||
this.app.use('/api/v1', omnlComplianceRoutes);
|
||||
this.app.use('/api/v2', plannerV2Routes);
|
||||
|
||||
// Admin routes (stricter rate limit)
|
||||
|
||||
Reference in New Issue
Block a user