UNPKG

@allan1361/iota-big3-sdk-middleware

Version:

🏆 A+ Grade Certified Enterprise Middleware Framework - Phase 3 Certified (90/100) with advanced resilience patterns, comprehensive type safety, and production-ready observability

276 lines 10.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.policyMiddleware = void 0; exports.createPolicyMiddleware = createPolicyMiddleware; exports.createLegacyPolicyMiddleware = createLegacyPolicyMiddleware; const tslib_1 = require("tslib"); const axios_1 = tslib_1.__importDefault(require("axios")); const INDUSTRY_DEFAULTS = { education: { defaultAllow: false, philosophyEnforcement: true, philosophyMinScore: 70, includeViolationDetails: true }, healthcare: { defaultAllow: false, philosophyEnforcement: false, includeViolationDetails: false, enforcementMode: 'enforce' }, finance: { defaultAllow: false, philosophyEnforcement: false, includeViolationDetails: false, enforcementMode: 'enforce' }, retail: { defaultAllow: true, philosophyEnforcement: false, includeViolationDetails: true, enforcementMode: 'monitor' }, government: { defaultAllow: false, philosophyEnforcement: false, includeViolationDetails: false, enforcementMode: 'enforce' } }; function createPolicyMiddleware(metadata, config = {}) { const industry = metadata.industry || metadata.tribe || 'education'; const industryDefaults = INDUSTRY_DEFAULTS[industry]; const finalConfig = { opaUrl: process?.env?.OPA_URL || 'http://localhost:8181', enforcementMode: 'enforce', cacheDecisions: true, cacheTTL: 60000, defaultAllow: false, includeViolationDetails: true, philosophyEnforcement: false, philosophyMinScore: 70, ...industryDefaults, ...config }; const opaClient = axios_1.default.create({ baseURL: finalConfig.opaUrl, timeout: 1000 }); const cache = new Map(); const metrics = { allowed: 0, denied: 0, errors: 0, cached: 0 }; async function buildPolicyInput(req) { const baseInput = { method: req.method, path: req.path, headers: req.headers, query: req.query || {}, body: req.body || {}, user: req.user || {}, service: metadata.serviceName, industry, ip: req.ip, timestamp: new Date().toISOString() }; if (finalConfig.inputBuilder) { const customInput = await finalConfig.inputBuilder(req); return { ...baseInput, ...customInput }; } return baseInput; } function getCacheKey(input) { return JSON.stringify({ method: input.method, path: input.path, userId: input.user?.id, resource: input.resource, action: input.action }); } async function evaluatePolicy(input) { const policyPath = `/v1/data/${metadata.serviceName}/authz`; try { const response = await opaClient.post(policyPath, { input }); const result = response.data?.result || {}; return { allowed: result.allow || false, reasons: result.reasons || [], appliedPolicies: result.applied_policies || [], filteredResponse: result.filtered_response }; } catch (error) { if (error.response?.status === 404 && finalConfig.defaultAllow) { return { allowed: true }; } throw error; } } const middleware = (async (req, res, next) => { if (finalConfig.enforcementMode === 'off') { return next(); } try { const input = await buildPolicyInput(req); let decision; const cacheKey = getCacheKey(input); if (finalConfig.cacheDecisions && cache.has(cacheKey)) { const cached = cache.get(cacheKey); if (cached && cached.expires > Date.now()) { decision = cached.decision; metrics.cached++; } else { cache.delete(cacheKey); decision = await evaluatePolicy(input); } } else { decision = await evaluatePolicy(input); } if (finalConfig.cacheDecisions) { cache.set(cacheKey, { decision, expires: Date.now() + finalConfig.cacheTTL }); } if (this.isEnabled) { Object.entries(decision.headers || {}).forEach(([key, value]) => { res.setHeader(key, value); }); } if (finalConfig.philosophyEnforcement && decision.philosophyScore !== undefined) { res.setHeader('X-Philosophy-Score', String(decision.philosophyScore)); if (decision.philosophyScore < finalConfig.philosophyMinScore) { throw new SDKError('Philosophy goals not met', 'PHILOSOPHY_SCORE_LOW', 503, { currentScore: decision.philosophyScore, requiredScore: finalConfig.philosophyMinScore }); } } if (!decision.allowed) { metrics.denied++; const error = new SDKError('Access denied by policy', 'POLICY_DENIED', 403, finalConfig.includeViolationDetails ? { violations: decision.reasons } : undefined); if (metadata.sdk) { metadata.sdk.recordTelemetry?.({ event: 'policy.denied', properties: { path: req.path, method: req.method, violations: decision.reasons?.length || 0 } }); } throw error; } metrics.allowed++; req.policyDecision = decision; if (decision.filteredResponse) { const originalJson = res.json; res.json = function (data) { return originalJson.call(this, decision.filteredResponse); }; } next(); } catch (error) { metrics.errors++; if (finalConfig.enforcementMode === 'monitor') { console.warn(`[${metadata.serviceName}] Policy error (monitor mode):`, error.message); next(); } else { next(error); } } }); middleware.express = middleware; middleware.fastify = async function (fastify) { fastify.addHook('onRequest', async (request, reply) => { if (finalConfig.enforcementMode === 'off') { return; } try { const input = await buildPolicyInput(request); const decision = await evaluatePolicy(input); if (this.isEnabled) { Object.entries(decision.headers || {}).forEach(([key, value]) => { reply.header(key, value); }); } if (finalConfig.philosophyEnforcement && decision.philosophyScore !== undefined) { reply.header('X-Philosophy-Score', String(decision.philosophyScore)); if (decision.philosophyScore < finalConfig.philosophyMinScore) { reply.code(503).send({ error: { code: 'PHILOSOPHY_SCORE_LOW', message: 'Philosophy goals not met', currentScore: decision.philosophyScore, requiredScore: finalConfig.philosophyMinScore } }); return; } } if (!decision.allowed) { metrics.denied++; reply.code(403).send({ error: { code: 'POLICY_DENIED', message: 'Access denied by policy', violations: finalConfig.includeViolationDetails ? decision.reasons : undefined } }); return; } metrics.allowed++; } catch (error) { metrics.errors++; if (finalConfig.enforcementMode === 'monitor') { console.warn(`[${metadata.serviceName}] Policy error (monitor mode):`, error.message); } else { reply.code(503).send({ error: { code: 'POLICY_ERROR', message: 'Policy evaluation failed' } }); } } }); }; middleware.clearCache = () => { cache.clear(); }; middleware.getMetrics = () => { const total = metrics.allowed + metrics.denied; return { ...metrics, total, allowRate: total > 0 ? (metrics.allowed / total) : 0, denyRate: total > 0 ? (metrics.denied / total) : 0, cacheHitRate: total > 0 ? (metrics.cached / total) : 0 }; }; return middleware; } function createLegacyPolicyMiddleware(config) { console.warn('⚠️ Using legacy policy middleware pattern. Please migrate to new pattern.'); const metadata = { serviceName: 'unknown-service', tribe: config?.tribe, industry: config?.tribe || 'education' }; return createPolicyMiddleware(metadata, config); } exports.policyMiddleware = createPolicyMiddleware; exports.default = createPolicyMiddleware; //# sourceMappingURL=policy-middleware.js.map