@@ -25,41 +25,81 @@ function FileSystemAdapter(options) {
25
25
}
26
26
}
27
27
28
- FileSystemAdapter . prototype . createFile = function ( filename , data ) {
28
+ FileSystemAdapter . prototype . createFile = function ( filename , data ) {
29
29
const filepath = this . _getLocalFilePath ( filename ) ;
30
30
const stream = fs . createWriteStream ( filepath ) ;
31
31
return new Promise ( ( resolve , reject ) => {
32
32
try {
33
- if ( this . _encryptionKey !== null ) {
34
- const iv = crypto . randomBytes ( 16 ) ;
35
- const cipher = crypto . createCipheriv (
36
- algorithm ,
37
- this . _encryptionKey ,
38
- iv
39
- ) ;
40
- const encryptedResult = Buffer . concat ( [
41
- cipher . update ( data ) ,
42
- cipher . final ( ) ,
43
- iv ,
44
- cipher . getAuthTag ( ) ,
45
- ] ) ;
46
- stream . write ( encryptedResult ) ;
47
- stream . end ( ) ;
48
- stream . on ( 'finish' , function ( ) {
49
- resolve ( data ) ;
50
- } ) ;
33
+ const iv = this . _encryptionKey !== null ? crypto . randomBytes ( 16 ) : null ;
34
+
35
+ const cipher =
36
+ this . _encryptionKey !== null && iv
37
+ ? crypto . createCipheriv ( this . _algorithm , this . _encryptionKey , iv )
38
+ : null ;
39
+
40
+ // when working with a Blob, it could be over the max size of a buffer, so we need to stream it
41
+ if ( data instanceof Blob ) {
42
+ let readableStream = data . stream ( ) ;
43
+
44
+ // may come in as a web stream, so we need to convert it to a node stream
45
+ if ( readableStream instanceof ReadableStream ) {
46
+ readableStream = Readable . fromWeb ( readableStream ) ;
47
+ }
48
+
49
+ if ( cipher && iv ) {
50
+ // we need to stream the data through the cipher
51
+ const cipherTransform = new Transform ( {
52
+ transform ( chunk , encoding , callback ) {
53
+ try {
54
+ const encryptedChunk = cipher . update ( chunk ) ;
55
+ callback ( null , encryptedChunk ) ;
56
+ } catch ( err ) {
57
+ callback ( err ) ;
58
+ }
59
+ } ,
60
+ // at the end we need to push the final cipher text, iv, and auth tag
61
+ flush ( callback ) {
62
+ try {
63
+ this . push ( cipher . final ( ) ) ;
64
+ this . push ( iv ) ;
65
+ this . push ( cipher . getAuthTag ( ) ) ;
66
+ callback ( ) ;
67
+ } catch ( err ) {
68
+ callback ( err ) ;
69
+ }
70
+ } ,
71
+ } ) ;
72
+ // pipe the stream through the cipher and then to the main stream
73
+ readableStream
74
+ . pipe ( cipherTransform )
75
+ . on ( "error" , reject )
76
+ . pipe ( stream )
77
+ . on ( "error" , reject ) ;
78
+ } else {
79
+ // if we don't have a cipher, we can just pipe the stream to the main stream
80
+ readableStream . pipe ( stream ) . on ( "error" , reject ) ;
81
+ }
51
82
} else {
52
- stream . write ( data ) ;
83
+ if ( cipher && iv ) {
84
+ const encryptedResult = Buffer . concat ( [
85
+ cipher . update ( data ) ,
86
+ cipher . final ( ) ,
87
+ iv ,
88
+ cipher . getAuthTag ( ) ,
89
+ ] ) ;
90
+ stream . write ( encryptedResult ) ;
91
+ } else {
92
+ stream . write ( data ) ;
93
+ }
53
94
stream . end ( ) ;
54
- stream . on ( 'finish' , function ( ) {
55
- resolve ( data ) ;
56
- } ) ;
57
95
}
58
- } catch ( err ) {
59
- return reject ( err ) ;
96
+ stream . on ( "finish" , resolve ) ;
97
+ stream . on ( "error" , reject ) ;
98
+ } catch ( e ) {
99
+ reject ( e ) ;
60
100
}
61
101
} ) ;
62
- }
102
+ } ;
63
103
64
104
FileSystemAdapter . prototype . deleteFile = function ( filename ) {
65
105
const filepath = this . _getLocalFilePath ( filename ) ;
0 commit comments