@zip.js/zip.js 2.6.26 → 2.6.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -35,6 +35,7 @@ import {
35
35
  ERR_INVALID_PASSWORD,
36
36
  ERR_INVALID_SIGNATURE
37
37
  } from "./streams/zip-entry-stream.js";
38
+ import { CodecStream } from "./streams/codec-stream.js";
38
39
 
39
40
  const CODEC_DEFLATE = "deflate";
40
41
  const CODEC_INFLATE = "inflate";
@@ -47,6 +48,7 @@ const MESSAGE_CLOSE = "close";
47
48
 
48
49
  export {
49
50
  Codec,
51
+ getCodecStreamClass,
50
52
  CODEC_DEFLATE,
51
53
  CODEC_INFLATE,
52
54
  ERR_INVALID_SIGNATURE,
@@ -61,17 +63,16 @@ export {
61
63
 
62
64
  class Codec {
63
65
 
64
- constructor(CodecConstructor, readable, writable, options, config) {
66
+ constructor(readable, writable, options, config) {
65
67
  const { codecType } = options;
66
- let StreamConstructor;
68
+ let CodecStream;
67
69
  if (codecType.startsWith(CODEC_DEFLATE)) {
68
- StreamConstructor = DeflateStream;
70
+ CodecStream = DeflateStream;
69
71
  } else if (codecType.startsWith(CODEC_INFLATE)) {
70
- StreamConstructor = InflateStream;
72
+ CodecStream = InflateStream;
71
73
  }
72
74
  Object.assign(this, {
73
- StreamConstructor,
74
- CodecConstructor,
75
+ CodecStream,
75
76
  readable,
76
77
  writable,
77
78
  options,
@@ -81,14 +82,13 @@ class Codec {
81
82
 
82
83
  async run() {
83
84
  const {
84
- StreamConstructor,
85
- CodecConstructor,
85
+ CodecStream,
86
86
  readable,
87
87
  writable,
88
88
  options,
89
89
  config
90
90
  } = this;
91
- const stream = new StreamConstructor(CodecConstructor, options, config);
91
+ const stream = new CodecStream(options, config);
92
92
  let size = 0;
93
93
  await readable
94
94
  .pipeThrough(stream)
@@ -104,4 +104,12 @@ class Codec {
104
104
  const { signature } = stream;
105
105
  return { size, signature };
106
106
  }
107
+ }
108
+
109
+ function getCodecStreamClass(Codec) {
110
+ return class extends CodecStream {
111
+ constructor(algorithm, options) {
112
+ super(Codec, options);
113
+ }
114
+ };
107
115
  }
@@ -50,10 +50,9 @@ class CodecWorker {
50
50
 
51
51
  constructor(workerData, stream, workerOptions, onTaskFinished) {
52
52
  const { readable, writable } = stream;
53
- const { options, config, streamOptions, useWebWorkers, transferStreams, scripts, codecConstructor } = workerOptions;
53
+ const { options, config, streamOptions, useWebWorkers, transferStreams, scripts } = workerOptions;
54
54
  Object.assign(workerData, {
55
55
  busy: true,
56
- codecConstructor,
57
56
  readable,
58
57
  writable,
59
58
  options: Object.assign({}, options),
@@ -106,7 +105,7 @@ async function callHandler(handler, ...parameters) {
106
105
  }
107
106
 
108
107
  function createWorkerInterface(workerData, config) {
109
- const interfaceCodec = new Codec(workerData.codecConstructor, workerData.readable, workerData.writable, workerData.options, config);
108
+ const interfaceCodec = new Codec(workerData.readable, workerData.writable, workerData.options, config);
110
109
  const { onTaskFinished } = workerData;
111
110
  const codec = {
112
111
  async run() {
@@ -58,7 +58,7 @@ async function runWorker(stream, workerOptions) {
58
58
  const streamCopy = !compressed && !signed && !encrypted && !workerOptions.transferStreams;
59
59
  workerOptions.useWebWorkers = !streamCopy && (useWebWorkers || (useWebWorkers === undefined && config.useWebWorkers));
60
60
  workerOptions.scripts = workerOptions.useWebWorkers && workerScripts ? workerScripts[codecType] : [];
61
- options.useCompressionStream = useCompressionStream === undefined ? config.useCompressionStream : useCompressionStream;
61
+ options.useCompressionStream = useCompressionStream || (useCompressionStream === undefined && config.useCompressionStream);
62
62
  let worker;
63
63
  if (pool.length < config.maxWorkers) {
64
64
  const workerData = { indexWorker };
@@ -26,16 +26,29 @@
26
26
  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
27
  */
28
28
 
29
- /* global navigator */
29
+ /* global navigator, CompressionStream, DecompressionStream */
30
+
31
+ import { getCodecStreamClass } from "./codec-interface.js";
30
32
 
31
33
  const MINIMUM_CHUNK_SIZE = 64;
32
- const UNDEFINED_TYPE = undefined;
34
+ const UNDEFINED_VALUE = undefined;
35
+ let maxWorkers = 2;
36
+ try {
37
+ if (typeof navigator != "undefined" && navigator.hardwareConcurrency) {
38
+ maxWorkers = navigator.hardwareConcurrency;
39
+ }
40
+ } catch (_error) {
41
+ // ignored
42
+ }
33
43
  const DEFAULT_CONFIGURATION = {
34
44
  chunkSize: 512 * 1024,
35
- maxWorkers: (typeof navigator != "undefined" && navigator.hardwareConcurrency) || 2,
45
+ maxWorkers,
36
46
  terminateWorkerTimeout: 5000,
37
47
  useWebWorkers: true,
38
- workerScripts: undefined
48
+ useCompressionStream: true,
49
+ workerScripts: undefined,
50
+ CompressionStreamNative: typeof CompressionStream != "undefined" && CompressionStream,
51
+ DecompressionStreamNative: typeof DecompressionStream != "undefined" && DecompressionStream
39
52
  };
40
53
 
41
54
  const config = Object.assign({}, DEFAULT_CONFIGURATION);
@@ -64,6 +77,8 @@ function configure(configuration) {
64
77
  useWebWorkers,
65
78
  Deflate,
66
79
  Inflate,
80
+ CompressionStream,
81
+ DecompressionStream,
67
82
  workerScripts
68
83
  } = configuration;
69
84
  setIfDefined("baseURL", baseURL);
@@ -72,9 +87,15 @@ function configure(configuration) {
72
87
  setIfDefined("terminateWorkerTimeout", terminateWorkerTimeout);
73
88
  setIfDefined("useCompressionStream", useCompressionStream);
74
89
  setIfDefined("useWebWorkers", useWebWorkers);
75
- setIfDefined("Deflate", Deflate);
76
- setIfDefined("Inflate", Inflate);
77
- if (workerScripts !== UNDEFINED_TYPE) {
90
+ if (Deflate) {
91
+ config.CompressionStream = getCodecStreamClass(Deflate);
92
+ }
93
+ if (Inflate) {
94
+ config.DecompressionStream = getCodecStreamClass(Inflate);
95
+ }
96
+ setIfDefined("CompressionStream", CompressionStream);
97
+ setIfDefined("DecompressionStream", DecompressionStream);
98
+ if (workerScripts !== UNDEFINED_VALUE) {
78
99
  const { deflate, inflate } = workerScripts;
79
100
  if (deflate || inflate) {
80
101
  if (!config.workerScripts) {
@@ -97,7 +118,7 @@ function configure(configuration) {
97
118
  }
98
119
 
99
120
  function setIfDefined(propertyName, propertyValue) {
100
- if (propertyValue !== UNDEFINED_TYPE) {
121
+ if (propertyValue !== UNDEFINED_VALUE) {
101
122
  config[propertyName] = propertyValue;
102
123
  }
103
124
  }
package/lib/core/io.js CHANGED
@@ -100,52 +100,6 @@ class Writer extends Stream {
100
100
  }
101
101
  }
102
102
 
103
- class TextReader extends Reader {
104
-
105
- constructor(text) {
106
- super();
107
- this.blobReader = new BlobReader(new Blob([text], { type: CONTENT_TYPE_TEXT_PLAIN }));
108
- }
109
-
110
- init() {
111
- const reader = this;
112
- super.init();
113
- reader.blobReader.init();
114
- reader.size = reader.blobReader.size;
115
- }
116
-
117
- readUint8Array(offset, length) {
118
- return this.blobReader.readUint8Array(offset, length);
119
- }
120
- }
121
-
122
- class TextWriter extends Writer {
123
-
124
- constructor(encoding) {
125
- super();
126
- this.encoding = encoding;
127
- this.blob = new Blob([], { type: CONTENT_TYPE_TEXT_PLAIN });
128
- }
129
-
130
- writeUint8Array(array) {
131
- this.blob = new Blob([this.blob, array.buffer], { type: CONTENT_TYPE_TEXT_PLAIN });
132
- }
133
-
134
- getData() {
135
- const writer = this;
136
- if (writer.blob.text && (writer.encoding === undefined || (writer.encoding && writer.encoding.toLowerCase() == "utf-8"))) {
137
- return writer.blob.text();
138
- } else {
139
- const reader = new FileReader();
140
- return new Promise((resolve, reject) => {
141
- reader.onload = event => resolve(event.target.result);
142
- reader.onerror = () => reject(reader.error);
143
- reader.readAsText(writer.blob, writer.encoding);
144
- });
145
- }
146
- }
147
- }
148
-
149
103
  class Data64URIReader extends Reader {
150
104
 
151
105
  constructor(dataURI) {
@@ -242,6 +196,42 @@ class BlobWriter extends Stream {
242
196
  }
243
197
  }
244
198
 
199
+ class TextReader extends BlobReader {
200
+
201
+ constructor(text) {
202
+ super(new Blob([text], { type: CONTENT_TYPE_TEXT_PLAIN }));
203
+ }
204
+ }
205
+
206
+ class TextWriter extends BlobWriter {
207
+
208
+ constructor(encoding) {
209
+ super(encoding);
210
+ Object.assign(this, {
211
+ encoding,
212
+ utf8: !encoding || encoding.toLowerCase() == "utf-8"
213
+ });
214
+ }
215
+
216
+ async getData() {
217
+ const {
218
+ encoding,
219
+ utf8
220
+ } = this;
221
+ const blob = await super.getData();
222
+ if (blob.text && utf8) {
223
+ return blob.text();
224
+ } else {
225
+ const reader = new FileReader();
226
+ return new Promise((resolve, reject) => {
227
+ reader.onload = ({ target }) => resolve(target.result);
228
+ reader.onerror = () => reject(reader.error);
229
+ reader.readAsText(blob, encoding);
230
+ });
231
+ }
232
+ }
233
+ }
234
+
245
235
  class FetchReader extends Reader {
246
236
 
247
237
  constructor(url, options) {
@@ -38,6 +38,7 @@ import {
38
38
  } from "./codecs/sjcl.js";
39
39
  import {
40
40
  ERR_INVALID_PASSWORD,
41
+ ERR_INVALID_SIGNATURE,
41
42
  getRandomValues
42
43
  } from "./common-crypto.js";
43
44
 
@@ -56,9 +57,10 @@ const COUNTER_DEFAULT_VALUE = [0, 0, 0, 0];
56
57
  const UNDEFINED_TYPE = "undefined";
57
58
  const FUNCTION_TYPE = "function";
58
59
  const CRYPTO_API_SUPPORTED = typeof crypto != UNDEFINED_TYPE;
59
- const SUBTLE_API_SUPPORTED = CRYPTO_API_SUPPORTED && typeof crypto.subtle != UNDEFINED_TYPE;
60
- const IMPORT_KEY_SUPPORTED = CRYPTO_API_SUPPORTED && SUBTLE_API_SUPPORTED && typeof crypto.subtle.importKey == FUNCTION_TYPE;
61
- const DERIVE_BITS_SUPPORTED = CRYPTO_API_SUPPORTED && SUBTLE_API_SUPPORTED && typeof crypto.subtle.deriveBits == FUNCTION_TYPE;
60
+ const subtle = CRYPTO_API_SUPPORTED && crypto.subtle;
61
+ const SUBTLE_API_SUPPORTED = CRYPTO_API_SUPPORTED && typeof subtle != UNDEFINED_TYPE;
62
+ const IMPORT_KEY_SUPPORTED = CRYPTO_API_SUPPORTED && SUBTLE_API_SUPPORTED && typeof subtle.importKey == FUNCTION_TYPE;
63
+ const DERIVE_BITS_SUPPORTED = CRYPTO_API_SUPPORTED && SUBTLE_API_SUPPORTED && typeof subtle.deriveBits == FUNCTION_TYPE;
62
64
  const codecBytes = codec.bytes;
63
65
  const Aes = cipher.aes;
64
66
  const CtrGladman = mode.ctrGladman;
@@ -67,7 +69,6 @@ const HmacSha1 = misc.hmacSha1;
67
69
  class AESDecryptionStream extends TransformStream {
68
70
 
69
71
  constructor(password, signed, strength) {
70
- let stream;
71
72
  super({
72
73
  start() {
73
74
  Object.assign(this, {
@@ -80,47 +81,51 @@ class AESDecryptionStream extends TransformStream {
80
81
  },
81
82
  async transform(chunk, controller) {
82
83
  const aesCrypto = this;
83
- if (aesCrypto.password) {
84
- const password = aesCrypto.password;
85
- aesCrypto.password = null;
86
- const preamble = subarray(chunk, 0, SALT_LENGTH[aesCrypto.strength] + 2);
87
- await createDecryptionKeys(aesCrypto, preamble, password);
88
- aesCrypto.ctr = new CtrGladman(new Aes(aesCrypto.keys.key), Array.from(COUNTER_DEFAULT_VALUE));
89
- aesCrypto.hmac = new HmacSha1(aesCrypto.keys.authentication);
90
- chunk = subarray(chunk, SALT_LENGTH[aesCrypto.strength] + 2);
91
- aesCrypto.resolveReady();
84
+ const {
85
+ password,
86
+ strength,
87
+ resolveReady,
88
+ ready
89
+ } = aesCrypto;
90
+ if (password) {
91
+ await createDecryptionKeys(aesCrypto, strength, password, subarray(chunk, 0, SALT_LENGTH[strength] + 2));
92
+ chunk = subarray(chunk, SALT_LENGTH[strength] + 2);
93
+ resolveReady();
92
94
  } else {
93
- await aesCrypto.ready;
95
+ await ready;
94
96
  }
95
97
  const output = new Uint8Array(chunk.length - SIGNATURE_LENGTH - ((chunk.length - SIGNATURE_LENGTH) % BLOCK_LENGTH));
96
98
  controller.enqueue(append(aesCrypto, chunk, output, 0, SIGNATURE_LENGTH, true));
97
99
  },
98
100
  async flush(controller) {
99
- const aesCrypto = this;
100
- await aesCrypto.ready;
101
- const pending = aesCrypto.pending;
101
+ const {
102
+ signed,
103
+ ctr,
104
+ hmac,
105
+ pending,
106
+ ready
107
+ } = this;
108
+ await ready;
102
109
  const chunkToDecrypt = subarray(pending, 0, pending.length - SIGNATURE_LENGTH);
103
110
  const originalSignature = subarray(pending, pending.length - SIGNATURE_LENGTH);
104
111
  let decryptedChunkArray = new Uint8Array();
105
112
  if (chunkToDecrypt.length) {
106
113
  const encryptedChunk = toBits(codecBytes, chunkToDecrypt);
107
- aesCrypto.hmac.update(encryptedChunk);
108
- const decryptedChunk = aesCrypto.ctr.update(encryptedChunk);
114
+ hmac.update(encryptedChunk);
115
+ const decryptedChunk = ctr.update(encryptedChunk);
109
116
  decryptedChunkArray = fromBits(codecBytes, decryptedChunk);
110
117
  }
111
- stream.valid = true;
112
- if (aesCrypto.signed) {
113
- const signature = subarray(fromBits(codecBytes, aesCrypto.hmac.digest()), 0, SIGNATURE_LENGTH);
118
+ if (signed) {
119
+ const signature = subarray(fromBits(codecBytes, hmac.digest()), 0, SIGNATURE_LENGTH);
114
120
  for (let indexSignature = 0; indexSignature < SIGNATURE_LENGTH; indexSignature++) {
115
121
  if (signature[indexSignature] != originalSignature[indexSignature]) {
116
- stream.valid = false;
122
+ throw new Error(ERR_INVALID_SIGNATURE);
117
123
  }
118
124
  }
119
125
  }
120
126
  controller.enqueue(decryptedChunkArray);
121
127
  }
122
128
  });
123
- stream = this;
124
129
  }
125
130
  }
126
131
 
@@ -139,31 +144,38 @@ class AESEncryptionStream extends TransformStream {
139
144
  },
140
145
  async transform(chunk, controller) {
141
146
  const aesCrypto = this;
147
+ const {
148
+ password,
149
+ strength,
150
+ resolveReady,
151
+ ready
152
+ } = aesCrypto;
142
153
  let preamble = new Uint8Array();
143
- if (aesCrypto.password) {
144
- const password = aesCrypto.password;
145
- aesCrypto.password = null;
146
- preamble = await createEncryptionKeys(aesCrypto, password);
147
- aesCrypto.ctr = new CtrGladman(new Aes(aesCrypto.keys.key), Array.from(COUNTER_DEFAULT_VALUE));
148
- aesCrypto.hmac = new HmacSha1(aesCrypto.keys.authentication);
149
- aesCrypto.resolveReady();
154
+ if (password) {
155
+ preamble = await createEncryptionKeys(aesCrypto, strength, password);
156
+ resolveReady();
150
157
  } else {
151
- await aesCrypto.ready;
158
+ await ready;
152
159
  }
153
160
  const output = new Uint8Array(preamble.length + chunk.length - (chunk.length % BLOCK_LENGTH));
154
161
  output.set(preamble, 0);
155
162
  controller.enqueue(append(aesCrypto, chunk, output, preamble.length, 0));
156
163
  },
157
164
  async flush(controller) {
158
- const aesCrypto = this;
159
- await aesCrypto.ready;
165
+ const {
166
+ ctr,
167
+ hmac,
168
+ pending,
169
+ ready
170
+ } = this;
171
+ await ready;
160
172
  let encryptedChunkArray = new Uint8Array();
161
- if (aesCrypto.pending.length) {
162
- const encryptedChunk = aesCrypto.ctr.update(toBits(codecBytes, aesCrypto.pending));
163
- aesCrypto.hmac.update(encryptedChunk);
173
+ if (pending.length) {
174
+ const encryptedChunk = ctr.update(toBits(codecBytes, pending));
175
+ hmac.update(encryptedChunk);
164
176
  encryptedChunkArray = fromBits(codecBytes, encryptedChunk);
165
177
  }
166
- stream.signature = fromBits(codecBytes, aesCrypto.hmac.digest()).slice(0, SIGNATURE_LENGTH);
178
+ stream.signature = fromBits(codecBytes, hmac.digest()).slice(0, SIGNATURE_LENGTH);
167
179
  controller.enqueue(concat(encryptedChunkArray, stream.signature));
168
180
  }
169
181
  });
@@ -178,20 +190,25 @@ export {
178
190
  };
179
191
 
180
192
  function append(aesCrypto, input, output, paddingStart, paddingEnd, verifySignature) {
193
+ const {
194
+ ctr,
195
+ hmac,
196
+ pending
197
+ } = aesCrypto;
181
198
  const inputLength = input.length - paddingEnd;
182
- if (aesCrypto.pending.length) {
183
- input = concat(aesCrypto.pending, input);
199
+ if (pending.length) {
200
+ input = concat(pending, input);
184
201
  output = expand(output, inputLength - (inputLength % BLOCK_LENGTH));
185
202
  }
186
203
  let offset;
187
204
  for (offset = 0; offset <= inputLength - BLOCK_LENGTH; offset += BLOCK_LENGTH) {
188
205
  const inputChunk = toBits(codecBytes, subarray(input, offset, offset + BLOCK_LENGTH));
189
206
  if (verifySignature) {
190
- aesCrypto.hmac.update(inputChunk);
207
+ hmac.update(inputChunk);
191
208
  }
192
- const outputChunk = aesCrypto.ctr.update(inputChunk);
209
+ const outputChunk = ctr.update(inputChunk);
193
210
  if (!verifySignature) {
194
- aesCrypto.hmac.update(outputChunk);
211
+ hmac.update(outputChunk);
195
212
  }
196
213
  output.set(fromBits(codecBytes, outputChunk), offset + paddingStart);
197
214
  }
@@ -199,36 +216,44 @@ function append(aesCrypto, input, output, paddingStart, paddingEnd, verifySignat
199
216
  return output;
200
217
  }
201
218
 
202
- async function createDecryptionKeys(decrypt, preambleArray, password) {
203
- await createKeys(decrypt, password, subarray(preambleArray, 0, SALT_LENGTH[decrypt.strength]));
204
- const passwordVerification = subarray(preambleArray, SALT_LENGTH[decrypt.strength]);
205
- const passwordVerificationKey = decrypt.keys.passwordVerification;
219
+ async function createDecryptionKeys(decrypt, strength, password, preamble) {
220
+ const passwordVerificationKey = await createKeys(decrypt, strength, password, subarray(preamble, 0, SALT_LENGTH[strength]));
221
+ const passwordVerification = subarray(preamble, SALT_LENGTH[strength]);
206
222
  if (passwordVerificationKey[0] != passwordVerification[0] || passwordVerificationKey[1] != passwordVerification[1]) {
207
223
  throw new Error(ERR_INVALID_PASSWORD);
208
224
  }
209
225
  }
210
226
 
211
- async function createEncryptionKeys(encrypt, password) {
212
- const salt = getRandomValues(new Uint8Array(SALT_LENGTH[encrypt.strength]));
213
- await createKeys(encrypt, password, salt);
214
- return concat(salt, encrypt.keys.passwordVerification);
227
+ async function createEncryptionKeys(encrypt, strength, password) {
228
+ const salt = getRandomValues(new Uint8Array(SALT_LENGTH[strength]));
229
+ const passwordVerification = await createKeys(encrypt, strength, password, salt);
230
+ return concat(salt, passwordVerification);
215
231
  }
216
232
 
217
- async function createKeys(target, password, salt) {
233
+ async function createKeys(aesCrypto, strength, password, salt) {
234
+ aesCrypto.password = null;
218
235
  const encodedPassword = encodeText(password);
219
- const basekey = await importKey(RAW_FORMAT, encodedPassword, BASE_KEY_ALGORITHM, false, DERIVED_BITS_USAGE);
220
- const derivedBits = await deriveBits(Object.assign({ salt }, DERIVED_BITS_ALGORITHM), basekey, 8 * ((KEY_LENGTH[target.strength] * 2) + 2));
236
+ const baseKey = await importKey(RAW_FORMAT, encodedPassword, BASE_KEY_ALGORITHM, false, DERIVED_BITS_USAGE);
237
+ const derivedBits = await deriveBits(Object.assign({ salt }, DERIVED_BITS_ALGORITHM), baseKey, 8 * ((KEY_LENGTH[strength] * 2) + 2));
221
238
  const compositeKey = new Uint8Array(derivedBits);
222
- target.keys = {
223
- key: toBits(codecBytes, subarray(compositeKey, 0, KEY_LENGTH[target.strength])),
224
- authentication: toBits(codecBytes, subarray(compositeKey, KEY_LENGTH[target.strength], KEY_LENGTH[target.strength] * 2)),
225
- passwordVerification: subarray(compositeKey, KEY_LENGTH[target.strength] * 2)
226
- };
239
+ const key = toBits(codecBytes, subarray(compositeKey, 0, KEY_LENGTH[strength]));
240
+ const authentication = toBits(codecBytes, subarray(compositeKey, KEY_LENGTH[strength], KEY_LENGTH[strength] * 2));
241
+ const passwordVerification = subarray(compositeKey, KEY_LENGTH[strength] * 2);
242
+ Object.assign(aesCrypto, {
243
+ keys: {
244
+ key,
245
+ authentication,
246
+ passwordVerification
247
+ },
248
+ ctr: new CtrGladman(new Aes(key), Array.from(COUNTER_DEFAULT_VALUE)),
249
+ hmac: new HmacSha1(authentication)
250
+ });
251
+ return passwordVerification;
227
252
  }
228
253
 
229
254
  function importKey(format, password, algorithm, extractable, keyUsages) {
230
255
  if (IMPORT_KEY_SUPPORTED) {
231
- return crypto.subtle.importKey(format, password, algorithm, extractable, keyUsages);
256
+ return subtle.importKey(format, password, algorithm, extractable, keyUsages);
232
257
  } else {
233
258
  return misc.importKey(password);
234
259
  }
@@ -236,7 +261,7 @@ function importKey(format, password, algorithm, extractable, keyUsages) {
236
261
 
237
262
  async function deriveBits(algorithm, baseKey, length) {
238
263
  if (DERIVE_BITS_SUPPORTED) {
239
- return await crypto.subtle.deriveBits(algorithm, baseKey, length);
264
+ return await subtle.deriveBits(algorithm, baseKey, length);
240
265
  } else {
241
266
  return misc.pbkdf2(baseKey, algorithm.salt, DERIVED_BITS_ALGORITHM.iterations, length);
242
267
  }
@@ -44,8 +44,7 @@ class CodecStream extends TransformStream {
44
44
  codec = new Codec(options);
45
45
  },
46
46
  transform(chunk, controller) {
47
- chunk = codec.append(chunk);
48
- controller.enqueue(chunk);
47
+ controller.enqueue(codec.append(chunk));
49
48
  },
50
49
  flush(controller) {
51
50
  const chunk = codec.flush();
@@ -35,10 +35,12 @@ import {
35
35
  } from "./codecs/sjcl.js";
36
36
 
37
37
  const ERR_INVALID_PASSWORD = "Invalid password";
38
+ const ERR_INVALID_SIGNATURE = "Invalid signature";
38
39
 
39
40
  export {
40
41
  getRandomValues,
41
- ERR_INVALID_PASSWORD
42
+ ERR_INVALID_PASSWORD,
43
+ ERR_INVALID_SIGNATURE
42
44
  };
43
45
 
44
46
  function getRandomValues(array) {
@@ -39,7 +39,6 @@ const HEADER_LENGTH = 12;
39
39
  class ZipCryptoDecryptionStream extends TransformStream {
40
40
 
41
41
  constructor(password, passwordVerification) {
42
- let stream;
43
42
  super({
44
43
  start() {
45
44
  Object.assign(this, {
@@ -59,12 +58,8 @@ class ZipCryptoDecryptionStream extends TransformStream {
59
58
  chunk = chunk.subarray(HEADER_LENGTH);
60
59
  }
61
60
  controller.enqueue(decrypt(zipCrypto, chunk));
62
- },
63
- flush() {
64
- stream.valid = true;
65
61
  }
66
62
  });
67
- stream = this;
68
63
  }
69
64
  }
70
65
 
@@ -128,21 +123,25 @@ function encrypt(target, input) {
128
123
  }
129
124
 
130
125
  function createKeys(target, password) {
131
- target.keys = [0x12345678, 0x23456789, 0x34567890];
132
- target.crcKey0 = new Crc32(target.keys[0]);
133
- target.crcKey2 = new Crc32(target.keys[2]);
126
+ const keys = [0x12345678, 0x23456789, 0x34567890];
127
+ Object.assign(target, {
128
+ keys,
129
+ crcKey0: new Crc32(keys[0]),
130
+ crcKey2: new Crc32(keys[2]),
131
+ });
134
132
  for (let index = 0; index < password.length; index++) {
135
133
  updateKeys(target, password.charCodeAt(index));
136
134
  }
137
135
  }
138
136
 
139
137
  function updateKeys(target, byte) {
138
+ let [key0, key1, key2] = target.keys;
140
139
  target.crcKey0.append([byte]);
141
- target.keys[0] = ~target.crcKey0.get();
142
- target.keys[1] = getInt32(target.keys[1] + getInt8(target.keys[0]));
143
- target.keys[1] = getInt32(Math.imul(target.keys[1], 134775813) + 1);
144
- target.crcKey2.append([target.keys[1] >>> 24]);
145
- target.keys[2] = ~target.crcKey2.get();
140
+ key0 = ~target.crcKey0.get();
141
+ key1 = getInt32(Math.imul(getInt32(key1 + getInt8(key0)), 134775813) + 1);
142
+ target.crcKey2.append([key1 >>> 24]);
143
+ key2 = ~target.crcKey2.get();
144
+ target.keys = [key0, key1, key2];
146
145
  }
147
146
 
148
147
  function getByte(target) {