@cygnuxlabs/tracekit 1.3.0 → 1.4.1

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.
@@ -3,12 +3,16 @@
3
3
  * DecompressionStream), no zip64, under the bundle limits. Names that could escape a directory, symlinks and duplicate
4
4
  * entries are refused.
5
5
  */
6
+ import { repr } from "./jcs.js";
6
7
  export const MAX_ENTRIES = 10_000;
7
8
  export const MAX_ENTRY = 64 << 20;
8
9
  export const MAX_TOTAL = 512 << 20;
9
10
  const NAME = /^[A-Za-z0-9_-][A-Za-z0-9._-]*(\/[A-Za-z0-9._-]+)*$/;
10
11
  export class Unusable extends Error {
11
12
  }
13
+ /** An entry whose bytes don't match its CRC-32: Python's zipfile names it so, and the reports print the name. */
14
+ class BadZipFile extends Unusable {
15
+ }
12
16
  let CRC;
13
17
  function crc32(data) {
14
18
  if (!CRC) {
@@ -83,7 +87,7 @@ export async function readZip(data) {
83
87
  throw new Unusable("not the canonical zip layout: entry count");
84
88
  let pos = 0;
85
89
  for (const e of entries) {
86
- const n = JSON.stringify(e.name.slice(0, 80));
90
+ const n = repr(e.name);
87
91
  if (e.csize === 0xffffffff || e.usize === 0xffffffff || e.local === 0xffffffff)
88
92
  throw new Unusable("zip64 is not supported");
89
93
  if (e.method !== 0 && e.method !== 8 || e.method === 0 && e.csize !== e.usize)
@@ -101,7 +105,7 @@ export async function readZip(data) {
101
105
  || v.getUint32(e.local + 18, true) !== e.csize || v.getUint32(e.local + 22, true) !== e.usize
102
106
  || v.getUint16(e.local + 26, true) !== e.raw.length || v.getUint16(e.local + 28, true)
103
107
  || local.some((b, i) => b !== e.raw[i]))
104
- throw new Unusable(`bad local header for ${n}: it does not repeat the central entry`);
108
+ throw new Unusable(`bad local header for ${n}`);
105
109
  pos = e.local + 30 + e.raw.length + e.csize;
106
110
  }
107
111
  if (pos !== cdOffset)
@@ -111,7 +115,7 @@ export async function readZip(data) {
111
115
  for (const e of entries) {
112
116
  const n = e.name;
113
117
  if (!NAME.test(n) || n.split("/").some((p) => /^\.+$/.test(p)))
114
- throw new Unusable(`bad entry name ${JSON.stringify(n.slice(0, 80))}`);
118
+ throw new Unusable(`bad entry name ${repr(n.slice(0, 80))}`);
115
119
  if (files.has(n))
116
120
  throw new Unusable(`duplicate entry ${n}`);
117
121
  if (((e.attr >>> 16) & 0o170000) === 0o120000)
@@ -129,15 +133,16 @@ export async function readZip(data) {
129
133
  out = await inflate(body, limit);
130
134
  }
131
135
  catch (x) {
136
+ // lean: the decompressor's own message, which differs from zlib's in the reference verifier's report
132
137
  throw new Unusable(`${n}: ${x.message}`);
133
138
  }
134
139
  }
135
140
  if (out.length > cap)
136
141
  throw new Unusable(`${n} is larger than the bundle limits`);
142
+ if (crc32(out) !== e.crc)
143
+ throw new BadZipFile(`Bad CRC-32 for file ${repr(n)}`); // first, as zipfile does
137
144
  if (out.length !== e.usize)
138
145
  throw new Unusable(`${n}: ${out.length} bytes, not the ${e.usize} its entry says`);
139
- if (crc32(out) !== e.crc)
140
- throw new Unusable(`${n}: bad CRC-32`);
141
146
  files.set(n, out);
142
147
  total += out.length;
143
148
  }