secure-gateway-sdk 1.0.1 → 1.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,70 +1,101 @@
1
- # Security Gateway SDK - Proxy Library
1
+ # Secure Gateway SDK - Proxy Library
2
2
 
3
- This package is a drop-in API Gateway library designed to secure and route traffic to a microservice ecosystem containing Auth, Enclave, and Audit endpoints.
3
+ This package is a modular API Gateway router library designed to secure and route traffic to a microservice ecosystem (Auth, Enclave, and Audit endpoints).
4
4
 
5
- It acts exclusively as an Express Middleware router.
5
+ ## 1. Installation
6
6
 
7
- ## How to use this Library
7
+ Install the package via the npm registry:
8
8
 
9
- As a third-party developer (Client), you will include this library inside your own backend express server to instantly spin up the Security Gateway shield over your logic.
9
+ ```bash
10
+ npm install secure-gateway-sdk
11
+ ```
12
+
13
+ ---
14
+
15
+ ## 2. Setup Requirements
16
+
17
+ To use this library, your Node.js/Express application must have:
18
+ * **Express** installed as a peer dependency.
19
+ * **JSON Parsing Middleware** (`express.json()`) mounted before the gateway.
20
+ * An active **JWT Token Secret** to decode and verify client identities.
10
21
 
11
- ### 1. Installation
12
- Ensure you have the gateway folder available in your workspace (or published via NPM if deployed).
22
+ ---
23
+
24
+ ## 3. Integration Code Example
25
+
26
+ Create your gateway server (e.g., `gateway.js`) and mount the middleware as follows:
13
27
 
14
- ### 2. Integration Example (Your main app)
15
28
  ```javascript
16
29
  const express = require('express');
17
- const { SecurityGateway } = require('security-gateway-sdk/proxy');
30
+ const { SecurityGateway } = require('secure-gateway-sdk');
18
31
 
19
32
  const app = express();
20
33
 
21
- // Mount the Security Gateway to any route string (e.g. /api)
34
+ // Required to parse JSON payloads for secure TEE channels
35
+ app.use(express.json());
36
+
37
+ // Initialize and mount the gateway router
22
38
  app.use('/api', SecurityGateway({
23
- jwtSecret: 'process.env.MY_SECRET', // Required: For verifying tokens
24
- authTarget: 'http://<auth-host>:<port>',
25
- enclaveTarget: 'http://<enclave-host>:<port>',
26
- auditTarget: 'http://<audit-host>:<port>'
39
+ jwtSecret: process.env.JWT_SECRET || 'your_secret_signing_key',
40
+ routes: [
41
+ {
42
+ path: '/auth',
43
+ target: 'http://<auth-service-host>:<port>',
44
+ protected: false
45
+ },
46
+ {
47
+ path: '/enclave',
48
+ target: 'http://<enclave-service-host>:<port>',
49
+ protected: true,
50
+ requiredClearance: 'TS',
51
+ useSecureChannel: true,
52
+ mrenclave: 'YOUR_EXPECTED_MRENCLAVE_HASH',
53
+ blsPrivateKey: process.env.BLS_PRIVATE_KEY || 'your_bls_private_key',
54
+ auditUrl: 'http://<audit-service-host>:<port>',
55
+ actionName: 'SECURE_COMPUTE'
56
+ }
57
+ ],
58
+ rbacPolicies: {
59
+ admin: { resources: ['*'], actions: ['*'] },
60
+ user: { resources: ['/enclave'], actions: ['GET'] }
61
+ },
62
+ mlsLattice: {
63
+ 'U': 10,
64
+ 'S': 30,
65
+ 'TS': 40
66
+ }
27
67
  }));
28
68
 
29
- app.listen(3000, () => {
30
- console.log('Main Application running on port 3000');
69
+ const PORT = process.env.PORT || 3000;
70
+ app.listen(PORT, () => {
71
+ console.log(`Security Gateway active on port ${PORT}`);
31
72
  });
32
73
  ```
33
74
 
34
- ### Routing Rules Under the Hood
35
- Once mounted (for example at `/api`), the library automatically protects traffic:
36
- * `POST /api/auth/register` -> Publicly proxies to `authTarget`
37
- * `GET /api/enclave/data` -> Instantly intercepted! Extracts JWT, validates against `jwtSecret`, and passes to `enclaveTarget` only if valid.
38
-
39
75
  ---
