@meru2802/aux-server 1.0.16 → 1.0.19

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.
@@ -9,274 +9,127 @@ class CoreController extends BaseController_1.BaseController {
9
9
  super(serviceContainer);
10
10
  this.getDownloadLink = async (req, res) => {
11
11
  try {
12
- const deviceGroupName = req.body.deviceGroupName;
13
- const deviceGroupId = req.body.deviceGroupId;
12
+ const { deviceGroupName, deviceGroupId } = req.body;
14
13
  if (deviceGroupId) {
15
- const inviteEncryptionKey = (0, utils_1.getBinaryKey)(this.config.meshcentralConfig.inviteEncryptionKey);
16
- const meshcookie = (0, utils_1.encodeCookie)({ m: deviceGroupId.split("/")[2] }, inviteEncryptionKey);
17
- const downloadLink = `https://${this.config.meshcentralConfig.server}/meshagents?id=10006&meshid=${meshcookie}&ac=02`;
18
- const response = {
19
- download_link: downloadLink,
20
- timestamp: new Date().toISOString(),
21
- };
22
- res.status(200).json(response);
14
+ const downloadLink = this.buildDownloadLink(deviceGroupId.split("/")[2]);
15
+ res.status(200).json(this.buildDownloadLinkResponse(downloadLink));
23
16
  return;
24
17
  }
25
18
  if (!deviceGroupName) {
26
- const errorResponse = {
27
- error: "'deviceGroupName' body param is required",
28
- timestamp: new Date().toISOString(),
29
- };
30
- res.status(400).json(errorResponse);
19
+ this.sendErrorResponse(res, 400, "'deviceGroupName' body param is required");
31
20
  return;
32
21
  }
22
+ if (!this.ensureWebSocket(res))
23
+ return;
33
24
  const meshesMessageSent = this.WebSocketService.sendMessage({
34
25
  action: "meshes",
35
26
  responseid: "meshctrl",
36
27
  });
37
- if (!meshesMessageSent) {
38
- const errorResponse = {
39
- error: "Could Not Send Message Over Socket",
40
- timestamp: new Date().toISOString(),
41
- };
42
- res.status(500).json(errorResponse);
43
- return;
44
- }
45
- if (!this.webSocket) {
46
- const errorResponse = {
47
- error: "Socket Not Found",
48
- timestamp: new Date().toISOString(),
49
- };
50
- res.status(500).json(errorResponse);
28
+ if (!this.ensureMessageSent(res, meshesMessageSent))
51
29
  return;
52
- }
53
- const waitForMeshResponse = new Promise((resolve, reject) => {
54
- let responseReceived = false;
55
- // Wait 60 second for ws message to arive
56
- const timeout = setTimeout(() => {
57
- if (!responseReceived) {
58
- responseReceived = true;
59
- reject(new Error("Timeout waiting for mesh response"));
60
- }
61
- }, 60000);
62
- const messageHandler = (data) => {
63
- var _a, _b;
64
- if (responseReceived)
65
- return;
66
- try {
67
- const message = JSON.parse(data.toString());
68
- if (message.action === types_1.MeshActions.MESH_ES) {
69
- responseReceived = true;
70
- clearTimeout(timeout);
71
- (_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.removeListener("message", messageHandler);
72
- const meshesMessasge = message;
73
- const mesh = meshesMessasge.meshes.find((mesh) => mesh.name == deviceGroupName);
74
- if (!mesh) {
75
- reject(new Error("Mesh Not Found"));
76
- return;
77
- }
78
- const inviteEncryptionKey = (0, utils_1.getBinaryKey)(this.config.meshcentralConfig.inviteEncryptionKey);
79
- const meshcookie = (0, utils_1.encodeCookie)({ m: mesh._id.split("/")[2] }, inviteEncryptionKey);
80
- const downloadLink = `https://${this.config.meshcentralConfig.server}/meshagents?id=10006&meshid=${meshcookie}&ac=02`;
81
- const response = {
82
- download_link: downloadLink,
83
- timestamp: new Date().toISOString(),
84
- };
85
- resolve(response);
86
- }
30
+ try {
31
+ const response = await this.waitForWebSocketResponse(60000, (message, resolve, reject) => {
32
+ if (message.action !== types_1.MeshActions.MESH_ES) {
33
+ return false;
87
34
  }
88
- catch (parseError) {
89
- if (!responseReceived) {
90
- responseReceived = true;
91
- clearTimeout(timeout);
92
- (_b = this.webSocket) === null || _b === void 0 ? void 0 : _b.removeListener("message", messageHandler);
93
- reject(parseError);
94
- }
35
+ const meshesMessage = message;
36
+ const mesh = meshesMessage.meshes.find((m) => m.name === deviceGroupName);
37
+ if (!mesh) {
38
+ reject(new Error("Mesh Not Found"));
39
+ return true;
95
40
  }
96
- };
97
- this.webSocket.on("message", messageHandler);
98
- });
99
- try {
100
- const response = await waitForMeshResponse;
41
+ const downloadLink = this.buildDownloadLink(mesh._id.split("/")[2] || "");
42
+ resolve(this.buildDownloadLinkResponse(downloadLink));
43
+ return true;
44
+ });
101
45
  res.status(200).json(response);
102
- return;
103
46
  }
104
47
  catch (error) {
105
48
  console.error("Error waiting for mesh response:", error);
106
- const errorResponse = {
107
- error: error instanceof Error
108
- ? error.message
109
- : "Failed to get mesh response",
110
- timestamp: new Date().toISOString(),
111
- };
112
- res.status(500).json(errorResponse);
113
- return;
49
+ this.sendErrorResponse(res, 500, error instanceof Error
50
+ ? error.message
51
+ : "Failed to get mesh response");
114
52
  }
115
53
  }
116
54
  catch (error) {
117
55
  console.error("Error creating download link:", error);
118
- const errorResponse = {
119
- error: "Internal server error",
120
- timestamp: new Date().toISOString(),
121
- };
122
- res.status(500).json(errorResponse);
123
- return;
56
+ this.sendErrorResponse(res, 500, "Internal server error");
124
57
  }
125
58
  };
126
59
  this.createDeviceGroup = async (req, res) => {
127
60
  try {
128
- const deviceGroupName = req.body.deviceGroupName;
129
- const description = req.body.description;
61
+ const { deviceGroupName, description } = req.body;
130
62
  if (!deviceGroupName) {
131
- const errorResponse = {
132
- error: "'deviceGroupName' body param is required",
133
- timestamp: new Date().toISOString(),
134
- };
135
- res.status(400).json(errorResponse);
63
+ this.sendErrorResponse(res, 400, "'deviceGroupName' body param is required");
136
64
  return;
137
65
  }
66
+ if (!this.ensureWebSocket(res))
67
+ return;
138
68
  const createMeshMessageSent = this.WebSocketService.sendMessage({
139
69
  action: "createmesh",
140
70
  meshname: deviceGroupName,
141
71
  meshtype: 2,
142
- desc: description ? description : "",
72
+ desc: description !== null && description !== void 0 ? description : "",
143
73
  });
144
- if (!createMeshMessageSent) {
145
- const errorResponse = {
146
- error: "Could Not Send Message Over Socket",
147
- timestamp: new Date().toISOString(),
148
- };
149
- res.status(500).json(errorResponse);
150
- return;
151
- }
152
- if (!this.webSocket) {
153
- const errorResponse = {
154
- error: "Socket Not Found",
155
- timestamp: new Date().toISOString(),
156
- };
157
- res.status(500).json(errorResponse);
74
+ if (!this.ensureMessageSent(res, createMeshMessageSent))
158
75
  return;
159
- }
160
- const waitForMeshResponse = new Promise((resolve, reject) => {
161
- let responseReceived = false;
162
- // Wait 10 second for ws message to arive
163
- const timeout = setTimeout(() => {
164
- if (!responseReceived) {
165
- responseReceived = true;
166
- reject(new Error("Timeout waiting for mesh response"));
167
- }
168
- }, 60000);
169
- const messageHandler = (data) => {
170
- var _a, _b;
171
- if (responseReceived)
172
- return;
173
- try {
174
- const message = JSON.parse(data.toString());
175
- if (message.action === types_1.MeshActions.CREATE_MESH) {
176
- responseReceived = true;
177
- clearTimeout(timeout);
178
- (_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.removeListener("message", messageHandler);
179
- const createMeshMessage = message;
180
- if (createMeshMessage.result != "ok") {
181
- reject(new Error(`Could Not Create Device Group with name: ${deviceGroupName}`));
182
- }
183
- const response = {
184
- result: createMeshMessage.result,
185
- deviceGroupId: createMeshMessage.meshid,
186
- timestamp: new Date().toISOString(),
187
- };
188
- resolve(response);
189
- }
190
- }
191
- catch (parseError) {
192
- if (!responseReceived) {
193
- responseReceived = true;
194
- clearTimeout(timeout);
195
- (_b = this.webSocket) === null || _b === void 0 ? void 0 : _b.removeListener("message", messageHandler);
196
- reject(parseError);
197
- }
198
- }
199
- };
200
- this.webSocket.on("message", messageHandler);
201
- });
202
76
  try {
203
- const response = await waitForMeshResponse;
77
+ const response = await this.waitForWebSocketResponse(60000, (message, resolve, reject) => {
78
+ const msg = message;
79
+ if (msg.action !== types_1.MeshActions.CREATE_MESH)
80
+ return false;
81
+ const createMeshMessage = message;
82
+ if (createMeshMessage.result !== "ok") {
83
+ reject(new Error(`Could Not Create Device Group with name: ${deviceGroupName}`));
84
+ return true;
85
+ }
86
+ resolve({
87
+ result: createMeshMessage.result,
88
+ deviceGroupId: createMeshMessage.meshid,
89
+ timestamp: new Date().toISOString(),
90
+ });
91
+ return true;
92
+ });
204
93
  res.status(200).json(response);
205
- return;
206
94
  }
207
95
  catch (error) {
208
96
  console.error("Error waiting for createmesh response:", error);
209
- const errorResponse = {
210
- error: error instanceof Error
211
- ? error.message
212
- : "Failed to get createmesh response",
213
- timestamp: new Date().toISOString(),
214
- };
215
- res.status(500).json(errorResponse);
97
+ this.sendErrorResponse(res, 500, error instanceof Error
98
+ ? error.message
99
+ : "Failed to get createmesh response");
216
100
  }
217
101
  }
218
102
  catch (error) {
219
103
  console.error("Error creating device group link:", error);
220
- const errorResponse = {
221
- error: "Internal server error",
222
- timestamp: new Date().toISOString(),
223
- };
224
- res.status(500).json(errorResponse);
104
+ this.sendErrorResponse(res, 500, "Internal server error");
225
105
  }
226
106
  };
227
107
  this.addUserToGroup = async (req, res) => {
228
108
  try {
229
109
  const { deviceGroupName, deviceGroupId, users } = req.body;
230
110
  if (!users || !Array.isArray(users) || users.length === 0) {
231
- const errorResponse = {
232
- error: "'users' body param is required and must be a non-empty array",
233
- timestamp: new Date().toISOString(),
234
- };
235
- res.status(400).json(errorResponse);
111
+ this.sendErrorResponse(res, 400, "'users' body param is required and must be a non-empty array");
236
112
  return;
237
113
  }
238
114
  if (!deviceGroupName && !deviceGroupId) {
239
- const errorResponse = {
240
- error: "Either 'deviceGroupName' or 'deviceGroupId' body param is required",
241
- timestamp: new Date().toISOString(),
242
- };
243
- res.status(400).json(errorResponse);
115
+ this.sendErrorResponse(res, 400, "Either 'deviceGroupName' or 'deviceGroupId' body param is required");
244
116
  return;
245
117
  }
246
- const meshUserIds = [];
247
- const failedUsers = [];
248
- try {
249
- const placeholders = users.map((_, index) => `$${index + 1}`).join(",");
250
- const nexus_epm_user_id_query = `SELECT username, id FROM accounts_user WHERE username IN (${placeholders})`;
251
- const nexus_epm_user_id = await this.dbPool.query(nexus_epm_user_id_query, users);
252
- const foundUsers = new Map();
253
- nexus_epm_user_id.rows.forEach((row) => {
254
- foundUsers.set(row.username, row.id);
255
- });
256
- for (const username of users) {
257
- const userId = foundUsers.get(username);
258
- if (userId) {
259
- const meshUserId = `user//${username}___${userId}`.toLowerCase();
260
- meshUserIds.push(meshUserId);
261
- }
262
- else {
263
- console.warn(`User '${username}' not found in database`);
264
- failedUsers.push(username);
265
- }
266
- }
267
- }
268
- catch (error) {
269
- console.error("Error fetching user IDs from database:", error);
270
- failedUsers.push(...users);
118
+ if (!this.ensureWebSocket(res))
119
+ return;
120
+ const { meshUsers, failedUsers } = await this.fetchMeshUsers(users);
121
+ if (meshUsers.length === 0) {
122
+ this.sendErrorResponse(res, 400, "No valid users found in the database");
123
+ return;
271
124
  }
272
- if (meshUserIds.length === 0) {
273
- const errorResponse = {
274
- error: "No valid users found in the database",
275
- timestamp: new Date().toISOString(),
276
- };
277
- res.status(400).json(errorResponse);
125
+ const { createdUsers, existingUsers, failedToCreate } = await this.createMeshUsers(meshUsers);
126
+ const usersToAddToGroup = [...createdUsers, ...existingUsers];
127
+ const allFailedUsers = [...failedUsers, ...failedToCreate];
128
+ if (usersToAddToGroup.length === 0) {
129
+ this.sendErrorResponse(res, 400, "Failed to create or find any users in MeshCentral");
278
130
  return;
279
131
  }
132
+ const meshUserIds = usersToAddToGroup.map((u) => u.meshId);
280
133
  const addMeshUserMessage = {
281
134
  action: "addmeshuser",
282
135
  meshid: deviceGroupId,
@@ -287,174 +140,337 @@ class CoreController extends BaseController_1.BaseController {
287
140
  };
288
141
  console.log(`Add Mesh User Message: ${JSON.stringify(addMeshUserMessage)}`);
289
142
  const addMeshUserMessageSent = this.WebSocketService.sendMessage(addMeshUserMessage);
290
- console.log(addMeshUserMessageSent);
291
- if (!addMeshUserMessageSent) {
292
- const errorResponse = {
293
- error: "Could Not Send Message Over Socket",
294
- timestamp: new Date().toISOString(),
295
- };
296
- res.status(500).json(errorResponse);
297
- return;
298
- }
299
- if (!this.webSocket) {
300
- const errorResponse = {
301
- error: "Socket Not Found",
302
- timestamp: new Date().toISOString(),
303
- };
304
- res.status(500).json(errorResponse);
143
+ if (!this.ensureMessageSent(res, addMeshUserMessageSent))
305
144
  return;
306
- }
307
- const waitForAddUserResponse = new Promise((resolve, reject) => {
308
- let responseReceived = false;
309
- const addedUsers = [];
310
- let expectedResponses = meshUserIds.length;
311
- // Wait 15 seconds for ws message to arrive (longer timeout for multiple users)
312
- const timeout = setTimeout(() => {
313
- if (!responseReceived) {
314
- responseReceived = true;
315
- if (addedUsers.length > 0) {
316
- // Partial success
317
- resolve({
318
- result: "partial",
319
- users_added: addedUsers,
320
- failed_users: failedUsers,
321
- timestamp: new Date().toISOString(),
322
- });
323
- }
324
- else {
325
- reject(new Error("Timeout waiting for add mesh user response"));
326
- }
327
- }
328
- }, 15000);
329
- const messageHandler = (data) => {
330
- var _a;
331
- if (responseReceived)
332
- return;
333
- try {
334
- const message = JSON.parse(data.toString());
335
- console.log(`Mesh Message received: ${JSON.stringify(message)}`);
336
- if (message.action == types_1.MeshActions.EVENT &&
337
- message.event.msgid == 78) {
338
- const changedUser = message.event.msgArgs[0];
339
- if (changedUser &&
340
- meshUserIds.some((userId) => userId.includes(changedUser))) {
341
- addedUsers.push(changedUser);
342
- expectedResponses--;
343
- if (expectedResponses <= 0) {
344
- responseReceived = true;
345
- clearTimeout(timeout);
346
- (_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.removeListener("message", messageHandler);
347
- const response = {
348
- result: "success",
349
- users_added: addedUsers,
350
- failed_users: failedUsers.length > 0 ? failedUsers : undefined,
351
- timestamp: new Date().toISOString(),
352
- };
353
- resolve(response);
354
- }
355
- }
356
- }
357
- }
358
- catch (parseError) {
359
- console.error("Error parsing WebSocket message:", parseError);
360
- reject(parseError);
361
- }
362
- };
363
- this.webSocket.on("message", messageHandler);
364
- });
365
145
  try {
366
- const response = await waitForAddUserResponse;
146
+ const response = await this.waitForAddUserToGroupResponse(meshUserIds, allFailedUsers);
367
147
  res.status(200).json(response);
368
- return;
369
148
  }
370
149
  catch (error) {
371
150
  console.error("Error waiting for add mesh user response:", error);
372
- const errorResponse = {
373
- error: error instanceof Error
374
- ? error.message
375
- : "Failed to add users to device group",
376
- timestamp: new Date().toISOString(),
377
- };
378
- res.status(500).json(errorResponse);
151
+ this.sendErrorResponse(res, 500, error instanceof Error
152
+ ? error.message
153
+ : "Failed to add users to device group");
379
154
  }
380
155
  }
381
156
  catch (error) {
382
157
  console.error("Error adding users to device group:", error);
383
- const errorResponse = {
384
- error: "Internal server error",
385
- timestamp: new Date().toISOString(),
386
- };
387
- res.status(500).json(errorResponse);
158
+ this.sendErrorResponse(res, 500, "Internal server error");
388
159
  }
389
160
  };
390
161
  this.getEndpointInstallScript = async (req, res) => {
391
162
  try {
392
163
  const { clientId, siteId, agentType, endpointUrl, os, installerToken } = req.body;
393
- const baseUrl = `${this.config.epmConfig.server}`;
394
- const iceberg_org_id_query = "SELECT string_value FROM clients_clientcustomfield WHERE client_id = $1";
395
- const iceberg_site_id_query = "SELECT string_value FROM clients_sitecustomfield WHERE site_id = $1";
396
- const iceberg_org_token_query = "SELECT string_value FROM clients_clientcustomfield WHERE client_id = $1 AND field_id = $2";
397
- const iceberg_asset_type_id_query = "SELECT string_value FROM clients_clientcustomfield WHERE client_id = $1 AND field_id = $2";
398
- console.log(`[getAgentDetails] Executing parallel queries for iceberg details`);
399
- const iceberg_org_id_promise = this.dbPool.query(iceberg_org_id_query, [clientId]);
400
- const iceberg_site_id_promise = this.dbPool.query(iceberg_site_id_query, [siteId]);
401
- const iceberg_org_token_promise = this.dbPool.query(iceberg_org_token_query, [
402
- clientId,
403
- this.config.epmConfig.tokenFieldId,
404
- ]);
405
- const iceberg_asset_type_id_promise = this.dbPool.query(iceberg_asset_type_id_query, [
406
- clientId,
407
- this.config.epmConfig.assetTypeFieldId,
408
- ]);
409
- let [iceberg_ord_id, iceberg_site_id, iceberg_org_token, iceberg_asset_type_id,] = await Promise.all([
410
- iceberg_org_id_promise,
411
- iceberg_site_id_promise,
412
- iceberg_org_token_promise,
413
- iceberg_asset_type_id_promise,
414
- ]);
415
- console.log(`[getAgentDetails] Iceberg queries completed with results:`, {
416
- org_id_rows: iceberg_ord_id.rows.length,
417
- site_id_rows: iceberg_site_id.rows.length,
418
- org_token_rows: iceberg_org_token.rows.length,
419
- asset_type_id_rows: iceberg_asset_type_id.rows.length,
420
- });
421
- if (iceberg_ord_id.rows.length > 0 &&
422
- iceberg_site_id.rows.length > 0 &&
423
- iceberg_org_token.rows.length > 0 &&
424
- iceberg_asset_type_id.rows.length > 0) {
425
- const siteRow = iceberg_site_id.rows[0];
426
- const orgRow = iceberg_ord_id.rows[0];
427
- const orgTokenRow = iceberg_org_token.rows[0];
428
- const assetTypeRow = iceberg_asset_type_id.rows[0];
429
- if (!siteRow || !orgRow || !orgTokenRow || !assetTypeRow) {
430
- const errorResponse = {
431
- error: "Either SiteId, OrgId, OrgToken, or AssetTypeId is missing",
432
- timestamp: new Date().toISOString(),
433
- };
434
- res.status(501).json(errorResponse);
164
+ const icebergDetails = await this.fetchIcebergDetails(clientId, siteId);
165
+ if (!icebergDetails) {
166
+ this.sendErrorResponse(res, 501, "Either SiteId, OrgId, OrgToken, or AssetTypeId is missing");
167
+ return;
168
+ }
169
+ const { assetTypeId, icebergSiteId, icebergOrgId, icebergOrgToken } = icebergDetails;
170
+ const baseUrl = this.config.epmConfig.server;
171
+ if (os === types_1.OperatingSystems.WINDOWS) {
172
+ const script = this.generateWindowsScript({
173
+ baseUrl,
174
+ clientId,
175
+ siteId,
176
+ agentType,
177
+ installerToken,
178
+ endpointUrl,
179
+ assetTypeId,
180
+ icebergSiteId,
181
+ icebergOrgId,
182
+ icebergOrgToken,
183
+ });
184
+ this.sendScript(res, "powershell", script);
185
+ return;
186
+ }
187
+ if (os === types_1.OperatingSystems.LINUX) {
188
+ if (!this.ensureWebSocket(res))
189
+ return;
190
+ const meshesMessageSent = this.WebSocketService.sendMessage({
191
+ action: "meshes",
192
+ responseid: "meshctrl",
193
+ });
194
+ if (!this.ensureMessageSent(res, meshesMessageSent))
435
195
  return;
196
+ try {
197
+ const { deviceGroupId } = await this.waitForWebSocketResponse(60000, (message, resolve, reject) => {
198
+ const msg = message;
199
+ if (msg.action !== types_1.MeshActions.MESH_ES)
200
+ return false;
201
+ const meshesMessage = message;
202
+ console.log(`meshes: ${JSON.stringify(meshesMessage)}`);
203
+ const mesh = meshesMessage.meshes.find((m) => m.name === "TacticalRMM");
204
+ if (!mesh) {
205
+ reject(new Error("Mesh Not Found"));
206
+ return true;
207
+ }
208
+ const groupId = mesh._id.split("/")[2];
209
+ if (!groupId) {
210
+ reject(new Error("Error parsing deviceGroupId"));
211
+ return true;
212
+ }
213
+ resolve({ deviceGroupId: groupId });
214
+ return true;
215
+ });
216
+ const script = this.generateLinuxScript({
217
+ baseUrl,
218
+ clientId,
219
+ siteId,
220
+ agentType,
221
+ installerToken,
222
+ endpointUrl,
223
+ assetTypeId,
224
+ icebergSiteId,
225
+ icebergOrgId,
226
+ icebergOrgToken,
227
+ deviceGroupId,
228
+ });
229
+ this.sendScript(res, "bash", script);
436
230
  }
437
- const assetTypeId = assetTypeRow.string_value;
438
- const icebergSiteId = siteRow.string_value;
439
- const icebergOrgId = orgRow.string_value;
440
- const icebergOrgToken = orgTokenRow.string_value;
441
- if (os == types_1.OperatingSystems.WINDOWS) {
442
- const script = `
231
+ catch (error) {
232
+ console.error("Error waiting for mesh response:", error);
233
+ this.sendErrorResponse(res, 500, error instanceof Error
234
+ ? error.message
235
+ : "Failed to get mesh response");
236
+ }
237
+ return;
238
+ }
239
+ if (os === types_1.OperatingSystems.MACOS) {
240
+ this.sendErrorResponse(res, 501, "Macos script is not supported yet");
241
+ return;
242
+ }
243
+ this.sendErrorResponse(res, 400, "Unsupported operating system");
244
+ }
245
+ catch (error) {
246
+ console.error("Error generating install script:", error);
247
+ this.sendErrorResponse(res, 500, "Internal server error");
248
+ }
249
+ };
250
+ }
251
+ sendErrorResponse(res, status, error) {
252
+ const errorResponse = {
253
+ error,
254
+ timestamp: new Date().toISOString(),
255
+ };
256
+ res.status(status).json(errorResponse);
257
+ }
258
+ ensureWebSocket(res) {
259
+ if (!this.webSocket) {
260
+ this.sendErrorResponse(res, 500, "Socket Not Found");
261
+ return false;
262
+ }
263
+ return true;
264
+ }
265
+ ensureMessageSent(res, sent) {
266
+ if (!sent) {
267
+ this.sendErrorResponse(res, 500, "Could Not Send Message Over Socket");
268
+ return false;
269
+ }
270
+ return true;
271
+ }
272
+ sendScript(res, type, script) {
273
+ res.setHeader("X-Script-Type", type);
274
+ res.setHeader("Content-Type", "text/plain; charset=utf-8");
275
+ res.status(200).send(script);
276
+ }
277
+ buildDownloadLink(meshId) {
278
+ const inviteEncryptionKey = (0, utils_1.getBinaryKey)(this.config.meshcentralConfig.inviteEncryptionKey);
279
+ const meshcookie = (0, utils_1.encodeCookie)({ m: meshId }, inviteEncryptionKey);
280
+ return `https://${this.config.meshcentralConfig.host}/meshagents?id=10006&meshid=${meshcookie}&ac=02`;
281
+ }
282
+ buildDownloadLinkResponse(downloadLink) {
283
+ return {
284
+ download_link: downloadLink,
285
+ timestamp: new Date().toISOString(),
286
+ };
287
+ }
288
+ waitForWebSocketResponse(timeoutMs, handler) {
289
+ return new Promise((resolve, reject) => {
290
+ let responseReceived = false;
291
+ const timeout = setTimeout(() => {
292
+ var _a;
293
+ if (!responseReceived) {
294
+ responseReceived = true;
295
+ (_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.removeListener("message", messageHandler);
296
+ reject(new Error("Timeout waiting for WebSocket response"));
297
+ }
298
+ }, timeoutMs);
299
+ const cleanup = () => {
300
+ var _a;
301
+ clearTimeout(timeout);
302
+ (_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.removeListener("message", messageHandler);
303
+ };
304
+ const messageHandler = (data) => {
305
+ if (responseReceived)
306
+ return;
307
+ try {
308
+ const message = JSON.parse(data.toString());
309
+ const handled = handler(message, (value) => {
310
+ responseReceived = true;
311
+ cleanup();
312
+ resolve(value);
313
+ }, (error) => {
314
+ responseReceived = true;
315
+ cleanup();
316
+ reject(error);
317
+ });
318
+ if (!handled)
319
+ return;
320
+ }
321
+ catch (parseError) {
322
+ if (!responseReceived) {
323
+ responseReceived = true;
324
+ cleanup();
325
+ reject(parseError);
326
+ }
327
+ }
328
+ };
329
+ this.webSocket.on("message", messageHandler);
330
+ });
331
+ }
332
+ waitForAddUserToGroupResponse(meshUserIds, failedUsers) {
333
+ return new Promise((resolve, reject) => {
334
+ let responseReceived = false;
335
+ const addedUsers = [];
336
+ let expectedResponses = meshUserIds.length;
337
+ const timeout = setTimeout(() => {
338
+ var _a;
339
+ if (!responseReceived) {
340
+ responseReceived = true;
341
+ (_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.removeListener("message", messageHandler);
342
+ if (addedUsers.length > 0) {
343
+ resolve({
344
+ result: "partial",
345
+ users_added: addedUsers,
346
+ failed_users: failedUsers.length > 0 ? failedUsers : undefined,
347
+ timestamp: new Date().toISOString(),
348
+ });
349
+ }
350
+ else {
351
+ reject(new Error("Timeout waiting for add mesh user response"));
352
+ }
353
+ }
354
+ }, 60000);
355
+ const messageHandler = (data) => {
356
+ var _a;
357
+ if (responseReceived)
358
+ return;
359
+ try {
360
+ const message = JSON.parse(data.toString());
361
+ console.log(`Mesh Message received: ${JSON.stringify(message)}`);
362
+ if (message.action === types_1.MeshActions.EVENT &&
363
+ message.event.msgid === 78) {
364
+ const changedUser = message.event.msgArgs[0];
365
+ if (changedUser &&
366
+ meshUserIds.some((userId) => userId.includes(changedUser))) {
367
+ addedUsers.push(changedUser);
368
+ expectedResponses--;
369
+ if (expectedResponses <= 0) {
370
+ responseReceived = true;
371
+ clearTimeout(timeout);
372
+ (_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.removeListener("message", messageHandler);
373
+ resolve({
374
+ result: "success",
375
+ users_added: addedUsers,
376
+ failed_users: failedUsers.length > 0 ? failedUsers : undefined,
377
+ timestamp: new Date().toISOString(),
378
+ });
379
+ }
380
+ }
381
+ }
382
+ }
383
+ catch (parseError) {
384
+ console.error("Error parsing WebSocket message:", parseError);
385
+ }
386
+ };
387
+ this.webSocket.on("message", messageHandler);
388
+ });
389
+ }
390
+ async fetchMeshUsers(users) {
391
+ const meshUsers = [];
392
+ const failedUsers = [];
393
+ try {
394
+ const placeholders = users.map((_, index) => `$${index + 1}`).join(",");
395
+ const query = `SELECT username, id, email, first_name, last_name FROM accounts_user WHERE username IN (${placeholders})`;
396
+ const result = await this.dbPool.query(query, users);
397
+ const foundUsers = new Map();
398
+ result.rows.forEach((row) => {
399
+ foundUsers.set(row.username, {
400
+ id: row.id,
401
+ firstName: row.first_name,
402
+ lastName: row.last_name,
403
+ email: row.email,
404
+ });
405
+ });
406
+ for (const username of users) {
407
+ const userDetails = foundUsers.get(username);
408
+ if (userDetails) {
409
+ const meshUserName = `${username}___${userDetails.id}`.toLowerCase();
410
+ meshUsers.push({
411
+ meshId: `user//${meshUserName}`,
412
+ meshUserName,
413
+ fullName: `${userDetails.firstName} ${userDetails.lastName}`,
414
+ email: userDetails.email,
415
+ });
416
+ }
417
+ else {
418
+ console.warn(`User '${username}' not found in database`);
419
+ failedUsers.push(username);
420
+ }
421
+ }
422
+ }
423
+ catch (error) {
424
+ console.error("Error fetching user IDs from database:", error);
425
+ failedUsers.push(...users);
426
+ }
427
+ return { meshUsers, failedUsers };
428
+ }
429
+ async fetchIcebergDetails(clientId, siteId) {
430
+ console.log(`[getAgentDetails] Executing parallel queries for iceberg details`);
431
+ const [icebergOrgId, icebergSiteId, icebergOrgToken, icebergAssetTypeId] = await Promise.all([
432
+ this.dbPool.query("SELECT string_value FROM clients_clientcustomfield WHERE client_id = $1", [clientId]),
433
+ this.dbPool.query("SELECT string_value FROM clients_sitecustomfield WHERE site_id = $1", [siteId]),
434
+ this.dbPool.query("SELECT string_value FROM clients_clientcustomfield WHERE client_id = $1 AND field_id = $2", [clientId, this.config.epmConfig.tokenFieldId]),
435
+ this.dbPool.query("SELECT string_value FROM clients_clientcustomfield WHERE client_id = $1 AND field_id = $2", [clientId, this.config.epmConfig.assetTypeFieldId]),
436
+ ]);
437
+ console.log(`[getAgentDetails] Iceberg queries completed with results:`, {
438
+ org_id_rows: icebergOrgId.rows.length,
439
+ site_id_rows: icebergSiteId.rows.length,
440
+ org_token_rows: icebergOrgToken.rows.length,
441
+ asset_type_id_rows: icebergAssetTypeId.rows.length,
442
+ });
443
+ const orgRow = icebergOrgId.rows[0];
444
+ const siteRow = icebergSiteId.rows[0];
445
+ const orgTokenRow = icebergOrgToken.rows[0];
446
+ const assetTypeRow = icebergAssetTypeId.rows[0];
447
+ if (!orgRow || !siteRow || !orgTokenRow || !assetTypeRow) {
448
+ return null;
449
+ }
450
+ return {
451
+ assetTypeId: assetTypeRow.string_value,
452
+ icebergSiteId: siteRow.string_value,
453
+ icebergOrgId: orgRow.string_value,
454
+ icebergOrgToken: orgTokenRow.string_value,
455
+ };
456
+ }
457
+ generateWindowsScript(params) {
458
+ return `
443
459
  $endpointsetup = 'nexus-endpoint-v0.1.0-i32-setup.exe'
444
- $api = '"${baseUrl}"'
445
- $clientid = '${clientId}'
446
- $siteid = '${siteId}'
447
- $agenttype = '"${agentType}"'
460
+ $api = '"${params.baseUrl}"'
461
+ $clientid = '${params.clientId}'
462
+ $siteid = '${params.siteId}'
463
+ $agenttype = '"${params.agentType}"'
448
464
  $power = 0
449
465
  $rdp = 1
450
466
  $ping = 0
451
- $auth = '"${installerToken}"'
452
- $endpointdownloadlink = '${endpointUrl}'
467
+ $auth = '"${params.installerToken}"'
468
+ $endpointdownloadlink = '${params.endpointUrl}'
453
469
  $apilink = $endpointdownloadlink.split('/')
454
- $assetTypeId = '"${assetTypeId}"'
455
- $icebergSiteId = '"${icebergSiteId}"'
456
- $icebergOrgId = '"${icebergOrgId}"'
457
- $icebergOrgToken = '"${icebergOrgToken}"'
470
+ $assetTypeId = '"${params.assetTypeId}"'
471
+ $icebergSiteId = '"${params.icebergSiteId}"'
472
+ $icebergOrgId = '"${params.icebergOrgId}"'
473
+ $icebergOrgToken = '"${params.icebergOrgToken}"'
458
474
  $assetEndpoint = '"${this.config.icebergConfig.assetEndpoint}"'
459
475
  [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
460
476
  $serviceName = 'nexusrmm'
@@ -517,81 +533,9 @@ If (Get-Service $serviceName -ErrorAction SilentlyContinue) {
517
533
  }
518
534
  }
519
535
  `;
520
- res.setHeader("X-Script-Type", "powershell");
521
- res.setHeader("Content-Type", "text/plain; charset=utf-8");
522
- res.status(200).send(script);
523
- }
524
- else if (os == types_1.OperatingSystems.LINUX) {
525
- const meshesMessageSent = this.WebSocketService.sendMessage({
526
- action: "meshes",
527
- responseid: "meshctrl",
528
- });
529
- if (!meshesMessageSent) {
530
- const errorResponse = {
531
- error: "Could Not Send Message Over Socket",
532
- timestamp: new Date().toISOString(),
533
- };
534
- res.status(500).json(errorResponse);
535
- return;
536
- }
537
- if (!this.webSocket) {
538
- const errorResponse = {
539
- error: "Socket Not Found",
540
- timestamp: new Date().toISOString(),
541
- };
542
- res.status(500).json(errorResponse);
543
- return;
544
- }
545
- const waitForMeshResponse = new Promise((resolve, reject) => {
546
- let responseReceived = false;
547
- const timeout = setTimeout(() => {
548
- if (!responseReceived) {
549
- responseReceived = true;
550
- reject(new Error("Timeout waiting for mesh response"));
551
- }
552
- }, 60000);
553
- const messageHandler = (data) => {
554
- var _a, _b;
555
- if (responseReceived)
556
- return;
557
- try {
558
- const message = JSON.parse(data.toString());
559
- if (message.action === types_1.MeshActions.MESH_ES) {
560
- responseReceived = true;
561
- clearTimeout(timeout);
562
- (_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.removeListener("message", messageHandler);
563
- const meshesMessasge = message;
564
- console.log(`meshes: ${JSON.stringify(meshesMessasge)}`);
565
- const mesh = meshesMessasge.meshes.find((mesh) => mesh.name == "TacticalRMM");
566
- if (!mesh) {
567
- reject(new Error("Mesh Not Found"));
568
- return;
569
- }
570
- const deviceGroupId = mesh._id.split("/")[2];
571
- if (!deviceGroupId) {
572
- reject(new Error("Error parsing deviceGroupId"));
573
- return;
574
- }
575
- const response = {
576
- deviceGroupId,
577
- };
578
- resolve(response);
579
- }
580
- }
581
- catch (parseError) {
582
- if (!responseReceived) {
583
- responseReceived = true;
584
- clearTimeout(timeout);
585
- (_b = this.webSocket) === null || _b === void 0 ? void 0 : _b.removeListener("message", messageHandler);
586
- reject(parseError);
587
- }
588
- }
589
- };
590
- this.webSocket.on("message", messageHandler);
591
- });
592
- try {
593
- const response = await waitForMeshResponse;
594
- const script = `
536
+ }
537
+ generateLinuxScript(params) {
538
+ return `
595
539
  #!/usr/bin/env bash
596
540
 
597
541
  if [ $EUID -ne 0 ]; then
@@ -625,7 +569,7 @@ echo "Downloading and installing Nexus Endpoint..."
625
569
  sudo apt-get update
626
570
  sudo apt-get install -y libwebkit2gtk-4.1-0 libgtk-3-0 libappindicator3-1 libayatana-appindicator3-1 libxdo-dev
627
571
  INSTALLER="nexus-endpoint-installer.deb"
628
- wget "${endpointUrl}" -O "$INSTALLER"
572
+ wget "${params.endpointUrl}" -O "$INSTALLER"
629
573
  sudo dpkg -i "$INSTALLER"
630
574
  rm -f "$INSTALLER"
631
575
 
@@ -634,17 +578,17 @@ INSECURE=0
634
578
  NOMESH=0
635
579
 
636
580
  agentDL='https://nexus-endpoint-desktop-app.s3.ap-south-1.amazonaws.com/rmmagent/linux/x64/nexusrmm-amd64'
637
- meshDL='https://${this.config.meshcentralConfig.server}/meshagents?id=${response.deviceGroupId}&installflags=2&meshinstall=6'
638
-
639
- apiURL='${baseUrl}'
640
- token='${installerToken}'
641
- clientID='${clientId}'
642
- siteID='${siteId}'
643
- agentType='${agentType}'
644
- assetTypeId='${assetTypeId}'
645
- icebergSiteId='${icebergSiteId}'
646
- icebergOrgId='${icebergOrgId}'
647
- icebergOrgToken='${icebergOrgToken}'
581
+ meshDL='https://${this.config.meshcentralConfig.host}/meshagents?id=${params.deviceGroupId}&installflags=2&meshinstall=6'
582
+
583
+ apiURL='${params.baseUrl}'
584
+ token='${params.installerToken}'
585
+ clientID='${params.clientId}'
586
+ siteID='${params.siteId}'
587
+ agentType='${params.agentType}'
588
+ assetTypeId='${params.assetTypeId}'
589
+ icebergSiteId='${params.icebergSiteId}'
590
+ icebergOrgId='${params.icebergOrgId}'
591
+ icebergOrgToken='${params.icebergOrgToken}'
648
592
  assetEndpoint='${this.config.icebergConfig.assetEndpoint}'
649
593
  proxy=''
650
594
 
@@ -848,50 +792,6 @@ systemctl start \${agentSvcName}
848
792
  sudo systemctl restart gdm3
849
793
  sudo systemctl restart systemd-logind
850
794
  sudo dmidecode --string system-serial-number`;
851
- res.setHeader("X-Script-Type", "bash");
852
- res.setHeader("Content-Type", "text/plain; charset=utf-8");
853
- res.status(200).send(script);
854
- return;
855
- }
856
- catch (error) {
857
- console.error("Error waiting for mesh response:", error);
858
- const errorResponse = {
859
- error: error instanceof Error
860
- ? error.message
861
- : "Failed to get mesh response",
862
- timestamp: new Date().toISOString(),
863
- };
864
- res.status(500).json(errorResponse);
865
- return;
866
- }
867
- }
868
- else if (os == types_1.OperatingSystems.MACOS) {
869
- const errorResponse = {
870
- error: "Macos script is not supported yet",
871
- timestamp: new Date().toISOString(),
872
- };
873
- res.status(501).json(errorResponse);
874
- return;
875
- }
876
- }
877
- else {
878
- const errorResponse = {
879
- error: "Either SiteId, OrgId, OrgToken, or AssetTypeId is missing",
880
- timestamp: new Date().toISOString(),
881
- };
882
- res.status(501).json(errorResponse);
883
- return;
884
- }
885
- }
886
- catch (error) {
887
- console.error("Error generating install script :", error);
888
- const errorResponse = {
889
- error: "Internal server error",
890
- timestamp: new Date().toISOString(),
891
- };
892
- res.status(500).json(errorResponse);
893
- }
894
- };
895
795
  }
896
796
  }
897
797
  exports.CoreController = CoreController;