cloudron 4.12.2 → 4.12.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jshintrc +1 -0
- package/package.json +7 -7
- package/src/actions.js +58 -63
- package/src/helper.js +6 -6
package/.jshintrc
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cloudron",
|
|
3
|
-
"version": "4.12.
|
|
3
|
+
"version": "4.12.6",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Cloudron Commandline Tool",
|
|
6
6
|
"main": "main.js",
|
|
@@ -17,23 +17,23 @@
|
|
|
17
17
|
},
|
|
18
18
|
"author": "Cloudron Developers <support@cloudron.io>",
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"async": "^3.2.
|
|
20
|
+
"async": "^3.2.1",
|
|
21
21
|
"cloudron-manifestformat": "^5.10.2",
|
|
22
22
|
"colors": "^1.4.0",
|
|
23
23
|
"commander": "^6.1.0",
|
|
24
|
-
"debug": "^4.3.
|
|
24
|
+
"debug": "^4.3.2",
|
|
25
25
|
"easy-table": "^1.1.1",
|
|
26
26
|
"ejs": "^3.1.6",
|
|
27
27
|
"eventsource": "^1.1.0",
|
|
28
28
|
"micromatch": "^4.0.4",
|
|
29
29
|
"mkdirp": "^1.0.4",
|
|
30
30
|
"once": "^1.4.0",
|
|
31
|
-
"open": "^8.2.
|
|
31
|
+
"open": "^8.2.1",
|
|
32
32
|
"progress": "^2.0.3",
|
|
33
33
|
"progress-stream": "^2.0.0",
|
|
34
34
|
"readline-sync": "^1.4.10",
|
|
35
35
|
"request": "^2.88.2",
|
|
36
|
-
"safetydance": "^2.0
|
|
36
|
+
"safetydance": "^2.2.0",
|
|
37
37
|
"split": "^1.0.1",
|
|
38
38
|
"superagent": "^6.1.0",
|
|
39
39
|
"superagent-sync": "^0.2.1",
|
|
@@ -42,12 +42,12 @@
|
|
|
42
42
|
"underscore": "^1.13.1"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
|
45
|
-
"node": ">=
|
|
45
|
+
"node": ">= 14.x.x"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"expect.js": "^0.3.1",
|
|
49
49
|
"memorystream": "^0.3.1",
|
|
50
|
-
"mocha": "^9.
|
|
50
|
+
"mocha": "^9.1.1",
|
|
51
51
|
"rimraf": "^3.0.2"
|
|
52
52
|
}
|
|
53
53
|
}
|
package/src/actions.js
CHANGED
|
@@ -20,6 +20,7 @@ const assert = require('assert'),
|
|
|
20
20
|
safe = require('safetydance'),
|
|
21
21
|
spawn = require('child_process').spawn,
|
|
22
22
|
split = require('split'),
|
|
23
|
+
superagent = require('superagent'),
|
|
23
24
|
Table = require('easy-table'),
|
|
24
25
|
tar = require('tar-fs'),
|
|
25
26
|
util = require('util'),
|
|
@@ -81,6 +82,8 @@ function requestOptions(options) {
|
|
|
81
82
|
|
|
82
83
|
// error for the request module
|
|
83
84
|
function requestError(response) {
|
|
85
|
+
if (response.statusCode === 401) return 'Invalid token. Use cloudron login again.';
|
|
86
|
+
|
|
84
87
|
return `${response.statusCode} message: ${response.body.message || response.body}`; // body is sometimes just a string like in 401
|
|
85
88
|
}
|
|
86
89
|
|
|
@@ -246,81 +249,73 @@ function startApp(app, options, callback) {
|
|
|
246
249
|
});
|
|
247
250
|
}
|
|
248
251
|
|
|
249
|
-
function
|
|
252
|
+
async function authenticate(adminFqdn, username, password, options) {
|
|
253
|
+
let totpToken;
|
|
254
|
+
|
|
255
|
+
const { rejectUnauthorized, askForTotpToken } = options;
|
|
256
|
+
if (askForTotpToken) totpToken = readlineSync.question('2FA Token: ', {});
|
|
257
|
+
|
|
258
|
+
const request = superagent.post(`https://${adminFqdn}/api/v1/cloudron/login`)
|
|
259
|
+
.timeout(10000)
|
|
260
|
+
.send({ username, password, totpToken })
|
|
261
|
+
.ok(() => true)
|
|
262
|
+
.set('User-Agent', 'cloudron-cli');
|
|
263
|
+
if (!rejectUnauthorized) request.disableTLSCerts();
|
|
264
|
+
const response = await request; // this triggers the request
|
|
265
|
+
if (response.status === 401) {
|
|
266
|
+
if (response.body.message === 'A totpToken must be provided') {
|
|
267
|
+
return await authenticate(username, password, { rejectUnauthorized, askForTotpToken: true });
|
|
268
|
+
} else if (response.body.message === 'Invalid totpToken') {
|
|
269
|
+
console.log('Invalid 2FA Token'.red);
|
|
270
|
+
return await authenticate(username, password, { rejectUnauthorized, askForTotpToken: true });
|
|
271
|
+
} else {
|
|
272
|
+
throw new Error('Invalid credentials');
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (response.statusCode !== 200) throw new Error(`Login failed: Status code: ${requestError(response)}`);
|
|
277
|
+
|
|
278
|
+
return response.body.accessToken;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
async function login(adminFqdn, options) {
|
|
250
282
|
if (!adminFqdn) adminFqdn = readlineSync.question('Cloudron Domain (e.g. my.example.com): ', {});
|
|
251
283
|
if (!adminFqdn) return exit('');
|
|
252
284
|
|
|
253
285
|
if (adminFqdn.indexOf('https://') === 0) adminFqdn = adminFqdn.slice('https://'.length);
|
|
254
286
|
if (adminFqdn.indexOf('/') !== -1) adminFqdn = adminFqdn.slice(0, adminFqdn.indexOf('/'));
|
|
255
287
|
|
|
256
|
-
|
|
257
|
-
config.setActive(adminFqdn);
|
|
258
|
-
|
|
259
|
-
const token = config.token();
|
|
260
|
-
if (!token) return callback('no token');
|
|
261
|
-
|
|
262
|
-
request.get(`https://${adminFqdn}/api/v1/profile?access_token=${token}`, {}, function (error, response) {
|
|
263
|
-
if (error) return callback(error);
|
|
264
|
-
if (response.statusCode !== 200) return callback(`Failed to get profile: ${requestError(response)}`);
|
|
288
|
+
config.setActive(adminFqdn);
|
|
265
289
|
|
|
290
|
+
let token = config.token();
|
|
291
|
+
if (token) { // check if the token is not expired
|
|
292
|
+
const [error, response] = await safe(superagent.get(`https://${adminFqdn}/api/v1/profile?access_token=${token}`)
|
|
293
|
+
.timeout(10000)
|
|
294
|
+
.ok(() => true));
|
|
295
|
+
if (error) return exit(error);
|
|
296
|
+
if (response.status === 200) {
|
|
266
297
|
console.log('Existing token still valid.'.green);
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
298
|
+
} else {
|
|
299
|
+
token = null;
|
|
300
|
+
console.log(`Existing token possibly expired: ${requestError(response)}`.red);
|
|
301
|
+
}
|
|
270
302
|
}
|
|
271
303
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
if (askForTotpToken) totpToken = readlineSync.question('2FA Token: ', {});
|
|
276
|
-
|
|
304
|
+
if (!token) {
|
|
305
|
+
const username = options.username || readlineSync.question('Username: ', {});
|
|
306
|
+
const password = options.password || readlineSync.question('Password: ', { noEchoBack: true });
|
|
277
307
|
const rejectUnauthorized = !(options.parent.allowSelfsigned || options.parent.acceptSelfsigned);
|
|
278
|
-
request.post(`https://${adminFqdn}/api/v1/cloudron/login`, {
|
|
279
|
-
headers: {
|
|
280
|
-
'User-Agent': 'cloudron-cli'
|
|
281
|
-
},
|
|
282
|
-
rejectUnauthorized,
|
|
283
|
-
json: {
|
|
284
|
-
username,
|
|
285
|
-
password,
|
|
286
|
-
totpToken
|
|
287
|
-
}
|
|
288
|
-
}, function (error, response) {
|
|
289
|
-
if (error) return exit(error);
|
|
290
|
-
if (response.statusCode === 401) {
|
|
291
|
-
if (response.body.message === 'A totpToken must be provided') {
|
|
292
|
-
return authenticate(username, password, true);
|
|
293
|
-
} else if (response.body.message === 'Invalid totpToken') {
|
|
294
|
-
console.log('Invalid 2FA Token'.red);
|
|
295
|
-
return authenticate(username, password, true);
|
|
296
|
-
} else {
|
|
297
|
-
exit('Invalid credentials');
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
if (response.statusCode !== 200) return exit(new Error(`Login failed: Status code: ${requestError(response)}`));
|
|
301
|
-
|
|
302
|
-
console.log('Login successful.'.green);
|
|
303
|
-
|
|
304
|
-
done(response.body.accessToken);
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
308
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
config.setToken(token);
|
|
312
|
-
config.setAllowSelfsigned(options.parent.allowSelfsigned || options.parent.acceptSelfsigned);
|
|
313
|
-
config.set('cloudrons.default', adminFqdn);
|
|
309
|
+
const [error, result] = await safe(authenticate(adminFqdn, username, password, { rejectUnauthorized, askForTotpToken: false }));
|
|
310
|
+
if (error) return exit(`Failed to login: ${error.message}`);
|
|
311
|
+
token = result;
|
|
314
312
|
}
|
|
315
313
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
authenticate(username, password, false);
|
|
323
|
-
});
|
|
314
|
+
config.setActive(adminFqdn);
|
|
315
|
+
config.setApiEndpoint(adminFqdn);
|
|
316
|
+
config.setToken(token);
|
|
317
|
+
config.setAllowSelfsigned(options.parent.allowSelfsigned || options.parent.acceptSelfsigned);
|
|
318
|
+
config.set('cloudrons.default', adminFqdn);
|
|
324
319
|
}
|
|
325
320
|
|
|
326
321
|
function logout() {
|
|
@@ -1162,7 +1157,7 @@ function backupList(options) {
|
|
|
1162
1157
|
response.body.backups.forEach(function (backup) {
|
|
1163
1158
|
t.cell('Id', backup.id);
|
|
1164
1159
|
t.cell('Creation Time', backup.creationTime);
|
|
1165
|
-
t.cell('Version', backup.
|
|
1160
|
+
t.cell('Version', backup.packageVersion);
|
|
1166
1161
|
|
|
1167
1162
|
t.newRow();
|
|
1168
1163
|
});
|
|
@@ -1387,7 +1382,7 @@ function exec(cmd, options) {
|
|
|
1387
1382
|
if (app.installationState !== 'installed') exit('App is not yet running. Try again later.');
|
|
1388
1383
|
|
|
1389
1384
|
if (cmd.length === 0) {
|
|
1390
|
-
cmd = [ '/bin/bash'
|
|
1385
|
+
cmd = [ '/bin/bash' ];
|
|
1391
1386
|
tty = true; // override
|
|
1392
1387
|
}
|
|
1393
1388
|
|
package/src/helper.js
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
const fs = require('fs'),
|
|
6
6
|
path = require('path'),
|
|
7
7
|
util = require('util');
|
|
8
8
|
|
|
9
9
|
exports = module.exports = {
|
|
10
|
-
exit
|
|
10
|
+
exit,
|
|
11
11
|
|
|
12
|
-
locateManifest
|
|
13
|
-
verifyArguments
|
|
12
|
+
locateManifest,
|
|
13
|
+
verifyArguments
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
function exit(error) {
|
|
@@ -21,9 +21,9 @@ function exit(error) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
function locateManifest() {
|
|
24
|
-
|
|
24
|
+
let curdir = process.cwd();
|
|
25
25
|
do {
|
|
26
|
-
|
|
26
|
+
const candidate = path.join(curdir, 'CloudronManifest.json');
|
|
27
27
|
if (fs.existsSync(candidate)) return candidate;
|
|
28
28
|
|
|
29
29
|
// check if we can't go further up (the previous check for '/' breaks on windows)
|