1 | var 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 |
|
21 | module.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 |