aip-master-node-sumit 1.0.2 → 1.0.6

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.
Files changed (2) hide show
  1. package/index.js +83 -14
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -1,24 +1,32 @@
1
1
  const axios = require('axios');
2
- const AIP_MASTER_API = process.env.AIP_MASTER_URL || 'http://localhost:8080/api/v1';
3
- const API_KEY = process.env.AIP_MASTER_API_KEY;
4
2
 
5
- // 🛡️ The Heartbeat System.
6
- // This continuously pings the Go Server every 5 minutes
7
- // to keep the dashboard "Live" without needing to restart the Express server!
3
+ // 🛡️ THE FIX: Smart URL Cleaner ensures the base API URL is exactly right
4
+ const getSafeMasterUrl = (url) => {
5
+ if (!url) return 'http://localhost:8080/api/v1';
6
+ let clean = url.replace(/\/+$/, '');
7
+ if (clean.endsWith('/iam')) {
8
+ clean = clean.substring(0, clean.length - 4);
9
+ }
10
+ return clean;
11
+ };
12
+
13
+ const AIP_MASTER_API = getSafeMasterUrl(process.env.AIP_MASTER_URL);
14
+ const API_KEY = process.env.AIP_MASTER_API_KEY;
15
+
8
16
  if (API_KEY) {
9
17
  const sendHeartbeat = async () => {
10
18
  try {
11
19
  await axios.post(`${AIP_MASTER_API}/iam/ping`, { module: 'middleware' }, {
12
20
  headers: { 'Authorization': `Bearer ${API_KEY}` },
13
- timeout: 5000 // Prevent hanging if master is slow
21
+ timeout: 5000
14
22
  });
15
23
  } catch (err) {
16
24
  // Silently fail so the client's app doesn't crash if Master API is updating
17
25
  }
18
26
  };
19
27
 
20
- sendHeartbeat(); // Fire immediately on server startup
21
- setInterval(sendHeartbeat, 5 * 60 * 1000); // Fire every 5 minutes forever
28
+ sendHeartbeat();
29
+ setInterval(sendHeartbeat, 5 * 60 * 1000);
22
30
  }
23
31
 
