Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pre-compute all paths to functions in the provided exposedMethods object #2

Open
chriscalo opened this issue Jul 6, 2021 · 4 comments

Comments

@chriscalo
Copy link
Owner

Use Object.keys() to navigate all possible paths that point to a function.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys

@chriscalo
Copy link
Owner Author

chriscalo commented Jul 8, 2021

To accomplish this we might need the following functions:

function isPrimitiveOrBoxed(value) {}
function isCallable(value) {}
function getEntries(value) {}
  • function isPrimitiveOrBoxed(value) {}
  • function isCallable(value) {}
  • function getNonNativeEntries(value) {}

Once these work they could be assembled something like the following:

function* deepEntries(value) {
  if (isPrimitiveOrBoxed(value)) {
    return;
  }
  
  if (isCallable(value)) {
    // register path to callable
    yield { path: [], callable: value };
  }
  
  for (const [k, v] of getNonNativeEntries(value)) {
    for (const { path, callable } of deepEntries(v)) {
      yield { path: [k, ...path], callable };
    }
  }
}
  • start at the root value
  • ignore primitive and boxed primitive values
    • if value is nullish (null or undefined) => ignore and exit
    • if value is a boxed primitive => ignore and exit
    • if value is a primitive => ignore and exit
  • if value is a function:
    • if value is a class, it's constructible but not callable, so don't allow calling it, but consider it for digging into its keys
    • otherwise, make it available for calling
  • get all keys and recurse into each value
    • if value has keys (including objects, functions, etc), enumerate them
      • construct the prototype chain for the value
      • exclude any built-in prototype objects (Object.prototype, Array.prototype, Function.prototype, etc)
      • get all key–value pairs, considering that keys higher in the prototype chain shadow everything lower
    • recurse into each value and repeat this algorithm

Libraries for getting the prototype chain:

@chriscalo
Copy link
Owner Author

chriscalo commented Jul 8, 2021

Tests:

  • must work for plain objects: { foo() {} }
  • must work for nested objects: { foo: { bar() {} } }
  • must work for class instance methods: new class { foo() {} }
  • must work for static class methods: class { static foo() {} }
  • must not expose methods of built-ins like String, Array, Object
    • examples include constructor(), toString(), etc
  • must not expose non-callables (class functions or non-functions)

@chriscalo
Copy link
Owner Author

This is proving to be quite a heavy lift.

Instead, it might make sense to keep the logic the same as today, but layer in:

  • with each property access:
  • don't allow navigating to a primitive or boxed primitive
  • only allow calling callables (not just any function)
  • don't allow navigating to native / built-in prototypes

@chriscalo
Copy link
Owner Author

Maybe the simplest method is:

  • for each property access:
  • compute the prototype chain for the value whose properties are being accessed
  • check each value in the prototype chain for the property being accessed
  • if it's from a native prototype object, disallow access to the property
  • then retrieve the value for the property
  • disqualify the value if it's a primitive, boxed primitive, constructable, etc
  • at this point the value should either be a callable or an object
  • of we are trying to invoke it, ensure it's a callable first
  • otherwise, proceed with deeper property access

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant