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.
- package/.github/workflows/build.yml +43 -0
- package/COPYING.md +636 -0
- 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 +50 -22
- package/dist/index.js +24 -23
- package/dist/serverHandlers.js +70 -33
- package/dist/util.js +14 -5
- package/npm-shrinkwrap.json +4855 -20113
- package/package.json +12 -9
- 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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "carta-controller",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0-beta.1.0.3",
|
|
4
4
|
"description": "NodeJS-based controller for CARTA",
|
|
5
5
|
"repository": "https://github.com/CARTAvis/carta-controller",
|
|
6
6
|
"homepage": "https://www.cartavis.org",
|
|
@@ -12,20 +12,24 @@
|
|
|
12
12
|
"scripts": {
|
|
13
13
|
"start": "npx ts-node src/index.ts",
|
|
14
14
|
"test": "npx ts-node src/index.ts --test",
|
|
15
|
-
"reformat": "npx
|
|
16
|
-
"checkformat": "npx
|
|
15
|
+
"reformat": "npx @biomejs/biome format --write",
|
|
16
|
+
"checkformat": "npx @biomejs/biome format",
|
|
17
|
+
"lint": "npx @biomejs/biome lint",
|
|
18
|
+
"fixlint": "npx @biomejs/biome lint --write",
|
|
19
|
+
"checkformat-and-lint": "npx @biomejs/biome check",
|
|
20
|
+
"reformat-and-fixlint": "npx @biomejs/biome check --write",
|
|
17
21
|
"prepare": "npx tsc",
|
|
18
22
|
"unit-test": "vitest run"
|
|
19
23
|
},
|
|
20
24
|
"author": "",
|
|
21
|
-
"license": "
|
|
25
|
+
"license": "GPLV3",
|
|
22
26
|
"dependencies": {
|
|
23
27
|
"@pm2/io": "^6.1.0",
|
|
24
28
|
"ajv": "^8.17.1",
|
|
25
29
|
"ajv-formats": "^3.0.1",
|
|
26
30
|
"axios": "^1.8.2",
|
|
27
31
|
"body-parser": "^1.19.0",
|
|
28
|
-
"carta-frontend": "^
|
|
32
|
+
"carta-frontend": "^6.0.0-beta.1.0.2",
|
|
29
33
|
"compression": "^1.8.0",
|
|
30
34
|
"cookie-parser": "^1.4.7",
|
|
31
35
|
"cors": "^2.8.5",
|
|
@@ -45,16 +49,17 @@
|
|
|
45
49
|
"moment-timezone": "^0.6.0",
|
|
46
50
|
"mongodb": "^5.8.0",
|
|
47
51
|
"ms": "^2.1.3",
|
|
48
|
-
"node-linux-pam": "
|
|
52
|
+
"node-linux-pam": "github:cartavis/node-linux-pam#v0.2.2",
|
|
49
53
|
"pug": "^3.0.0",
|
|
50
54
|
"read": "^2.0.0",
|
|
51
55
|
"tcp-port-used": "^1.0.2",
|
|
52
56
|
"uuid": "^9.0.0",
|
|
53
|
-
"websocket": "^1.0.
|
|
57
|
+
"websocket": "^1.0.35",
|
|
54
58
|
"winston": "^3.17.0",
|
|
55
59
|
"yargs": "^17.0.1"
|
|
56
60
|
},
|
|
57
61
|
"devDependencies": {
|
|
62
|
+
"@biomejs/biome": "2.1.4",
|
|
58
63
|
"@types/compression": "^1.7.0",
|
|
59
64
|
"@types/cookie-parser": "^1.4.8",
|
|
60
65
|
"@types/cors": "^2.8.10",
|
|
@@ -68,8 +73,6 @@
|
|
|
68
73
|
"@types/uuid": "^9.0.0",
|
|
69
74
|
"@types/websocket": "^1.0.2",
|
|
70
75
|
"@types/yargs": "^17.0.22",
|
|
71
|
-
"patch-package": "^7.0.0",
|
|
72
|
-
"prettier": "2.8.4",
|
|
73
76
|
"ts-node": "^10.9.1",
|
|
74
77
|
"typescript": "^5.5.4",
|
|
75
78
|
"vitest": "^3.1.4"
|
package/public/dashboard.js
CHANGED
|
@@ -12,7 +12,6 @@ const isPopup = urlParams.get("popup");
|
|
|
12
12
|
|
|
13
13
|
let serverCheckHandle;
|
|
14
14
|
|
|
15
|
-
let authenticationType = "";
|
|
16
15
|
let authenticatedUser = "";
|
|
17
16
|
let token = "";
|
|
18
17
|
let tokenLifetime = -1;
|
|
@@ -22,8 +21,7 @@ let notyf;
|
|
|
22
21
|
|
|
23
22
|
let apiBase;
|
|
24
23
|
getApiBase = async () => {
|
|
25
|
-
if (apiBase)
|
|
26
|
-
return apiBase;
|
|
24
|
+
if (apiBase) return apiBase;
|
|
27
25
|
else {
|
|
28
26
|
try {
|
|
29
27
|
const configData = await fetch(`${strippedPath}config`);
|
|
@@ -35,7 +33,7 @@ getApiBase = async () => {
|
|
|
35
33
|
return "/api"; // use default
|
|
36
34
|
}
|
|
37
35
|
}
|
|
38
|
-
}
|
|
36
|
+
};
|
|
39
37
|
|
|
40
38
|
apiCall = async (callName, jsonBody, method, authRequired) => {
|
|
41
39
|
const options = {
|
|
@@ -43,13 +41,13 @@ apiCall = async (callName, jsonBody, method, authRequired) => {
|
|
|
43
41
|
};
|
|
44
42
|
if (method !== "get" && jsonBody) {
|
|
45
43
|
options.body = JSON.stringify(jsonBody);
|
|
46
|
-
options.headers = {"Content-Type": "application/json"}
|
|
44
|
+
options.headers = {"Content-Type": "application/json"};
|
|
47
45
|
} else {
|
|
48
46
|
options.headers = {};
|
|
49
47
|
}
|
|
50
48
|
|
|
51
49
|
if (token) {
|
|
52
|
-
options.headers
|
|
50
|
+
options.headers.Authorization = `Bearer ${token}`;
|
|
53
51
|
}
|
|
54
52
|
|
|
55
53
|
const currentTime = Date.now() / 1000;
|
|
@@ -62,12 +60,12 @@ apiCall = async (callName, jsonBody, method, authRequired) => {
|
|
|
62
60
|
}
|
|
63
61
|
}
|
|
64
62
|
return fetch(`${await getApiBase()}/${callName}`, options);
|
|
65
|
-
}
|
|
63
|
+
};
|
|
66
64
|
|
|
67
65
|
function setToken(tokenString, expiresIn) {
|
|
68
66
|
token = tokenString;
|
|
69
67
|
tokenLifetime = expiresIn;
|
|
70
|
-
if (isFinite(tokenLifetime) && tokenLifetime > 0) {
|
|
68
|
+
if (Number.isFinite(tokenLifetime) && tokenLifetime > 0) {
|
|
71
69
|
console.log(`Token updated and valid for ${tokenLifetime.toFixed()} seconds`);
|
|
72
70
|
const currentTimeSeconds = Date.now() / 1000;
|
|
73
71
|
tokenExpiryTime = currentTimeSeconds + tokenLifetime;
|
|
@@ -98,7 +96,7 @@ showMessage = (message, error, elementId) => {
|
|
|
98
96
|
statusElement.className = "success-message";
|
|
99
97
|
}
|
|
100
98
|
statusElement.innerHTML = message;
|
|
101
|
-
}
|
|
99
|
+
};
|
|
102
100
|
|
|
103
101
|
setButtonDisabled = (elementId, disabled) => {
|
|
104
102
|
const button = document.getElementById(elementId);
|
|
@@ -107,10 +105,10 @@ setButtonDisabled = (elementId, disabled) => {
|
|
|
107
105
|
if (disabled) {
|
|
108
106
|
button.classList.add("button-disabled");
|
|
109
107
|
} else {
|
|
110
|
-
button.classList.remove("button-disabled")
|
|
108
|
+
button.classList.remove("button-disabled");
|
|
111
109
|
}
|
|
112
110
|
}
|
|
113
|
-
}
|
|
111
|
+
};
|
|
114
112
|
|
|
115
113
|
updateServerStatus = async () => {
|
|
116
114
|
let hasServer = false;
|
|
@@ -130,15 +128,15 @@ updateServerStatus = async () => {
|
|
|
130
128
|
}
|
|
131
129
|
updateRedirectURL(hasServer);
|
|
132
130
|
serverRunning = hasServer;
|
|
133
|
-
}
|
|
131
|
+
};
|
|
134
132
|
|
|
135
|
-
updateRedirectURL =
|
|
133
|
+
updateRedirectURL = hasServer => {
|
|
136
134
|
if (hasServer) {
|
|
137
135
|
showMessage("CARTA server running", false, "carta-status");
|
|
138
136
|
} else {
|
|
139
137
|
showMessage(`Logged in as ${authenticatedUser}`, false, "carta-status");
|
|
140
138
|
}
|
|
141
|
-
}
|
|
139
|
+
};
|
|
142
140
|
|
|
143
141
|
handleLogin = async () => {
|
|
144
142
|
setButtonDisabled("login", true);
|
|
@@ -156,20 +154,19 @@ handleLogin = async () => {
|
|
|
156
154
|
} else {
|
|
157
155
|
onLoginFailed(res.status);
|
|
158
156
|
}
|
|
159
|
-
} catch (
|
|
157
|
+
} catch (_e) {
|
|
160
158
|
onLoginFailed(500);
|
|
161
159
|
}
|
|
162
160
|
setButtonDisabled("login", false);
|
|
163
161
|
};
|
|
164
162
|
|
|
165
|
-
onLoginFailed =
|
|
163
|
+
onLoginFailed = status => {
|
|
166
164
|
clearToken();
|
|
167
165
|
notyf.error(status === 403 ? "Invalid username/password combination" : "Could not authenticate correctly");
|
|
168
|
-
}
|
|
166
|
+
};
|
|
169
167
|
|
|
170
168
|
onLoginSucceeded = async (username, type) => {
|
|
171
169
|
authenticatedUser = username;
|
|
172
|
-
authenticationType = type;
|
|
173
170
|
localStorage.setItem("authenticationType", type);
|
|
174
171
|
notyf.success(`Logged in as ${authenticatedUser}`);
|
|
175
172
|
if (autoRedirect) {
|
|
@@ -181,7 +178,7 @@ onLoginSucceeded = async (username, type) => {
|
|
|
181
178
|
serverCheckHandle = setInterval(updateServerStatus, 5000);
|
|
182
179
|
await updateServerStatus();
|
|
183
180
|
}
|
|
184
|
-
}
|
|
181
|
+
};
|
|
185
182
|
|
|
186
183
|
handleServerStop = async () => {
|
|
187
184
|
try {
|
|
@@ -202,7 +199,7 @@ handleServerStop = async () => {
|
|
|
202
199
|
notyf.error("Failed to stop CARTA server");
|
|
203
200
|
console.log(e);
|
|
204
201
|
}
|
|
205
|
-
}
|
|
202
|
+
};
|
|
206
203
|
|
|
207
204
|
handleLogout = async () => {
|
|
208
205
|
localStorage.removeItem("authenticationType");
|
|
@@ -210,11 +207,11 @@ handleLogout = async () => {
|
|
|
210
207
|
await handleServerStop();
|
|
211
208
|
}
|
|
212
209
|
window.open(`${await getApiBase()}/auth/logout`, "_self");
|
|
213
|
-
}
|
|
210
|
+
};
|
|
214
211
|
|
|
215
212
|
handleOpenCarta = () => {
|
|
216
213
|
window.open(redirectUrl, "_self");
|
|
217
|
-
}
|
|
214
|
+
};
|
|
218
215
|
|
|
219
216
|
handleLog = async () => {
|
|
220
217
|
// Disable log buttons for 5 seconds
|
|
@@ -230,7 +227,7 @@ handleLog = async () => {
|
|
|
230
227
|
const res = await apiCall("server/log", undefined, "get", true);
|
|
231
228
|
const body = await res.json();
|
|
232
229
|
if (body.success && body.log) {
|
|
233
|
-
document.getElementById("log-modal").style.display = "block"
|
|
230
|
+
document.getElementById("log-modal").style.display = "block";
|
|
234
231
|
document.getElementById("main-div").classList.add("blurred");
|
|
235
232
|
const outputElement = document.getElementById("log-output");
|
|
236
233
|
if (outputElement) {
|
|
@@ -244,25 +241,25 @@ handleLog = async () => {
|
|
|
244
241
|
} catch (e) {
|
|
245
242
|
console.log(e);
|
|
246
243
|
}
|
|
247
|
-
}
|
|
244
|
+
};
|
|
248
245
|
|
|
249
246
|
handleHideLog = () => {
|
|
250
|
-
document.getElementById("log-modal").style.display = "none"
|
|
247
|
+
document.getElementById("log-modal").style.display = "none";
|
|
251
248
|
document.getElementById("main-div").classList.remove("blurred");
|
|
252
|
-
}
|
|
249
|
+
};
|
|
253
250
|
|
|
254
251
|
handleLocalLogout = async () => {
|
|
255
252
|
await apiCall("auth/logout", undefined, "post", false);
|
|
256
|
-
}
|
|
253
|
+
};
|
|
257
254
|
|
|
258
|
-
handleKeyup =
|
|
255
|
+
handleKeyup = e => {
|
|
259
256
|
if (e.keyCode === 13) {
|
|
260
257
|
const loginButton = document.getElementById("login");
|
|
261
258
|
if (loginButton && !loginButton.disabled) {
|
|
262
259
|
handleLogin();
|
|
263
260
|
}
|
|
264
261
|
}
|
|
265
|
-
}
|
|
262
|
+
};
|
|
266
263
|
|
|
267
264
|
refreshLocalToken = async () => {
|
|
268
265
|
try {
|
|
@@ -277,46 +274,47 @@ refreshLocalToken = async () => {
|
|
|
277
274
|
notyf.error("Error refreshing authentication");
|
|
278
275
|
console.log(err);
|
|
279
276
|
}
|
|
280
|
-
}
|
|
277
|
+
};
|
|
281
278
|
|
|
282
|
-
showCartaForm =
|
|
279
|
+
showCartaForm = show => {
|
|
283
280
|
const cartaForm = document.getElementsByClassName("carta-form")[0];
|
|
284
281
|
if (show) {
|
|
285
282
|
cartaForm.style.display = "block";
|
|
286
283
|
} else {
|
|
287
284
|
cartaForm.style.display = "none";
|
|
288
|
-
|
|
289
285
|
}
|
|
290
|
-
}
|
|
286
|
+
};
|
|
291
287
|
|
|
292
|
-
showLoginForm =
|
|
288
|
+
showLoginForm = show => {
|
|
293
289
|
const loginForm = document.getElementsByClassName("login-form")[0];
|
|
294
290
|
if (show) {
|
|
295
291
|
loginForm.style.display = "block";
|
|
296
292
|
} else {
|
|
297
293
|
loginForm.style.display = "none";
|
|
298
|
-
|
|
299
294
|
}
|
|
300
|
-
}
|
|
295
|
+
};
|
|
301
296
|
|
|
302
297
|
window.onload = async () => {
|
|
303
298
|
notyf = new Notyf({
|
|
304
299
|
ripple: true,
|
|
305
300
|
position: {x: "center"},
|
|
306
|
-
types: [
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
301
|
+
types: [
|
|
302
|
+
{
|
|
303
|
+
type: "warning",
|
|
304
|
+
background: "orange"
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
type: "info",
|
|
308
|
+
background: "#4c84af"
|
|
309
|
+
}
|
|
310
|
+
]
|
|
313
311
|
});
|
|
314
312
|
|
|
315
313
|
// Check for completed login
|
|
316
314
|
const usp = new URLSearchParams(window.location.search);
|
|
317
315
|
if (usp.has("oidcuser")) {
|
|
318
316
|
await refreshLocalToken();
|
|
319
|
-
onLoginSucceeded(usp.get("oidcuser"), "oidc")
|
|
317
|
+
onLoginSucceeded(usp.get("oidcuser"), "oidc");
|
|
320
318
|
} else if (usp.has("googleuser")) {
|
|
321
319
|
await refreshLocalToken();
|
|
322
320
|
if (localStorage.getItem("redirectParams")) {
|
|
@@ -324,7 +322,7 @@ window.onload = async () => {
|
|
|
324
322
|
localStorage.removeItem("redirectParams");
|
|
325
323
|
autoRedirect = true;
|
|
326
324
|
}
|
|
327
|
-
onLoginSucceeded(usp.get("googleuser"), "google")
|
|
325
|
+
onLoginSucceeded(usp.get("googleuser"), "google");
|
|
328
326
|
} else if (usp.has("err")) {
|
|
329
327
|
console.log(usp.get("err"));
|
|
330
328
|
notyf.open({type: "error", message: usp.get("err")});
|
|
@@ -375,7 +373,9 @@ window.onload = async () => {
|
|
|
375
373
|
|
|
376
374
|
const oidcLoginButton = document.getElementById("oidcLogin");
|
|
377
375
|
if (oidcLoginButton) {
|
|
378
|
-
oidcLoginButton.onclick = async () => {
|
|
376
|
+
oidcLoginButton.onclick = async () => {
|
|
377
|
+
window.location.href = `${await getApiBase()}/auth/login${window.location.search}`;
|
|
378
|
+
};
|
|
379
379
|
}
|
|
380
380
|
|
|
381
381
|
document.getElementById("stop").onclick = handleServerStop;
|
|
@@ -384,5 +384,4 @@ window.onload = async () => {
|
|
|
384
384
|
document.getElementById("refresh-logs").onclick = handleLog;
|
|
385
385
|
document.getElementById("hide-logs").onclick = handleHideLog;
|
|
386
386
|
document.getElementById("logout").onclick = handleLogout;
|
|
387
|
-
|
|
388
|
-
}
|
|
387
|
+
};
|