¿Es una mala práctica usar `with` con Proxies?

8

En primer lugar, quiero aclarar, sé que withestá en desuso , y usarlo generalmente es una mala práctica .

Sin embargo, mi pregunta es sobre un caso especial: usar un Proxyobjeto especial como parámetro de with.


Antecedentes

Estoy trabajando en un proyecto, donde tengo que limitar el acceso de un código al alcance global.

Un enfoque podría ser usar un bucle con eval, que crea variables constantes con el valor de undefinedpara cada propiedad del objeto global, pero eso parece aún peor que usar with, y no puede limitar el acceso a las variables creadas con lety const.

La idea

La idea es utilizar a Proxycomo argumento de with, cuyo ...

  • hastrap siempre regresa true, por lo tanto, no permite que ninguna búsqueda o tarea vaya más allá de la withdeclaración
  • gettrap funciona normalmente, excepto que arrojan ReferenceErrors cuando intentan acceder a una variable no existente (es decir, propiedad)
  • set la trampa funciona normalmente (o puede contener alguna lógica personalizada)
  • targetel objeto no tiene [[Prototype]](es decir, se creó con Object.create(null))
  • targetEl objeto tiene una @@unscopablespropiedad, con el valor de un objeto vacío, para permitir el alcance de cada propiedad

Entonces, algo como este código:

const scope = Object.create(null)
Object.assign(scope, {
  undefined,
  console,
  String,
  Number,
  Boolean,
  Array,
  Object,
  /* etc. */
  [Symbol.unscopables]: Object.create(null)
})

const scopeProxy = new Proxy(scope, {
  get: (obj, prop) => {
    if (prop in obj)
      return obj[prop]
    else
      throw new ReferenceError(`${prop} is not defined`)
  },
  set: Reflect.set,
  has: () => true
})

with(scopeProxy) {
  //Sandboxed code
  
  foo = Number('42')
  console.log(foo) //42
  
  try{
    console.log(scopeProxy) //Inaccessible
  }catch(e){
    console.error(e) //ReferenceError: scopeProxy is not defined
  }
}

Evitar contras

Hay varias contras enumeradas en la página de MDN sobre la withdeclaración , pero este uso elimina todas.

1. Rendimiento

  • El problema:

    Buscar identificadores que no sean miembros del withobjeto de parámetro de la declaración es menos eficaz.

  • Evitación:

    Ninguna búsqueda puede ir más allá del objeto de parámetro.

2. Ambigüedad

  • El problema:

    Es difícil decidir qué identificador se busca de aquellos con el mismo nombre.

  • Evitación:

    Todas las búsquedas y asignaciones recuperan o modifican la propiedad del objeto de parámetro.

3. compatibilidad hacia adelante

  • El problema:

    Las propiedades de los objetos de parámetros o sus prototipos pueden cambiar en el futuro.

  • Evitación:

    El objeto de parámetro está inicialmente vacío y no tiene prototipo, por lo tanto, ninguna propiedad puede cambiar.

Pregunta

El código anterior funciona perfectamente, y los contras enumerados en MDN no se aplican a esto.

Entonces, mi pregunta es:

¿Sigue siendo una mala práctica usar la withdeclaración, y si es así, cuáles son las desventajas de usarla en este caso?

FZs
fuente
Parece que lo que realmente quieres es ejecutar código dentro de un sandbox. Sí, un sandbox podría usar un proxy en su implementación, pero probablemente no debería escribirlo usted mismo.
Bergi
@ Bergi, sé que un mecanismo de sandbox debería ser más complicado que este, pero mi pregunta no es realmente si este sandbox es seguro y bueno, sino si usarlo de withesta manera es malo o no.
FZs
Bueno, todavía le impide usar el modo estricto y acceder a las propiedades a través de withun proxy todavía es bastante lento. Intentaría buscar una solución diferente para el problema subyacente, pero aparte de eso, solo lo está utilizando withcomo una herramienta que parece hacer lo que necesita.
Bergi

Respuestas:

1

Suena como el viejo tema de alcance léxico vs dinámico . En general, el alcance léxico es más seguro, pero en algunas situaciones el alcance dinámico tiene sentido, ya que simplifica mucho algunas soluciones. Diría que su ejemplo es uno de los casos, donde puede ser útil.

ceving
fuente