cbor-extract 2.2.1 → 2.2.3

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.
Files changed (2) hide show
  1. package/package.json +8 -8
  2. package/src/extract.cpp +47 -21
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cbor-extract",
3
3
  "author": "Kris Zyp",
4
- "version": "2.2.1",
4
+ "version": "2.2.3",
5
5
  "description": "Node addon for string extraction for cbor-x",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -18,7 +18,7 @@
18
18
  "prebuild-libc": "prebuildify-platform-packages --tag-libc --target 24.14.0 && ENABLE_V8_FUNCTIONS=false prebuildify-platform-packages --platform-packages --napi --tag-libc --target 20.20.0",
19
19
  "prebuild-libc-alpine": "ENABLE_V8_FUNCTIONS=false prebuildify-cross --image alpine --tag-libc --napi --target 20.20.0",
20
20
  "publish-all": "cd prebuilds/darwin-x64 && npm publish --access public && cd ../darwin-arm64 && npm publish --access public && cd ../linux-x64 && npm publish --access public && cd ../linux-arm64 && npm publish --access public && cd ../linux-arm && npm publish --access public && cd ../.. && npm publish --access public",
21
- "test": "node ./index.js"
21
+ "test": "node ./index.js && node test/scan.cjs && node test/strings.cjs"
22
22
  },
23
23
  "main": "./index.js",
24
24
  "gypfile": true,
@@ -40,11 +40,11 @@
40
40
  "prebuildify-cross": "5.0.0"
41
41
  },
42
42
  "optionalDependencies": {
43
- "@cbor-extract/cbor-extract-darwin-arm64": "2.2.1",
44
- "@cbor-extract/cbor-extract-darwin-x64": "2.2.1",
45
- "@cbor-extract/cbor-extract-linux-arm": "2.2.1",
46
- "@cbor-extract/cbor-extract-linux-arm64": "2.2.1",
47
- "@cbor-extract/cbor-extract-linux-x64": "2.2.1",
48
- "@cbor-extract/cbor-extract-win32-x64": "2.2.1"
43
+ "@cbor-extract/cbor-extract-darwin-arm64": "2.2.3",
44
+ "@cbor-extract/cbor-extract-darwin-x64": "2.2.3",
45
+ "@cbor-extract/cbor-extract-linux-arm": "2.2.3",
46
+ "@cbor-extract/cbor-extract-linux-arm64": "2.2.3",
47
+ "@cbor-extract/cbor-extract-linux-x64": "2.2.3",
48
+ "@cbor-extract/cbor-extract-win32-x64": "2.2.3"
49
49
  }
50
50
  }
package/src/extract.cpp CHANGED
@@ -39,7 +39,24 @@ public:
39
39
  uint32_t stringStart = 0;
40
40
  uint32_t lastStringEnd = 0;
41
41
 
