cloudron 4.15.1 → 5.0.0
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/README.md +2 -2
- package/bin/cloudron +1 -1
- package/bin/cloudron-appstore +1 -1
- package/bin/cloudron-backup +3 -3
- package/bin/cloudron-env +1 -1
- package/package.json +8 -8
- package/src/actions.js +32 -12
- package/src/backup-tools.js +8 -8
- package/src/templates/Dockerfile.ejs +8 -2
- package/src/templates/start.sh.ejs +3 -0
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# The Cloudron CLI tool
|
|
2
2
|
|
|
3
|
-
The [Cloudron](https://cloudron.io) CLI tool allows you to install, configure and test apps on your Cloudron.
|
|
3
|
+
The [Cloudron](https://cloudron.io) [CLI tool](https://docs.cloudron.io/packaging/cli/) allows you to install, configure and test apps on your Cloudron.
|
|
4
4
|
It is also used to submit your app to the Cloudron Store. The `machine` subcommand can be used for
|
|
5
5
|
various maintenance tasks on a selfhosted Cloudron.
|
|
6
6
|
|
|
7
|
-
Read the Cloudron.io [documentation](https://cloudron.io/
|
|
7
|
+
Read the Cloudron.io [documentation](https://docs.cloudron.io/) for in-depth information.
|
|
8
8
|
|
|
9
9
|
## Installation
|
|
10
10
|
|
package/bin/cloudron
CHANGED
|
@@ -257,7 +257,7 @@ program.command('update')
|
|
|
257
257
|
|
|
258
258
|
const knownCommand = program.commands.some(function (command) { return command._name === process.argv[2] || command._alias === process.argv[2]; });
|
|
259
259
|
if (!knownCommand) {
|
|
260
|
-
console.log('Unknown command: ' + process.argv[2]
|
|
260
|
+
console.log('Unknown command: ' + process.argv[2] + '.\nTry ' + 'cloudron help');
|
|
261
261
|
process.exit(1);
|
|
262
262
|
}
|
|
263
263
|
})();
|
package/bin/cloudron-appstore
CHANGED
|
@@ -71,7 +71,7 @@ if (!process.argv.slice(2).length) {
|
|
|
71
71
|
|
|
72
72
|
var knownCommand = program.commands.some(function (command) { return command._name === process.argv[2] || command._alias === process.argv[2]; });
|
|
73
73
|
if (!knownCommand) {
|
|
74
|
-
console.log('Unknown command: ' + process.argv[2]
|
|
74
|
+
console.log('Unknown command: ' + process.argv[2] + '.\nTry ' + 'cloudron appstore help');
|
|
75
75
|
process.exit(1);
|
|
76
76
|
}
|
|
77
77
|
return;
|
package/bin/cloudron-backup
CHANGED
|
@@ -20,12 +20,12 @@ program.command('list')
|
|
|
20
20
|
.action(actions.backupList);
|
|
21
21
|
|
|
22
22
|
program.command('decrypt <file>')
|
|
23
|
-
.description('Decrypt
|
|
23
|
+
.description('Decrypt an encrypted file')
|
|
24
24
|
.option('--password <password>', 'password')
|
|
25
25
|
.action(backupTools.decrypt);
|
|
26
26
|
|
|
27
27
|
program.command('decrypt-dir <indir> <outdir>')
|
|
28
|
-
.description('Decrypt
|
|
28
|
+
.description('Decrypt an encrypted directory')
|
|
29
29
|
.option('--password <password>', 'password')
|
|
30
30
|
.action(backupTools.decryptDir);
|
|
31
31
|
|
|
@@ -56,7 +56,7 @@ if (!process.argv.slice(2).length) {
|
|
|
56
56
|
|
|
57
57
|
var knownCommand = program.commands.some(function (command) { return command._name === process.argv[2] || command._alias === process.argv[2]; });
|
|
58
58
|
if (!knownCommand) {
|
|
59
|
-
console.log('Unknown command: ' + process.argv[2]
|
|
59
|
+
console.log('Unknown command: ' + process.argv[2] + '.\nTry ' + 'cloudron backup help');
|
|
60
60
|
process.exit(1);
|
|
61
61
|
}
|
|
62
62
|
return;
|
package/bin/cloudron-env
CHANGED
|
@@ -39,7 +39,7 @@ if (!process.argv.slice(2).length) {
|
|
|
39
39
|
|
|
40
40
|
var knownCommand = program.commands.some(function (command) { return command._name === process.argv[2] || command._alias === process.argv[2]; });
|
|
41
41
|
if (!knownCommand) {
|
|
42
|
-
console.log('Unknown command: ' + process.argv[2]
|
|
42
|
+
console.log('Unknown command: ' + process.argv[2] + '.\nTry ' + 'cloudron env help');
|
|
43
43
|
process.exit(1);
|
|
44
44
|
}
|
|
45
45
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cloudron",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Cloudron Commandline Tool",
|
|
6
6
|
"main": "main.js",
|
|
@@ -20,12 +20,12 @@
|
|
|
20
20
|
"async": "^3.2.3",
|
|
21
21
|
"cloudron-manifestformat": "^5.15.2",
|
|
22
22
|
"commander": "^6.1.0",
|
|
23
|
-
"debug": "^4.3.
|
|
23
|
+
"debug": "^4.3.4",
|
|
24
24
|
"delay": "^5.0.0",
|
|
25
25
|
"easy-table": "^1.2.0",
|
|
26
|
-
"ejs": "^3.1.
|
|
27
|
-
"eventsource": "^
|
|
28
|
-
"micromatch": "^4.0.
|
|
26
|
+
"ejs": "^3.1.8",
|
|
27
|
+
"eventsource": "^2.0.2",
|
|
28
|
+
"micromatch": "^4.0.5",
|
|
29
29
|
"once": "^1.4.0",
|
|
30
30
|
"open": "^8.4.0",
|
|
31
31
|
"progress": "^2.0.3",
|
|
@@ -33,9 +33,9 @@
|
|
|
33
33
|
"readline-sync": "^1.4.10",
|
|
34
34
|
"safetydance": "^2.2.0",
|
|
35
35
|
"split": "^1.0.1",
|
|
36
|
-
"superagent": "^7.
|
|
36
|
+
"superagent": "^7.1.3",
|
|
37
37
|
"tar-fs": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.12.0.tgz",
|
|
38
|
-
"underscore": "^1.13.
|
|
38
|
+
"underscore": "^1.13.3"
|
|
39
39
|
},
|
|
40
40
|
"engines": {
|
|
41
41
|
"node": ">= 14.x.x"
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"expect.js": "^0.3.1",
|
|
45
45
|
"memorystream": "^0.3.1",
|
|
46
|
-
"mocha": "^
|
|
46
|
+
"mocha": "^10.0.0",
|
|
47
47
|
"rimraf": "^3.0.2"
|
|
48
48
|
}
|
|
49
49
|
}
|
package/src/actions.js
CHANGED
|
@@ -14,7 +14,6 @@ const assert = require('assert'),
|
|
|
14
14
|
path = require('path'),
|
|
15
15
|
ProgressBar = require('progress'),
|
|
16
16
|
ProgressStream = require('progress-stream'),
|
|
17
|
-
querystring = require('querystring'),
|
|
18
17
|
readlineSync = require('readline-sync'),
|
|
19
18
|
safe = require('safetydance'),
|
|
20
19
|
spawn = require('child_process').spawn,
|
|
@@ -1309,19 +1308,30 @@ async function exec(cmd, options) {
|
|
|
1309
1308
|
|
|
1310
1309
|
if (tty && !stdin.isTTY) exit('stdin is not tty');
|
|
1311
1310
|
|
|
1311
|
+
const request = createRequest('POST', `/api/v1/apps/${app.id}/exec`, options);
|
|
1312
|
+
const response = await request.send({ cmd, tty });
|
|
1313
|
+
if (response.statusCode !== 200) return exit(`Failed to create exec: ${requestError(response)}`);
|
|
1314
|
+
const execId = response.body.id;
|
|
1315
|
+
|
|
1316
|
+
async function exitWithCode() {
|
|
1317
|
+
const response2 = await createRequest('GET', `/api/v1/apps/${app.id}/exec/${execId}`, options);
|
|
1318
|
+
if (response2.statusCode !== 200) return exit(`Failed to get exec code: ${requestError(response2)}`);
|
|
1319
|
+
|
|
1320
|
+
process.exit(response2.body.exitCode);
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1312
1323
|
const { adminFqdn, token, rejectUnauthorized } = requestOptions(options);
|
|
1313
1324
|
|
|
1314
|
-
const
|
|
1315
|
-
rows: stdout.rows,
|
|
1316
|
-
columns: stdout.columns,
|
|
1325
|
+
const searchParams = new URLSearchParams({
|
|
1326
|
+
rows: stdout.rows || 24,
|
|
1327
|
+
columns: stdout.columns || 80,
|
|
1317
1328
|
access_token: token,
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
};
|
|
1329
|
+
tty
|
|
1330
|
+
});
|
|
1321
1331
|
|
|
1322
1332
|
const req = https.request({
|
|
1323
1333
|
hostname: adminFqdn,
|
|
1324
|
-
path: `/api/v1/apps/${app.id}/exec
|
|
1334
|
+
path: `/api/v1/apps/${app.id}/exec/${execId}/start?${searchParams.toString()}`,
|
|
1325
1335
|
method: 'GET',
|
|
1326
1336
|
headers: {
|
|
1327
1337
|
'Connection': 'Upgrade',
|
|
@@ -1345,8 +1355,8 @@ async function exec(cmd, options) {
|
|
|
1345
1355
|
stdin.setRawMode(true);
|
|
1346
1356
|
stdin.pipe(socket, { end: false }); // the remote will close the connection
|
|
1347
1357
|
socket.pipe(stdout); // in tty mode, stdout/stderr is merged
|
|
1348
|
-
socket.on('end',
|
|
1349
|
-
} else {// create stdin process on demand
|
|
1358
|
+
socket.on('end', exitWithCode); // server closed the socket
|
|
1359
|
+
} else { // create stdin process on demand
|
|
1350
1360
|
if (typeof stdin === 'function') stdin = stdin();
|
|
1351
1361
|
|
|
1352
1362
|
stdin.on('data', function (d) {
|
|
@@ -1361,7 +1371,7 @@ async function exec(cmd, options) {
|
|
|
1361
1371
|
socket.write(buf);
|
|
1362
1372
|
});
|
|
1363
1373
|
|
|
1364
|
-
stdout.on('close',
|
|
1374
|
+
stdout.on('close', exitWithCode); // this is only emitted when stdout is a file and not the terminal
|
|
1365
1375
|
|
|
1366
1376
|
demuxStream(socket, stdout, process.stderr); // can get separate streams in non-tty mode
|
|
1367
1377
|
socket.on('end', function () { // server closed the socket
|
|
@@ -1371,7 +1381,7 @@ async function exec(cmd, options) {
|
|
|
1371
1381
|
socket.end();
|
|
1372
1382
|
|
|
1373
1383
|
// process._getActiveHandles(); process._getActiveRequests();
|
|
1374
|
-
if (stdout === process.stdout) setImmediate(
|
|
1384
|
+
if (stdout === process.stdout) setImmediate(exitWithCode); // otherwise, we rely on the 'close' event above
|
|
1375
1385
|
});
|
|
1376
1386
|
}
|
|
1377
1387
|
});
|
|
@@ -1457,6 +1467,7 @@ function init() {
|
|
|
1457
1467
|
const manifestTemplate = fs.readFileSync(path.join(__dirname, 'templates/', 'CloudronManifest.json.ejs'), 'utf8');
|
|
1458
1468
|
const dockerfileTemplate = fs.readFileSync(path.join(__dirname, 'templates/', 'Dockerfile.ejs'), 'utf8');
|
|
1459
1469
|
const dockerignoreTemplate = fs.readFileSync(path.join(__dirname, 'templates/', 'dockerignore.ejs'), 'utf8');
|
|
1470
|
+
const startShTemplate = fs.readFileSync(path.join(__dirname, 'templates/', 'start.sh.ejs'), 'utf8');
|
|
1460
1471
|
|
|
1461
1472
|
const data = {
|
|
1462
1473
|
version: '0.1.0',
|
|
@@ -1481,6 +1492,15 @@ function init() {
|
|
|
1481
1492
|
fs.writeFileSync('.dockerignore', dockerignore, 'utf8');
|
|
1482
1493
|
}
|
|
1483
1494
|
|
|
1495
|
+
if (fs.existsSync('start.sh')) {
|
|
1496
|
+
console.log('start.sh already exists, skipping');
|
|
1497
|
+
} else {
|
|
1498
|
+
const dockerignore = ejs.render(startShTemplate, {});
|
|
1499
|
+
fs.writeFileSync('start.sh', dockerignore, 'utf8');
|
|
1500
|
+
fs.chmodSync('start.sh', 0o0775);
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
|
|
1484
1504
|
console.log();
|
|
1485
1505
|
console.log('Now edit the CloudronManifest.json');
|
|
1486
1506
|
console.log();
|
package/src/backup-tools.js
CHANGED
|
@@ -23,7 +23,7 @@ function encryptFilePath(filePath, encryption) {
|
|
|
23
23
|
assert.strictEqual(typeof filePath, 'string');
|
|
24
24
|
assert.strictEqual(typeof encryption, 'object');
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
const encryptedParts = filePath.split('/').map(function (part) {
|
|
27
27
|
let hmac = crypto.createHmac('sha256', Buffer.from(encryption.filenameHmacKey, 'hex'));
|
|
28
28
|
const iv = hmac.update(part).digest().slice(0, 16); // iv has to be deterministic, for our sync (copy) logic to work
|
|
29
29
|
const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(encryption.filenameKey, 'hex'), iv);
|
|
@@ -42,7 +42,7 @@ function decryptFilePath(filePath, encryption) {
|
|
|
42
42
|
assert.strictEqual(typeof filePath, 'string');
|
|
43
43
|
assert.strictEqual(typeof encryption, 'object');
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
const decryptedParts = [];
|
|
46
46
|
for (let part of filePath.split('/')) {
|
|
47
47
|
part = part + Array(part.length % 4).join('='); // add back = padding
|
|
48
48
|
part = part.replace(/-/g, '/'); // replace with '/'
|
|
@@ -197,9 +197,9 @@ function encrypt(input, options) {
|
|
|
197
197
|
|
|
198
198
|
const encryption = aesKeysFromPassword(options.password);
|
|
199
199
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
200
|
+
const inStream = fs.createReadStream(input);
|
|
201
|
+
const outStream = process.stdout;
|
|
202
|
+
const encryptStream = new EncryptStream(encryption);
|
|
203
203
|
|
|
204
204
|
inStream.on('error', exit);
|
|
205
205
|
encryptStream.on('error', exit);
|
|
@@ -227,9 +227,9 @@ function decrypt(input, options) {
|
|
|
227
227
|
|
|
228
228
|
const encryption = aesKeysFromPassword(options.password);
|
|
229
229
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
230
|
+
const inStream = fs.createReadStream(input);
|
|
231
|
+
const outStream = process.stdout;
|
|
232
|
+
const decryptStream = new DecryptStream(encryption);
|
|
233
233
|
|
|
234
234
|
inStream.on('error', exit);
|
|
235
235
|
decryptStream.on('error', exit);
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
-
FROM cloudron/base:3.
|
|
1
|
+
FROM cloudron/base:3.2.0@sha256:ba1d566164a67c266782545ea9809dc611c4152e27686fd14060332dd88263ea
|
|
2
|
+
|
|
3
|
+
RUN mkdir -p /app/code
|
|
4
|
+
WORKDIR /app/code
|
|
5
|
+
|
|
6
|
+
COPY start.sh /app/pkg/
|
|
7
|
+
|
|
8
|
+
CMD [ "/app/pkg/start.sh" ]
|
|
2
9
|
|
|
3
|
-
EXPOSE <%- httpPort %>
|