Skip to content

Commit 085872a

Browse files
committed
allow the creation of large files via blob
1 parent 97afce7 commit 085872a

File tree

1 file changed

+66
-26
lines changed

1 file changed

+66
-26
lines changed

index.js

+66-26
Original file line numberDiff line numberDiff line change
@@ -25,41 +25,81 @@ function FileSystemAdapter(options) {
2525
}
2626
}
2727

28-
FileSystemAdapter.prototype.createFile = function(filename, data) {
28+
FileSystemAdapter.prototype.createFile = function (filename, data) {
2929
const filepath = this._getLocalFilePath(filename);
3030
const stream = fs.createWriteStream(filepath);
3131
return new Promise((resolve, reject) => {
3232
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+
}
5182
} 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+
}
5394
stream.end();
54-
stream.on('finish', function() {
55-
resolve(data);
56-
});
5795
}
58-
} catch(err) {
59-
return reject(err);
96+
stream.on("finish", resolve);
97+
stream.on("error", reject);
98+
} catch (e) {
99+
reject(e);
60100
}
61101
});
62-
}
102+
};
63103

64104
FileSystemAdapter.prototype.deleteFile = function(filename) {
65105
const filepath = this._getLocalFilePath(filename);

0 commit comments

Comments
 (0)