carta-controller 5.0.3 → 6.0.0-beta.1.0.2
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/.github/workflows/build.yml +43 -0
- package/COPYING.md +636 -0
- package/README.md +4 -7
- package/biome.jsonc +37 -0
- package/dist/auth/external.js +10 -4
- package/dist/auth/external.js.map +1 -1
- package/dist/auth/google.js +18 -11
- package/dist/auth/google.js.map +1 -1
- package/dist/auth/index.js +12 -12
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/ldap.js +6 -3
- package/dist/auth/ldap.js.map +1 -1
- package/dist/auth/local.js +30 -14
- package/dist/auth/local.js.map +1 -1
- package/dist/auth/oidc.js +95 -91
- package/dist/auth/oidc.js.map +1 -1
- package/dist/auth/oidcRefreshManager.js +21 -24
- package/dist/auth/oidcRefreshManager.js.map +1 -1
- package/dist/auth/pam.js +8 -5
- package/dist/auth/pam.js.map +1 -1
- package/dist/config.js +17 -16
- package/dist/controllerTests.js +10 -10
- package/dist/database.js +64 -27
- package/dist/index.js +24 -23
- package/dist/serverHandlers.js +70 -33
- package/dist/util.js +14 -5
- package/package.json +13 -10
- package/public/dashboard.js +47 -48
- package/public/templated.css +155 -143
- package/test/auth.external.test.ts +19 -18
- package/.prettierrc.json +0 -18
package/dist/config.js
CHANGED
|
@@ -38,23 +38,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
38
38
|
var _a, _b;
|
|
39
39
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
40
|
exports.testUser = exports.RuntimeConfig = exports.ServerConfig = void 0;
|
|
41
|
-
const
|
|
42
|
-
const
|
|
43
|
-
const
|
|
44
|
-
const path = __importStar(require("path"));
|
|
45
|
-
const JSONC = __importStar(require("jsonc-parser"));
|
|
46
|
-
const lodash_1 = __importDefault(require("lodash"));
|
|
41
|
+
const fs = __importStar(require("node:fs"));
|
|
42
|
+
const path = __importStar(require("node:path"));
|
|
43
|
+
const url = __importStar(require("node:url"));
|
|
47
44
|
const ajv_1 = __importDefault(require("ajv"));
|
|
48
45
|
const ajv_formats_1 = __importDefault(require("ajv-formats"));
|
|
49
|
-
const
|
|
50
|
-
const
|
|
46
|
+
const JSONC = __importStar(require("jsonc-parser"));
|
|
47
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
51
48
|
const moment_timezone_1 = __importDefault(require("moment-timezone"));
|
|
49
|
+
const winston_1 = __importDefault(require("winston"));
|
|
50
|
+
const yargs_1 = __importDefault(require("yargs"));
|
|
51
|
+
const util_1 = require("./util");
|
|
52
52
|
let timeZone;
|
|
53
53
|
const customTimestamp = () => {
|
|
54
54
|
if (timeZone)
|
|
55
|
-
return (0, moment_timezone_1.default)().tz(timeZone).format(
|
|
55
|
+
return (0, moment_timezone_1.default)().tz(timeZone).format("YYYY-MM-DD HH:mm:ss");
|
|
56
56
|
else
|
|
57
|
-
return (0, moment_timezone_1.default)().format(
|
|
57
|
+
return (0, moment_timezone_1.default)().format("YYYY-MM-DD HH:mm:ss");
|
|
58
58
|
};
|
|
59
59
|
// Different log formats
|
|
60
60
|
const logTextFormat = winston_1.default.format.combine(winston_1.default.format.timestamp({ format: customTimestamp }), winston_1.default.format.printf(({ level, message, timestamp }) => {
|
|
@@ -68,7 +68,7 @@ const logJsonFormat = winston_1.default.format.combine(winston_1.default.format.
|
|
|
68
68
|
const defaultConfigPath = "/etc/carta/config.json";
|
|
69
69
|
const argv = yargs_1.default
|
|
70
70
|
.parserConfiguration({
|
|
71
|
-
|
|
71
|
+
"short-option-groups": false
|
|
72
72
|
})
|
|
73
73
|
.options({
|
|
74
74
|
config: {
|
|
@@ -114,7 +114,7 @@ const consoleTransport = new winston_1.default.transports.Console({
|
|
|
114
114
|
});
|
|
115
115
|
util_1.logger.add(consoleTransport);
|
|
116
116
|
try {
|
|
117
|
-
|
|
117
|
+
const configFiles = [];
|
|
118
118
|
if (fs.existsSync(argv.config)) {
|
|
119
119
|
configFiles.push(argv.config);
|
|
120
120
|
const jsonString = fs.readFileSync(argv.config).toString();
|
|
@@ -170,10 +170,11 @@ try {
|
|
|
170
170
|
// Validate timezone setting
|
|
171
171
|
if (serverConfig.timezone) {
|
|
172
172
|
try {
|
|
173
|
-
new Intl.DateTimeFormat(
|
|
173
|
+
new Intl.DateTimeFormat("en-US", { timeZone: serverConfig.timezone });
|
|
174
174
|
timeZone = serverConfig.timezone;
|
|
175
175
|
}
|
|
176
176
|
catch (err) {
|
|
177
|
+
util_1.logger.debug(err);
|
|
177
178
|
util_1.logger.error(`Ignoring invalid timezone "${serverConfig.timezone}" in config file`);
|
|
178
179
|
}
|
|
179
180
|
}
|
|
@@ -196,7 +197,7 @@ try {
|
|
|
196
197
|
util_1.logger.add(new winston_1.default.transports.File({
|
|
197
198
|
level: serverConfig.logLevelFile,
|
|
198
199
|
filename: serverConfig.logFile,
|
|
199
|
-
format: serverConfig.logTypeFile === "json" ? logJsonFormat : logTextFormat
|
|
200
|
+
format: serverConfig.logTypeFile === "json" ? logJsonFormat : logTextFormat
|
|
200
201
|
}));
|
|
201
202
|
util_1.logger.info(`Started logging to ${serverConfig.logFile}`);
|
|
202
203
|
}
|
|
@@ -241,8 +242,8 @@ if (serverConfig.authProviders.external) {
|
|
|
241
242
|
runtimeConfig.logoutAddress = serverConfig.authProviders.external.logoutAddress;
|
|
242
243
|
}
|
|
243
244
|
else {
|
|
244
|
-
runtimeConfig.tokenRefreshAddress = runtimeConfig.apiAddress
|
|
245
|
-
runtimeConfig.logoutAddress = runtimeConfig.apiAddress
|
|
245
|
+
runtimeConfig.tokenRefreshAddress = `${runtimeConfig.apiAddress}/auth/refresh`;
|
|
246
|
+
runtimeConfig.logoutAddress = `${runtimeConfig.apiAddress}/auth/logout`;
|
|
246
247
|
}
|
|
247
248
|
if (runtimeConfig.tokenRefreshAddress) {
|
|
248
249
|
const authUrl = url.parse(runtimeConfig.tokenRefreshAddress);
|
package/dist/controllerTests.js
CHANGED
|
@@ -46,17 +46,17 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
46
46
|
};
|
|
47
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
48
|
exports.runTests = runTests;
|
|
49
|
-
const
|
|
50
|
-
const fs = __importStar(require("fs"));
|
|
51
|
-
const
|
|
49
|
+
const node_child_process_1 = require("node:child_process");
|
|
50
|
+
const fs = __importStar(require("node:fs"));
|
|
51
|
+
const path = __importStar(require("node:path"));
|
|
52
52
|
const ldapauth_fork_1 = __importDefault(require("ldapauth-fork"));
|
|
53
53
|
const logSymbols = __importStar(require("log-symbols"));
|
|
54
54
|
const moment_1 = __importDefault(require("moment"));
|
|
55
|
-
const
|
|
56
|
-
const child_process_1 = require("child_process");
|
|
57
|
-
const util_1 = require("./util");
|
|
55
|
+
const mongodb_1 = require("mongodb");
|
|
58
56
|
const websocket_1 = require("websocket");
|
|
59
57
|
const local_1 = require("./auth/local");
|
|
58
|
+
const config_1 = require("./config");
|
|
59
|
+
const util_1 = require("./util");
|
|
60
60
|
const read = require("read");
|
|
61
61
|
function runTests(username) {
|
|
62
62
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -194,7 +194,7 @@ function testFrontend() {
|
|
|
194
194
|
}
|
|
195
195
|
let indexContents;
|
|
196
196
|
try {
|
|
197
|
-
indexContents = fs.readFileSync(config_1.ServerConfig.frontendPath
|
|
197
|
+
indexContents = fs.readFileSync(`${config_1.ServerConfig.frontendPath}/index.html`).toString();
|
|
198
198
|
}
|
|
199
199
|
catch (e) {
|
|
200
200
|
util_1.logger.debug(e);
|
|
@@ -238,7 +238,7 @@ function testBackendStartup(username) {
|
|
|
238
238
|
args.push(config_1.ServerConfig.baseFolderTemplate.replace("{username}", username));
|
|
239
239
|
util_1.logger.debug(`running sudo ${args.join(" ")}`);
|
|
240
240
|
// Use same stdout and stderr stream for the backend process
|
|
241
|
-
const backendProcess = (0,
|
|
241
|
+
const backendProcess = (0, node_child_process_1.spawn)("sudo", args, { stdio: "inherit" });
|
|
242
242
|
yield (0, util_1.delay)(2000);
|
|
243
243
|
if (backendProcess.signalCode) {
|
|
244
244
|
throw new Error(`Backend process terminated with code ${backendProcess.signalCode}. Please check your sudoers config, processCommand option and additionalArgs section`);
|
|
@@ -251,7 +251,7 @@ function testBackendStartup(username) {
|
|
|
251
251
|
wsClient.on("connect", () => {
|
|
252
252
|
wsConnected = true;
|
|
253
253
|
});
|
|
254
|
-
wsClient.on("connectFailed",
|
|
254
|
+
wsClient.on("connectFailed", e => {
|
|
255
255
|
util_1.logger.debug(e);
|
|
256
256
|
});
|
|
257
257
|
wsClient.connect(`ws://localhost:${port}`);
|
|
@@ -272,7 +272,7 @@ function testKillScript(username, existingProcess) {
|
|
|
272
272
|
}
|
|
273
273
|
const args = ["-u", `${username}`, config_1.ServerConfig.killCommand, `${existingProcess.pid}`];
|
|
274
274
|
util_1.logger.debug(`running sudo ${args.join(" ")}`);
|
|
275
|
-
const res = (0,
|
|
275
|
+
const res = (0, node_child_process_1.spawnSync)("sudo", args, { encoding: "utf8" });
|
|
276
276
|
if (res.error) {
|
|
277
277
|
util_1.logger.debug(res.error);
|
|
278
278
|
util_1.logger.debug(`stdout:\t${res.stdout}`);
|
package/dist/database.js
CHANGED
|
@@ -14,13 +14,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.databaseRouter = void 0;
|
|
16
16
|
exports.initDB = initDB;
|
|
17
|
-
const express_1 = __importDefault(require("express"));
|
|
18
17
|
const ajv_1 = __importDefault(require("ajv"));
|
|
19
18
|
const ajv_formats_1 = __importDefault(require("ajv-formats"));
|
|
19
|
+
const express_1 = __importDefault(require("express"));
|
|
20
20
|
const mongodb_1 = require("mongodb");
|
|
21
21
|
const auth_1 = require("./auth");
|
|
22
|
-
const util_1 = require("./util");
|
|
23
22
|
const config_1 = require("./config");
|
|
23
|
+
const util_1 = require("./util");
|
|
24
24
|
const PREFERENCE_SCHEMA_VERSION = 2;
|
|
25
25
|
const LAYOUT_SCHEMA_VERSION = 2;
|
|
26
26
|
const SNIPPET_SCHEMA_VERSION = 1;
|
|
@@ -29,12 +29,14 @@ const preferenceSchema = require("../schemas/preferences_schema_2.json");
|
|
|
29
29
|
const layoutSchema = require("../schemas/layout_schema_2.json");
|
|
30
30
|
const snippetSchema = require("../schemas/snippet_schema_1.json");
|
|
31
31
|
const workspaceSchema = require("../schemas/workspace_schema_1.json");
|
|
32
|
-
const ajv = new ajv_1.default({ useDefaults:
|
|
32
|
+
const ajv = new ajv_1.default({ useDefaults: false, strictTypes: false });
|
|
33
|
+
const ajvWithDefaults = new ajv_1.default({ useDefaults: true, strictTypes: false });
|
|
33
34
|
(0, ajv_formats_1.default)(ajv);
|
|
35
|
+
(0, ajv_formats_1.default)(ajvWithDefaults);
|
|
34
36
|
const validatePreferences = ajv.compile(preferenceSchema);
|
|
35
|
-
const validateLayout =
|
|
36
|
-
const validateSnippet =
|
|
37
|
-
const validateWorkspace =
|
|
37
|
+
const validateLayout = ajvWithDefaults.compile(layoutSchema);
|
|
38
|
+
const validateSnippet = ajvWithDefaults.compile(snippetSchema);
|
|
39
|
+
const validateWorkspace = ajvWithDefaults.compile(workspaceSchema);
|
|
38
40
|
let client;
|
|
39
41
|
let preferenceCollection;
|
|
40
42
|
let layoutsCollection;
|
|
@@ -73,13 +75,17 @@ function initDB() {
|
|
|
73
75
|
preferenceCollection = yield createOrGetCollection(db, "preferences");
|
|
74
76
|
workspacesCollection = yield createOrGetCollection(db, "workspaces");
|
|
75
77
|
// Remove any existing validation in preferences collection
|
|
76
|
-
yield db.command({
|
|
78
|
+
yield db.command({
|
|
79
|
+
collMod: "preferences",
|
|
80
|
+
validator: {},
|
|
81
|
+
validationLevel: "off"
|
|
82
|
+
});
|
|
77
83
|
// Update collection indices if necessary
|
|
78
84
|
yield updateUsernameIndex(layoutsCollection, false);
|
|
79
85
|
yield updateUsernameIndex(snippetsCollection, false);
|
|
80
86
|
yield updateUsernameIndex(workspacesCollection, false);
|
|
81
87
|
yield updateUsernameIndex(preferenceCollection, true);
|
|
82
|
-
util_1.logger.info(`Connected to ${client.options.dbName} on ${client.options.hosts} (Authenticated: ${client.options.credentials ?
|
|
88
|
+
util_1.logger.info(`Connected to ${client.options.dbName} on ${client.options.hosts} (Authenticated: ${client.options.credentials ? "Yes" : "No"})`);
|
|
83
89
|
}
|
|
84
90
|
catch (err) {
|
|
85
91
|
util_1.logger.debug(err);
|
|
@@ -106,12 +112,14 @@ function handleGetPreferences(req, res, next) {
|
|
|
106
112
|
if (doc) {
|
|
107
113
|
const isValid = validatePreferences(doc);
|
|
108
114
|
if (!isValid) {
|
|
109
|
-
|
|
115
|
+
const errors = JSON.stringify(validatePreferences.errors);
|
|
116
|
+
util_1.logger.warning(`Returning invalid preferences:\n${errors}`);
|
|
110
117
|
}
|
|
111
118
|
res.json({ success: true, preferences: doc });
|
|
112
119
|
}
|
|
113
120
|
else {
|
|
114
|
-
|
|
121
|
+
util_1.logger.debug(`No preferences found for user ${req.username}`);
|
|
122
|
+
res.json({ success: true, preferences: {} });
|
|
115
123
|
}
|
|
116
124
|
}
|
|
117
125
|
catch (err) {
|
|
@@ -131,20 +139,24 @@ function handleSetPreferences(req, res, next) {
|
|
|
131
139
|
const update = req.body;
|
|
132
140
|
// Check for malformed update
|
|
133
141
|
if (!update || !Object.keys(update).length || update.username || update._id) {
|
|
142
|
+
util_1.logger.warning("Malformed preference update received");
|
|
134
143
|
return next({ statusCode: 400, message: "Malformed preference update" });
|
|
135
144
|
}
|
|
136
145
|
update.version = PREFERENCE_SCHEMA_VERSION;
|
|
137
146
|
const validUpdate = validatePreferences(update);
|
|
138
147
|
if (!validUpdate) {
|
|
139
|
-
|
|
148
|
+
const errors = JSON.stringify(validatePreferences.errors);
|
|
149
|
+
util_1.logger.warning(`Rejecting invalid preference update:\n${errors}`);
|
|
140
150
|
return next({ statusCode: 400, message: "Invalid preference update" });
|
|
141
151
|
}
|
|
142
152
|
try {
|
|
143
153
|
const updateResult = yield preferenceCollection.updateOne({ username: req.username }, { $set: update }, { upsert: true });
|
|
144
154
|
if (updateResult.acknowledged) {
|
|
155
|
+
util_1.logger.debug("Preferences updated");
|
|
145
156
|
res.json({ success: true });
|
|
146
157
|
}
|
|
147
158
|
else {
|
|
159
|
+
util_1.logger.warning("Error updating preferences");
|
|
148
160
|
return next({ statusCode: 500, message: "Problem updating preferences" });
|
|
149
161
|
}
|
|
150
162
|
}
|
|
@@ -166,6 +178,7 @@ function handleClearPreferences(req, res, next) {
|
|
|
166
178
|
const keys = (_a = req.body) === null || _a === void 0 ? void 0 : _a.keys;
|
|
167
179
|
// Check for malformed update
|
|
168
180
|
if (!keys || !Array.isArray(keys) || !keys.length) {
|
|
181
|
+
util_1.logger.debug("Malformed key list received for clearing preferences");
|
|
169
182
|
return next({ statusCode: 400, message: "Malformed key list" });
|
|
170
183
|
}
|
|
171
184
|
const update = {};
|
|
@@ -175,13 +188,16 @@ function handleClearPreferences(req, res, next) {
|
|
|
175
188
|
try {
|
|
176
189
|
const updateResult = yield preferenceCollection.updateOne({ username: req.username }, { $unset: update });
|
|
177
190
|
if (updateResult.acknowledged) {
|
|
191
|
+
util_1.logger.debug("Preferences cleared");
|
|
178
192
|
res.json({ success: true });
|
|
179
193
|
}
|
|
180
194
|
else {
|
|
195
|
+
util_1.logger.debug("Error clearing preferences");
|
|
181
196
|
return next({ statusCode: 500, message: "Problem clearing preferences" });
|
|
182
197
|
}
|
|
183
198
|
}
|
|
184
199
|
catch (err) {
|
|
200
|
+
util_1.logger.debug("Error clearing preferences");
|
|
185
201
|
util_1.logger.debug(err);
|
|
186
202
|
return next({ statusCode: 500, message: "Problem clearing preferences" });
|
|
187
203
|
}
|
|
@@ -202,7 +218,8 @@ function handleGetLayouts(req, res, next) {
|
|
|
202
218
|
if (entry.name && entry.layout) {
|
|
203
219
|
const isValid = validateLayout(entry.layout);
|
|
204
220
|
if (!isValid) {
|
|
205
|
-
|
|
221
|
+
const errors = JSON.stringify(validateLayout.errors);
|
|
222
|
+
util_1.logger.warning(`Returning invalid layout '${entry.name}':\n${errors}`);
|
|
206
223
|
}
|
|
207
224
|
layouts[entry.name] = entry.layout;
|
|
208
225
|
}
|
|
@@ -232,7 +249,8 @@ function handleSetLayout(req, res, next) {
|
|
|
232
249
|
}
|
|
233
250
|
const validUpdate = validateLayout(layout);
|
|
234
251
|
if (!validUpdate) {
|
|
235
|
-
|
|
252
|
+
const errors = JSON.stringify(validateLayout.errors);
|
|
253
|
+
util_1.logger.warning(`Rejecting invalid layout update:\n${errors}`);
|
|
236
254
|
return next({ statusCode: 400, message: "Invalid layout update" });
|
|
237
255
|
}
|
|
238
256
|
try {
|
|
@@ -261,7 +279,10 @@ function handleClearLayout(req, res, next) {
|
|
|
261
279
|
}
|
|
262
280
|
const layoutName = (_a = req.body) === null || _a === void 0 ? void 0 : _a.layoutName;
|
|
263
281
|
try {
|
|
264
|
-
const deleteResult = yield layoutsCollection.deleteOne({
|
|
282
|
+
const deleteResult = yield layoutsCollection.deleteOne({
|
|
283
|
+
username: req.username,
|
|
284
|
+
name: layoutName
|
|
285
|
+
});
|
|
265
286
|
if (deleteResult.acknowledged) {
|
|
266
287
|
res.json({ success: true });
|
|
267
288
|
}
|
|
@@ -290,7 +311,8 @@ function handleGetSnippets(req, res, next) {
|
|
|
290
311
|
if (entry.name && entry.snippet) {
|
|
291
312
|
const isValid = validateSnippet(entry.snippet);
|
|
292
313
|
if (!isValid) {
|
|
293
|
-
|
|
314
|
+
const errors = JSON.stringify(validateSnippet.errors);
|
|
315
|
+
util_1.logger.warning(`Returning invalid snippet '${entry.name}':\n${errors}`);
|
|
294
316
|
}
|
|
295
317
|
snippets[entry.name] = entry.snippet;
|
|
296
318
|
}
|
|
@@ -320,7 +342,8 @@ function handleSetSnippet(req, res, next) {
|
|
|
320
342
|
}
|
|
321
343
|
const validUpdate = validateSnippet(snippet);
|
|
322
344
|
if (!validUpdate) {
|
|
323
|
-
|
|
345
|
+
const errors = JSON.stringify(validateSnippet.errors);
|
|
346
|
+
util_1.logger.error(`Rejecting invalid snippet update:\n${errors}`);
|
|
324
347
|
return next({ statusCode: 400, message: "Invalid snippet update" });
|
|
325
348
|
}
|
|
326
349
|
try {
|
|
@@ -349,7 +372,10 @@ function handleClearSnippet(req, res, next) {
|
|
|
349
372
|
}
|
|
350
373
|
const snippetName = (_a = req.body) === null || _a === void 0 ? void 0 : _a.snippetName;
|
|
351
374
|
try {
|
|
352
|
-
const deleteResult = yield snippetsCollection.deleteOne({
|
|
375
|
+
const deleteResult = yield snippetsCollection.deleteOne({
|
|
376
|
+
username: req.username,
|
|
377
|
+
name: snippetName
|
|
378
|
+
});
|
|
353
379
|
if (deleteResult.acknowledged) {
|
|
354
380
|
res.json({ success: true });
|
|
355
381
|
}
|
|
@@ -365,7 +391,7 @@ function handleClearSnippet(req, res, next) {
|
|
|
365
391
|
}
|
|
366
392
|
function handleClearWorkspace(req, res, next) {
|
|
367
393
|
return __awaiter(this, void 0, void 0, function* () {
|
|
368
|
-
var _a
|
|
394
|
+
var _a;
|
|
369
395
|
if (!req.username) {
|
|
370
396
|
return next({ statusCode: 403, message: "Invalid username" });
|
|
371
397
|
}
|
|
@@ -374,9 +400,12 @@ function handleClearWorkspace(req, res, next) {
|
|
|
374
400
|
}
|
|
375
401
|
const workspaceName = (_a = req.body) === null || _a === void 0 ? void 0 : _a.workspaceName;
|
|
376
402
|
// TODO: handle CRUD with workspace ID instead of name
|
|
377
|
-
const workspaceId =
|
|
403
|
+
// const workspaceId = req.body?.id;
|
|
378
404
|
try {
|
|
379
|
-
const deleteResult = yield workspacesCollection.deleteOne({
|
|
405
|
+
const deleteResult = yield workspacesCollection.deleteOne({
|
|
406
|
+
username: req.username,
|
|
407
|
+
name: workspaceName
|
|
408
|
+
});
|
|
380
409
|
if (deleteResult.acknowledged) {
|
|
381
410
|
res.json({ success: true });
|
|
382
411
|
}
|
|
@@ -401,7 +430,10 @@ function handleGetWorkspaceList(req, res, next) {
|
|
|
401
430
|
}
|
|
402
431
|
try {
|
|
403
432
|
const workspaceList = yield workspacesCollection.find({ username: req.username }, { projection: { _id: 1, name: 1, "workspace.date": 1 } }).toArray();
|
|
404
|
-
const workspaces = (_a = workspaceList === null || workspaceList === void 0 ? void 0 : workspaceList.map(w => {
|
|
433
|
+
const workspaces = (_a = workspaceList === null || workspaceList === void 0 ? void 0 : workspaceList.map(w => {
|
|
434
|
+
var _a;
|
|
435
|
+
return (Object.assign(Object.assign({}, w), { id: w._id.toString(), date: (_a = w.workspace) === null || _a === void 0 ? void 0 : _a.date }));
|
|
436
|
+
})) !== null && _a !== void 0 ? _a : [];
|
|
405
437
|
res.json({ success: true, workspaces });
|
|
406
438
|
}
|
|
407
439
|
catch (err) {
|
|
@@ -428,10 +460,11 @@ function handleGetWorkspaceByName(req, res, next) {
|
|
|
428
460
|
return next({ statusCode: 404, message: "Workspace not found" });
|
|
429
461
|
}
|
|
430
462
|
else {
|
|
431
|
-
const workspace = Object.assign({ id: queryResult._id, name: queryResult.name, editable: true }, queryResult.workspace);
|
|
463
|
+
const workspace = Object.assign({ id: queryResult._id.toString(), name: queryResult.name, editable: true }, queryResult.workspace);
|
|
432
464
|
const isValid = validateWorkspace(workspace);
|
|
433
465
|
if (!isValid) {
|
|
434
|
-
|
|
466
|
+
const errors = JSON.stringify(validateWorkspace.errors);
|
|
467
|
+
util_1.logger.warning(`Returning invalid workspace '${workspace.name}':\n${errors}`);
|
|
435
468
|
}
|
|
436
469
|
res.json({ success: true, workspace: workspace });
|
|
437
470
|
}
|
|
@@ -456,7 +489,9 @@ function handleGetWorkspaceByKey(req, res, next) {
|
|
|
456
489
|
}
|
|
457
490
|
try {
|
|
458
491
|
const objectId = Buffer.from(req.params.key, "base64url").toString("hex");
|
|
459
|
-
const queryResult = yield workspacesCollection.findOne({
|
|
492
|
+
const queryResult = yield workspacesCollection.findOne({
|
|
493
|
+
_id: new mongodb_1.ObjectId(objectId)
|
|
494
|
+
});
|
|
460
495
|
if (!(queryResult === null || queryResult === void 0 ? void 0 : queryResult.workspace)) {
|
|
461
496
|
return next({ statusCode: 404, message: "Workspace not found" });
|
|
462
497
|
}
|
|
@@ -464,10 +499,11 @@ function handleGetWorkspaceByKey(req, res, next) {
|
|
|
464
499
|
return next({ statusCode: 403, message: "Workspace not accessible" });
|
|
465
500
|
}
|
|
466
501
|
else {
|
|
467
|
-
const workspace = Object.assign({ id: queryResult._id, name: queryResult.name, editable: queryResult.username === req.username }, queryResult.workspace);
|
|
502
|
+
const workspace = Object.assign({ id: queryResult._id.toString(), name: queryResult.name, editable: queryResult.username === req.username }, queryResult.workspace);
|
|
468
503
|
const isValid = validateWorkspace(workspace);
|
|
469
504
|
if (!isValid) {
|
|
470
|
-
|
|
505
|
+
const errors = JSON.stringify(validateWorkspace.errors);
|
|
506
|
+
util_1.logger.warning(`Returning invalid workspace '${workspace.name}':\n${errors}`);
|
|
471
507
|
}
|
|
472
508
|
res.json({ success: true, workspace: workspace });
|
|
473
509
|
}
|
|
@@ -495,7 +531,8 @@ function handleSetWorkspace(req, res, next) {
|
|
|
495
531
|
}
|
|
496
532
|
const validUpdate = validateWorkspace(workspace);
|
|
497
533
|
if (!validUpdate) {
|
|
498
|
-
|
|
534
|
+
const errors = JSON.stringify(validateWorkspace.errors);
|
|
535
|
+
util_1.logger.error(`Rejecting invalid workspace update:\n${errors}`);
|
|
499
536
|
return next({ statusCode: 400, message: "Invalid workspace update" });
|
|
500
537
|
}
|
|
501
538
|
try {
|
package/dist/index.js
CHANGED
|
@@ -46,22 +46,22 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
46
46
|
};
|
|
47
47
|
var _a;
|
|
48
48
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
49
|
-
const
|
|
49
|
+
const fs = __importStar(require("node:fs"));
|
|
50
|
+
const http = __importStar(require("node:http"));
|
|
51
|
+
const path = __importStar(require("node:path"));
|
|
52
|
+
const url = __importStar(require("node:url"));
|
|
50
53
|
const bodyParser = __importStar(require("body-parser"));
|
|
51
|
-
const
|
|
54
|
+
const compression_1 = __importDefault(require("compression"));
|
|
52
55
|
const cookie_parser_1 = __importDefault(require("cookie-parser"));
|
|
53
|
-
const http_proxy_1 = __importDefault(require("http-proxy"));
|
|
54
|
-
const http = __importStar(require("http"));
|
|
55
|
-
const url = __importStar(require("url"));
|
|
56
56
|
const cors_1 = __importDefault(require("cors"));
|
|
57
|
-
const
|
|
58
|
-
const
|
|
59
|
-
const
|
|
60
|
-
const config_1 = require("./config");
|
|
61
|
-
const serverHandlers_1 = require("./serverHandlers");
|
|
57
|
+
const express_1 = __importDefault(require("express"));
|
|
58
|
+
const express_bearer_token_1 = __importDefault(require("express-bearer-token"));
|
|
59
|
+
const http_proxy_1 = __importDefault(require("http-proxy"));
|
|
62
60
|
const auth_1 = require("./auth");
|
|
63
|
-
const
|
|
61
|
+
const config_1 = require("./config");
|
|
64
62
|
const controllerTests_1 = require("./controllerTests");
|
|
63
|
+
const database_1 = require("./database");
|
|
64
|
+
const serverHandlers_1 = require("./serverHandlers");
|
|
65
65
|
const util_1 = require("./util");
|
|
66
66
|
if (config_1.testUser) {
|
|
67
67
|
(0, controllerTests_1.runTests)(config_1.testUser).then(() => {
|
|
@@ -74,7 +74,7 @@ if (config_1.testUser) {
|
|
|
74
74
|
});
|
|
75
75
|
}
|
|
76
76
|
else {
|
|
77
|
-
|
|
77
|
+
const app = (0, express_1.default)();
|
|
78
78
|
app.use(bodyParser.urlencoded({ extended: true }));
|
|
79
79
|
app.use((0, cookie_parser_1.default)());
|
|
80
80
|
app.use((0, express_bearer_token_1.default)());
|
|
@@ -85,7 +85,7 @@ else {
|
|
|
85
85
|
app.use("/api/auth", bodyParser.json(), auth_1.authRouter);
|
|
86
86
|
app.use("/api/server", bodyParser.json(), serverHandlers_1.serverRouter);
|
|
87
87
|
app.use("/api/database", bodyParser.json(), database_1.databaseRouter);
|
|
88
|
-
app.use("/config", (
|
|
88
|
+
app.use("/config", (_req, res) => {
|
|
89
89
|
return res.json(config_1.RuntimeConfig);
|
|
90
90
|
});
|
|
91
91
|
// Prevent caching of the frontend HTML code
|
|
@@ -96,7 +96,9 @@ else {
|
|
|
96
96
|
};
|
|
97
97
|
if (config_1.ServerConfig.frontendPath) {
|
|
98
98
|
util_1.logger.info(`Serving CARTA frontend from ${config_1.ServerConfig.frontendPath}`);
|
|
99
|
-
app.use("/", express_1.default.static(config_1.ServerConfig.frontendPath, {
|
|
99
|
+
app.use("/", express_1.default.static(config_1.ServerConfig.frontendPath, {
|
|
100
|
+
setHeaders: staticHeaderHandler
|
|
101
|
+
}));
|
|
100
102
|
}
|
|
101
103
|
else {
|
|
102
104
|
const frontendPackage = require("../node_modules/carta-frontend/package.json");
|
|
@@ -109,24 +111,24 @@ else {
|
|
|
109
111
|
const isBannerSvg = config_1.ServerConfig.dashboard.bannerImage.toLowerCase().endsWith(".svg");
|
|
110
112
|
const bannerDataBase64 = fs.readFileSync(config_1.ServerConfig.dashboard.bannerImage, "base64");
|
|
111
113
|
if (isBannerSvg) {
|
|
112
|
-
bannerDataUri =
|
|
114
|
+
bannerDataUri = `data:image/svg+xml;base64,${bannerDataBase64}`;
|
|
113
115
|
}
|
|
114
116
|
else {
|
|
115
|
-
bannerDataUri =
|
|
117
|
+
bannerDataUri = `data:image/png;base64,${bannerDataBase64}`;
|
|
116
118
|
}
|
|
117
119
|
}
|
|
118
120
|
app.get("/frontend", (req, res) => {
|
|
119
121
|
var _a, _b, _c;
|
|
120
122
|
const queryString = (_a = url.parse(req.url, false)) === null || _a === void 0 ? void 0 : _a.query;
|
|
121
123
|
if (queryString) {
|
|
122
|
-
return res.redirect((
|
|
124
|
+
return res.redirect(`${(_b = config_1.ServerConfig.serverAddress) !== null && _b !== void 0 ? _b : ""}/?${queryString}`);
|
|
123
125
|
}
|
|
124
126
|
else {
|
|
125
127
|
return res.redirect((_c = config_1.ServerConfig.serverAddress) !== null && _c !== void 0 ? _c : "");
|
|
126
128
|
}
|
|
127
129
|
});
|
|
128
130
|
const packageJson = require(path.join(__dirname, "../package.json"));
|
|
129
|
-
app.get("/dashboard", (
|
|
131
|
+
app.get("/dashboard", (_req, res) => {
|
|
130
132
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
131
133
|
res.render("templated", {
|
|
132
134
|
googleClientId: (_a = config_1.ServerConfig.authProviders.google) === null || _a === void 0 ? void 0 : _a.clientId,
|
|
@@ -147,11 +149,10 @@ else {
|
|
|
147
149
|
const backendProxy = http_proxy_1.default.createServer({ ws: true });
|
|
148
150
|
app.post("/api/scripting/*", auth_1.authGuard, (0, serverHandlers_1.createScriptingProxyHandler)(backendProxy));
|
|
149
151
|
// Simplified error handling
|
|
150
|
-
app.use((err,
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
status: err.status,
|
|
152
|
+
app.use((err, _req, res, _next) => {
|
|
153
|
+
var _a, _b;
|
|
154
|
+
res.status((_a = err.statusCode) !== null && _a !== void 0 ? _a : 500).json({
|
|
155
|
+
status: (_b = err.status) !== null && _b !== void 0 ? _b : "error",
|
|
155
156
|
message: err.message
|
|
156
157
|
});
|
|
157
158
|
});
|