carta-controller 5.1.1 → 6.0.0-beta.1.0.3

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.
@@ -46,19 +46,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
46
46
  };
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
48
  exports.serverRouter = exports.createScriptingProxyHandler = exports.createUpgradeHandler = void 0;
49
+ const node_child_process_1 = require("node:child_process");
50
+ const fs = __importStar(require("node:fs"));
51
+ const querystring = __importStar(require("node:querystring"));
52
+ const url = __importStar(require("node:url"));
53
+ const io_1 = __importDefault(require("@pm2/io"));
49
54
  const express_1 = __importDefault(require("express"));
50
- const url = __importStar(require("url"));
51
- const fs = __importStar(require("fs"));
55
+ const mnemonist_1 = require("mnemonist");
52
56
  const moment_1 = __importDefault(require("moment"));
53
- const querystring = __importStar(require("querystring"));
54
- const uuid_1 = require("uuid");
55
- const io_1 = __importDefault(require("@pm2/io"));
56
57
  const tcpPortUsed = __importStar(require("tcp-port-used"));
57
- const child_process_1 = require("child_process");
58
- const mnemonist_1 = require("mnemonist");
59
- const util_1 = require("./util");
58
+ const uuid_1 = require("uuid");
60
59
  const auth_1 = require("./auth");
61
60
  const config_1 = require("./config");
61
+ const util_1 = require("./util");
62
62
  const processMap = new Map();
63
63
  const logMap = new Map();
64
64
  const LOG_LIMIT = 1000;