40
76
 
41
- ## Testing (cURL Examples)
42
-
43
- Since we mounted the `SecurityGateway` directly into the Auth service, the Gateway is currently running actively on `http://localhost:7001/api`. You can use these commands to test the integration:
44
-
45
- ### 1. Register a new user (Public Route)
46
- ```bash
47
- curl -X POST http://localhost:7001/api/auth/register \
48
- -H "Content-Type: application/json" \
49
- -d '{"username": "test_user", "password": "password123", "role": "admin"}'
50
- ```
51
-
52
- ### 2. Login to get a JWT Token (Public Route)
53
- ```bash
54
- curl -X POST http://localhost:7001/api/auth/login \
55
- -H "Content-Type: application/json" \
56
- -d '{"username": "test_user", "password": "password123"}'
57
- ```
58
-
59
- ### 3. Access the Enclave (Protected Route - Success)
60
- Replace `<YOUR_TOKEN>` with the token string received from the login command.
61
- ```bash
62
- curl -X GET http://localhost:7001/api/enclave \
63
- -H "Authorization: Bearer <YOUR_TOKEN>"
64
- ```
65
-
66
- ### 4. Access the Enclave (Protected Route - Failure)
67
- If you try to access the enclave without attaching the token header, the SDK will proactively block you.
68
- ```bash
69
- curl -X GET http://localhost:7001/api/enclave
70
- ```
77
+ ## 4. Configuration Reference
78
+
79
+ ### SecurityGateway Options
80
+
81
+ | Property | Type | Required | Description |
82
+ | :--- | :--- | :--- | :--- |
83
+ | `jwtSecret` | String | Yes | Secret key used to verify client JWT signatures. |
84
+ | `routes` | Array | Yes | List of route definitions to protect and proxy. |
85
+ | `rbacPolicies` | Object | No | Map of roles to allowed resources and request methods. |
86
+ | `mlsLattice` | Object | No | Clearance level hierarchy definitions (e.g., `U`, `S`, `TS`). |
87
+ | `rateLimit` | Object | No | Custom intervals and maximum requests for the rate limiters. |
88
+
89
+ ### Route Object Schema
90
+
91
+ | Property | Type | Required | Description |
92
+ | :--- | :--- | :--- | :--- |
93
+ | `path` | String | Yes | Route mount path (e.g., `/enclave`). |
94
+ | `target` | String | Yes | Microservice downstream target URL. |
95
+ | `protected` | Boolean | Yes | Whether requests require JWT authentication and RBAC validation. |
96
+ | `requiredClearance`| String | No | Level needed to pass Bell-LaPadula clearance validation. |
97
+ | `useSecureChannel` | Boolean | No | Toggles automated TEE Handshake (ECDH key exchange). |
98
+ | `mrenclave` | String | No | Expected hardware enclave hash identity. |
99
+ | `blsPrivateKey` | String | No | Private key used to sign transaction aggregate proofs. |
100
+ | `auditUrl` | String | No | Endpoint of the centralized Cryptographic Audit Log Service. |
101
+ | `actionName` | String | No | Identifier label for the audited action type. |
package/index.js CHANGED
@@ -1,7 +1,10 @@
1
1
  const express = require('express');
2
+ const fetch = require('node-fetch');
2
3
  const { createProxyMiddleware } = require('http-proxy-middleware');
3
4
  const { createSecurityMiddleware } = require('./middleware/security');
4
5
  const { createMLSMiddleware } = require('./middleware/mls');
6
+ const { createRBACMiddleware } = require('./middleware/rbac');
7
+ const { createGlobalRateLimit, createAuthRateLimit, createSensitiveRateLimit } = require('./middleware/rateLimit');
5
8
 
