Vulnerabilidades del Sistema de Navegación
Clase 3 de 5 • Taller de Secretos Ocultos de JavaScript: Protección de Clases y Objetos
Contenido del curso
Clase 3 de 5 • Taller de Secretos Ocultos de JavaScript: Protección de Clases y Objetos
Bramucci Candela
Juan Castro
Bramucci Candela
Juan Castro
Miguel Ángel Torres Vargas
Juan Castro
CRISTIAN DARIO AGUDELO PORRAS
Andre Huaman Yovera
Dayane Coronado Guzmán
Francisco Arturo Leon Velasco
Andrés Schuster
luis carlos rojano vergara
Jorge Méndez Ortega
Paula Inés Cudicio
Juan Castro
Paula Inés Cudicio
Harold Zurita Simon
Daniel Carmona
Jacobo Burbano
Mauricio Carrasco
Frandel Corporan Rodríguez
Octavio Villavicencio Cruz
El dolor que sentí al no poder usar private fields :,)
X2, esa iba a ser la solución oficial original Muy pronto podremos!!
:eyes:
Clases que pueden ayudarte a solucionar este desafío:
Me dolio la cabeza pero hice 3 soluciones, la cual una de ellas me deja pensando en el proceso:
#_spaceShipKey; y los llamamos respectivamente this.#_spaceShipKey; Funciona PERO no funciona en el simulador de platzi, ya que desactivaron estas reglas.export function simulador(astronaut, spaceShip, direction) { astronaut.navigate(spaceShip, direction); return spaceShip._movements; } export class Astronaut { // Private #_spaceShipKey; constructor({ name }) { this.name = name; } setAccessKey(accessKey) { this.#_spaceShipKey = accessKey; } navigate(spaceShip, direction) { spaceShip.navigator(direction, { accessKey: this.#_spaceShipKey }); } } export class SpaceShip { // Private #_key; constructor({ key }) { this.#_key = key; this._movements = []; } getAccessKey(astronaut) { const isAstronaut = astronaut instanceof Astronaut; if (isAstronaut) { astronaut.setAccessKey(this.#_key); } } navigator(direction, { accessKey }) { if (this.#_key == accessKey) { this._movements.push(direction) } else { this._movements.push("Incorrect Access Key"); } } }
export class Astronaut { constructor({ name }) { this.name = name; let _spaceShipKey; this.setAccessKey = (accessKey) => _spaceShipKey = accessKey; this.getAccessKey = () => _spaceShipKey; } navigate(spaceShip, direction) { spaceShip.navigator(direction, this); } } export class SpaceShip { constructor({ key }) { this._key = key; this._movements = []; } getAccessKey(astronaut) { if (astronaut instanceof Astronaut) { astronaut.setAccessKey(this._key); } } navigator(direction, astronaut) { if (astronaut instanceof Astronaut && this._key === astronaut.getAccessKey()) { this._movements.push(direction) } else { this._movements.push("Incorrect Access Key"); } } } export function simulador(astronaut, spaceShip, direction) { astronaut.navigate(spaceShip, direction); return spaceShip._movements; }
Object.defineProperty como se menciona en el rescurso de los comentarios se llega a definir la clase y sus atributos de una manera privada para que no se lea su contendio sino que se defina solo cuando es necesarioexport class Astronaut { constructor({ name }) { this.name = name; this._spaceShipKey; Object.defineProperty(this, '_spaceShipKey', { value: undefined, writable: false, enumerable: false, configurable: false }); } setAccessKey(accessKey) { this._spaceShipKey = accessKey; } navigate(spaceShip, direction) { spaceShip.navigator(direction, this); } } export class SpaceShip { constructor({ key }) { Object.defineProperty(this, '_key', { value: key, writable: false, enumerable: false, configurable: false }); this._movements = []; } getAccessKey(astronaut) { if (astronaut instanceof Astronaut) { astronaut.setAccessKey(this._key); } } navigator(direction, astronaut) { if (astronaut instanceof Astronaut && this._key === astronaut._spaceShipKey) { this._movements.push(direction) } else { this._movements.push("Incorrect Access Key"); } } } export function simulador(astronaut, spaceShip, direction) { astronaut.navigate(spaceShip, direction); return spaceShip._movements; }
Pero (Y aqui viene la pregunta), Veo que si se define en el constructor o en el metodo el Object.defineProperty no aplicara en la gran mayoria de casos su funcion y hay que sacarlo para medio "hackiar", el proceso, pero aun asi siguien siendo largo el proceso, algo similar a:
... ... export function simulador(astronaut, spaceShip, direction) { astronaut.navigate(spaceShip, direction); return spaceShip._movements; } Object.defineProperty(Astronaut.prototype, "_spaceShipKey", { writable: false, configurable: false, enumerable: false, value: undefined, }); Object.defineProperty(Astronaut.prototype, "setAccessKey", { writable: false, configurable: false, enumerable: false, value: function (accessKey) { Object.defineProperty(this, "_spaceShipKey", { writable: true, configurable: false, enumerable: false, value: accessKey, }); }, });
pero no aplica para key ya que adentro es diferente su funcion.
La pregunta despues de todo es:
Como usar Object.defineProperty para que funcione en todos los casos.
Igual (si llega a funcionar con Object.defineProperty, en platzi me deja el ultimo (Capitán Impostor) con la informacion correcta como si las pruebas no fueran unitarias de todo si no en conjunto), vease esto presionando varias veces los botones en Vista.
Gracias por su tiempo y disculpen la extensión del post.
Las 3 soluciones que propones están excelentes. Exactamente así imaginamos el código con el que se resolvería el problema.
En efecto, los private fields son muy divertidos y cómodos de usar, aunque todavía no tengan buen soporte.
Programar todo desde el constructor para trabajar con variables locales funciona, aunque todo el código quede un poco "apeñuscado".
Y defineProperty definitivamente es lo más parecido que tenemos a hackear JavaScript para evitar completamente el acceso y modificación a nuestras propiedades, aunque llega incluso a ser demasiada protección, a veces no es tan conveniente.
Gracias por el aporte, ya que en el curso no se explico el uso del __ # __ para definir la privacidad usando la sintaxis de class , ya que intentando con .defineProperty y con get&set no me fue posible dar solucion al problema!!
Para solucionar el problema de seguridad en la navegación de la nave espacial, debes abordar las vulnerabilidades identificadas. En el código proporcionado, hay dos vulnerabilidades principales: .
_spaceShipKey del Capitán DC._key de la nave espacial..
Para abordar la primera vulnerabilidad, debes asegurarte de que la propiedad _spaceShipKey del Capitán DC no sea accesible para otros astronautas. Puedes lograrlo haciendo la siguiente modificación en el código:
export class Astronaut { constructor({ name }) { this.name = name; this._spaceShipKey = undefined; } setAccessKey(accessKey) { if (!this._spaceShipKey) { // Agrega esta verificación para evitar reemplazar la llave existente this._spaceShipKey = accessKey; } } navigate(spaceShip, direction) { spaceShip.navigator(direction, { accessKey: this._spaceShipKey }); } }
Con esta modificación, el Capitán DC solo puede establecer su llave de acceso una vez. Si se intenta establecer nuevamente, se ignorará la nueva llave.
.
Para abordar la segunda vulnerabilidad, debes asegurarte de que no se pueda acceder ni modificar directamente la propiedad _key de la nave espacial. Puedes lograrlo mediante el uso de una técnica llamada "encapsulación" o "protección de acceso" en JavaScript. Modifica el constructor de la clase SpaceShip y define una función getKey() para acceder a la llave:
export class SpaceShip { constructor({ key }) { let _key = key; // Utiliza una variable local para almacenar la llave this.getKey = () => { return _key; }; this._movements = []; } getAccessKey(astronaut) { const isAstronaut = astronaut instanceof Astronaut; if (isAstronaut) { astronaut.setAccessKey(this.getKey()); } } navigator(direction, { accessKey }) { if (this.getKey() === accessKey) { this._movements.push(direction); } else { this._movements.push("Incorrect Access Key"); } } }
Con esta modificación, la propiedad _key de la nave espacial se vuelve inaccesible directamente desde fuera de la clase, y solo se puede obtener a través de la función getKey(). Esto evita la clonación no autorizada de la llave de acceso.
.
Una vez realizadas estas modificaciones, el código debería ser más seguro y las vulnerabilidades identificadas estarán mitigadas.
Gracias por tu información me ayudo a entender mejor como solucionar la segunda vulnerabilidad del ejercicio. Excelente explicación para tu solución.
function simulador(astronaut, spaceShip, direction) { astronaut.navigate(spaceShip, direction); return spaceShip._movements; } class Astronaut { #_spaceShipKey constructor({ name }) { this.name = name; this.#_spaceShipKey = undefined; } setAccessKey(accessKey) { this.#_spaceShipKey = accessKey; } navigate(spaceShip, direction) { spaceShip.navigator(direction, { accessKey: this.#_spaceShipKey }); } } class SpaceShip { #_key constructor({ key }) { this.#_key = key; this._movements = []; } getAccessKey(astronaut) { const isAstronaut = astronaut instanceof Astronaut; if (isAstronaut) { astronaut.setAccessKey(this.#_key); } } navigator(direction, { accessKey }) { if (this.#_key == accessKey) { this._movements.push(direction) } else { this._movements.push("Incorrect Access Key"); } } }
export function simulador(astronaut, spaceShip, direction) { astronaut.navigate(spaceShip, direction); return spaceShip.movements; } export class Astronaut { constructor({ name }) { this.name = name; this._spaceShipKey = undefined; } set spaceShipKey(key) { if (this._spaceShipKey === undefined) { this._spaceShipKey = key; } } navigate(spaceShip, direction) { spaceShip.navigator(direction, { astronaut: this }); } } export class SpaceShip { constructor({ key }) { this._key = key; this._movements = []; this._astronauts = []; } get movements() { return this._movements; } get astronauts() { return this._astronauts; } addAstronaut(astronaut) { const isAstronaut = astronaut instanceof Astronaut; if (isAstronaut) { this._astronauts.push(astronaut); } } getAccessKey(astronaut) { const isAstronaut = astronaut instanceof Astronaut; if (isAstronaut) { astronaut.spaceShipKey = this._key; this.addAstronaut(astronaut); // Agregar astronauta a la lista de astronautas a bordo de la nave } } navigator(direction, { astronaut }) { const isAstronautAccessKeyValid = this._astronautAccessKeyValid(astronaut); if (isAstronautAccessKeyValid) { this._movements.push(direction); } else { this._movements.push("Incorrect Access Key"); } } _astronautAccessKeyValid(astronaut) { return this._astronauts.some(a => a === astronaut && a._spaceShipKey === this._key); } }
Propuesta aprovechando el closure en el constructor.
export function simulador(astronaut, spaceShip, direction) { astronaut.navigate(spaceShip, direction); return spaceShip._movements; } export class Astronaut { constructor({ name }) { this.name = name; let _spaceShipKey = undefined; this.setAccessKey = function (accessKey) { _spaceShipKey = accessKey; } this.navigate = function(spaceShip, direction) { spaceShip.navigator(direction, { accessKey: _spaceShipKey }); } } } export class SpaceShip { constructor({ key }) { let _key = key; this._movements = []; this.getAccessKey = function(astronaut) { const isAstronaut = astronaut instanceof Astronaut; if (isAstronaut) { astronaut.setAccessKey(_key); } } this.navigator = function (direction, { accessKey }) { if (_key == accessKey) { this._movements.push(direction) } else { this._movements.push("Incorrect Access Key"); } } } }
genial interesante, pero el capitán podrá mantener el rumbo
Ya esta!! y ahora?? jajaja no me deja seguir a la siguiente clase, es normal? lo van cargando de a poco??
Muy buena modalidad! me encantó!
Puedes entrar a esta clase, Paula...? https://platzi.com/clases/5943-secretos-javascript/58541-estabilicemos-el-motor/
Gracias!!!
Solución 😄..
export function simulador(astronaut, spaceShip, direction) { astronaut.navigate(spaceShip, direction); return spaceShip._movements; } export class Astronaut { constructor({ name }) { this.name = name; this.private = { _spaceShipKey: undefined }; } setAccessKey(accessKey) { this.private["_spaceShipKey"] = accessKey; } navigate(spaceShip, direction) { spaceShip.navigator(direction, { accessKey: this.private["_spaceShipKey"] }); } } export class SpaceShip { constructor({ key }) { this.private = { _key: key }; this._movements = []; } getAccessKey(astronaut) { const isAstronaut = astronaut instanceof Astronaut; if (isAstronaut) { astronaut.setAccessKey(this.private["_key"]); } } navigator(direction, { accessKey }) { if (this.private["_key"] == accessKey) { this._movements.push(direction) } else { this._movements.push("Incorrect Access Key"); } } }
Estan buenos estos ejercicios!
Usando el método estático defineProperty
export class Astronaut { constructor({ name }) { this.name = name; let _spaceShipKey = undefined; Object.defineProperty(this, 'accessKey', { get(){return _spaceShipKey}, set (accessKey){_spaceShipKey = accessKey} }) } navigate(spaceShip, direction) { spaceShip.navigator(direction, {accessKey : this.accessKey}); } }
Solución con namespaces:
export function simulador(astronaut, spaceShip, direction) { astronaut.navigate(spaceShip, direction); return spaceShip._movements; } export class Astronaut { constructor({ name }) { this.name = name; // this._spaceShipKey = undefined; this.private = { _spaceShipKey: undefined }; } setAccessKey(accessKey) { this.private["_spaceShipKey"] = accessKey; } navigate(spaceShip, direction) { spaceShip.navigator(direction, { accessKey: this.private["_spaceShipKey"], }); } } export class SpaceShip { constructor({ key }) { this.private = { _key: key, _movements: [], }; } getAccessKey(astronaut) { const isAstronaut = astronaut instanceof Astronaut; if (isAstronaut) { astronaut.setAccessKey(this.private["_key"]); } } get _movements() { return this.private["_movements"]; } navigator(direction, { accessKey }) { if (this.private["_key"] == accessKey) { this.private["_movements"].push(direction); } else { this.private["_movements"].push("Incorrect Access Key"); } } }
Sistema de navegacion arreglado ahora a culpar a capitan DC porque el es el impostor jajaja
export function simulador(astronaut, spaceShip, direction) { astronaut.navigate(spaceShip, direction); return spaceShip._movements; } export class Astronaut { constructor({ name }) { this.name = name; this.private = { _spaceShipKey: undefined } } setAccessKey(accessKey) { this.private["_spaceShipKey"] = accessKey; } navigate(spaceShip, direction) { spaceShip.navigator(direction, { accessKey: this.private["_spaceShipKey"] }); } } export class SpaceShip { constructor({ key }) { this.private={ _key: key } this._movements = []; } getAccessKey(astronaut) { const isAstronaut = astronaut instanceof Astronaut; if (isAstronaut) { astronaut.setAccessKey(this.private["_key"]); } } navigator(direction, { accessKey }) { if (this.private["_key"] == accessKey) { this._movements.push(direction) } else { this._movements.push("Incorrect Access Key"); } } }
el poder de un gato "#"