rsync: encrypted download (fs backend)

Part of #440
This commit is contained in:
Girish Ramakrishnan
2018-07-27 11:46:42 -07:00
parent b3c8767d79
commit a5daad2e1a
+41 -3
View File
@@ -191,12 +191,32 @@ function encryptFilePath(filePath, key) {
const cipher = crypto.createCipher('aes-256-cbc', key);
let crypt = cipher.update(part);
crypt = Buffer.concat([ crypt, cipher.final() ]);
return crypt.toString('base64').replace(/\//g, '-').replace(/=/g,'');
return crypt.toString('base64') // ensures path is valid
.replace(/\//g, '-') // replace '/' of base64 since it conflicts with path separator
.replace(/=/g,''); // strip trailing = padding. this is only needed if we concat base64 strings, which we don't
});
return encryptedParts.join('/');
}
function decryptFilePath(filePath, key) {
assert.strictEqual(typeof filePath, 'string');
assert.strictEqual(typeof key, 'string');
var decryptedParts = filePath.split('/').map(function (part) {
part = part + Array(part.length % 4).join('='); // add back = padding
part = part.replace(/-/g, '/'); // replace with '/'
var decrypt = crypto.createDecipher('aes-256-cbc', 'incremental');
let text = decrypt.update(Buffer.from(part, 'base64'));
text = Buffer.concat([ text, decrypt.final() ]);
return text.toString('utf8');
});
return decryptedParts.join('/');
}
function createReadStream(sourceFile, key) {
assert.strictEqual(typeof sourceFile, 'string');
assert(key === null || typeof key === 'string');
@@ -225,6 +245,24 @@ function createReadStream(sourceFile, key) {
}
}
function createWriteStream(destFile, key) {
assert.strictEqual(typeof destFile, 'string');
assert(key === null || typeof key === 'string');
var stream = fs.createWriteStream(destFile);
if (key !== null) {
var decrypt = crypto.createDecipher('aes-256-cbc', key);
decrypt.on('error', function (error) {
debug('createWriteStream: decrypt stream error.', error);
});
decrypt.pipe(stream);
return decrypt;
} else {
return stream;
}
}
function createTarPackStream(sourceDir, key) {
assert.strictEqual(typeof sourceDir, 'string');
assert(key === null || typeof key === 'string');
@@ -454,7 +492,7 @@ function downloadDir(backupConfig, backupFilePath, destDir, callback) {
function downloadFile(entry, callback) {
const sourceFilePath = path.join(backupFilePath, entry.path);
const destFilePath = path.join(destDir, entry.path);
const destFilePath = path.join(destDir, backupConfig.key ? decryptFilePath(entry.path, backupConfig.key) : entry.path);
mkdirp(path.dirname(destFilePath), function (error) {
if (error) return callback(new BackupsError(BackupsError.EXTERNAL_ERROR, error.message));
@@ -464,7 +502,7 @@ function downloadDir(backupConfig, backupFilePath, destDir, callback) {
sourceStream.on('error', callback);
let destStream = fs.createWriteStream(destFilePath);
let destStream = createWriteStream(destFilePath, backupConfig.key || null);
destStream.on('error', callback);
log(`downloadDir: Copying ${sourceFilePath} to ${destFilePath}`);