6
9
  /**
7
10
  * Universal Security Gateway Library (Publishable SDK)
@@ -13,25 +16,49 @@ function SecurityGateway(options) {
13
16
  throw new Error('[SecurityGateway] Fatal: "jwtSecret" must be provided in configuration options.');
14
17
  }
15
18
 
19
+ // --- Availability: Rate Limiting & DDoS Protection ---
20
+ const globalLimiter = createGlobalRateLimit(options.rateLimit?.global);
21
+ const authLimiter = createAuthRateLimit(options.rateLimit?.auth);
22
+ const sensitiveLimiter = createSensitiveRateLimit(options.rateLimit?.sensitive);
23
+
24
+ // Apply global rate limit to ALL requests through the gateway
25
+ router.use(globalLimiter);
26
+ console.log('[SecurityGateway] DDoS Protection: Global rate limiter active');
27
+
16
28
  const verifyToken = createSecurityMiddleware(options.jwtSecret);
29
+ const rbacMiddleware = createRBACMiddleware(options.rbacPolicies);
30
+ const enclaveClients = new Map(); // Cache to maintain persistent secure sessions
31
+ const blsAuditInstances = new Map(); // Cache to maintain aggregate signatures per route
17
32
 
18
33
  if (options.routes && Array.isArray(options.routes)) {
19
34
  options.routes.forEach(route => {
20
35
  const middlewares = [];
21
36
 
22
37
  if (route.protected) {
38
+ // Stricter rate limit on sensitive/protected endpoints
39
+ middlewares.push(sensitiveLimiter);
23
40
  middlewares.push(verifyToken);
41
+ middlewares.push(rbacMiddleware);
24
42
  if (route.requiredClearance) {
25
- middlewares.push(createMLSMiddleware(route.requiredClearance));
43
+ middlewares.push(createMLSMiddleware(route.requiredClearance, options.mlsLattice));
26
44
  }
27
45
  }
28
46
 
29
47
  if (route.useSecureChannel) {
30
48
  const EnclaveClient = require('./lib/enclave-client');
31
- // Security params are now pulled directly from the ROUTE config!
32
- const enclaveClient = new EnclaveClient(route.target, route.mrenclave);
33
49
  const BLSAuditSim = require('./lib/bls');
34
- const blsAudit = new BLSAuditSim(route.blsPrivateKey);
50
+
51
+ // Get or Create a persistent client for this specific target
52
+ if (!enclaveClients.has(route.target)) {
53
+ enclaveClients.set(route.target, new EnclaveClient(route.target, route.mrenclave));
54
+ }
55
+ const enclaveClient = enclaveClients.get(route.target);
56
+
57
+ // Get or Create a persistent BLS instance to maintain aggregate signatures
58
+ if (!blsAuditInstances.has(route.path)) {
59
+ blsAuditInstances.set(route.path, new BLSAuditSim(route.blsPrivateKey));
60
+ }
61
+ const blsAudit = blsAuditInstances.get(route.path);
35
62
 
36
63
  middlewares.push(express.json());
37
64
  middlewares.push(async (req, res) => {
@@ -68,6 +95,8 @@ function SecurityGateway(options) {
68
95
  }
69
96
  });
70
97
  } else {
98
+ // Auth endpoints get brute-force protection
99
+ middlewares.push(authLimiter);
71
100
  const proxyConfig = {
72
101
  target: route.target,
73
102
  changeOrigin: true
@@ -90,5 +119,8 @@ module.exports = {
90
119
  SecurityGateway,
91
120
  createSecurityMiddleware,
92
121
  createMLSMiddleware,
93
- SecureChannel
122
+ SecureChannel,
123
+ createGlobalRateLimit,
124
+ createAuthRateLimit,
125
+ createSensitiveRateLimit
94
126
  };
@@ -1,5 +1,6 @@
1
1
  const { SecureChannel } = require('./crypto');
2
2
  const crypto = require('crypto');
3
+ const fetch = require('node-fetch');
3
4
 
4
5
  /**
5
6
  * EnclaveClient acts as the secure intermediary between the Proxy and the TEE.
@@ -46,33 +47,73 @@ class EnclaveClient {
46
47
  console.log('[Proxy->Enclave] Attestation successful. ECDH secure channel established.');
47
48
  }
48
49
 
50
+ async seal(payload, label, token) {
51
+ if (!this.isAttested) await this.attestAndHandshake();
52
+ const encrypted = this.channel.encrypt(payload);
53
+ const response = await fetch(`${this.enclaveUrl}/seal`, {
54
+ method: 'POST',
55
+ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
56
+ body: JSON.stringify({ ...encrypted, label })
57
+ });
58
+ return response.json();
59
+ }
60
+
61
+ async unseal(label, token) {
62
+ if (!this.isAttested) await this.attestAndHandshake();
63
+ const response = await fetch(`${this.enclaveUrl}/unseal`, {
64
+ method: 'POST',
65
+ headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
66
+ body: JSON.stringify({ label })
67
+ });
68
+ const data = await response.json();
69
+ if (!response.ok) throw new Error(data.error || 'Unseal failed');
70
+ return this.channel.decrypt(data);
71
+ }
72
+
49
73
  async execute(payload, token) {
50
74
  // If we haven't verified the enclave yet, do it now
51
75
  if (!this.isAttested) {
52
76
  await this.attestAndHandshake();
53
77
  }
54
78
 
55
- // Encrypt the payload using AES-256-GCM
56
- const encrypted = this.channel.encrypt(payload);
57
-
58
- // Send to Enclave
59
- const response = await fetch(`${this.enclaveUrl}/execute`, {
60
- method: 'POST',
61
- headers: {
62
- 'Content-Type': 'application/json',
63
- 'Authorization': `Bearer ${token}` // Pass the user's JWT to prove they passed proxy auth
64
- },
65
- body: JSON.stringify(encrypted)
66
- });
79
+ try {
80
+ // Encrypt the payload using AES-256-GCM
81
+ const encrypted = this.channel.encrypt(payload);
82
+
83
+ // Send to Enclave
84
+ const response = await fetch(`${this.enclaveUrl}/execute`, {
85
+ method: 'POST',
86
+ headers: {
87
+ 'Content-Type': 'application/json',
88
+ 'Authorization': `Bearer ${token}`
89
+ },
90
+ body: JSON.stringify(encrypted)
91
+ });
67
92
 
68
- const data = await response.json();
69
-
70
- if (!response.ok) {
71
- throw new Error(data.error || 'Execution failed');
72
- }
93
+ const data = await response.json();
94
+
95
+ if (!response.ok) {
96
+ // AUTO-RETRY LOGIC: If enclave restarted, re-attest once
97
+ if (data.error && data.error.includes("Shared secret not computed")) {
98
+ console.warn('[Proxy] Enclave session lost. Re-attesting and retrying...');
99
+ this.isAttested = false;
100
+ await this.attestAndHandshake();
101
+ return this.execute(payload, token); // Recursive retry
102
+ }
103
+ throw new Error(data.error || 'Execution failed');
104
+ }
73
105
 
74
- // Decrypt the response
75
- return this.channel.decrypt(data);
106
+ // Decrypt the response
107
+ return this.channel.decrypt(data);
108
+ } catch (error) {
109
+ // If encryption failed because secret was somehow null (concurrency), retry
110
+ if (error.message.includes("not computed")) {
111
+ this.isAttested = false;
112
+ await this.attestAndHandshake();
113
+ return this.execute(payload, token);
114
+ }
115
+ throw error;
116
+ }
76
117
  }
77
118
  }
78
119
 
package/middleware/mls.js CHANGED
@@ -3,15 +3,16 @@
3
3
  * Implements Bell-LaPadula Lattice logic for the SDK.
4
4
  */