42
- void readString(napi_env env, uint32_t length, bool allowStringBlocks) {
42
+ // false with a RangeError pending when V8 rejects the string (longer than its maximum length)
43
+ bool createString(napi_env env, uint32_t start, uint32_t length, bool latin1, napi_value* value) {
44
+ napi_status status = latin1 ?
45
+ napi_create_string_latin1(env, (const char*) source + start, length, value) :
46
+ napi_create_string_utf8(env, (const char*) source + start, length, value);
47
+ if (status != napi_ok) {
48
+ napi_throw_range_error(env, NULL, "Unable to create a string from the buffer");
49
+ return false;
50
+ }
51
+ return true;
52
+ }
53
+ bool appendString(napi_env env, uint32_t start, uint32_t length, bool latin1) {
54
+ if (!createString(env, start, length, latin1, &target[writePosition]))
55
+ return false;
56
+ writePosition++;
57
+ return true;
58
+ }
59
+ bool readString(napi_env env, uint32_t length, bool allowStringBlocks) {
43
60
  uint32_t start = position;
44
61
  uint32_t end = position + length;
45
62
  if (allowStringBlocks) { // for larger strings, we don't bother to check every character for being latin, and just go right to creating a new string
@@ -54,40 +71,39 @@ public:
54
71
  if (position < end) {
55
72
  // non-latin character
56
73
  if (lastStringEnd) {
57
- napi_value value;
58
- napi_create_string_latin1(env, (const char*) source + stringStart, lastStringEnd - stringStart, &value);
59
- target[writePosition++] = value;
74
+ if (!appendString(env, stringStart, lastStringEnd - stringStart, true))
75
+ return false;
60
76
  lastStringEnd = 0;
61
77
  }
62
78
  // use standard utf-8 conversion
63
- napi_value value;
64
- napi_create_string_utf8(env, (const char*) source + start, (int) length, &value);
65
- target[writePosition++] = value;
79
+ if (!appendString(env, start, length, false))
80
+ return false;
66
81
  position = end;
67
- return;
82
+ return true;
68
83
  }
69
84
 
70
85
  if (lastStringEnd) {
71
86
  if (start - lastStringEnd > 40 || end - stringStart > 6000) {
72
- napi_value value;
73
- napi_create_string_latin1(env, (const char*) source + stringStart, lastStringEnd - stringStart, &value);
74
- target[writePosition++] = value;
87
+ if (!appendString(env, stringStart, lastStringEnd - stringStart, true))
88
+ return false;
75
89
  stringStart = start;
76
90
  }
77
91
  } else {
78
92
  stringStart = start;
79
93
  }
80
94
  lastStringEnd = end;
95
+ return true;
81
96
  }
82
97
  napi_value extractStrings(napi_env env, uint32_t startingPosition, uint32_t size, uint32_t firstStringSize, uint8_t* inputSource) {
83
98
  writePosition = 0;
84
99
  lastStringEnd = 0;
85
100
  position = startingPosition;
86
101
  source = inputSource;
87
- if (startingPosition + firstStringSize > size) {
102
+ if ((uint64_t)startingPosition + firstStringSize > size) {
88
103
  return unexpectedEnd(env);
89
104
  }
90
- readString(env, firstStringSize, firstStringSize < 0x100);
105
+ if (!readString(env, firstStringSize, firstStringSize < 0x100))
106
+ return NULL;
91
107
  while (position < size) {
92
108
  uint8_t token = source[position++];
93
109
  uint8_t majorType = token >> 5;
@@ -96,23 +112,23 @@ public:
96
112
  uint32_t length;
97
113
  switch (token) {
98
114
  case 0x18:
99
- if (position + 1 > size) {
115
+ if (size - position < 1) {
100
116
  return unexpectedEnd(env);
101
117
  }
102
118
  length = source[position++];
103
119
  break;
104
120
  case 0x19:
105
- if (position + 2 > size) {
121
+ if (size - position < 2) {
106
122
  return unexpectedEnd(env);
107
123
  }
108
124
  length = source[position++] << 8;
109
125
  length += source[position++];
110
126
  break;
111
127
  case 0x1a:
112
- if (position + 4 > size) {
128
+ if (size - position < 4) {
113
129
  return unexpectedEnd(env);
114
130
  }
115
- length = source[position++] << 24;
131
+ length = (uint32_t) source[position++] << 24;
116
132
  length += source[position++] << 16;
117
133
  length += source[position++] << 8;
118
134
  length += source[position++];
@@ -124,13 +140,16 @@ public:
124
140
  }
125
141
  if (majorType == 3) {
126
142
  // string
127
- if (length + position > size) {
143
+ if (length > size - position) {
128
144
  return unexpectedEnd(env);
129
145
  }
130
- readString(env, length, length < 0x100);
131
- if (writePosition >= MAX_TARGET_SIZE)
146
+ if (!readString(env, length, length < 0x100))
147
+ return NULL;
148
+ if (writePosition >= MAX_TARGET_SIZE - 1) // reserve slot for double-write
132
149
  break;
133
150
  } else { // binary data
151
+ if (length >= size - position) // a declared length that reaches the end ends the scan, and can't wrap position
152
+ break;
134
153
  position += length;
135
154
  }
136
155
 
@@ -153,7 +172,8 @@ public:
153
172
  }
154
173
  if (lastStringEnd) {
155
174
  napi_value value;
156
- napi_create_string_latin1(env, (const char*) source + stringStart, lastStringEnd - stringStart, &value);
175
+ if (!createString(env, stringStart, lastStringEnd - stringStart, true, &value))
176
+ return NULL;
157
177
  if (writePosition == 0) {
158
178
  return value;
159
179
  }
@@ -194,6 +214,12 @@ napi_value extractStrings(napi_env env, napi_callback_info info) {
194
214
  napi_throw_type_error(env, NULL, "Unexpected buffer type, expected a Buffer");
195
215
  return args[0];
196
216
  }
217
+ if (size > buffer_size || position > buffer_size) {
218
+ return unexpectedEnd(env);
219
+ }
220
+ // fixed-size skips advance by at most 8 past a position below size, so this keeps them from wrapping
221
+ if (size > UINT32_MAX - 8)
222
+ size = UINT32_MAX - 8;
197
223
  return extractor->extractStrings(env, position, size, firstStringSize, source);
198
224
  }
199
225
  #define EXPORT_NAPI_FUNCTION(name, func) { napi_property_descriptor desc = { name, 0, func, 0, 0, 0, (napi_property_attributes) (napi_writable | napi_configurable), 0 }; napi_define_properties(env, exports, 1, &desc); }