UNPKG

6.61 kBJavaScriptView Raw
1var fs = require('fs')
2 , loadRecipients = require('../utils/loadRecipients')
3 , crypto = require('crypto')
4 , constants = require('../lib/constants')
5 , makeNonce = require('../utils/makeNonce')
6 , encrypt = require('../lib/encrypt')
7 , printHeader = require('../utils/printHeader')
8 , translateHeader = require('../utils/translateHeader')
9 , Progress = require('progress')
10 , loadWallet = require('../utils/loadWallet')
11 , pempal = require('pempal')
12 , through = require('through')
13 , prompt = require('cli-prompt')
14 , createGist = require('../utils/createGist')
15 , tar = require('tar')
16 , zlib = require('zlib')
17 , fstream = require('fstream')
18 , tmpDir = require('os').tmpDir()
19 , path = require('path')
20
21module.exports = function (inFile, outFile, options) {
22 var walletDir = options.parent.wallet
23 if (options.message || options.gist) options.armor = true
24 if (!options.armor) {
25 var stat = fs.statSync(inFile)
26 if (!outFile) {
27 outFile = crypto.randomBytes(4).toString('hex') + '.salty'
28 }
29 try {
30 fs.statSync(outFile)
31 if (!options.parent.force) {
32 throw new Error('Refusing to overwrite ' + outFile + '. Use --force to ignore this.')
33 }
34 }
35 catch (err) {
36 if (err && err.code !== 'ENOENT') {
37 throw err
38 }
39 }
40 }
41 var nonce = options.nonce ? Buffer(options.nonce, 'base64') : makeNonce()
42 loadRecipients(walletDir, function (err, recipients) {
43 if (err) throw err
44 var recipient = options.to ? recipients[options.to] : recipients.self
45 if (!recipient) {
46 throw new Error('Recipient not found')
47 }
48 if (options.sign) {
49 loadWallet(walletDir, function (err, wallet) {
50 if (err) throw err
51 withWallet(wallet)
52 })
53 }
54 else withWallet()
55 function withWallet (wallet) {
56 if (options.message) {
57 process.stderr.write('Compose message: (CTL-D when done)\n\n> ')
58 var lines = []
59 process.stdin.once('end', function () {
60 lines.push('')
61 var m = Buffer(lines.join('\n'))
62 withMessage(m)
63 })
64 ;(function getLine () {
65 prompt(null, function (line) {
66 lines.push(line)
67 getLine()
68 })
69 })()
70 function withMessage (m) {
71 var mStream = through()
72 var encryptor = encrypt(mStream, recipient, nonce, m.length, wallet, true)
73 withEncryptor(encryptor, m.length)
74 mStream.end(m)
75 }
76 }
77 else {
78 var inStat = fs.statSync(inFile)
79 var headers = {}, inStream, encryptor
80 if (inStat.isDirectory()) {
81 var tarStream = tar.Pack({fromBase: true})
82 gzipStream = tarStream.pipe(zlib.createGzip())
83 var tmpFile = path.join(tmpDir, crypto.randomBytes(16).toString('hex'))
84 var tmpStream = fs.createWriteStream(tmpFile, {mode: parseInt('0600', 8)})
85 process.on('uncaughtException', function (err) {
86 try {
87 fs.unlinkSync(tmpFile)
88 }
89 catch (e) {}
90 throw err
91 })
92 function onExit () {
93 try {
94 fs.unlinkSync(tmpFile)
95 }
96 catch (e) {}
97 process.exit(1)
98 }
99 process.once('SIGINT', onExit)
100 process.once('SIGTERM', onExit)
101 tmpStream.once('finish', function () {
102 inStat = fs.statSync(tmpFile)
103 inStream = fs.createReadStream(tmpFile)
104 inStream.once('end', function () {
105 fs.unlinkSync(tmpFile)
106 })
107 encryptor = encrypt(inStream, recipient, nonce, inStat.size, wallet, options.armor, headers)
108 withEncryptor(encryptor, inStat.size)
109 })
110 headers['content-type'] = 'application/x-tar'
111 headers['content-encoding'] = 'x-gzip'
112 var reader = fstream.Reader({
113 path: inFile,
114 type: 'Directory',
115 sort: 'alpha',
116 mode: parseInt('0700', 8)
117 })
118 var bar
119 reader.once('entries', function (entries) {
120 bar = new Progress(' packing [:bar] :percent ETA: :etas', { total: entries.length, width: 80 })
121 })
122 reader.on('entry', function (entry) {
123 bar.tick()
124 })
125 reader.on('end', function () {
126 bar.terminate()
127 })
128 gzipStream.pipe(tmpStream)
129 reader.pipe(tarStream)
130 }
131 else {
132 inStream = fs.createReadStream(inFile)
133 encryptor = encrypt(inStream, recipient, nonce, inStat.size, wallet, options.armor, headers)
134 withEncryptor(encryptor, inStat.size)
135 }
136 }
137 var header, outStream
138 function withEncryptor (encryptor, totalSize) {
139 encryptor.once('header', function (h) {
140 header = translateHeader(h, recipients)
141 })
142 if (options.armor) {
143 var chunks = []
144 outStream = through(function write (buf) {
145 chunks.push(buf)
146 }, function end () {
147 var buf = Buffer.concat(chunks)
148 var str = pempal.encode(buf, {tag: 'SALTY MESSAGE'})
149 if (options.gist) {
150 createGist(str, function (err, gist) {
151 if (err) throw err
152 console.log(gist.html_url)
153 })
154 }
155 else console.log(str)
156 })
157 }
158 else {
159 outStream = fs.createWriteStream(outFile, {mode: parseInt('0644', 8)})
160 outStream.once('finish', function () {
161 bar.terminate()
162 printHeader(header)
163 console.log('Encrypted to', outFile)
164 })
165 process.on('uncaughtException', function (err) {
166 try {
167 fs.unlinkSync(outFile)
168 }
169 catch (e) {}
170 throw err
171 })
172 function onExit () {
173 try {
174 fs.unlinkSync(outFile)
175 }
176 catch (e) {}
177 process.exit(1)
178 }
179 process.once('SIGINT', onExit)
180 process.once('SIGTERM', onExit)
181 var bar = new Progress(' encrypting [:bar] :percent ETA: :etas', { total: totalSize, width: 80 })
182 var chunkCounter = 0
183 var tickCounter = 0
184 encryptor.on('data', function (chunk) {
185 chunkCounter++
186 tickCounter += chunk.length
187 if (chunkCounter % 100 === 0) {
188 bar.tick(tickCounter)
189 tickCounter = 0
190 }
191 })
192 }
193 encryptor.pipe(outStream)
194 }
195 }
196 })
197}
\No newline at end of file