Ver Fonte

feat: purifyObj function

Sv443 há 1 mês atrás
pai
commit
5d71770
5 ficheiros alterados com 56 adições e 1 exclusões
  1. 5 0
      .changeset/long-apricots-wave.md
  2. 1 0
      README-summary.md
  3. 1 0
      README.md
  4. 39 0
      docs.md
  5. 10 1
      lib/misc.ts

+ 5 - 0
.changeset/long-apricots-wave.md

@@ -0,0 +1,5 @@
+---
+"@sv443-network/userutils": minor
+---
+
+Added function `purifyObj()` to remove an object's prototype chain (i.e. omit all inherited properties like `toString`, `__proto__`, etc.)

+ 1 - 0
README-summary.md

@@ -74,6 +74,7 @@ View the documentation of previous major releases:
     - [`consumeGen()`](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#consumegen) - consumes a ValueGen and returns the value
     - [`consumeStringGen()`](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#consumestringgen) - consumes a StringGen and returns the string
     - [`getListLength()`](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#getlistlength) - get the length of any object with a numeric `length`, `count` or `size` property
+    - [`purifyObj()`](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#purifyobj) - removes the prototype chain (all default properties like `toString`, `__proto__`, etc.) from an object
 - **Arrays:**
     - [`randomItem()`](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#randomitem) - returns a random item from an array
     - [`randomItemIndex()`](https://github.com/Sv443-Network/UserUtils/blob/main/docs.md#randomitemindex) - returns a tuple of a random item and its index from an array

+ 1 - 0
README.md

@@ -77,6 +77,7 @@ View the documentation of previous major releases:
     - [`consumeGen()`](./docs.md#consumegen) - consumes a ValueGen and returns the value
     - [`consumeStringGen()`](./docs.md#consumestringgen) - consumes a StringGen and returns the string
     - [`getListLength()`](./docs.md#getlistlength) - get the length of any object with a numeric `length`, `count` or `size` property
+    - [`purifyObj()`](./docs.md#purifyobj) - removes the prototype chain (all default properties like `toString`, `__proto__`, etc.) from an object
   - [**Arrays:**](./docs.md#arrays)
     - [`randomItem()`](./docs.md#randomitem) - returns a random item from an array
     - [`randomItemIndex()`](./docs.md#randomitemindex) - returns a tuple of a random item and its index from an array

+ 39 - 0
docs.md

@@ -66,6 +66,7 @@ For submitting bug reports or feature requests, please use the [GitHub issue tra
     - [`consumeGen()`](#consumegen) - consumes a ValueGen and returns the value
     - [`consumeStringGen()`](#consumestringgen) - consumes a StringGen and returns the string
     - [`getListLength()`](#getlistlength) - get the length of any object with a numeric `length`, `count` or `size` property
+    - [`purifyObj()`](#purifyobj) - removes the prototype chain (all default properties like `toString`, `__proto__`, etc.) from an object
   - [**Arrays:**](#arrays)
     - [`randomItem()`](#randomitem) - returns a random item from an array
     - [`randomItemIndex()`](#randomitemindex) - returns a tuple of a random item and its index from an array
@@ -2624,6 +2625,42 @@ getListLength({ foo: "bar" }, false); // NaN
 ```
 </details>
 
+<br>
+
+### purifyObj()
+Signature:  
+```ts
+purifyObj<TObj extends object>(obj: TObj): TObj
+```
+  
+Turns the passed object into a "pure" object without a prototype chain, meaning it won't have any default properties like `toString`, `__proto__`, `__defineGetter__`, etc.  
+This could be useful to prevent prototype pollution attacks or to clean up object literals, at the cost of being harder to work with in some cases.  
+It also effectively transforms a [`Stringifiable`](#stringifiable) value into one that will throw a TypeError when stringified instead of defaulting to `[object Object]`  
+  
+<details><summary><b>Example - click to view</b></summary>
+
+```ts
+import { purifyObj } from "@sv443-network/userutils";
+
+const impureObj = {
+  foo: "bar",
+};
+
+console.log(impureObj.toString);         // [Function: toString]
+console.log(impureObj.__proto__);        // { ... }
+console.log(impureObj.__defineGetter__); // [Function: __defineGetter__]
+console.log(`${impureObj}`);             // "[object Object]"
+
+
+const pureObj = purifyObj(impureObj);
+
+console.log(pureObj.toString);         // undefined
+console.log(pureObj.__proto__);        // undefined
+console.log(pureObj.__defineGetter__); // undefined
+console.log(`${pureObj}`);             // TypeError: Cannot convert object to string
+```
+</details>
+
 <br><br>
 
 <!-- #region Arrays -->
@@ -3318,6 +3355,8 @@ To be considered stringifiable, the object needs to have a `toString()` method t
 Most primitives have this method, but something like undefined or null does not.  
 Having this method allows not just explicit conversion by using `.toString()`, but also implicit conversion by passing it into the `String()` constructor or interpolating it in a template literal string.  
   
+To make an object explicitly *not stringifiable* (so it throws an error when being converted to a string), you can pass it to [`purifyObj()`](#purifyobj) to remove its prototype chain, including the `toString()` method.  
+  
 <details><summary><b>Example - click to view</b></summary>
 
 ```ts

+ 10 - 1
lib/misc.ts

@@ -123,7 +123,7 @@ export async function consumeGen<TValueType>(valGen: ValueGen<TValueType>): Prom
   return await (typeof valGen === "function"
     ? (valGen as (() => Promise<TValueType> | TValueType))()
     : valGen
-  )as TValueType;
+  ) as TValueType;
 }
 
 /**
@@ -165,3 +165,12 @@ export function getListLength(obj: ListWithLength, zeroOnInvalid = true): number
           ? 0
           : NaN;
 }
+
+/**
+ * Turns the passed object into a "pure" object without a prototype chain, meaning it won't have any default properties like `toString`, `__proto__`, `__defineGetter__`, etc.  
+ * This makes the object immune to prototype pollution attacks and allows for cleaner object literals, at the cost of being harder to work with in some cases.  
+ * It also effectively transforms a `Stringifiable` value into one that will throw a TypeError when stringified instead of defaulting to `[object Object]`
+ */
+export function purifyObj<TObj extends object>(obj: TObj): TObj {
+  return Object.assign(Object.create(null), obj);
+}