lib0 1.0.0-rc.33 → 1.0.0-rc.34

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lib0",
3
- "version": "1.0.0-rc.33",
3
+ "version": "1.0.0-rc.34",
4
4
  "description": "isomorphic utility functions",
5
5
  "sideEffects": false,
6
6
  "type": "module",
package/src/buffer.js CHANGED
@@ -80,12 +80,13 @@ const fromBase64Browser = /* @__PURE__ */(() =>
80
80
  /* c8 ignore stop */
81
81
 
82
82
  /**
83
+ * Copies the result: small Buffers are allocated from Node's shared pool, and a view on it would expose unrelated
84
+ * memory via `.buffer`.
85
+ *
83
86
  * @param {string} s
87
+ * @return {Uint8Array<ArrayBuffer>}
84
88
  */
85
- const fromBase64Node = s => {
86
- const buf = Buffer.from(s, 'base64')
87
- return createUint8ArrayViewFromArrayBuffer(buf.buffer, buf.byteOffset, buf.byteLength)
88
- }
89
+ const fromBase64Node = s => new Uint8Array(Buffer.from(s, 'base64'))
89
90
 
90
91
  /* c8 ignore next */
91
92
  export const toBase64 = /* @__PURE__ */(() => env.isBrowser ? toBase64Browser : toBase64Node)()
package/src/decoding.js CHANGED
@@ -23,6 +23,10 @@
23
23
  * decoding.hasContent(decoder) // => false - all data is read
24
24
  * ```
25
25
  *
26
+ * Security: Decoders process untrusted input, and `decoder.arr` may be a view on a larger (possibly pooled) ArrayBuffer.
27
+ * Never create views via `new Uint8Array(arr.buffer, ..)` / `new DataView(arr.buffer, ..)`; use the private `subarray` /
28
+ * `subdataview` helpers, which throw on out-of-bounds access instead of exposing foreign memory.
29
+ *
26
30
  * @module decoding
27
31
  */
28
32
 
@@ -36,6 +40,42 @@ import * as encoding from './encoding.js'
36
40
  const errorUnexpectedEndOfArray = error.create('Unexpected end of array')
37
41
  const errorIntegerOutOfRange = error.create('Integer out of Range')
38
42
 
43
+ /**
44
+ * Create a view of `len` bytes of `arr`, starting at `begin`. Throws if the range exceeds `arr`.
45
+ *
46
+ * Security: Always use this (or `subdataview`) instead of `new Uint8Array(arr.buffer, ..)`. `arr` may be a view on a
47
+ * larger (possibly shared/pooled) ArrayBuffer. An unchecked view could expose memory outside of `arr`.
48
+ *
49
+ * @template {ArrayBufferLike} Buf
50
+ * @param {Uint8Array<Buf>} arr
51
+ * @param {number} begin
52
+ * @param {number} len
53
+ * @return {Uint8Array<Buf>}
54
+ */
55
+ const subarray = (arr, begin, len) => {
56
+ if (begin < 0 || len < 0 || begin + len > arr.length) {
57
+ throw errorUnexpectedEndOfArray
58
+ }
59
+ return new Uint8Array(arr.buffer, arr.byteOffset + begin, len)
60
+ }
61
+
62
+ /**
63
+ * Create a DataView of `len` bytes of `arr`, starting at `begin`. Throws if the range exceeds `arr`.
64
+ *
65
+ * Security: See `subarray`.
66
+ *
67
+ * @param {Uint8Array} arr
68
+ * @param {number} begin
69
+ * @param {number} len
70
+ * @return {DataView}
71
+ */
72
+ const subdataview = (arr, begin, len) => {
73
+ if (begin < 0 || len < 0 || begin + len > arr.length) {
74
+ throw errorUnexpectedEndOfArray
75
+ }
76
+ return new DataView(arr.buffer, arr.byteOffset + begin, len)
77
+ }
78
+
39
79
  /**
40
80
  * A Decoder handles the decoding of an Uint8Array.
41
81
  * @template {ArrayBufferLike} [Buf=ArrayBufferLike]
@@ -103,10 +143,7 @@ export const clone = (decoder, newPos = decoder.pos) => {
103
143
  * @return {Uint8Array<Buf>}
104
144
  */
105
145
  export const readUint8Array = (decoder, len) => {
106
- if (len < 0 || len > decoder.arr.length - decoder.pos) {
107
- throw errorUnexpectedEndOfArray
108
- }
109
- const view = new Uint8Array(decoder.arr.buffer, decoder.pos + decoder.arr.byteOffset, len)
146
+ const view = subarray(decoder.arr, decoder.pos, len)
110
147
  decoder.pos += len
111
148
  return view
112
149
  }
@@ -437,7 +474,7 @@ export const peekVarString = decoder => {
437
474
  * @return {DataView}
438
475
  */
439
476
  export const readFromDataView = (decoder, len) => {
440
- const dv = new DataView(decoder.arr.buffer, decoder.arr.byteOffset + decoder.pos, len)
477
+ const dv = subdataview(decoder.arr, decoder.pos, len)
441
478
  decoder.pos += len
442
479
  return dv
443
480
  }