cloudron 5.6.2 → 5.7.1
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/bin/cloudron +2 -2
- package/package.json +1 -1
- package/src/actions.js +2 -0
- package/src/backup-tools.js +44 -37
- package/src/templates/dockerignore.ejs +2 -0
- package/src/templates/logo.png +0 -0
package/bin/cloudron
CHANGED
|
@@ -53,7 +53,7 @@ backupCommand.command('list')
|
|
|
53
53
|
.option('--app <id>', 'App id')
|
|
54
54
|
.action(actions.backupList);
|
|
55
55
|
|
|
56
|
-
backupCommand.command('decrypt <
|
|
56
|
+
backupCommand.command('decrypt <infile> <outfile>')
|
|
57
57
|
.description('Decrypt an encrypted file')
|
|
58
58
|
.option('--password <password>', 'password')
|
|
59
59
|
.action(backupTools.decrypt);
|
|
@@ -68,7 +68,7 @@ backupCommand.command('decrypt-filename <path>')
|
|
|
68
68
|
.option('--password <password>', 'password')
|
|
69
69
|
.action(backupTools.decryptFilename);
|
|
70
70
|
|
|
71
|
-
backupCommand.command('encrypt <
|
|
71
|
+
backupCommand.command('encrypt <infile> <outfile>')
|
|
72
72
|
.description('Encrypt a file')
|
|
73
73
|
.option('--password <password>', 'password')
|
|
74
74
|
.action(backupTools.encrypt);
|
package/package.json
CHANGED
package/src/actions.js
CHANGED
|
@@ -1526,6 +1526,8 @@ function init(localOptions, cmd) {
|
|
|
1526
1526
|
fs.chmodSync('start.sh', 0o0775);
|
|
1527
1527
|
}
|
|
1528
1528
|
|
|
1529
|
+
fs.copyFileSync(path.join(__dirname, 'templates/', 'logo.png'), 'logo.png');
|
|
1530
|
+
|
|
1529
1531
|
if (options.appstore) {
|
|
1530
1532
|
if (!fs.existsSync('.gitignore')) fs.writeFileSync('.gitignore', 'node_modules/\n', 'utf8');
|
|
1531
1533
|
if (!fs.existsSync('DESCRIPTION.md')) fs.writeFileSync('DESCRIPTION.md', '## About\n\nThis app changes everything\n\n', 'utf8');
|
package/src/backup-tools.js
CHANGED
|
@@ -18,6 +18,7 @@ const assert = require('assert'),
|
|
|
18
18
|
path = require('path'),
|
|
19
19
|
readlinePromises = require('readline/promises'),
|
|
20
20
|
safe = require('safetydance'),
|
|
21
|
+
stream = require('stream/promises'),
|
|
21
22
|
TransformStream = require('stream').Transform;
|
|
22
23
|
|
|
23
24
|
function encryptFilePath(filePath, encryption) {
|
|
@@ -25,7 +26,7 @@ function encryptFilePath(filePath, encryption) {
|
|
|
25
26
|
assert.strictEqual(typeof encryption, 'object');
|
|
26
27
|
|
|
27
28
|
const encryptedParts = filePath.split('/').map(function (part) {
|
|
28
|
-
|
|
29
|
+
const hmac = crypto.createHmac('sha256', Buffer.from(encryption.filenameHmacKey, 'hex'));
|
|
29
30
|
const iv = hmac.update(part).digest().subarray(0, 16); // iv has to be deterministic, for our sync (copy) logic to work
|
|
30
31
|
const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(encryption.filenameKey, 'hex'), iv);
|
|
31
32
|
let crypt = cipher.update(part);
|
|
@@ -193,24 +194,23 @@ function aesKeysFromPassword(password) {
|
|
|
193
194
|
};
|
|
194
195
|
}
|
|
195
196
|
|
|
196
|
-
async function encrypt(
|
|
197
|
+
async function encrypt(infile, outfile, options) {
|
|
198
|
+
if (!fs.existsSync(infile)) return exit(`Could not open ${infile}`);
|
|
199
|
+
|
|
197
200
|
if (!options.password) {
|
|
198
201
|
const rl = readlinePromises.createInterface({ input: process.stdin, output: process.stdout });
|
|
199
|
-
options.password = rl.question('Enter encryption password: ');
|
|
202
|
+
options.password = await rl.question('Enter encryption password: ');
|
|
200
203
|
rl.close();
|
|
201
204
|
if (!options.password) return exit('--password is needed');
|
|
202
205
|
}
|
|
203
206
|
|
|
204
207
|
const encryption = aesKeysFromPassword(options.password);
|
|
205
|
-
|
|
206
|
-
const
|
|
207
|
-
const outStream = process.stdout;
|
|
208
|
+
const inStream = fs.createReadStream(infile);
|
|
209
|
+
const outStream = outfile === '-' ? process.stdout : fs.createWriteStream(outfile);
|
|
208
210
|
const encryptStream = new EncryptStream(encryption);
|
|
209
211
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
inStream.pipe(encryptStream).pipe(outStream);
|
|
212
|
+
const [encryptError] = await safe(stream.pipeline(inStream, encryptStream, outStream));
|
|
213
|
+
if (encryptError) return exit(`Could not encrypt: ${encryptError.message}`);
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
async function encryptFilename(filePath, options) {
|
|
@@ -226,7 +226,14 @@ async function encryptFilename(filePath, options) {
|
|
|
226
226
|
console.log(encryptFilePath(filePath, encryption));
|
|
227
227
|
}
|
|
228
228
|
|
|
229
|
-
async function decrypt(
|
|
229
|
+
async function decrypt(infile, outfile, options) {
|
|
230
|
+
const fd = safe.fs.openSync(infile, 'r'); // returns a number!
|
|
231
|
+
if (!fd || fd === -1) return exit(`Could not open ${infile} for read: ${safe.error.message}`);
|
|
232
|
+
const header = Buffer.alloc(4);
|
|
233
|
+
if (!safe.fs.readSync(fd, header, 0, 4, 0)) return exit(safe.error);
|
|
234
|
+
if (!header.equals(Buffer.from('CBV2'))) return exit('Legacy stream decryption not implemented yet');
|
|
235
|
+
safe.fs.closeSync(fd);
|
|
236
|
+
|
|
230
237
|
if (!options.password) {
|
|
231
238
|
const rl = readlinePromises.createInterface({ input: process.stdin, output: process.stdout });
|
|
232
239
|
options.password = await rl.question('Enter encryption password: ');
|
|
@@ -234,23 +241,17 @@ async function decrypt(input, options) {
|
|
|
234
241
|
if (!options.password) return exit('--password is needed');
|
|
235
242
|
}
|
|
236
243
|
|
|
237
|
-
const fd = safe.fs.openSync(input, 'r');
|
|
238
|
-
if (!fd) return exit(safe.error);
|
|
239
|
-
let header = Buffer.alloc(4);
|
|
240
|
-
if (!safe.fs.readSync(fd, header, 0, 4, 0)) return exit(safe.error);
|
|
241
|
-
if (!header.equals(Buffer.from('CBV2'))) return exit('Legacy stream decryption not implemented yet');
|
|
242
|
-
safe.fs.closeSync(fd);
|
|
243
|
-
|
|
244
244
|
const encryption = aesKeysFromPassword(options.password);
|
|
245
245
|
|
|
246
|
-
const inStream = fs.createReadStream(
|
|
247
|
-
const outStream = process.stdout;
|
|
246
|
+
const inStream = fs.createReadStream(infile);
|
|
247
|
+
const outStream = outfile === '-' ? process.stdout : fs.createWriteStream(outfile);
|
|
248
248
|
const decryptStream = new DecryptStream(encryption);
|
|
249
249
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
250
|
+
const [decryptError] = await safe(stream.pipeline(inStream, decryptStream, outStream));
|
|
251
|
+
if (decryptError) {
|
|
252
|
+
safe.fs.rmSync(outfile);
|
|
253
|
+
return exit(`Could not decrypt: ${decryptError.message}`);
|
|
254
|
+
}
|
|
254
255
|
}
|
|
255
256
|
|
|
256
257
|
async function decryptDir(inDir, outDir, options) {
|
|
@@ -266,31 +267,37 @@ async function decryptDir(inDir, outDir, options) {
|
|
|
266
267
|
const inDirAbs = path.resolve(process.cwd(), inDir);
|
|
267
268
|
const outDirAbs = path.resolve(process.cwd(), outDir);
|
|
268
269
|
|
|
269
|
-
|
|
270
|
+
const tbd = [ '' ]; // only has paths relative to inDirAbs
|
|
270
271
|
async.whilst((done) => done(null, tbd.length !== 0), function iteratee(whilstCallback) {
|
|
271
272
|
const cur = tbd.pop();
|
|
272
273
|
const entries = fs.readdirSync(path.join(inDirAbs, cur), { withFileTypes: true });
|
|
273
|
-
async.eachSeries(entries, function (entry
|
|
274
|
+
async.eachSeries(entries, async function (entry) {
|
|
274
275
|
if (entry.isDirectory()) {
|
|
275
276
|
tbd.push(path.join(cur, entry.name));
|
|
276
|
-
return
|
|
277
|
+
return;
|
|
277
278
|
} else if (!entry.isFile()) {
|
|
278
|
-
return
|
|
279
|
+
return;
|
|
279
280
|
}
|
|
280
281
|
|
|
281
282
|
const encryptedFilePath = path.join(cur, entry.name);
|
|
282
|
-
const { error, decryptedFilePath } = decryptFilePath(encryptedFilePath, encryption);
|
|
283
|
-
if (error) return iteratorCallback(error);
|
|
284
283
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
let outStream = fs.createWriteStream(path.join(outDirAbs, decryptedFilePath));
|
|
288
|
-
let decryptStream = new DecryptStream(encryption);
|
|
284
|
+
const { error, decryptedFilePath } = decryptFilePath(encryptedFilePath, encryption);
|
|
285
|
+
if (error) throw error;
|
|
289
286
|
|
|
290
|
-
|
|
291
|
-
decryptStream.on('error', iteratorCallback);
|
|
287
|
+
console.log(`Decrypting ${decryptedFilePath}`);
|
|
292
288
|
|
|
293
|
-
|
|
289
|
+
const infile = path.join(inDirAbs, cur, entry.name);
|
|
290
|
+
const inStream = fs.createReadStream(infile);
|
|
291
|
+
fs.mkdirSync(path.dirname(path.join(outDirAbs, decryptedFilePath)), { recursive: true });
|
|
292
|
+
const outfile = path.join(outDirAbs, decryptedFilePath);
|
|
293
|
+
const outStream = fs.createWriteStream(outfile);
|
|
294
|
+
const decryptStream = new DecryptStream(encryption);
|
|
295
|
+
|
|
296
|
+
const [decryptError] = await safe(stream.pipeline(inStream, decryptStream, outStream));
|
|
297
|
+
if (decryptError) {
|
|
298
|
+
safe.fs.rmSync(outfile);
|
|
299
|
+
throw new Error(`Could not decrypt ${infile}: ${decryptError.message}`);
|
|
300
|
+
}
|
|
294
301
|
}, whilstCallback);
|
|
295
302
|
}, exit);
|
|
296
303
|
}
|
|
Binary file
|