@stonyx/orm 0.3.2-alpha.55 → 0.3.2-alpha.56

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/dist/main.d.ts CHANGED
@@ -81,8 +81,23 @@ export default class Orm {
81
81
  * collection the request is ADDRESSED TO -- owners -- while being asked about
82
82
  * animals, and per #202's thesis it answers wrong in the granting direction.
83
83
  *
84
+ * OWN PROPERTIES ONLY. A bare `this.accessFiles[modelName]` walks the
85
+ * prototype chain, so `getAccess('constructor')` resolved `Object` and
86
+ * `getAccess('toString')` resolved `Object.prototype.toString` -- both
87
+ * callable, and the documented `predicate?.(request, ctx)` pattern then
88
+ * returned a TRUTHY value (`Object(request)` is the request), bypassing the
89
+ * `undefined`-means-deny contract entirely. Nothing in the ORM calls
90
+ * `getAccess` yet, so it was not exploitable as shipped -- but #207 takes the
91
+ * model name from the REQUEST BODY (`data.relationships.<key>.data.type`),
92
+ * which would have made a one-field body an authorization bypass. Guarded
93
+ * here at the read point rather than by constructing the map with a null
94
+ * prototype, because the field is public and reassignable and the guard has
95
+ * to hold whatever object it is holding.
96
+ *
84
97
  * @param modelName - Model name as declared and stored (kebab-case).
85
- * @returns The predicate, or `undefined` when the model has no access class.
98
+ * @returns The predicate, or `undefined` when no predicate could be resolved
99
+ * for that name. `undefined` is NOT "this model is unrestricted" -- see the
100
+ * note above. Treat it as deny.
86
101
  */
87
102
  getAccess(modelName: string): AccessFunction | undefined;
88
103
  startup(): Promise<void>;
package/dist/main.js CHANGED
@@ -187,10 +187,27 @@ export default class Orm {
187
187
  * collection the request is ADDRESSED TO -- owners -- while being asked about
188
188
  * animals, and per #202's thesis it answers wrong in the granting direction.
189
189
  *
190
+ * OWN PROPERTIES ONLY. A bare `this.accessFiles[modelName]` walks the
191
+ * prototype chain, so `getAccess('constructor')` resolved `Object` and
192
+ * `getAccess('toString')` resolved `Object.prototype.toString` -- both
193
+ * callable, and the documented `predicate?.(request, ctx)` pattern then
194
+ * returned a TRUTHY value (`Object(request)` is the request), bypassing the
195
+ * `undefined`-means-deny contract entirely. Nothing in the ORM calls
196
+ * `getAccess` yet, so it was not exploitable as shipped -- but #207 takes the
197
+ * model name from the REQUEST BODY (`data.relationships.<key>.data.type`),
198
+ * which would have made a one-field body an authorization bypass. Guarded
199
+ * here at the read point rather than by constructing the map with a null
200
+ * prototype, because the field is public and reassignable and the guard has
201
+ * to hold whatever object it is holding.
202
+ *
190
203
  * @param modelName - Model name as declared and stored (kebab-case).
191
- * @returns The predicate, or `undefined` when the model has no access class.
204
+ * @returns The predicate, or `undefined` when no predicate could be resolved
205
+ * for that name. `undefined` is NOT "this model is unrestricted" -- see the
206
+ * note above. Treat it as deny.
192
207
  */
193
208
  getAccess(modelName) {
209
+ if (!Object.hasOwn(this.accessFiles, modelName))
210
+ return undefined;
194
211
  return this.accessFiles[modelName];
195
212
  }
196
213
  async startup() {
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "stonyx-async",
5
5
  "stonyx-module"
6
6
  ],
7
- "version": "0.3.2-alpha.55",
7
+ "version": "0.3.2-alpha.56",
8
8
  "description": "",
9
9
  "main": "dist/index.js",
10
10
  "type": "module",
package/src/main.ts CHANGED
@@ -240,10 +240,27 @@ export default class Orm {
240
240
  * collection the request is ADDRESSED TO -- owners -- while being asked about
241
241
  * animals, and per #202's thesis it answers wrong in the granting direction.
242
242
  *
243
+ * OWN PROPERTIES ONLY. A bare `this.accessFiles[modelName]` walks the
244
+ * prototype chain, so `getAccess('constructor')` resolved `Object` and
245
+ * `getAccess('toString')` resolved `Object.prototype.toString` -- both
246
+ * callable, and the documented `predicate?.(request, ctx)` pattern then
247
+ * returned a TRUTHY value (`Object(request)` is the request), bypassing the
248
+ * `undefined`-means-deny contract entirely. Nothing in the ORM calls
249
+ * `getAccess` yet, so it was not exploitable as shipped -- but #207 takes the
250
+ * model name from the REQUEST BODY (`data.relationships.<key>.data.type`),
251
+ * which would have made a one-field body an authorization bypass. Guarded
252
+ * here at the read point rather than by constructing the map with a null
253
+ * prototype, because the field is public and reassignable and the guard has
254
+ * to hold whatever object it is holding.
255
+ *
243
256
  * @param modelName - Model name as declared and stored (kebab-case).
244
- * @returns The predicate, or `undefined` when the model has no access class.
257
+ * @returns The predicate, or `undefined` when no predicate could be resolved
258
+ * for that name. `undefined` is NOT "this model is unrestricted" -- see the
259
+ * note above. Treat it as deny.
245
260
  */
246
261
  getAccess(modelName: string): AccessFunction | undefined {
262
+ if (!Object.hasOwn(this.accessFiles, modelName)) return undefined;
263
+
247
264
  return this.accessFiles[modelName];
248
265
  }
249
266