5
5
 
6
- const LATTICE = {
6
+ const DEFAULT_LATTICE = {
7
7
  'U': 10, // Unclassified
8
8
  'C': 20, // Confidential
9
9
  'S': 30, // Secret
10
10
  'TS': 40 // Top Secret
11
11
  };
12
12
 
13
- function createMLSMiddleware(routeRequiredClearance) {
14
- const routeLevel = LATTICE[routeRequiredClearance?.toUpperCase()];
13
+ function createMLSMiddleware(routeRequiredClearance, customLattice) {
14
+ const lattice = customLattice || DEFAULT_LATTICE;
15
+ const routeLevel = lattice[routeRequiredClearance?.toUpperCase()];
15
16
 
16
17
  if (!routeLevel) {
17
18
  throw new Error(`[MLS Engine] Fatal: Invalid clearance level provided: ${routeRequiredClearance}. Must be U, C, S, or TS.`);
@@ -24,12 +25,16 @@ function createMLSMiddleware(routeRequiredClearance) {
24
25
  return res.status(403).json({ error: 'MLS Blocked: User clearance level is not defined.' });
25
26
  }
26
27
 
27
- const userLevel = LATTICE[req.user.clearance.toUpperCase()];
28
+ const userLevel = lattice[req.user.clearance.toUpperCase()];
28
29
  if (!userLevel) {
29
30
  return res.status(403).json({ error: `MLS Blocked: Unknown user clearance header '${req.user.clearance}'` });
30
31
  }
31
32
 
32
- const isRead = ['GET', 'HEAD', 'OPTIONS'].includes(req.method);
33
+ // Secure execution or TEE retrieval endpoints are functionally reads (requesting sensitive output)
34
+ const isRead = ['GET', 'HEAD', 'OPTIONS'].includes(req.method) ||
35
+ req.path.includes('/enclave') ||
36
+ req.path.includes('/execute') ||
37
+ req.path.includes('/unseal');
33
38
  const isWrite = ['POST', 'PUT', 'PATCH', 'DELETE'].includes(req.method);
34
39
 
35
40
  // ----------------------------------------------------
@@ -0,0 +1,108 @@
1
+ const rateLimit = require('express-rate-limit');
2
+
3
+ /**
4
+ * Rate Limiting & DDoS Protection Middleware
5
+ *
6
+ * Provides the Availability property of the CIA triad by preventing
7
+ * resource exhaustion through excessive requests.
8
+ *
9
+ * Three tiers of protection:
10
+ * 1. Global rate limit — caps total requests per IP
11
+ * 2. Auth rate limit — stricter limit on login/register (brute-force protection)
12
+ * 3. Sensitive route rate limit — strictest limit on protected endpoints
13
+ */
14
+
15
+ const isDev = process.env.NODE_ENV === 'development';
16
+
17
+ /**
18
+ * Creates a global rate limiter for all gateway traffic.
19
+ * Default: 100 requests per 15 minutes per IP.
20
+ * In development, window is 15 seconds to allow fast simulator resets.
21
+ */
22
+ function createGlobalRateLimit(options = {}) {
23
+ const windowMs = process.env.RATE_LIMIT_GLOBAL_WINDOW_MS
24
+ ? parseInt(process.env.RATE_LIMIT_GLOBAL_WINDOW_MS)
25
+ : (options.windowMs || (isDev ? 15 * 1000 : 15 * 60 * 1000));
26
+ const max = process.env.RATE_LIMIT_GLOBAL_MAX
27
+ ? parseInt(process.env.RATE_LIMIT_GLOBAL_MAX)
28
+ : (options.max || 100);
29
+
30
+ return rateLimit({
31
+ windowMs,
32
+ max,
33
+ standardHeaders: true, // Return rate limit info in headers
34
+ legacyHeaders: false,
35
+ message: {
36
+ error: 'Too many requests from this IP. Please try again later.',
37
+ retryAfterMs: windowMs
38
+ },
39
+ handler: (req, res, next, options) => {
40
+ console.warn(`[DDoS Protection] Global rate limit exceeded for IP: ${req.ip}`);
41
+ res.status(429).json(options.message);
42
+ }
43
+ });
44
+ }
45
+
46
+ /**
47
+ * Creates a strict rate limiter for authentication endpoints.
48
+ * Default: 10 requests per 15 minutes per IP (brute-force protection).
49
+ * In development, window is 15 seconds to allow fast simulator resets.
50
+ */
51
+ function createAuthRateLimit(options = {}) {
52
+ const windowMs = process.env.RATE_LIMIT_AUTH_WINDOW_MS
53
+ ? parseInt(process.env.RATE_LIMIT_AUTH_WINDOW_MS)
54
+ : (options.windowMs || (isDev ? 15 * 1000 : 15 * 60 * 1000));
55
+ const max = process.env.RATE_LIMIT_AUTH_MAX
56
+ ? parseInt(process.env.RATE_LIMIT_AUTH_MAX)
57
+ : (options.max || 10);
58
+
59
+ return rateLimit({
60
+ windowMs,
61
+ max,
62
+ standardHeaders: true,
63
+ legacyHeaders: false,
64
+ message: {
65
+ error: 'Too many authentication attempts. Account protection triggered.',
66
+ retryAfterMs: windowMs
67
+ },
68
+ handler: (req, res, next, options) => {
69
+ console.warn(`[DDoS Protection] Auth rate limit exceeded for IP: ${req.ip} on ${req.path}`);
70
+ res.status(429).json(options.message);
71
+ }
72
+ });
73
+ }
74
+
75
+ /**
76
+ * Creates a strict rate limiter for sensitive/protected routes (e.g., Enclave access).
77
+ * Default: 20 requests per 15 minutes per IP.
78
+ * In development, window is 15 seconds and max is 10 to guarantee simulator triggers and resets.
79
+ */
80
+ function createSensitiveRateLimit(options = {}) {
81
+ const windowMs = process.env.RATE_LIMIT_SENSITIVE_WINDOW_MS
82
+ ? parseInt(process.env.RATE_LIMIT_SENSITIVE_WINDOW_MS)
83
+ : (options.windowMs || (isDev ? 15 * 1000 : 15 * 60 * 1000));
84
+ const max = process.env.RATE_LIMIT_SENSITIVE_MAX
85
+ ? parseInt(process.env.RATE_LIMIT_SENSITIVE_MAX)
86
+ : (options.max || (isDev ? 10 : 20));
87
+
88
+ return rateLimit({
89
+ windowMs,
90
+ max,
91
+ standardHeaders: true,
92
+ legacyHeaders: false,
93
+ message: {
94
+ error: 'Too many requests to protected resource. Access temporarily restricted.',
95
+ retryAfterMs: windowMs
96
+ },
97
+ handler: (req, res, next, options) => {
98
+ console.warn(`[DDoS Protection] Sensitive route rate limit exceeded for IP: ${req.ip}`);
99
+ res.status(429).json(options.message);
100
+ }
101
+ });
102
+ }
103
+
104
+ module.exports = {
105
+ createGlobalRateLimit,
106
+ createAuthRateLimit,
107
+ createSensitiveRateLimit
108
+ };
@@ -0,0 +1,54 @@
1
+ /**
2
+ * RBAC Engine (Role-Based Access Control)
3
+ * Enforces policies provided at initialization.
4
+ */
5
+
6
+ function createRBACMiddleware(policies) {
7
+ if (!policies) {
8
+ console.warn('[RBAC Engine] Warning: No policies provided. All access will be denied.');
9
+ }
10
+
11
+ return (req, res, next) => {
12
+ // verifyToken MUST run before this middleware so req.user exists
13
+ if (!req.user || !req.user.role) {
14
+ console.error('[RBAC Engine] Missing role from JWT Payload!');
15
+ return res.status(403).json({ error: 'RBAC Blocked: User role is not defined.' });
16
+ }
17
+
18
+ const userRole = req.user.role.toLowerCase();
19
+ const policy = policies ? policies[userRole] : null;
20
+
21
+ if (!policy) {
22
+ return res.status(403).json({ error: `RBAC Blocked: No policy defined for role '${userRole}'` });
23
+ }
24
+
25
+ const { resources, actions } = policy;
26
+ const requestPath = req.path;
27
+ const requestMethod = req.method.toUpperCase();
28
+
29
+ // 1. Check Action Permission
30
+ if (!actions.includes('*') && !actions.includes(requestMethod)) {
31
+ console.warn(`[RBAC] Blocked Action: Role(${userRole}) cannot perform ${requestMethod}`);
32
+ return res.status(403).json({ error: `RBAC Violation: Your role (${userRole}) is not permitted to perform ${requestMethod} operations.` });
33
+ }
34
+
35
+ // 2. Check Resource Permission (Simple glob-like matching)
36
+ const hasAccess = resources.some(pattern => {
37
+ if (pattern === '*') return true;
38
+ const regex = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$');
39
+ return regex.test(requestPath);
40
+ });
41
+
42
+ if (!hasAccess) {
43
+ console.warn(`[RBAC] Blocked Resource: Role(${userRole}) cannot access ${requestPath}`);
44
+ return res.status(403).json({ error: `RBAC Violation: Your role (${userRole}) does not have access to the resource ${requestPath}.` });
45
+ }
46
+
47
+ console.log(`[RBAC Engine] Passed policy checks for user ${req.user.sub} (Role: ${userRole})`);
48
+ next();
49
+ };
50
+ }
51
+
52
+ module.exports = {
53
+ createRBACMiddleware
54
+ };
package/package.json CHANGED
@@ -1,15 +1,17 @@
1
1
  {
2
2
  "name": "secure-gateway-sdk",
3
- "version": "1.0.1",
3
+ "version": "1.2.1",
4
4
  "scripts": {
5
- "dev": "node server.js"
5
+ "dev": "nodemon server.js"
6
6
  },
7
7
  "dependencies": {
8
8
  "cors": "^2.8.6",
9
9
  "dotenv": "^16.6.1",
10
10
  "express": "^5.2.1",
11
+ "express-rate-limit": "^8.5.2",
11
12
  "http-proxy-middleware": "^3.0.5",
12
- "jsonwebtoken": "^9.0.3"
13
+ "jsonwebtoken": "^9.0.3",
14
+ "node-fetch": "^2.7.0"
13
15
  },
14
16
  "description": "This package is a drop-in API Gateway library designed to secure and route traffic to a microservice ecosystem containing Auth, Enclave, and Audit endpoints.",
15
17
  "main": "index.js",
package/server.js CHANGED
@@ -1,20 +1,69 @@
1
- require('dotenv').config({ path: '../.env' });
1
+ const dotenv = require('dotenv');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+
5
+ // Robust workspace-aware dotenv loading
6
+ if (fs.existsSync(path.join(process.cwd(), '.env'))) {
7
+ dotenv.config({ path: path.join(process.cwd(), '.env') });
8
+ } else if (fs.existsSync(path.join(process.cwd(), '..', '.env'))) {
9
+ dotenv.config({ path: path.join(process.cwd(), '..', '.env') });
10
+ } else {
11
+ dotenv.config();
12
+ }
2
13
  const express = require('express');
14
+ const cors = require('cors');
3
15
  const { SecurityGateway } = require('./index');
4
16
 
5
17
  const app = express();
18
+ app.use(cors());
19
+
6
20
  const PORT = process.env.PROXY_PORT || 3000;
7
21
 
8
- const gatewayRoutes = require('../config/gateway-routes.json');
22
+ /**
23
+ * PROJECT-AGNOSTIC CONFIG LOADER
24
+ * The proxy no longer reaches out to '../config'.
25
+ * It looks for a 'gateway-config.json' in the current working directory
26
+ * or a path specified by GATEWAY_CONFIG_PATH.
27
+ */
28
+ let configPath = process.env.GATEWAY_CONFIG_PATH
29
+ ? path.resolve(process.env.GATEWAY_CONFIG_PATH)
30
+ : path.join(process.cwd(), 'gateway-config.json');
31
+
32
+ // Robust fallback: check parent directory if not found in current working directory
33
+ if (!fs.existsSync(configPath)) {
34
+ const parentConfigPath = path.join(process.cwd(), '..', 'gateway-config.json');
35
+ if (fs.existsSync(parentConfigPath)) {
36
+ configPath = parentConfigPath;
37
+ }
38
+ }
39
+
40
+ let gatewayConfig = { routes: [], rbacPolicies: {}, mlsLattice: {} };
41
+
42
+ if (fs.existsSync(configPath)) {
43
+ try {
44
+ gatewayConfig = JSON.parse(fs.readFileSync(configPath, 'utf8'));
45
+ console.log(`[Proxy] Configuration loaded from: ${configPath}`);
46
+ } catch (err) {
47
+ console.error(`[Proxy] Failed to parse config at ${configPath}:`, err.message);
48
+ }
49
+ } else {
50
+ console.warn(`[Proxy] Warning: No config file found at ${configPath}. Using defaults.`);
51
+ }
9
52
 
10
- // Initialize the Security Gateway as a standalone server
53
+ // Initialize the Security Gateway using the injected configuration
11
54
  app.use('/api', SecurityGateway({
12
- jwtSecret: process.env.JWT_SECRET,
13
- routes: gatewayRoutes
55
+ jwtSecret: process.env.JWT_SECRET || 'fallback_secret',
56
+ routes: gatewayConfig.routes || [],
57
+ rbacPolicies: gatewayConfig.rbacPolicies || {},
58
+ mlsLattice: gatewayConfig.mlsLattice || {}
14
59
  }));
15
60
 
16
61
  app.get('/', (req, res) => {
17
- res.json({ message: 'Security Gateway Standalone Server is running.' });
62
+ res.json({
63
+ message: 'Security Gateway Standalone Server is running.',
64
+ config_source: configPath,
65
+ active_routes: (gatewayConfig.routes || []).length
66
+ });
18
67
  });
19
68
 
20
69
  app.listen(PORT, () => {