24
32
  const aipGuard = (options = { requireLogin: true }) => {
@@ -26,6 +34,7 @@ const aipGuard = (options = { requireLogin: true }) => {
26
34
 
27
35
  // LAYER 1: INFRASTRUCTURE SHIELD
28
36
  const MAX_PAYLOAD_BYTES = 2 * 1024 * 1024;
37
+
29
38
  if (req.headers['transfer-encoding'] && req.headers['transfer-encoding'].includes('chunked')) {
30
39
  return res.status(411).send("AIP Infrastructure Shield: Chunked encoding rejected.");
31
40
  }
@@ -39,8 +48,8 @@ const aipGuard = (options = { requireLogin: true }) => {
39
48
  res.setHeader('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
40
49
  res.setHeader('Access-Control-Allow-Origin', process.env.AIP_ALLOWED_ORIGIN || '*');
41
50
 
42
- // Robust Token Extraction (Checks query, cookies, and Authorization headers)
43
51
  let token = req.query.token || (req.cookies && req.cookies.aip_session);
52
+
44
53
  if (!token && req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
45
54
  token = req.headers.authorization.split(' ')[1];
46
55
  } else if (!token && req.headers['x-aip-token']) {
@@ -50,22 +59,24 @@ const aipGuard = (options = { requireLogin: true }) => {
50
59
  // LAYER 2: IDENTITY CHECK & RBAC
51
60
  if (options.requireLogin) {
52
61
  if (!token) return res.status(401).send("Unauthorized: Missing AIP Session Token");
62
+
53
63
  try {
54
64
  const currentAction = req.method + " " + (req.baseUrl + req.path);
65
+
55
66
  const authRes = await axios.post(`${AIP_MASTER_API}/iam/verify-session`,
56
67
  { session_token: token, action: currentAction },
57
68
  { headers: { 'Authorization': `Bearer ${API_KEY}` } }
58
69
  );
70
+
59
71
  req.user = authRes.data.user;
60
72
 
61
73
  const isProd = process.env.NODE_ENV === 'production';
62
74
  res.cookie('aip_session', token, { httpOnly: true, secure: isProd });
75
+
63
76
  } catch (error) {
64
77
  const status = error.response?.status || 500;
65
78
  const errMsg = error.response?.data?.error || "AIP Identity Blocked: Invalid Token.";
66
-
67
- // 🛡️ CRITICAL FIX: Only clear the session cookie if the token is actually dead (401).
68
- // If it is an RBAC block (403), we just deny the action but keep them logged in!
79
+
69
80
  if (status === 401 && res.clearCookie) {
70
81
  res.clearCookie('aip_session');
71
82
  }
@@ -80,8 +91,10 @@ const aipGuard = (options = { requireLogin: true }) => {
80
91
  body: req.body || {},
81
92
  query: req.query || {}
82
93
  });
94
+
83
95
  const forwardedFor = req.headers['x-forwarded-for'];
84
96
  let clientIp = req.ip || (req.connection && req.connection.remoteAddress) || "0.0.0.0";
97
+
85
98
  if (forwardedFor) {
86
99
  clientIp = Array.isArray(forwardedFor)
87
100
  ? forwardedFor[0].trim()
@@ -96,9 +109,9 @@ const aipGuard = (options = { requireLogin: true }) => {
96
109
  payload: payloadData,
97
110
  origin: req.headers.origin || "",
98
111
  user_agent: req.headers['user-agent'] || "",
99
- session_token: token || "" // Explicitly forwarding the token to the Master WAF
112
+ session_token: token || ""
100
113
  });
101
-
114
+
102
115
  if (wafRes.data.action === "block") {
103
116
  return res.status(403).send(`AIP Firewall Blocked Request: ${wafRes.data.reason}`);
104
117
  }
@@ -112,4 +125,60 @@ const aipGuard = (options = { requireLogin: true }) => {
112
125
  };
113
126
  };
114
127
 
128
+ // ==========================================
129
+ // 🛡️ NEW: IaaS Admin Client SDK
130
+ // ==========================================
131
+ class AipAdminClient {
132
+ constructor(apiKey = process.env.AIP_MASTER_API_KEY, masterUrl = process.env.AIP_MASTER_URL) {
133
+ if (!apiKey) throw new Error("AIP Admin Client requires an API Key");
134
+ this.apiKey = apiKey;
135
+ this.baseUrl = getSafeMasterUrl(masterUrl);
136
+
137
+ this.client = axios.create({
138
+ baseURL: this.baseUrl,
139
+ headers: { 'Authorization': `Bearer ${this.apiKey}` }
140
+ });
141
+ }
142
+
143
+ // --- User Management ---
144
+ async getUsers() {
145
+ const res = await this.client.get('/sdk/admin/users');
146
+ return res.data;
147
+ }
148
+
149
+ async createUser({ name, email, password, role_id, send_email = false }) {
150
+ const res = await this.client.post('/sdk/admin/users', { name, email, password, role_id, send_email });
151
+ return res.data;
152
+ }
153
+
154
+ async updateUser(userId, { name, role_id }) {
155
+ const res = await this.client.put(`/sdk/admin/users/${userId}`, { name, role_id });
156
+ return res.data;
157
+ }
158
+
159
+ async updateRBAC(userId, permissions) {
160
+ const res = await this.client.put(`/sdk/admin/users/${userId}/rbac`, { permissions });
161
+ return res.data;
162
+ }
163
+
164
+ async deleteUser(userId) {
165
+ const res = await this.client.delete(`/sdk/admin/users/${userId}`);
166
+ return res.data;
167
+ }
168
+
169
+ // --- Role Management ---
170
+ async getRoles() {
171
+ const res = await this.client.get('/sdk/admin/roles');
172
+ return res.data;
173
+ }
174
+
175
+ async createRole({ name, slug, permissions }) {
176
+ const res = await this.client.post('/sdk/admin/roles', { name, slug, permissions });
177
+ return res.data;
178
+ }
179
+ }
180
+
181
+ // 🛡️ Attach the Admin Client directly to the Guard export for backward compatibility
182
+ aipGuard.AipAdminClient = AipAdminClient;
183
+
115
184
  module.exports = aipGuard;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aip-master-node-sumit",
3
- "version": "1.0.2",
3
+ "version": "1.0.6",
4
4
  "description": "Enterprise-grade WAF and IAM security middleware for Node.js.",
5
5
  "main": "index.js",
6
6
  "scripts": {