@@ -101,7 +101,7 @@ function deleteProcess(username) {
101
101
  function nextAvailablePort() {
102
102
  return __awaiter(this, void 0, void 0, function* () {
103
103
  // Get a map of all the ports in the range currently in use
104
- let existingPorts = new Map();
104
+ const existingPorts = new Map();
105
105
  processMap.forEach(value => {
106
106
  existingPorts.set(value.port, true);
107
107
  });
@@ -176,7 +176,7 @@ function handleStartServer(req, res, next) {
176
176
  const existingProcess = processMap.get(username);
177
177
  if (existingProcess) {
178
178
  // Kill the process via the kill script
179
- (0, child_process_1.spawnSync)("sudo", ["-u", `${username}`, config_1.ServerConfig.killCommand, `${existingProcess.process.pid}`]);
179
+ (0, node_child_process_1.spawnSync)("sudo", ["-u", `${username}`, config_1.ServerConfig.killCommand, `${existingProcess.process.pid}`]);
180
180
  // Delay to allow the parent process to exit
181
181
  yield (0, util_1.delay)(10);
182
182
  deleteProcess(username);
@@ -185,7 +185,10 @@ function handleStartServer(req, res, next) {
185
185
  catch (e) {
186
186
  util_1.logger.debug(e);
187
187
  util_1.logger.error(`Error killing existing process belonging to user ${username}`);
188
- return next({ statusCode: 400, message: "Problem killing existing process" });
188
+ return next({
189
+ statusCode: 400,
190
+ message: "Problem killing existing process"
191
+ });
189
192
  }
190
193
  }
191
194
  else {
@@ -210,7 +213,10 @@ function startServer(username) {
210
213
  try {
211
214
  const port = yield nextAvailablePort();
212
215
  if (port < 0) {
213
- throw { statusCode: 500, message: "No available ports for the backend process" };
216
+ throw {
217
+ statusCode: 500,
218
+ message: "No available ports for the backend process"
219
+ };
214
220
  }
215
221
  let args = [];
216
222
  if (config_1.ServerConfig.preserveEnv) {
@@ -238,9 +244,14 @@ function startServer(username) {
238
244
  // Finally, add the positional argument for the base folder
239
245
  args.push(config_1.ServerConfig.baseFolderTemplate.replace("{username}", username));
240
246
  const headerToken = (0, uuid_1.v4)();
241
- const child = (0, child_process_1.spawn)("sudo", args, { env: { CARTA_AUTH_TOKEN: headerToken } });
242
- if ((child === null || child === void 0 ? void 0 : child.pid) == undefined) {
243
- throw { statusCode: 500, message: `Problem starting process for user ${username}` };
247
+ const child = (0, node_child_process_1.spawn)("sudo", args, {
248
+ env: { CARTA_AUTH_TOKEN: headerToken }
249
+ });
250
+ if ((child === null || child === void 0 ? void 0 : child.pid) == null) {
251
+ throw {
252
+ statusCode: 500,
253
+ message: `Problem starting process for user ${username}`
254
+ };
244
255
  }
245
256
  setPendingProcess(username, port, headerToken, child);
246
257
  let logLocation;
@@ -248,16 +259,16 @@ function startServer(username) {
248
259
  logLocation = config_1.ServerConfig.backendLogFileTemplate.replace("{username}", username).replace("{pid}", child.pid.toString()).replace("{datetime}", (0, moment_1.default)().format("YYYYMMDD.h_mm_ss"));
249
260
  try {
250
261
  logStream = fs.createWriteStream(logLocation, { flags: "a" });
251
- if (logStream == undefined) {
262
+ if (logStream == null) {
252
263
  throw new Error("Unable to open stream");
253
264
  }
254
265
  child.stdout.pipe(logStream);
255
266
  child.stderr.pipe(logStream);
256
- child.stdout.on("data", function (data) {
267
+ child.stdout.on("data", data => {
257
268
  const line = data.toString();
258
269
  appendLog(username, line);
259
270
  });
260
- child.stderr.on("data", function (data) {
271
+ child.stderr.on("data", data => {
261
272
  const line = data.toString();
262
273
  appendLog(username, line);
263
274
  });
@@ -269,12 +280,12 @@ function startServer(username) {
269
280
  }
270
281
  else {
271
282
  logLocation = "stdout";
272
- child.stdout.on("data", function (data) {
283
+ child.stdout.on("data", data => {
273
284
  const line = data.toString();
274
285
  appendLog(username, line);
275
286
  util_1.logger.info(line);
276
287
  });
277
- child.stderr.on("data", function (data) {
288
+ child.stderr.on("data", data => {
278
289
  const line = data.toString();
279
290
  appendLog(username, line);
280
291
  util_1.logger.error(line);
@@ -288,7 +299,10 @@ function startServer(username) {
288
299
  // Check for early exit of backend process
289
300
  yield (0, util_1.delay)(config_1.ServerConfig.startDelay);
290
301
  if (child.exitCode || child.signalCode) {
291
- throw { statusCode: 500, message: `Problem starting process for user ${username}` };
302
+ throw {
303
+ statusCode: 500,
304
+ message: `Problem starting process for user ${username}`
305
+ };
292
306
  }
293
307
  else {
294
308
  util_1.logger.info(`Started process with PID ${child.pid} for user ${username} on port ${port}. Outputting to ${logLocation}`);
@@ -304,7 +318,10 @@ function startServer(username) {
304
318
  throw e;
305
319
  }
306
320
  else {
307
- throw { statusCode: 500, message: `Problem starting process for user ${username}` };
321
+ throw {
322
+ statusCode: 500,
323
+ message: `Problem starting process for user ${username}`
324
+ };
308
325
  }
309
326
  }
310
327
  });
@@ -320,7 +337,7 @@ function handleStopServer(req, res, next) {
320
337
  if (existingProcess) {
321
338
  existingProcess.process.removeAllListeners();
322
339
  // Kill the process via the kill script
323
- (0, child_process_1.spawnSync)("sudo", ["-u", `${req.username}`, config_1.ServerConfig.killCommand, `${existingProcess.process.pid}`]);
340
+ (0, node_child_process_1.spawnSync)("sudo", ["-u", `${req.username}`, config_1.ServerConfig.killCommand, `${existingProcess.process.pid}`]);
324
341
  // Delay to allow the parent process to exit
325
342
  yield (0, util_1.delay)(10);
326
343
  util_1.logger.info(`Process with PID ${existingProcess.process.pid} for user ${req.username} exited via stop request`);
@@ -328,13 +345,19 @@ function handleStopServer(req, res, next) {
328
345
  res.json({ success: true });
329
346
  }
330
347
  else {
331
- return next({ statusCode: 400, message: `No existing process belonging to user ${req.username}` });
348
+ return next({
349
+ statusCode: 400,
350
+ message: `No existing process belonging to user ${req.username}`
351
+ });
332
352
  }
333
353
  }
334
354
  catch (e) {
335
355
  util_1.logger.debug(e);
336
356
  util_1.logger.error(`Error killing existing process belonging to user ${req.username}`);
337
- return next({ statusCode: 500, message: "Problem killing existing process" });
357
+ return next({
358
+ statusCode: 500,
359
+ message: "Problem killing existing process"
360
+ });
338
361
  }
339
362
  });
340
363
  }
@@ -344,12 +367,12 @@ const createUpgradeHandler = (server) => (req, socket, head) => __awaiter(void 0
344
367
  if (!(req === null || req === void 0 ? void 0 : req.url)) {
345
368
  return socket.end();
346
369
  }
347
- let parsedUrl = url.parse(req.url);
370
+ const parsedUrl = url.parse(req.url);
348
371
  if (!(parsedUrl === null || parsedUrl === void 0 ? void 0 : parsedUrl.query)) {
349
372
  util_1.logger.warning(`Incoming Websocket upgrade request could not be parsed: ${req.url}`);
350
373
  return socket.end();
351
374
  }
352
- let queryParameters = querystring.parse(parsedUrl.query);
375
+ const queryParameters = querystring.parse(parsedUrl.query);
353
376
  const tokenString = queryParameters === null || queryParameters === void 0 ? void 0 : queryParameters.token;
354
377
  if (!tokenString || Array.isArray(tokenString)) {
355
378
  util_1.logger.warning(`Incoming Websocket upgrade request is missing an authentication token`);
@@ -362,7 +385,7 @@ const createUpgradeHandler = (server) => (req, socket, head) => __awaiter(void 0
362
385
  }
363
386
  const remoteAddress = ((_a = req.headers) === null || _a === void 0 ? void 0 : _a["x-forwarded-for"]) || ((_b = req.connection) === null || _b === void 0 ? void 0 : _b.remoteAddress);
364
387
  util_1.logger.info(`WS upgrade request from ${remoteAddress} for authenticated user ${token.username}`);
365
- const username = (0, auth_1.getUser)(token.username, token.iss);
388
+ const username = (0, auth_1.getUser)(token.username, `${token.iss}`);
366
389
  if (!username) {
367
390
  util_1.logger.error(`Could not find username ${token.username} in the user map`);
368
391
  return socket.end();
@@ -382,7 +405,9 @@ const createUpgradeHandler = (server) => (req, socket, head) => __awaiter(void 0
382
405
  util_1.logger.info(`Redirecting to backend process for ${username} (port ${existingProcess.port})`);
383
406
  req.headers["carta-auth-token"] = existingProcess.headerToken;
384
407
  req.url = "/";
385
- return server.ws(req, socket, head, { target: { host: "localhost", port: existingProcess.port } });
408
+ return server.ws(req, socket, head, {
409
+ target: { host: "localhost", port: existingProcess.port }
410
+ });
386
411
  }
387
412
  else {
388
413
  util_1.logger.error(`Backend process could not be started`);
@@ -403,10 +428,14 @@ const createScriptingProxyHandler = (server) => (req, res, next) => __awaiter(vo
403
428
  return next({ statusCode: 401, message: "Not authorized" });
404
429
  }
405
430
  if (!req.scripting) {
406
- return next({ statusCode: 403, message: "API token supplied does not permit scripting" });
431
+ return next({
432
+ statusCode: 403,
433
+ message: "API token supplied does not permit scripting"
434
+ });
407
435
  }
408
436
  try {
409
437
  const remoteAddress = ((_a = req.headers) === null || _a === void 0 ? void 0 : _a["x-forwarded-for"]) || ((_b = req.connection) === null || _b === void 0 ? void 0 : _b.remoteAddress);
438
+ util_1.logger.info(`Scripting proxy request from ${remoteAddress} for authenticated user ${username}`);
410
439
  let existingProcess = processMap.get(username);
411
440
  if (!(existingProcess === null || existingProcess === void 0 ? void 0 : existingProcess.process) || existingProcess.process.signalCode) {
412
441
  // Attempt to start new process
@@ -420,16 +449,24 @@ const createScriptingProxyHandler = (server) => (req, res, next) => __awaiter(vo
420
449
  yield (0, util_1.delay)(config_1.ServerConfig.startDelay);
421
450
  }
422
451
  req.headers["carta-auth-token"] = existingProcess.headerToken;
423
- return server.web(req, res, { target: { host: "localhost", port: existingProcess.port } });
452
+ return server.web(req, res, {
453
+ target: { host: "localhost", port: existingProcess.port }
454
+ });
424
455
  }
425
456
  else {
426
- return next({ statusCode: 500, message: `Backend process could not be started for ${username}` });
457
+ return next({
458
+ statusCode: 500,
459
+ message: `Backend process could not be started for ${username}`
460
+ });
427
461
  }
428
462
  }
429
463
  catch (err) {
430
464
  util_1.logger.error(`Error proxying scripting request for ${req.username}`);
431
465
  util_1.logger.debug(err);
432
- return next({ statusCode: 500, message: `Error proxying scripting request for ${req.username}` });
466
+ return next({
467
+ statusCode: 500,
468
+ message: `Error proxying scripting request for ${req.username}`
469
+ });
433
470
  }
434
471
  });
435
472
  exports.createScriptingProxyHandler = createScriptingProxyHandler;
package/dist/util.js CHANGED
@@ -16,11 +16,12 @@ exports.logger = void 0;
16
16
  exports.delay = delay;
17
17
  exports.noCache = noCache;
18
18
  exports.getUserId = getUserId;
19
- const child_process_1 = require("child_process");
19
+ exports.generateUrlSafeString = generateUrlSafeString;
20
+ const node_child_process_1 = require("node:child_process");
20
21
  const winston_1 = __importDefault(require("winston"));
21
22
  exports.logger = winston_1.default.createLogger({
22
23
  // Detailed setup is completed in config.ts
23
- levels: winston_1.default.config.syslog.levels,
24
+ levels: winston_1.default.config.syslog.levels
24
25
  });
25
26
  // Delay for the specified number of milliseconds
26
27
  function delay(delay) {
@@ -30,7 +31,7 @@ function delay(delay) {
30
31
  });
31
32
  });
32
33
  }
33
- function noCache(req, res, next) {
34
+ function noCache(_req, res, next) {
34
35
  res.header("Cache-Control", "private, no-cache, no-store, must-revalidate");
35
36
  res.header("Expires", "-1");
36
37
  res.header("Pragma", "no-cache");
@@ -40,13 +41,21 @@ function getUserId(username) {
40
41
  if (!username) {
41
42
  throw new Error("Missing argument for username");
42
43
  }
43
- const result = (0, child_process_1.spawnSync)("id", ["-u", username]);
44
+ const result = (0, node_child_process_1.spawnSync)("id", ["-u", username]);
44
45
  if (!result.status && (result === null || result === void 0 ? void 0 : result.stdout)) {
45
46
  const uid = Number.parseInt(result.stdout.toString());
46
- if (isFinite(uid)) {
47
+ if (Number.isFinite(uid)) {
47
48
  return uid;
48
49
  }
49
50
  }
50
51
  throw new Error(`Can't find uid for username ${username}`);
51
52
  }
53
+ function generateUrlSafeString(length) {
54
+ const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~";
55
+ let sessionId = "";
56
+ for (let i = 0; i < length; i++) {
57
+ sessionId += charset[Math.floor(Math.random() * charset.length)];
58
+ }
59
+ return sessionId;
60
+ }
52
61
  //# sourceMappingURL=util.js.map