firmament-vita
Version:
Firmament module for automating VITA tasks
122 lines (112 loc) • 4.74 kB
text/typescript
import {injectable, inject} from 'inversify';
import {spawn} from 'child_process';
import {VitaDecryptUnTar} from "../interfaces/vita-decrypt-untar";
import {DecryptAndUnTarOptions, DecryptAndUnTarResult, DecryptAndUnTarStatus} from "../interfaces/vita-options-results";
import {ForceErrorImpl, CommandUtil} from "firmament-yargs";
import {VitaFileUtil} from "../interfaces/vita-file-util";
import {VitaSpawn} from "../interfaces/vita-spawn";
const fs = require('fs');
const path = require('path');
const async = require('async');
const mkdirp = require('mkdirp');
const through2Filter = require('through2-filter');
const _ = require('lodash');
()
export class VitaDecryptUnTarImpl extends ForceErrorImpl implements VitaDecryptUnTar {
constructor(('VitaSpawn') private vitaSpawn: VitaSpawn,
('CommandUtil') private commandUtil: CommandUtil,
('VitaFileUtil') private vitaFileUtil: VitaFileUtil) {
super();
}
process(options: DecryptAndUnTarOptions,
cbStatus: (err: Error, decryptAndUnTarStatus: DecryptAndUnTarStatus) => void,
cbFinal: (err: Error, decryptAndUnTarResults: DecryptAndUnTarResult[]) => void) {
cbFinal = this.checkCallback(cbFinal);
cbStatus = this.checkCallback(cbStatus);
let fnArray = [];
options.targetFolder = options.targetFolder || null;
options.encryptedFiles = options.encryptedFiles || [];
options.encryptedFilePattern = options.encryptedFilePattern || /\.enc$/;
options.foldersOfEncryptedFiles = options.foldersOfEncryptedFiles || [];
options.encryptedFiles = this.vitaFileUtil.findFilesSync({
pattern: options.encryptedFilePattern,
files: options.encryptedFiles,
folders: options.foldersOfEncryptedFiles
});
options.encryptedFiles.forEach(file => {
fnArray.push(async.apply(this.spawnDecryptAndUnTarOperation.bind(this),
file,
options.password,
options.targetFolder,
(err: Error, decryptAndUnTarStatus: DecryptAndUnTarStatus) => {
decryptAndUnTarStatus.decryptAndUnTarOptions = <DecryptAndUnTarOptions>_.omit(options, ['password', 'encryptedFilePattern']);
cbStatus(err, decryptAndUnTarStatus);
}
));
});
async.parallelLimit(fnArray, 3, cbFinal);
}
private spawnDecryptAndUnTarOperation(inFile: string,
password: string,
targetFolder: string,
cbStatus: (err: Error, decryptAndUnTarStatus: DecryptAndUnTarStatus) => void,
cbFinal: (err: Error, decryptAndUnTarResult: DecryptAndUnTarResult) => void) {
cbStatus = this.checkCallback(cbStatus);
cbFinal = this.checkCallback(cbFinal);
if (!targetFolder) {
//Put decrypted file in same folder as encrypted file
targetFolder = path.dirname(inFile);
}
mkdirp(targetFolder, err => {
if (this.commandUtil.callbackIfError(cbFinal, err)) {
return;
}
let inputFileSize = fs.statSync(inFile)['size'];
let totalBytesStreamed = 0;
let openSslProcessExited = false;
let tarProcessExited = false;
let tarArgs = [
'x',
'--strip-components=3',
'-C',
targetFolder
];
let tarProcess = spawn('tar', tarArgs);
let openSslArgs =
[
'aes-256-cbc',
'-d',
'-in',
inFile,
'-k',
password];
let openSslProcess = spawn('openssl', openSslArgs);
tarProcess.on('close', (code: number, signal: string) => {
tarProcessExited = true;
if (openSslProcessExited) {
this.callbackFromDecryptAndUnTarFiles(cbFinal, targetFolder);
}
});
openSslProcess.on('close', (code: number, signal: string) => {
openSslProcessExited = true;
if (tarProcessExited) {
this.callbackFromDecryptAndUnTarFiles(cbFinal, targetFolder);
}
});
openSslProcess.stdout.pipe(
through2Filter((dataChunk) => {
totalBytesStreamed += dataChunk.length;
let taskName = `Decrypting [${path.basename(inFile)}] `;
let current = totalBytesStreamed;
let total = inputFileSize;
cbStatus(null, {taskName, current, total});
return true;
})).pipe(tarProcess.stdin);
});
}
private callbackFromDecryptAndUnTarFiles(cb: (err: Error, decryptAndUnTarResult: DecryptAndUnTarResult) => void, folder: string) {
this.vitaFileUtil.findFiles({pattern: /\.gz$/, folders: [folder]}, (err, files) => {
cb(err, {exportDir: folder, zipFiles: files});
});
}
}