1
1
import { Command } from "commander" ;
2
-
3
2
import fs , { existsSync } from "fs" ;
4
3
import fsAsync from "fs/promises" ;
5
4
import pathProgram from "path" ;
@@ -8,7 +7,6 @@ import throat from "throat";
8
7
import Encryption from "../Encryption" ;
9
8
import Tree from "../Tree" ;
10
9
import FileMap from "../FileMap" ;
11
-
12
10
import Logger from "../Logger" ;
13
11
import Timer from "../Timer" ;
14
12
@@ -85,7 +83,10 @@ export default new Command("decrypt")
85
83
process . exit ( ) ;
86
84
}
87
85
88
- // Loops through given paths and gets information about them
86
+ /**
87
+ * Loops through given paths (the cli arguments), runs
88
+ * some checks and maps them.
89
+ */
89
90
let inputItems = await Promise . all (
90
91
inputPaths . map (
91
92
async (
@@ -99,7 +100,8 @@ export default new Command("decrypt")
99
100
// Reads current path stats
100
101
let pathStats = await fsAsync . stat ( inputPath ) ;
101
102
102
- let humanReadableItemType = pathStats . isFile ( )
103
+ // Creates human addressed and readable item type
104
+ let humanAddressedItemType = pathStats . isFile ( )
103
105
? "file"
104
106
: pathStats . isDirectory ( )
105
107
? "directory"
@@ -108,7 +110,7 @@ export default new Command("decrypt")
108
110
// Checks if the item exists
109
111
if ( ! existsSync ( inputPath ) ) {
110
112
logger . error (
111
- `This ${ humanReadableItemType } doesn't exist.\n(path: ${ inputPath } )`
113
+ `This ${ humanAddressedItemType } doesn't exist.\n(path: ${ inputPath } )`
112
114
) ;
113
115
process . exit ( ) ;
114
116
}
@@ -136,7 +138,7 @@ export default new Command("decrypt")
136
138
} catch ( e ) {
137
139
logger . debugOnly . error ( e ) ;
138
140
logger . error (
139
- `Failed to overwrite the output ${ humanReadableItemType } .\n(path: ${ outputPath } )`
141
+ `Failed to overwrite the output ${ humanAddressedItemType } .\n(path: ${ outputPath } )`
140
142
) ;
141
143
}
142
144
} else {
@@ -153,6 +155,10 @@ export default new Command("decrypt")
153
155
}
154
156
}
155
157
158
+ /**
159
+ * Returns different objects whether the item is
160
+ * a directory, a file or something else
161
+ */
156
162
if ( pathStats . isDirectory ( ) ) {
157
163
return {
158
164
type : "directory" ,
@@ -168,7 +174,7 @@ export default new Command("decrypt")
168
174
} ;
169
175
} else {
170
176
logger . warn (
171
- "An item that is neither a file nor directory was found, skipping.. .\n" . concat (
177
+ "An item that is neither a file nor directory was found, it will be skipped .\n" . concat (
172
178
`(path: ${ inputPath } )`
173
179
)
174
180
) ;
@@ -189,14 +195,12 @@ export default new Command("decrypt")
189
195
let clean = async ( ) => {
190
196
try {
191
197
await Promise . all (
192
- inputItems . map (
193
- throat ( 10 , async ( item ) => {
194
- await fsAsync . rm ( item . outputPath , {
195
- recursive : true ,
196
- force : true ,
197
- } ) ;
198
- } )
199
- )
198
+ inputItems . map ( async ( i ) => {
199
+ await fsAsync . rm ( i . outputPath , {
200
+ recursive : true ,
201
+ force : true ,
202
+ } ) ;
203
+ } )
200
204
) ;
201
205
} catch ( e ) {
202
206
logger . debugOnly . error ( e ) ;
@@ -210,18 +214,18 @@ export default new Command("decrypt")
210
214
try {
211
215
let allValid = (
212
216
await Promise . all (
213
- inputItems . map ( async ( i ) => {
214
- if ( i . type === "directory" ) {
217
+ inputItems . map ( async ( item ) => {
218
+ if ( item . type === "directory" ) {
215
219
return (
216
220
await Promise . all (
217
- await i . tree ! . map ( ( i ) =>
221
+ await item . tree ! . map ( ( i ) =>
218
222
encryption . validateStream ( fs . createReadStream ( i . path ) )
219
223
)
220
224
)
221
225
) . every ( ( i ) => ! ! i ) ;
222
226
} else {
223
227
return await encryption . validateStream (
224
- fs . createReadStream ( i . inputPath )
228
+ fs . createReadStream ( item . inputPath )
225
229
) ;
226
230
}
227
231
} )
@@ -251,8 +255,8 @@ export default new Command("decrypt")
251
255
await Promise . all (
252
256
inputItems . map ( async ( inputItem ) => {
253
257
/**
254
- * Check if the item is a directory, a file or
255
- * something else
258
+ * Do something whether the item is a directory,
259
+ * a file or something else
256
260
*/
257
261
if ( inputItem . type === "directory" ) {
258
262
// Creates base directory (typically [name of the dir to encrypt].encrypted)
@@ -264,65 +268,84 @@ export default new Command("decrypt")
264
268
process . exit ( ) ;
265
269
}
266
270
267
- // Finds file map
268
- let fileMap = (
271
+ // Finds file map (the encrypted file itself)
272
+ let fileMapPath = (
269
273
await Promise . all (
270
274
await inputItem . tree ! . map (
271
- throat ( 20 , async ( item ) => {
272
- let bufferedName = Buffer . from ( item . name , "base64url" ) ;
273
- if (
274
- encryption . validate ( bufferedName ) &&
275
- encryption . decrypt ( bufferedName ) . toString ( "utf8" ) ===
275
+ throat ( 60 , async ( item ) => {
276
+ let itemName = Buffer . from ( item . name , "base64url" ) ;
277
+ /**
278
+ * You might think this is not secure
279
+ * because an encrypted file could also
280
+ * be named "fileMap", it will be found
281
+ * and used as file map, in this case
282
+ * please see `../encrypt.ts` at line
283
+ * 286
284
+ */
285
+ return encryption . validate ( itemName ) &&
286
+ encryption . decrypt ( itemName ) . toString ( "utf8" ) ===
276
287
"fileMap"
277
- ) {
278
- let parsed = FileMap . parse (
279
- encryption
280
- . decrypt ( await fsAsync . readFile ( item . path ) )
281
- . toString ( "utf8" )
282
- ) ?. items ;
283
- if ( ! parsed ) return null ;
284
- else return parsed ;
285
- } else return null ;
288
+ ? item . path
289
+ : undefined ;
286
290
} )
287
291
)
288
292
)
289
293
) . find ( ( i ) => ! ! i ) ;
290
- if ( ! fileMap ) {
294
+ if ( ! fileMapPath ) {
291
295
logger . error (
292
296
"Couldn't decrypt because file map can't be found"
293
297
) ;
294
298
process . exit ( ) ;
295
299
}
296
300
297
301
/**
298
- * Reads file map and decrypt items depending
302
+ * Creates FileMap object
303
+ */
304
+ let fileMap = await FileMap . new ( ) ;
305
+ /**
306
+ * Decrypts file map and write the result in
307
+ * the temporary file map created when using
308
+ * FileMap.new();
309
+ */
310
+ await encryption . decryptStream (
311
+ fs . createReadStream ( fileMapPath ) ,
312
+ fs . createWriteStream ( fileMap . tmpFilePath )
313
+ ) ;
314
+
315
+ /**
316
+ * Parses file map and decrypts items depending
299
317
* on it
300
318
*/
301
319
await Promise . all (
302
- fileMap . map (
303
- throat ( 20 , async ( [ plain , randomized ] ) => {
320
+ await fileMap . parseAndMap (
321
+ throat ( 60 , async ( [ plain , encrypted ] ) => {
322
+ if ( plain === "fileMap" ) return ;
304
323
let newPath = pathProgram . join ( inputItem . outputPath , plain ) ;
324
+ /**
325
+ * Creates directories if necessary
326
+ */
305
327
await fsAsync . mkdir (
306
328
pathProgram . resolve ( pathProgram . dirname ( newPath ) ) ,
307
329
{
308
330
recursive : true ,
309
331
}
310
332
) ;
333
+ /**
334
+ * Decrypts item
335
+ */
311
336
await encryption . decryptStream (
312
337
fs . createReadStream (
313
- pathProgram . join ( inputItem . inputPath , randomized )
338
+ pathProgram . join ( inputItem . inputPath , encrypted )
314
339
) ,
315
340
fs . createWriteStream ( newPath )
316
341
) ;
317
342
} )
318
343
)
319
344
) ;
320
-
321
- // Removes file map
322
- await fsAsync . rm (
323
- pathProgram . join ( inputItem . outputPath , "fileMap" )
324
- ) ;
325
345
} else if ( inputItem . type === "file" ) {
346
+ /**
347
+ * Decrypts file
348
+ */
326
349
await encryption . decryptStream (
327
350
fs . createReadStream ( inputItem . inputPath ) ,
328
351
fs . createWriteStream ( inputItem . outputPath )
0 commit comments