@naturalcycles/js-lib 15.71.1 → 15.71.2

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.
@@ -450,6 +450,7 @@ export class LocalDate {
450
450
  return this.toISODate();
451
451
  }
452
452
  format(fmt) {
453
+ // oxlint-disable-next-line no-restricted-globals
453
454
  if (fmt instanceof Intl.DateTimeFormat) {
454
455
  return fmt.format(this.toDate());
455
456
  }
@@ -647,6 +647,7 @@ export class LocalTime {
647
647
  return this.unix;
648
648
  }
649
649
  format(fmt) {
650
+ // oxlint-disable-next-line no-restricted-globals
650
651
  if (fmt instanceof Intl.DateTimeFormat) {
651
652
  return fmt.format(this.$date);
652
653
  }
@@ -862,6 +863,7 @@ class LocalTimeFactory {
862
863
  isTimezoneValid(tz) {
863
864
  if (tz === 'UTC')
864
865
  return true; // we deliberately consider UTC a valid timezone, while it's mostly used in testing
866
+ // oxlint-disable-next-line no-restricted-globals
865
867
  return Intl.supportedValuesOf('timeZone').includes(tz);
866
868
  }
867
869
  sort(items, dir = 'asc', opt = {}) {
package/dist/intl/intl.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { _Memo } from '../decorators/memo.decorator.js';
3
+ // oxlint-disable no-restricted-globals
3
4
  /**
4
5
  * Returns cached Intl.* formatters, because they are known to be
5
6
  * very slow to create.
@@ -113,6 +113,8 @@ export function _filterObject(obj, predicate, opt = {}) {
113
113
  }
114
114
  return obj;
115
115
  }
116
+ // Not vulnerable to prototype pollution: writes to a new {}, where __proto__
117
+ // assignment only changes the new object's prototype, not Object.prototype.
116
118
  const r = {};
117
119
  for (const [k, v] of _objectEntries(obj)) {
118
120
  if (predicate(k, v, obj)) {
@@ -133,6 +135,8 @@ export function _filterObject(obj, predicate, opt = {}) {
133
135
  * To skip some key-value pairs - use _mapObject instead.
134
136
  */
135
137
  export function _mapValues(obj, mapper, opt = {}) {
138
+ // Not vulnerable to prototype pollution: writes to a new {} (or mutates the
139
+ // source in-place where own data properties shadow the __proto__ accessor).
136
140
  const map = opt.mutate ? obj : {};
137
141
  for (const [k, v] of Object.entries(obj)) {
138
142
  map[k] = mapper(k, v, obj);
@@ -148,6 +152,8 @@ export function _mapValues(obj, mapper, opt = {}) {
148
152
  * To skip some key-value pairs - use _mapObject instead.
149
153
  */
150
154
  export function _mapKeys(obj, mapper) {
155
+ // Not vulnerable to prototype pollution: writes to a new {}, where __proto__
156
+ // assignment only changes the new object's prototype, not Object.prototype.
151
157
  const map = {};
152
158
  for (const [k, v] of Object.entries(obj)) {
153
159
  map[mapper(k, v, obj)] = v;
@@ -171,6 +177,8 @@ export function _mapKeys(obj, mapper) {
171
177
  * Non-string keys are passed via String(...)
172
178
  */
173
179
  export function _mapObject(obj, mapper) {
180
+ // Not vulnerable to prototype pollution: writes to a new {}, where __proto__
181
+ // assignment only changes the new object's prototype, not Object.prototype.
174
182
  const map = {};
175
183
  for (const [k, v] of Object.entries(obj)) {
176
184
  const r = mapper(k, v, obj);
@@ -204,6 +212,8 @@ export function _deepCopy(o, reviver) {
204
212
  * otherwise it's not worth it (use normal object spread then).
205
213
  */
206
214
  export function _mergeObjects(obj1, obj2) {
215
+ // Not vulnerable to prototype pollution: writes to a new {}, where __proto__
216
+ // assignment only changes the new object's prototype, not Object.prototype.
207
217
  const map = {};
208
218
  for (const k of Object.keys(obj1))
209
219
  map[k] = obj1[k];
@@ -259,6 +269,8 @@ export function _merge(target, ...sources) {
259
269
  if (!_isObject(source))
260
270
  continue;
261
271
  for (const key of Object.keys(source)) {
272
+ if (key === '__proto__' || key === 'constructor' || key === 'prototype')
273
+ continue;
262
274
  if (_isObject(source[key])) {
263
275
  ;
264
276
  target[key] ||= {};
@@ -284,6 +296,9 @@ export function _deepTrim(o) {
284
296
  return o.trim();
285
297
  }
286
298
  if (typeof o === 'object') {
299
+ // Not vulnerable to prototype pollution: mutates in-place on the same object.
300
+ // If __proto__ is an own data property (e.g. from JSON.parse), reads and writes
301
+ // go through the own property, not the Object.prototype accessor.
287
302
  for (const k of Object.keys(o)) {
288
303
  o[k] = _deepTrim(o[k]);
289
304
  }
@@ -301,6 +316,9 @@ export function _unset(obj, prop) {
301
316
  return;
302
317
  }
303
318
  const segs = prop.split('.');
319
+ // Prevent prototype pollution
320
+ if (segs.includes('__proto__') || segs.includes('constructor'))
321
+ return;
304
322
  let last = segs.pop();
305
323
  while (segs.length && segs[segs.length - 1].endsWith('\\')) {
306
324
  last = segs.pop().slice(0, -1) + '.' + last;
@@ -363,6 +381,10 @@ export function _set(obj, path, value) {
363
381
  else if (!path.length) {
364
382
  return obj;
365
383
  }
384
+ // Prevent prototype pollution
385
+ if (path.includes('__proto__') || path.includes('constructor')) {
386
+ return obj;
387
+ }
366
388
  // oxlint-disable-next-line unicorn/no-array-reduce
367
389
  ;
368
390
  path.slice(0, -1).reduce((a, c, i) => Object(a[c]) === a[c] // Does the key exist and is its value an object?
@@ -410,6 +432,8 @@ export function _has(obj, path) {
410
432
  * Based on: https://github.com/substack/deep-freeze/blob/master/index.js
411
433
  */
412
434
  export function _deepFreeze(o) {
435
+ // Not vulnerable to prototype pollution: read-only traversal, only calls
436
+ // Object.freeze — never assigns properties from one object to another.
413
437
  Object.freeze(o);
414
438
  Object.getOwnPropertyNames(o).forEach(prop => {
415
439
  if (o.hasOwnProperty(prop) &&
@@ -61,6 +61,5 @@ function decamelize(s) {
61
61
  function escapeStringRegexp(s) {
62
62
  // Escape characters with special meaning either inside or outside character sets.
63
63
  // Use a simple backslash escape when it’s always valid, and a `\xnn` escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar.
64
- // oxlint-disable-next-line unicorn/escape-case, unicorn/no-hex-escape
65
64
  return s.replaceAll(/[|\\{}()[\]^$+*?.]/g, String.raw `\$&`).replaceAll('-', String.raw `\x2d`);
66
65
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@naturalcycles/js-lib",
3
3
  "type": "module",
4
- "version": "15.71.1",
4
+ "version": "15.71.2",
5
5
  "dependencies": {
6
6
  "tslib": "^2"
7
7
  },
@@ -532,6 +532,7 @@ export class LocalDate {
532
532
  }
533
533
 
534
534
  format(fmt: Intl.DateTimeFormat | LocalDateFormatter): string {
535
+ // oxlint-disable-next-line no-restricted-globals
535
536
  if (fmt instanceof Intl.DateTimeFormat) {
536
537
  return fmt.format(this.toDate())
537
538
  }
@@ -778,6 +778,7 @@ export class LocalTime {
778
778
  }
779
779
 
780
780
  format(fmt: Intl.DateTimeFormat | LocalTimeFormatter): string {
781
+ // oxlint-disable-next-line no-restricted-globals
781
782
  if (fmt instanceof Intl.DateTimeFormat) {
782
783
  return fmt.format(this.$date)
783
784
  }
@@ -1009,6 +1010,7 @@ class LocalTimeFactory {
1009
1010
  */
1010
1011
  isTimezoneValid(tz: string): boolean {
1011
1012
  if (tz === 'UTC') return true // we deliberately consider UTC a valid timezone, while it's mostly used in testing
1013
+ // oxlint-disable-next-line no-restricted-globals
1012
1014
  return Intl.supportedValuesOf('timeZone').includes(tz)
1013
1015
  }
1014
1016
 
package/src/intl/intl.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { _Memo } from '../decorators/memo.decorator.js'
2
2
  import type { IANATimezone } from '../types.js'
3
3
 
4
+ // oxlint-disable no-restricted-globals
5
+
4
6
  /**
5
7
  * Returns cached Intl.* formatters, because they are known to be
6
8
  * very slow to create.
@@ -153,6 +153,8 @@ export function _filterObject<T extends AnyObject>(
153
153
  return obj
154
154
  }
155
155
 
156
+ // Not vulnerable to prototype pollution: writes to a new {}, where __proto__
157
+ // assignment only changes the new object's prototype, not Object.prototype.
156
158
  const r = {} as T
157
159
  for (const [k, v] of _objectEntries(obj)) {
158
160
  if (predicate(k, v, obj)) {
@@ -178,6 +180,8 @@ export function _mapValues<OUT = unknown, IN extends AnyObject = AnyObject>(
178
180
  mapper: ObjectMapper<IN, any>,
179
181
  opt: MutateOptions = {},
180
182
  ): OUT {
183
+ // Not vulnerable to prototype pollution: writes to a new {} (or mutates the
184
+ // source in-place where own data properties shadow the __proto__ accessor).
181
185
  const map: any = opt.mutate ? obj : {}
182
186
  for (const [k, v] of Object.entries(obj)) {
183
187
  map[k] = mapper(k, v, obj)
@@ -194,6 +198,8 @@ export function _mapValues<OUT = unknown, IN extends AnyObject = AnyObject>(
194
198
  * To skip some key-value pairs - use _mapObject instead.
195
199
  */
196
200
  export function _mapKeys<T extends AnyObject>(obj: T, mapper: ObjectMapper<T, string>): T {
201
+ // Not vulnerable to prototype pollution: writes to a new {}, where __proto__
202
+ // assignment only changes the new object's prototype, not Object.prototype.
197
203
  const map = {} as T
198
204
  for (const [k, v] of Object.entries(obj)) {
199
205
  map[mapper(k, v, obj) as keyof T] = v
@@ -221,6 +227,8 @@ export function _mapObject<OUT = unknown, IN extends AnyObject = AnyObject>(
221
227
  obj: IN,
222
228
  mapper: ObjectMapper<IN, KeyValueTuple<string, any> | typeof SKIP>,
223
229
  ): OUT {
230
+ // Not vulnerable to prototype pollution: writes to a new {}, where __proto__
231
+ // assignment only changes the new object's prototype, not Object.prototype.
224
232
  const map: any = {}
225
233
  for (const [k, v] of Object.entries(obj)) {
226
234
  const r = mapper(k, v, obj)
@@ -260,6 +268,8 @@ export function _deepCopy<T>(o: T, reviver?: Reviver): T {
260
268
  * otherwise it's not worth it (use normal object spread then).
261
269
  */
262
270
  export function _mergeObjects<T>(obj1: StringMap<T>, obj2: StringMap<T>): StringMap<T> {
271
+ // Not vulnerable to prototype pollution: writes to a new {}, where __proto__
272
+ // assignment only changes the new object's prototype, not Object.prototype.
263
273
  const map: StringMap<T> = {}
264
274
  for (const k of Object.keys(obj1)) map[k] = obj1[k]
265
275
  for (const k of Object.keys(obj2)) map[k] = obj2[k]
@@ -316,6 +326,8 @@ export function _merge<T extends AnyObject>(target: T, ...sources: any[]): T {
316
326
  if (!_isObject(source)) continue
317
327
 
318
328
  for (const key of Object.keys(source)) {
329
+ if (key === '__proto__' || key === 'constructor' || key === 'prototype') continue
330
+
319
331
  if (_isObject(source[key])) {
320
332
  ;(target as any)[key] ||= {}
321
333
  _merge(target[key], source[key])
@@ -340,6 +352,9 @@ export function _deepTrim<T extends AnyObject | string>(o: T): T {
340
352
  return o.trim() as T
341
353
  }
342
354
  if (typeof o === 'object') {
355
+ // Not vulnerable to prototype pollution: mutates in-place on the same object.
356
+ // If __proto__ is an own data property (e.g. from JSON.parse), reads and writes
357
+ // go through the own property, not the Object.prototype accessor.
343
358
  for (const k of Object.keys(o)) {
344
359
  o[k] = _deepTrim(o[k])
345
360
  }
@@ -361,6 +376,10 @@ export function _unset<T extends AnyObject>(obj: T, prop: string): void {
361
376
  }
362
377
 
363
378
  const segs = prop.split('.')
379
+
380
+ // Prevent prototype pollution
381
+ if (segs.includes('__proto__') || segs.includes('constructor')) return
382
+
364
383
  let last = segs.pop()
365
384
  while (segs.length && segs[segs.length - 1]!.endsWith('\\')) {
366
385
  last = segs.pop()!.slice(0, -1) + '.' + last
@@ -431,6 +450,11 @@ export function _set<T extends AnyObject>(obj: T, path: PropertyPath, value: any
431
450
  return obj as any
432
451
  }
433
452
 
453
+ // Prevent prototype pollution
454
+ if ((path as any[]).includes('__proto__') || (path as any[]).includes('constructor')) {
455
+ return obj
456
+ }
457
+
434
458
  // oxlint-disable-next-line unicorn/no-array-reduce
435
459
  ;(path as any[]).slice(0, -1).reduce(
436
460
  (
@@ -487,6 +511,8 @@ export function _has<T extends AnyObject>(obj: T, path: string): boolean {
487
511
  * Based on: https://github.com/substack/deep-freeze/blob/master/index.js
488
512
  */
489
513
  export function _deepFreeze(o: any): void {
514
+ // Not vulnerable to prototype pollution: read-only traversal, only calls
515
+ // Object.freeze — never assigns properties from one object to another.
490
516
  Object.freeze(o)
491
517
 
492
518
  Object.getOwnPropertyNames(o).forEach(prop => {
@@ -102,6 +102,5 @@ function decamelize(s: string): string {
102
102
  function escapeStringRegexp(s: string): string {
103
103
  // Escape characters with special meaning either inside or outside character sets.
104
104
  // Use a simple backslash escape when it’s always valid, and a `\xnn` escape when the simpler form would be disallowed by Unicode patterns’ stricter grammar.
105
- // oxlint-disable-next-line unicorn/escape-case, unicorn/no-hex-escape
106
105
  return s.replaceAll(/[|\\{}()[\]^$+*?.]/g, String.raw`\$&`).replaceAll('-', String.raw`\x2d`)
107
106
  }