cloudron 5.4.1 → 5.4.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cloudron",
3
- "version": "5.4.1",
3
+ "version": "5.4.2",
4
4
  "license": "MIT",
5
5
  "description": "Cloudron Commandline Tool",
6
6
  "main": "main.js",
package/src/actions.js CHANGED
@@ -346,7 +346,7 @@ async function authenticate(adminFqdn, username, password, options) {
346
346
 
347
347
  const request = superagent.post(`https://${adminFqdn}/api/v1/auth/login`)
348
348
  .timeout(60000)
349
- .send({ username, password, totpToken })
349
+ .send({ username, password, totpToken, type: 'cid-cli' })
350
350
  .ok(() => true)
351
351
  .set('User-Agent', 'cloudron-cli');
352
352
  if (!rejectUnauthorized) request.disableTLSCerts();
@@ -16,6 +16,7 @@ const assert = require('assert'),
16
16
  debug = require('debug')('cloudron-backup'),
17
17
  fs = require('fs'),
18
18
  path = require('path'),
19
+ readlinePromises = require('readline/promises'),
19
20
  safe = require('safetydance'),
20
21
  TransformStream = require('stream').Transform;
21
22
 
@@ -25,7 +26,7 @@ function encryptFilePath(filePath, encryption) {
25
26
 
26
27
  const encryptedParts = filePath.split('/').map(function (part) {
27
28
  let hmac = crypto.createHmac('sha256', Buffer.from(encryption.filenameHmacKey, 'hex'));
28
- const iv = hmac.update(part).digest().slice(0, 16); // iv has to be deterministic, for our sync (copy) logic to work
29
+ const iv = hmac.update(part).digest().subarray(0, 16); // iv has to be deterministic, for our sync (copy) logic to work
29
30
  const cipher = crypto.createCipheriv('aes-256-cbc', Buffer.from(encryption.filenameKey, 'hex'), iv);
30
31
  let crypt = cipher.update(part);
31
32
  crypt = Buffer.concat([ iv, crypt, cipher.final() ]);
@@ -49,22 +50,22 @@ function decryptFilePath(filePath, encryption) {
49
50
 
50
51
  try {
51
52
  const buffer = Buffer.from(part, 'base64');
52
- const iv = buffer.slice(0, 16);
53
+ const iv = buffer.subarray(0, 16);
53
54
 
54
55
  const decrypt = crypto.createDecipheriv('aes-256-cbc', Buffer.from(encryption.filenameKey, 'hex'), iv);
55
- const plainText = decrypt.update(buffer.slice(16));
56
+ const plainText = decrypt.update(buffer.subarray(16));
56
57
  const plainTextString = Buffer.concat([ plainText, decrypt.final() ]).toString('utf8');
57
58
  const hmac = crypto.createHmac('sha256', Buffer.from(encryption.filenameHmacKey, 'hex'));
58
- if (!hmac.update(plainTextString).digest().slice(0, 16).equals(iv)) return { error: new Error(`mac error decrypting part ${part} of path ${filePath}`) };
59
+ if (!hmac.update(plainTextString).digest().subarray(0, 16).equals(iv)) return { error: new Error(`mac error decrypting part ${part} of path ${filePath}`) };
59
60
 
60
61
  decryptedParts.push(plainTextString);
61
62
  } catch (error) {
62
63
  debug(`Error decrypting file ${filePath} part ${part}:`, error);
63
- return null;
64
+ return { error };
64
65
  }
65
66
  }
66
67
 
67
- return { decryptedFilePath: decryptedParts.join('/') };
68
+ return { error: null, decryptedFilePath: decryptedParts.join('/') };
68
69
  }
69
70
 
70
71
  class EncryptStream extends TransformStream {
@@ -131,27 +132,27 @@ class DecryptStream extends TransformStream {
131
132
 
132
133
  debug('got chunk', chunk.length);
133
134
  if (this._header.length !== 20) { // not gotten IV yet
134
- this._header = Buffer.concat([this._header, chunk.slice(0, needed)]);
135
+ this._header = Buffer.concat([this._header, chunk.subarray(0, needed)]);
135
136
  if (this._header.length !== 20) return callback();
136
137
 
137
- if (!this._header.slice(0, 4).equals(new Buffer.from('CBV2'))) return callback(new Error('Invalid magic in header'));
138
+ if (!this._header.subarray(0, 4).equals(new Buffer.from('CBV2'))) return callback(new Error('Invalid magic in header'));
138
139
 
139
- const iv = this._header.slice(4);
140
+ const iv = this._header.subarray(4);
140
141
  this._decipher = crypto.createDecipheriv('aes-256-cbc', this._key, iv);
141
142
  this._hmac.update(this._header);
142
143
  }
143
144
 
144
145
  debug('needed is', needed);
145
- this._buffer = Buffer.concat([ this._buffer, chunk.slice(needed) ]);
146
+ this._buffer = Buffer.concat([ this._buffer, chunk.subarray(needed) ]);
146
147
  debug('buffer is ', this._buffer.length);
147
148
  if (this._buffer.length < 32) return callback();
148
149
 
149
150
  try {
150
- const cipherText = this._buffer.slice(0, -32);
151
+ const cipherText = this._buffer.subarray(0, -32);
151
152
  debug('Got:', cipherText.toString('hex'));
152
153
  this._hmac.update(cipherText);
153
154
  const plainText = this._decipher.update(cipherText);
154
- this._buffer = this._buffer.slice(-32);
155
+ this._buffer = this._buffer.subarray(-32);
155
156
  callback(null, plainText);
156
157
  } catch (error) {
157
158
  callback(error);
@@ -185,15 +186,20 @@ function exit(msgOrError) {
185
186
  function aesKeysFromPassword(password) {
186
187
  const derived = crypto.scryptSync(password, Buffer.from('CLOUDRONSCRYPTSALT', 'utf8'), 128);
187
188
  return {
188
- dataKey: derived.slice(0, 32).toString('hex'),
189
- dataHmacKey: derived.slice(32, 64).toString('hex'),
190
- filenameKey: derived.slice(64, 96).toString('hex'),
191
- filenameHmacKey: derived.slice(96).toString('hex')
189
+ dataKey: derived.subarray(0, 32).toString('hex'),
190
+ dataHmacKey: derived.subarray(32, 64).toString('hex'),
191
+ filenameKey: derived.subarray(64, 96).toString('hex'),
192
+ filenameHmacKey: derived.subarray(96).toString('hex')
192
193
  };
193
194
  }
194
195
 
195
- function encrypt(input, options) {
196
- if (!options.password) return exit('--password is needed');
196
+ async function encrypt(input, options) {
197
+ if (!options.password) {
198
+ const rl = readlinePromises.createInterface({ input: process.stdin, output: process.stdout });
199
+ options.password = rl.question('Enter encryption password: ');
200
+ rl.close();
201
+ if (!options.password) return exit('--password is needed');
202
+ }
197
203
 
198
204
  const encryption = aesKeysFromPassword(options.password);
199
205
 
@@ -207,16 +213,26 @@ function encrypt(input, options) {
207
213
  inStream.pipe(encryptStream).pipe(outStream);
208
214
  }
209
215
 
210
- function encryptFilename(filePath, options) {
211
- if (!options.password) return exit('--password is needed');
216
+ async function encryptFilename(filePath, options) {
217
+ if (!options.password) {
218
+ const rl = readlinePromises.createInterface({ input: process.stdin, output: process.stdout });
219
+ options.password = await rl.question('Enter encryption password: ');
220
+ rl.close();
221
+ if (!options.password) return exit('--password is needed');
222
+ }
212
223
 
213
224
  const encryption = aesKeysFromPassword(options.password);
214
225
 
215
226
  console.log(encryptFilePath(filePath, encryption));
216
227
  }
217
228
 
218
- function decrypt(input, options) {
219
- if (!options.password) return exit('--password is needed');
229
+ async function decrypt(input, options) {
230
+ if (!options.password) {
231
+ const rl = readlinePromises.createInterface({ input: process.stdin, output: process.stdout });
232
+ options.password = await rl.question('Enter encryption password: ');
233
+ rl.close();
234
+ if (!options.password) return exit('--password is needed');
235
+ }
220
236
 
221
237
  const fd = safe.fs.openSync(input, 'r');
222
238
  if (!fd) return exit(safe.error);
@@ -237,8 +253,13 @@ function decrypt(input, options) {
237
253
  inStream.pipe(decryptStream).pipe(outStream);
238
254
  }
239
255
 
240
- function decryptDir(inDir, outDir, options) {
241
- if (!options.password) return exit('--password is needed');
256
+ async function decryptDir(inDir, outDir, options) {
257
+ if (!options.password) {
258
+ const rl = readlinePromises.createInterface({ input: process.stdin, output: process.stdout });
259
+ options.password = await rl.question('Enter encryption password: ');
260
+ rl.close();
261
+ if (!options.password) return exit('--password is needed');
262
+ }
242
263
 
243
264
  const encryption = aesKeysFromPassword(options.password);
244
265
 
@@ -274,8 +295,13 @@ function decryptDir(inDir, outDir, options) {
274
295
  }, exit);
275
296
  }
276
297
 
277
- function decryptFilename(filePath, options) {
278
- if (!options.password) return exit('--password is needed');
298
+ async function decryptFilename(filePath, options) {
299
+ if (!options.password) {
300
+ const rl = readlinePromises.createInterface({ input: process.stdin, output: process.stdout });
301
+ options.password = await rl.question('Enter encryption password: ');
302
+ rl.close();
303
+ if (!options.password) return exit('--password is needed');
304
+ }
279
305
 
280
306
  const encryption = aesKeysFromPassword(options.password);
281
307